dotNetChris @ Marisic.Net

March 15, 2010

Creating a common generic and extensible NHiberate Repository version 2

This is a follow up to my original post on this topic Creating a common generic and extensible NHiberate Repository and further progression of it taking advantage of DetachedCriterias and Future queries.

I’m going to start with my interface as a jumping off point.

public interface IRepository<T> { 
/// <summary>
/// Adds the specified <see cref="T"/>. 
/// </summary> 
/// <param name="obj">The obj.</param> 
void Add(T obj);  
/// <summary>  
/// Deletes the specified <see cref="T"/>. 
/// </summary> 
/// <param name="obj">The obj.</param> 
void Delete(T obj);  
/// <summary> 
/// Defers the detached crteria execution which will return a result set that is an <see cref="IEnumerable{T}"/>. 
/// </summary> 
/// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
IEnumerable<T> FutureList(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Executes the detached crteria immediately returning a single item <see cref="T"/>
/// This will also cause the execution of any defered queries to be executed. 
/// </summary> /// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
T FutureSingle(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Gets the specified <see cref="T"/>. 
/// </summary> 
/// <typeparam name="U"></typeparam> 
/// <param name="id">The id.</param>
 /// <returns></returns> 
T Get<U>(U id); 
/// <summary> 
/// Executes the detached crteria immediately returning a result set that is an <see cref="IList{T}"/>. 
/// This will also cause the execution of any defered queries to be executed. 
/// </summary> 
/// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
IList<T> QueryList(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Executes the detached crteria immediately returning a single item <see cref="T"/> 
/// </summary> 
/// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
T QuerySingle(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Inserts or updates the specified <see cref="T"/>. 
/// </summary>
/// <param name="obj">The obj.</param> 
void SaveOrUpdate(T obj); 
/// <summary> 
/// Updates the specified <see cref="T"/>. 
/// </summary> 
/// <param name="obj">The obj.</param>
 void Update(T obj); } 

I think my interface is very well defined and with the XMLDoc comments easy to follow what will be implemented. The most notable changes from my original post is the removal of the GetAll and GetRange methods that returned an ICriteria, these always felt like a kludge to me as they clearly bleed concern by allowing the raw ICriteria to be exposed however back then I didn’t have the tools and knowledge available to create a better solution.

The new methods are related to the DetachedCriterias QuerySingle, QueryList and to the Future based queries FutureSingle and FutureList. Future is a newer construct in NHibernate that allows you to specify a query that you want NHibernate to understand and know at some point in the Future it will need this execution so you can batch more than 1 query together and reduce the number of calls to a database. This is a great bonus as the database is usually always the biggest slow down in an application.

On to the actual implementation of the interface

public class Repository<T> : IRepository<T> { 
private readonly IBusinessConversation _conversation;

public Repository(IBusinessConversation conversation) { _conversation = conversation; } 

IList<T> IRepository<T>.QueryList(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).List<T>(); 
} 

T IRepository<T>.QuerySingle(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).UniqueResult<T>(); 
} 

T IRepository<T>.FutureSingle(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).FutureValue<T>().Value; 
} 

IEnumerable<T> IRepository<T>.FutureList(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).Future<T>(); 
} 

T IRepository<T>.Get<U>(U id) { return _conversation.Session.Get<T>(id); } 

void IRepository<T>.SaveOrUpdate(T obj) { _conversation.Session.SaveOrUpdate(obj); } 

void IRepository<T>.Add(T obj) { _conversation.Session.Save(obj); } 

void IRepository<T>.Update(T obj) { _conversation.Session.Update(obj); } 

void IRepository<T>.Delete(T businessObj) { _conversation.Session.Delete(businessObj); } } 

The one that might be confusing is the _conversation dependency this relates to another post Implementing NHibernate Long Conversation with no HttpModules or AOP build time weaving. You can take a look at this if you haven’t and are curious however it’s not needed to understand my code here as you can really view _conversation to be the raw NHibernate ISession and understand what is going on here.

This class houses the generic CRUD operations that are made generic to allow you to handle any custom object easily. The methods that are once again of interest are the ones I discussed as new additions to my Repository. The beauty of all them regardless is in their simplicity that they can all be written in 1 concise line yet offer immense flexibility.

With the QuerySingle and QueryList methods these allow you to take in a DetachedCriteria and get back either a single object or a IList collection which should be pretty self explanatory from both the code and method names.

The FutureList and FutureSingle are not so much as obvious. As I stated before these allow you to make these happen in the future. In my implementation only the FutureList will really allow you to relegate multiple events into the future but it also makes the most sense since individual lookups are frequently done by indexed columns that should be quick even done in multiple seperate calls. For each call you make to FutureList it will have NHibernate queue up the specified DetachedQuery and wait for one of the following either code causes any of IEnumerables returned to be enumerated which will fire off 1 mulit-query to get all of the result sets or you call FutureSingle.

FutureSingle is some what of a more unusual animal because a regular object doesn’t have the lazy access method that IEnumerables do either it exists, or it doesn’t. There is no transient stage as there is with IEnumerables. To overcome this fact the developers of NHibernate created this transient stage by wrapping object with a generic interface for IFutureValue<T> this gives a construct to have a 3rd stage that you need to call .Value to invoke the actual execution which will process all future queries. In my repository I actually call .Value immediately on a DetachedCriteria being passed into this, why? Because I’d need to return a IFutureValue<T> instead of just T as the result from the method. This in my opinion would be just as much of a kludge as returning ICriteria was from my previous implementation as it bleeds NHibernate understanding logic outside of the repository. This purely a subjective point and if you disagree with my sentiment you could easily return IFutureValue<T> and have a wider range of flexibility with the Future support.

Now on to actual usage of this in a real world scenario. I am going to be taking advantage of a framework I recently learned about called NHibernate Lambda Expressions this allows you to write Criteria and DetachedCriteria queries without the need to rely on magic strings. The point of this post won’t be to cover the usage of this as it should be mostly understandable for my example.

 public class DataProvider : IDataProvider {  
private readonly IRepository<Person> _personRepository;  

public DataProvider(IRepository<Person> personRepository) { _personRepository = personRepository; } 

public IList<Person> GetPersons(State state) { 
  var query = DetachedCriteria.For<Person>() 
 .CreateCriteria<Person>(x => x.PrimaryZip) 
 .CreateCriteria<Zip>(x => x.State) 
 .Add<State>(x => x.StateCode == state.StateCode);  
 return _personRepository.FutureList(query); 
} 

public Person GetPerson(Guid personID) {  return _personRepository.Get(personID); } } 

If you look at my GetPersons method you should see I have a somewhat deep object graph that is realistic, I have a collection of Persons in my database where I assign them a zip code object that contains among other things the zip code and the state that zip code lives in. I create a DetachedCriteria that lets me find all persons that exist in a state and I pass that down to my generic IRepository by delegation instead of inheritance. Many examples similar to my post use inheritance where you will inherit from Repository<Person> instead of having a delegate inside of a non generic class I feel this is the wrong way because it then limits you to having 1 repository per data object instead of being able to drop multiple IRepositorys inside of a single DataProvider.

Taking this a step further I can even remove the need to ever create a physical implementation of Repository<Person> through the use of an inversion of control / dependency injection framework in this case specifically StructureMap. In literally 1 line I can create an infinite amount of IRepositories for any application I need.

For(typeof (IRepository<>)).LifecycleIs(new HybridLifecycle()).Use(typeof (Repository<>)); 

This instructs StructureMap that anytime I need a IRepository<Person> or any other data object that it’s to give it a usage of Repository
completely absolving me of the responsibility of defining a Repository<Person> combining the functionality I’ve outlined in this post it offers a broad range of usage that allows you to interact with NHibernate without ever needing to write a single line of code again except the specific DetachedCriterias which will need written in one shape or form irregardless because they will have custom sql be the end result of them and to just wire up Methods to allow access to the underlying CRUD methods. You could actually expose the generic methods themselves however I feel that is exposing too much logic to be available to an API and prefer to shroud my generic repositories in the classes I call DataProviders as it also lets me group repositories in meaningful ways.

kick it on DotNetKicks.com

Shout it

BloggingContext.ApplicationInstance.CompleteRequest();

December 18, 2009

Implementing NHibernate Long Conversation with no HttpModules or AOP build time weaving

GIANT WARNING STICKER

This code is some major caveats to be taken when considered for production usage. If this would be used to solely power a shopping cart application it should work fine however if it will also govern the objects such as having administration functionality to update products etc it can lead to very inconsistent results due to users having the object in their first level cache (the ISession object) that you have modified and there seems to be no way to handle this correctly.

I have an open stack overflow question regarding this nature however there has been no positive feedback and even the direct NHibernate documents say “As the ISession is also the (mandatory) first-level cache and contains all loaded objects, we can propably use this strategy only for a few request/response cycles. This is indeed recommended, as the ISession will soon also have stale data.” So all in all it seems like a giant failure to attempt and after years worth of effort to solve this I have given up unless my SO thread is ever answered meaningful.

This post has been almost a year coming and it’s finally here. I still haven’t been posting much even being in the full swing of development, I just usually end up drained between work and overtime when I have years worth of development plans for my company that they would love to have all of them tomorrow. Fortunately my current employer is definitely is the best environment I’ve ever been in aside from that they give me all the tools I need to complete job they give me basically full reign on system architecture that I finally get to develop and put into production code I’ve worked off and on for over a year now. Also they have very realistic expectations that I’m not rushed to make poor decisions to push a product out the door that’s poorly designed. Now getting back on track.

It all started with Conversation Per Business Transaction using PostSharp and IoC written almost a year ago from today. This post at the time was definitely one of my largest successes in my development career however even though I solved the problem I wanted I still was not happy with the solution (probably because with PostSharp atleast back then my solution would take 5 minutes+ to build) still it was somewhat fragile for how I had to decorate classes with my [BusinessConversation] attributes that a nested method call would cause all hell to break loose.

To start I’m going to show you my final product, this is one of my model classes in the Model-View-Presenter software pattern

public class NotificationModel : INotificationModel
{
    private readonly INotificationProvider _NotificationProvider;

    public NotificationModel(INotificationProvider NotificationProvider)
    {
        _NotificationProvider = NotificationProvider;
    }

    [ConversationPersistance(ConversationCommitMode.Rollback)]
    public void AddButRollBack(NotifyRun notifyRun)
    {
        _NotificationProvider.Add(notifyRun);
    }

    public void Add(NotifyRun notifyRun)
    {
        _NotificationProvider.Add(notifyRun);
    }
}

As you can see on the AddAndRollBack method I do decorate the method with a custom attribute which does make my model somewhat aware of my implementation of my repository but I feel this is an acceptable pollution as it is reasonable to expect any method in the MVP pattern to know whether it’s role is to get data, save data or cancel an action. As you can see though the other method has no decoration and doesn’t require any decoration for the default action you configure.

Next I’m going to start with my inversion of control container, I use StructureMap however I believe this should also be able to be acheived using most other major DI frameworks.

private sealed class StructureMapRegistry : Registry
{
    public StructureMapRegistry()
    {
    //Configure default persisance mode
        ForRequestedType<ConversationCommitMode>().TheDefault.IsThis(ConversationCommitMode.Commit);

    //Castle DynamicProxy
        ForRequestedType<ProxyGenerator>().TheDefaultIsConcreteType<ProxyGenerator>()
      .CacheBy(InstanceScope.Singleton);

    //Castle DynamicProxy IInterceptor 
        ForRequestedType<ConversationInterceptor>().TheDefaultIsConcreteType<ConversationInterceptor>()
      .CacheBy(InstanceScope.Singleton);

     //Configuration wrapper of NH, this could be configured inline here but it's rather verbose
        ForRequestedType<INHibernateSessionManager>().TheDefaultIsConcreteType<NHibernateSessionManager>()
      .CacheBy(InstanceScope.Singleton);

    //This is a lightweight wrapper of the NH ISession that supports lazy access with the session
        ForRequestedType<IBusinessConversation>().TheDefaultIsConcreteType<LazyBusinessConversation>()
      .CacheBy(InstanceScope.HybridHttpSession);

    //This is my NH repository
        ForRequestedType<INotificationProvider>().TheDefaultIsConcreteType<NotificationProvider>()
      .CacheBy(InstanceScope.Hybrid);

    //This is a model class in the MVP pattern  that uses the above NH Provider
        ForRequestedType<INotificationModel>().TheDefaultIsConcreteType<NotificationModel>().CacheBy(InstanceScope.Hybrid)
            .EnrichWith((ctx, model) =>
      ctx.GetInstance<ProxyGenerator>().CreateInterfaceProxyWithTarget(model, ctx.GetInstance<ConversationInterceptor>()));

    //Set rules for what properties are injected on ObjectFactory.BuildUp(this)
        SetAllProperties(policy => policy.NameMatches(name => name.EndsWith("Provider") || name.EndsWith("Model")));
    }
}

I’m not going to explain my NotificationProvider class as it’s irrelevant to this post, it’s a class entirely derived from Creating a common generic and extensible NHiberate Repository, the SetAllProperties is just a StructureMap convention, ConversationCommitMode lets you inject your default configuration to the conversation, and the SessionManager also is unrelated to this post it’s just a wrapper class for boostrapping my NH session factory with Fluent NHibernate. The ProxyGenerator is a class in Castle DynamicProxy, I just use the version that’s already included with my NH. So now I’ll start with my Conversation class that has changed since my previous post. The biggest change is the client no longer needs to be aware of starting the session, connecting or disconnecting the session in anyway. The only need to care about what happens with the ISession after it is consumed.

public interface IBusinessConversation
{
    bool IsInTransaction { get; }
    bool IsNull { get; }
    ISession Session { get; }

    void Abort();
    void Commit();
    void CommitAndFlush();
    void End();
    void Rollback();
}

Part of the reason behind my BusinessConversation class is that I can implement the Null object pattern and lazy loading of the ISession itself so the session is delayed creation until one of my Repositories actually goes to use it and after it exists it’s only connected in instances that actually need it, not on every single page request! Onto the actual implementation.


public sealed class LazyBusinessConversation : IBusinessConversation
{
  private readonly INHibernateSessionManager _sessionManager;
  private ISession _session;

  public LazyBusinessConversation(INHibernateSessionManager sessionManager)
  {
    _sessionManager = sessionManager;
  }

  #region IBusinessConversation Members

  /// <summary>
  /// Rollback and do not commit the current transaction
  /// </summary>
  public void Rollback()
  {
    Rollback(_session);
  }

  /// <summary>
  /// Gets a value indicating whether this instance is in transaction.
  /// </summary>
  /// <value>
  ///   <c>true</c> if this instance is in transaction; otherwise, <c>false</c>.
  /// </value>
  public bool IsInTransaction
  {
    get { return _session.Is().Not.Null && _session.Is().InTransaction; }
  }

  /// <summary>
  /// Gets a value indicating whether this instance is null.
  /// </summary>
  /// <value><c>true</c> if this instance is null; otherwise, <c>false</c>.</value>
  public bool IsNull
  {
    get { return _session.Is().Null; }
  }

  /// <summary>
  /// Aborts this instance.
  /// </summary>
  public void Abort()
  {
    Abort(ref _session);
  }

  /// <summary>
  /// Commits the open transaction the session. Does not flush the session
  /// </summary>
  public void Commit()
  {
    Commit(_session, false);
  }

  /// <summary>
  /// Commits any open transaction in the session and
  /// flushes all pending changes to the database
  /// </summary>
  public void CommitAndFlush()
  {
    Commit(_session, true);
  }

  /// <summary>
  /// Ends this instance committing and flushing all data in session.
  /// </summary>
  public void End()
  {
    End(ref _session);
  }

  public ISession Session
  {
    get
    {
      if (!IsInTransaction)
      {
        Resume(_sessionManager, ref _session);
      }

      return _session;
    }
  }

  #endregion

  #region Class Methods

  private static void Abort(ref ISession session)
  {
    if (session.Is().NullOrClosed) return;

    Rollback(session);
    TerminateSession(ref session);
  }

  private static void Commit(ISession session, bool flush)
  {
    if (session == null)
      throw new ArgumentNullException("session");

    if (session.Is().InTransaction)
      session.Transaction.Commit();

    if (flush)
      session.Flush();

    session.Disconnect();
  }

  private static void End(ref ISession session)
  {
    if (session.Is().NullOrClosed) return;

    Reconnect(session);

    Commit(session, true);

    TerminateSession(ref session);
  }

  private static void Reconnect(ISession session)
  {
    if (session == null)
      throw new ArgumentNullException("session");

    if (session.IsConnected) return;

    session.Reconnect();
  }

  private static void Resume(INHibernateSessionManager sessionManager, ref ISession session)
  {
    if (session.Is().NullOrClosed)
      session = sessionManager.GetSession();

    if (session.Is().Null)
      throw new AccessViolationException("Session could not be created");

    Reconnect(session);

    if (session.Is().Not.InTransaction)
      session.Transaction.Begin();
  }

  private static void Rollback(ISession session)
  {
    if (session == null)
      throw new ArgumentNullException("session");

    if (session.Is().InTransaction)
      session.Transaction.Rollback();
  }

  private static void TerminateSession(ref ISession session)
  {
    session.Close();
    session.Dispose();

    /// Safety net incase conversation is reused
    /// this will guarantee a new session is created
    session = null;
  }

  #endregion
}

Sorry, long block of code I know, before I get into the specifics of it the majority of this class is pretty simple I inject my SessionFactory to the Conversation so I can new sessions when I need them. Other than that the majority of the methods do exactly what they are named and just complete the session or transaction in 1 way or another. Also I’m sure you noticed I call session.Is() this is an extension method that allows me to fluently check session state instead of having to do if(session != null && session.IsInTransaction) etc. Where all of the work really occurs is ISession { get }

IsInTransaction will always return false the first time .Session is accessed during a page request because either the session will be null or it will be disconnected. So the first time it’s accessed it calls Resume. Inside Resume I check to see if it exists, if not, new a session. If it already existed it needs to be reconnected. This handles all of the lazy loading (or lazy reconnection) this is a big advantage over pretty much every solution I’ve seen for the Long Conversation pattern is that they are based on instantiating a session for every user, connecting it at the start of every page request and committing it at the end of every page request regardless of whether or not they need the session at all! Also many of these patterns rely on HttpModules which makes testing so much harder!

At some point this class could probably use some refactoring to split out the methods that actually reattach the session, currently I have a few them with static methods and ref pointers so that you couldn’t call Resume(_sessionManager, Session) from inside the class easily and cause all kinds of unnecessary recursion. Of course as I type this I realize an explicitly defined Session { get } would go a long way for that, I also might consider wrapping my static methods into a class of their own and actually injecting that into the conversation. Now that you can see what my conversation class does we’ll take a look at what’s going on with

ForRequestedType<INotificationModel>().TheDefaultIsConcreteType<NotificationModel>().CacheBy(InstanceScope.Hybrid)
  .EnrichWith(
  (ctx, model) =>
  ctx.GetInstance<ProxyGenerator>().CreateInterfaceProxyWithTarget(model, ctx.GetInstance<ConversationInterceptor>()));

Per the StructureMap documentation

EnrichWith() — Registers a Func that runs against the new object after creation and gives you the option of returning a different object than the original object

So what happens here is you’re intercepting StructureMap giving you an instance of the NotificationModel and doing something with it. In this case what we’re going to do with it is use Castle DynamicProxy to actually create an entirely new NotificationModel that will wrap all of our methods with what we do in the ConversationInterceptor!

public class ConversationInterceptor : IInterceptor
{
  private readonly ConversationCommitMode _conversationCommitMode;

  public ConversationInterceptor(ConversationCommitMode conversationCommitMode)
  {
    _conversationCommitMode = conversationCommitMode;
  }

  private ConversationCommitMode GetConversationMode(ICustomAttributeProvider methodInfo)
  {
    var attribute = methodInfo.GetCustomAttributes(typeof (ConversationPersistanceAttribute), true);

    return attribute == null || attribute.Length == 0
           ? _conversationCommitMode
           : ((ConversationPersistanceAttribute) attribute[0]).ConversationMode;
  }

  #region IInterceptor Members

  public void Intercept(IInvocation invocation)
  {
    invocation.Proceed();

    var conversation = ObjectFactory.GetInstance<IBusinessConversation>();

    if (conversation.IsNull) return;

    switch (GetConversationMode(invocation.Method))
    {
      case ConversationCommitMode.CommitAndFlush:
        conversation.CommitAndFlush();
        break;
      case ConversationCommitMode.Rollback:
        conversation.Rollback();
        break;
      case ConversationCommitMode.Abort:
        conversation.Abort();
        break;
      case ConversationCommitMode.Commit:
      default:
        conversation.Commit();
        break;
    }
  }

  #endregion
}

So what happens after the ProxyGenerator creates our new class is instead of directly calling each method in the Model it will execute the code in Intercept(IInvocation) which for our case will first immediately run the method because we only need to do more AFTER it completes. Now as it runs the method it will call down to the Provider which will then use the lazyBusinessConversation.Sesssion property which will activate our session, run it’s NH commands and start to trace the call chain back after it finishes the execution of the original method call for any of the Model methods it returns back to the Intercept method.

The first thing we’ll check is if the session is null because if it is (meaning we didn’t touch it in our method) we don’t need to do anything else! I’ll explain why this will be very useful in a minute. Assuming we did an NH operation we’re going to check to see if I have our custom attribute added to the method like I do for AddAndRollBack in the model. If it’s there it will return that otherwise it will return the default commit operation that we injected into our IoC container. The switch statement is self explanatory. If we didn’t actually interact with NH on our round trip but the session was created before it still calls conversation.Commit() but looking above you can see it verifies it has an open transaction otherwise it will do nothing, this covers our lazy connection handling without having to embed that logic inside the interceptor.

Now the reason why I handle the null checking as some of you may have wondered, why would the session ever be null when the model is basically just a wrapper around the NH provider classes, the flexibility my solution offers is if you move the .EnrichWith() method in our StructureMap registry off of the Model classes you can put them on either your View or Presenter classes so that the session will be connected for basically the full page life cycle so you should get full support from lazy loading! Also since alot of methods in your views or presenters will have nothing to do talking to NH it will skip all of the work with NH on those requests! This is where I would Enrich my classes outside of my test project.

I would really like to thank Sam over on the StructureMap forums for his very insightful post that gave me the knowledge I needed to see how to solve the Long Transaction pattern using the castle dynamic proxy framework!

Right now none of this code is in my StructuredWeb SVN currently but I will merge all my current work back into SW soon!

kick it on DotNetKicks.com

Shout it

BloggingContext.ApplicationInstance.CompleteRequest();

January 27, 2009

Conversation Per Business Transaction using PostSharp and IoC

Earlier this month I encountered the notion of the Conversation per Business transaction paradigm for NHibernate session management as the overrall successor to the session per request pattern. With my exploration on this topic I found it quite confusing to implement in the only existing examples of it. Which is why I wrote a simple version for myself leveraging inversion of control and PostSharp.

Firstly,  everything drives off an IConversation:

public interface IConversation
{
    void Start();
    void Pause();
    void Resume();
    void End();
    void Abort();
    ISession Session { get; }
}

The conversation is a fairly simple idea, just as in a real life conversation you have a start to it, you can pause the conversation (which is how to commit the conversations), resume the conversation, end the conversation and abort the conversation. Imagine the scenario of a school class and students who have learning commited to their memory. A day could follow a similar context as this:

8:00 Class starts
Math is taught, Science is taught
12:00 Class is paused for recess (all information is committed)
13:00 Class is resumed
Creationism is taught, but realized to be made up and Class is aborted
14:00 Class is started again
More subjects are taught
15:00 Class is ended and all information flushed to students long term memory.

This example is fairly contrived but if you replace students with the database and act of class being taught with the conversation it should be pretty clear a flow that could occur over a single session for a conversation.

Next is the actual implementation of the Conversation class.

public class Conversation : IConversation, IDisposable
{
    private readonly INHibernateSessionManager _sessionManager;

    public ISession Session { private set; get; }

    [InjectionConstructor]
    public Conversation(INHibernateSessionManager sessionManager)
    {
        _sessionManager = sessionManager;
    }

    /// <summary>
    /// Starts this instance.
    /// </summary>
    public void Start()
    {
        if (Session != null && (Session.IsOpen || Session.IsConnected))
        {
            Abort();
        }
        Session = _sessionManager.GetSession(FlushMode.Never);
        Resume();
    }

    /// <summary>
    /// Pauses this instance.
    /// </summary>
    public void Pause()
    {
        Commit(Session);

    }

    /// <summary>
    /// Resumes this instance.
    /// </summary>
    public void Resume()
    {
        if (Session == null)
            Start();

        if (Session == null)
            throw new AccessViolationException("Session could not be created");

        if (!Session.IsConnected)
        {
            Session.Reconnect();
        }
        Session.BeginTransaction();
    }

    /// <summary>
    /// Ends this instance.
    /// </summary>
    public void End()
    {
        if (Session == null || !Session.IsOpen) return;

        FlushAndCommit(Session);
        Session.Close();
    }

    /// <summary>
    /// Aborts this instance.
    /// </summary>
    public void Abort()
    {
        if (Session == null || !Session.IsOpen) return;

        if (Session.Transaction != null && Session.Transaction.IsActive)
        {
            Session.Transaction.Rollback();
        }
        Session.Close();
    }

    /// <summary>
    /// Commits the specified session.
    /// </summary>
    /// <param name="session">The session.</param>
    private static void Commit(ISession session)
    {
        if (session.Transaction != null && session.Transaction.IsActive)
        {
            session.Transaction.Commit();
        }
    }

    /// <summary>
    /// Flushes the and commit.
    /// </summary>
    /// <param name="session">The session.</param>
    private static void FlushAndCommit(ISession session)
    {
        if (session.Transaction == null || !session.Transaction.IsActive) return;

        session.Flush();
        session.Transaction.Commit();
    }

    #region Implementation of IDisposable

    public void Dispose()
    {
        End();
    }

    #endregion
}

This class is a little bit long but nothing is that complex and I think every method is very straight forward. I’m going to skip over a few things that are not needed for understanding what this class does. The INHibernateSessionManager is an interface to a class that is a basically a wrapper to NHibernate’s ISessionFactory. For all intensive purposes this class could be ISessionFactory instead and the implementation wouldn’t change other than it would be session = Factory.OpenSession(); session.FlushMode = FlushMode.Never;

The InjectionConstructor attribute is a Microsoft Unity (Inversion of Control framework) specific convention that informs Unity to inject the NHibernate SessionFactory dependency into a Conversation anytime it is created. Unity will store a singleton copy of the SessionFactory for the life of the application.

Next up is the DataProvider class that will actually use the Conversation to talk to the database physically.

public class EmployeeDataProvider : IEmployeeDataProvider
{
    private readonly IConversation _conversation;

    [InjectionConstructor]
    public EmployeeDataProvider(IConversation conversation)
    {
        _conversation = conversation;
    }

    IList<Employee> IEmployeeDataProvider.GetEmployees()
    {
        return _conversation.Session.CreateCriteria(typeof (Employee)).List<Employee>();
    }
}

This is a very basic method that is used with NHiberate, it’s the syntax to get a list of objects from the database. I have some other methods in my provider but the code is less important now onto calling the provider.

[Test]
[BusinessConversation]
public void BusinessConversationTest()
{
    const int id = 9;
    var employee = _provider.GetEmployee(id);
    Assert.IsNotNull(employee);

    var employees = _provider.GetEmployees();
    Assert.IsTrue(employees.Count > 0);

    var territories = _provider.GetTerritories();
    Assert.IsTrue(territories.Count > 0);
}

In the setup call for this test Unity will resolve the _provider and assign it a Conversation which has the SessionFactory in it for opening the session. The same session is used for each of the calls to the database and committed as a single transaction when the method exits. This is done automagically by PostSharp.

PostSharp is an aspect orientated programming framework that allows you to create attributes can trigger methods before entering a method with the attribute and after exiting. The code for the BusinesConversation attribute is

[Serializable]
public sealed class BusinessConversation : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionEventArgs eventArgs)
    {
        var container = HttpContext.Current != null ?
            HttpContext.Current.Application.GetContainer() : UnityTestContainer.Instance;
        var conversation = container.Resolve<IConversation>();
        conversation.Resume();
    }

    public override void OnExit(MethodExecutionEventArgs eventArgs)
    {
        var container = HttpContext.Current != null ?
            HttpContext.Current.Application.GetContainer() : UnityTestContainer.Instance;
        var conversation = container.Resolve<IConversation>();
        conversation.Pause();
    }
}

Now this has some Unity specific code in it where it calls to the container to resolve the Conversation but the important part is that OnEntry to a method with the BusinessConversation attribute the conversation is resumed. This will either resume an existing conversation that’s stored in the session or it will create a new one. When it exits the method the conversation is paused which commits the transaction to the database.

The other code where it does resolution checking on HttpContext or reads from my UntityTestContainer does not really make me happy and eventually will be refactored to be cleaner in one way or another. But this code would be specific to how you interact with your container that would store the Conversations.

The only other issue I have with any of this is exposing the Session from the Conversation, I couldn’t figure out a simplier way for allowing my data providers to actually interact with the session to physically hit the database otherwise. I considered instead of a Conversation containing a session to actually make it implement ISession and assign it to itself during the creation but that didn’t sound right to me even more so.

I’d be grateful for any feedback on my implementation here: good, bad or indifferent. I feel I’ve finally put together a clean simple to understand post on how to correctly manage NHibernate’s session that doesn’t require implementing the UnitOfWork pattern and leverages dependency injection to keep the code seperated and decoupled as much as possible. The full source to my project as always can be found on my Assembla page.

kick it on DotNetKicks.com

Shout it

BloggingContext.ApplicationInstance.CompleteRequest();

November 11, 2008

Working with QueryStrings, a critique and different solution.

Filed under: Programming — Tags: , , — dotnetchris @ 5:20 pm

Today I was reading DotNetKicks like I normally do and came across this article in the up and coming section, Parsing query string in ASP.NET safely. I felt the author had quite a bit of conflicting code in his blog post.

I was not a fan of having get properties that had associated private member backing fields but the backing fields weren’t even reliably used. The other issue I had was the fact the int? return property would default to 0 instead of null which overrides the point of using nullables, the last issue I had was the GET properties would cause conversion to be done on the RequestString every time.

private string QueryText
{
    get { return (string) (ViewState["ViewStateQueryText"] ??
 (ViewState["ViewStateQueryText"] = string.Empty)); }
    set { ViewState["ViewStateQueryText"] = value; }
}

private int? QueryId
{
    get { return (int?) (ViewState["ViewStateQueryId"]); }
    set { ViewState["ViewStateQueryText"] = value; }
}

private Guid? QueryGuid
{
    get { return (Guid?) (ViewState["ViewStateQueryGuid"]); }
    set { ViewState["ViewStateQueryGuid"] = value; }
}

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        QueryText = ConverQuerystringToString("QueryText");

        QueryId = ConverQuerystringToInt("QueryId");

        QueryGuid = ConvertQueryStringToGuid("QueryGuid");

        bool hasValue = QueryGuid.HasValue;
        hasValue = QueryId.HasValue;
    }
}

/// <summary>
/// Converts the query string to GUID.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
private Guid? ConvertQueryStringToGuid(string key)
{
    if (string.IsNullOrEmpty(Request.QueryString[key]))
        return null;

    try
    {
        return new Guid(Request.QueryString[key]);
    }
    catch
    {
        return null;
    }
}

/// <summary>
/// Convers the querystring to string.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
private string ConverQuerystringToString(string key)
{
    return Request.QueryString[key] ?? string.Empty;
}

/// <summary>
/// Convers the querystring to int.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
private int? ConverQuerystringToInt(string key)
{
    int tmpParse;
    return int.TryParse(Request.QueryString[key], out tmpParse) ?
tmpParse : (int?) null;
}

This is how I handle reading the query string in my applications. If you’re wondering what’s going on inside the QueryText property I am doing 1 line lazy loading on the ViewState. This takes advantage of the lesser known fact that the assignment operator does not return void but actually returns itself which you can combine with the null coalescing operator to create 1 line lazy loading.

Let me know what you think about my practices. I love nullables for always having .HasValue and .GetValueOrDefault() to handle how I want to deal with defaults. I hate having to pick arbitrary values for default checks like -1 or 0 for ints etc.

UPDATE: 11/12

So I’m going to include a version for us on 3.5 where these methods are in an extension method over the querystring NameValueCollection.

public static class QueryStringExtensions
{
    /// <summary>
    /// Converts the query string to GUID.
    /// </summary>
    /// <param name="queryString">The query string.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static Guid? GetGuid(this NameValueCollection queryString, string key)
    {
        if (string.IsNullOrEmpty(queryString[key]))
            return null;

        try
        {
            return new Guid(queryString[key]);
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// Convers the querystring to string.
    /// </summary>
    /// <param name="queryString">The query string.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static string GetString(this NameValueCollection queryString, string key)
    {
        return queryString[key] ?? string.Empty;
    }

    /// <summary>
    /// Convers the querystring to int.
    /// </summary>
    /// <param name="queryString">The query string.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static int? GetInt(this NameValueCollection queryString, string key)
    {
        int tmpParse;
        return int.TryParse(queryString[key], out tmpParse) ?
tmpParse : (int?) null;
    }
}

Usage example (using same .aspx page as above)

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        QueryText = Request.QueryString.GetString("QueryText");

        QueryId = Request.QueryString.GetInt("QueryId");

        QueryGuid = Request.QueryString.GetGuid("QueryGuid");

        bool hasValue = QueryGuid.HasValue;
        hasValue = QueryId.HasValue;
    }
}

BloggingContext.ApplicationInstance.CompleteRequest();

kick it on DotNetKicks.com

November 4, 2008

Unity LifetimeManagers + ASP.NET

Filed under: Programming — Tags: , , , , , , — dotnetchris @ 6:00 pm

So recently I’ve really been looking into Unity and how to use it to handle IoC/DI for a future project of mine, I compeltely gave up on Web Client Software Factory (WCSF) something happened to that project where it just doesn’t work right anymore after having to deal with “Invalid owner for DynamicMethod” over and over again from ObjectBuilder(1.0 that’s in WCSF) I finally scrapped it and started looking at ways to use Unity to handle the MVP pattern instead.

This really had me scratching me on head on the implications of the page life cycle and correctly resolving instances, I’ve seen some examples around that go as far as creating HttpHandlers to intercept the BuildUp event to handle the injection which while I could go that route it definitely adds some complexity to the project. Which sadly I’ve learned especially when using new technology the code needs to be as simple as possible to avoid getting pushback from other developers but simple is good so I’d rather end up with a simple elegant solution vs a complex elegant solution.

Today I ran across a blog post (it’s a little old from May 08) regarding all of this Unity – lifetime management in a web application

I also did alot of referencing back and forth with the MSDN – Using Lifetime Managers

After doing some implemenation of all this I started to see why it makes sense to use the HttpModule to handle processing the build up. I used the HttpModule / Container wrapper extension method that Michael Puleio wrote on his blog Proof of Concept: a simple DI solution for ASP.NET WebForms.

Pretty soon I will be deploying a new solution to Assembla with links on here that will have an Unity driven DI model using the Model View Presenter (MVP) design pattern with a NHibernate back end (since LINQ-TO-SQL is on the death march) over the Microsoft Northwind db sample.

C# ASP.NET Response.Redirect Open Into New Window

Filed under: Programming — Tags: , , , — dotnetchris @ 12:37 pm

UPDATED: 11/04/2008 (see bottom of post)

So I came across the day the desire to have a button open up a new window instead of just using an anchor tag, as usual I run the idea through google and mostly come back with responses saying it’s not possible that way, or to add javascript to the page to capture events. Not quite the solution I was looking for after doing some more searching I came across a javascript solution that would work but wasn’t elegant at all which led me to ponder on adapting it to be cleaner and this is what I came up with.

<asp:Button ID="btnNewEntry" runat="Server" CssClass="button" Text="New Entry"

OnClick="btnNewEntry_Click" OnClientClick="aspnetForm.target ='_blank';"/>

protected void btnNewEntry_Click(object sender, EventArgs e)
{
    Response.Redirect("New.aspx");
}

It even works using Server.Transfer. There you have it a simple unobtrusive solution to handle Response.Redirect into a new window without needing to add any javascript tags and only take advantage of the OnClientClick event on the button itself.

Update 10/22/2008:

I’d like to thank one of my commenters, Dan, for his solution for accessing the form inside a master page on the child page level.

Button1.OnClientClick=string.Format(”{0}.target=’_blank’;”,

 ((HtmlForm)Page.Master.FindControl(”form1″)).ClientID);

This code will dig down into the controls collection and find your form and allow you to get access to the client id so you can be sure you have proper naming of it for the javascript to function correctly. Make sure you replace “form1″ with whatever you have your parent form id=”name” set to inside your Master’s page markup.

Update 11/04/2008:

If you have multiple buttons on a single page and only want a specific button to launch into a new windows and want the rest to stay on the current form make sure you decorate your other buttons like

<asp:Button ID="btnStayOnPage" runat="Server" CssClass="button" Text="Stay here"

OnClick="btnStayOnPage_Click" OnClientClick="aspnetForm.target ='_self';"/>

protected void btnStayOnPage_Click(object sender, EventArgs e)
{
   //Do normal code for postback
}

BloggingContext.ApplicationInstance.CompleteRequest();

kick it on DotNetKicks.com

September 24, 2008

Scheduled Task – Status, Start, Stop of Windows Service

So yesterday I created a task scheduler, today I wanted to be able to figure out the status of service and be able to start/stop it. I thought this would be a great time to just implement a new task in my project for task schedule and be on my way.

I found the code for accessing services using System.ServiceProcess quite easily and in my test project it worked great. Infact too great, I was even concerned at how easy it was to start/stop a service from visual studio further reflection on this I assumed since I was debugging a test project it was most likely running under my admin rights (proved true.) So I dropped it into actual ASP.NET and of course was issued security exceptions.

This led me down needing to figure out how to assume the identity of a user that can start/stop the service and then use their credientials to handle it. With a little bit of shameless stealing from MSDN and code clean up I was able to create my new task.

#region Using Statements

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;
using System.ServiceProcess;

#endregion

namespace Tasks
{
    [assembly: SecurityPermission(SecurityAction.RequestMinimum, UnmanagedCode = true)]
    [assembly: PermissionSet(SecurityAction.RequestMinimum, Name = "FullTrust")]
    public class ServiceUpTask : Task
    {
        public string ServiceName { get; set; }

        #region Overrides of Task

        public override void Run()
        {
            if (!string.IsNullOrEmpty(ServiceName))
            {
                WindowsImpersonationContext impersonationContext = null;

                try
                {
                    impersonationContext = AssumeIdentity("userName", "someDomain", "password");

                    using (var service = new ServiceController(ServiceName))
                    {
                        Debug.Print(string.Format("Service {0}, Status {1}", service.ServiceName, service.Status));

                        if (service.CanStop)
                        {
                            service.Stop();
                        }
                    }

                    using (var service = new ServiceController(ServiceName))
                    {
                        if (service.Status == ServiceControllerStatus.Stopped)
                        {
                            service.Start();
                        }
                    }
                }
                finally
                {
                    //Make sure we release the identity in case of an exception no matter what.
                    StopImpersonating(impersonationContext);
                }
            }
        }

        ///<summary>
        ///Assumes the identity. Steal shamelessly from MSDN.
        ///</summary>
        ///<returns></returns>
        private static WindowsImpersonationContext AssumeIdentity(string userName, string domain, string password)
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int dwLogonProvider = LOGON32_PROVIDER_DEFAULT;

            //This parameter causes LogonUser to create a primary token.
            const int LOGON32_LOGON_INTERACTIVE = 2;
            const int dwLogonType = LOGON32_LOGON_INTERACTIVE;

            var phToken = new IntPtr();
            if (LogonUser(userName, domain, password, dwLogonType, dwLogonProvider, ref phToken))
            {
                if (phToken != IntPtr.Zero)
                {
                    var windowsIdentity = new WindowsIdentity(phToken);
                    var impersonationContext = windowsIdentity.Impersonate();
                    CloseHandle(phToken);
                    return impersonationContext;
                }
            }

            return null;
        }

        /// <summary>
        /// Stops the WindowsIdentity impersonating.
        /// </summary>
        /// <param name="impersonationContext">The impersonation context.</param>
        private static void StopImpersonating(WindowsImpersonationContext impersonationContext)
        {
            //Stop impersonating the user.
            if (impersonationContext != null) impersonationContext.Undo();

            //Check the identity name.
            //Name of the identity after performing an Undo on the impersonation:
            //Uncomment for debugging if to check identity if needed
            //var identity = WindowsIdentity.GetCurrent();
        }

        #endregion

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
                                            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool DuplicateToken(IntPtr ExistingTokenHandle,
                                                 int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
    }
}

These changes are all checked into my SVN for access see the Assembla page or the post below.

BloggingContext.ApplicationInstance.CompleteRequest();

September 23, 2008

Update: Scheduled Tasks in ASP.NET!

Filed under: Programming — Tags: , , , — dotnetchris @ 4:09 pm

So as I promised I did write my sample project for using this. I’ll include the full files later as the majority of it is just wrappers around classes the files that really do all the magic is the code behind for the default.aspx and the TaskManager.cs file.

public partial class _Default : Page
{
private readonly TaskManager taskManager = new TaskManager();

protected void Page_Load(object sender, EventArgs e)
{
var printTask = taskManager.TaskList.Find(t =&gt; t.Id.GetValueOrDefault() == 1);

lblStatus.Text = printTask != null ? (printTask.Active ? "Active" : "InActive") : "Task not found";
}

protected void btnStartTasks_Click(object sender, EventArgs e)
{
taskManager.TaskList.Add(new PrintTask {Active = true, Id = 1, Name = "PrintTask1"});
taskManager.TaskList.Add(new PrintTaskOther {Active = true, Id = 2, Name = "PrintTaskOther2"});
taskManager.TaskList.Add(new PrintTask {Active = true, Id = 3, Name = "PrintTask3"});
taskManager.TaskList.Add(new PrintTask {Active = true, Id = 4, Name = "PrintTask4"});
taskManager.TaskList.Add(new PrintTaskOther {Active = true, Id = 5, Name = "PrintTaskOther5"});
}
}

The real magic that is occuring in here basically your just loading up the task objects into a List object however a few operations are overloaded that change the normal functionality of a List

public class TaskList : IList
{
private readonly List _tasks = new List();
private readonly Cache _cache = HttpRuntime.Cache;
//How long for jobs to wait before waking.
private const double sleepLength = 1;

public List Tasks
{
get
{
if (Count == 0)
{
var enumerator = _cache.GetEnumerator();
do
{
if (enumerator.Current is Task)
_tasks.Add(enumerator.Current as Task);
} while (enumerator.MoveNext());
}
return _tasks;
}
}
public void Add(Task item)
{
var task = _tasks.Find(t =&gt; t.Name == item.Name);
if (task == null)
{
_tasks.Add(item);
CacheAdd(item);
}
else
{
task.Id = item.Id;
task.Active = item.Active;
task.LastRan = item.LastRan;

CacheUpdate(item);
}
}

private void CacheUpdate(Task item)
{
_cache.Remove(item.Name);

CacheAdd(item);
}

private void CacheAdd(Task item)
{
if (_cache[item.Name] == null)
{
_cache.Add(item.Name, item, null, DateTime.Now.AddMinutes(sleepLength),
Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable,
CacheItemRemovedCallback);
}
}

public CacheItemRemovedCallback CacheItemRemovedCallback { get; set; }

Basically all it does is overrides saving the list solely to the server’s ram and writes it out to the Cache also when objects are added. It also has the Get method overrided so it will read the existing cache objects out by default for the list.

What pulls it all together to make everything work is the

public CacheItemRemovedCallback CacheItemRemovedCallback { get; set; }

This is the method that will get called when a task is removed from the cache’s dictionary. This was set in

public CacheItemRemovedCallback CacheItemRemovedCallback { get; set; }

So whenever a cache item is removed from the stack the event fires off to

public static void TaskExecuting(string key, object value, CacheItemRemovedReason reason)

Which is where we do the real execution of the job. At the end of the job we stick the item back in the cache so it will continue to loop. This is also the spot where you would put in logic to stop the service after so many iterations or it reaches some kind of predefined condition.

Updated: I have moved my source over to Assembla, you can download it directly or setup an SVN connection to view my source. Download Task Scheduler.

BloggingContext.ApplicationInstance.CompleteRequest();

kick it on DotNetKicks.com

Scheduled Tasks in ASP.NET!

Filed under: Programming — Tags: , , , — dotnetchris @ 10:29 am

I never would have thought there was a way to get around from needing a scheduled task to execute without implementing a windows service or a scheduled task run of a compiled executable.

Well I thought wrong.

Lately I’ve been doing alot of reading to keep up with everything .Net related and have been finding some incredible information, this has got to be one of the most profound things I have found in my ASP.NET experience.

The whole premise of a task scheduler is it needs to be atomic that every predefined interval the scheduler needs to wake up and figure out if it needs to do anything and then sleep until the next interval when it’s finished. Emulating this in ASP.NET would be impossible as far as I ever thought due to the fact that so much of all code execution is all instance based and the server itself will even sleep due to inactivity. Neither of those 2 core functionalities are desirable for a scheduler as it defeats the whole purpose of it.

This is where caching comes in. Yes, you read that right, caching. Not the standard practice of caching data for performance we’re all used to do doing but using the cache to store a cache object with a callback function and near future expiration to create our atomized tick.

Bill Beckelmen on his blog refreshes information that was spawned the whole way back in 2005 on CodeProject and improved from Microsoft’s MVP Omar Zabir’s original idea. Bill wrote Simulate a Windows Service Using ASP.NET to Run Scheduled Jobs

For the basic idea take a look over at Bill’s blog or check back as I might implement a draft of this to test it myself for a project that could potentially use it as a web driven service manager.

BloggingContext.ApplicationInstance.CompleteRequest();

April 18, 2008

Working with Property Proxy Validators

Filed under: Programming — Tags: , , , — dotnetchris @ 10:48 am

I’ve been using Enterprise Library and Property Proxy Validators to do some validation for the web search form I’m developing. The form has a few fields relevant to a person that are optional to search on, however there is a minimum to search on either Last Name or SSN.

In the RuleSet I setup for the search none of the Validators seem to really give the ability to handle checking for atleast 1 not null. The way I got around this was setup however you want your validators to be for regular data. Make sure that the empty string case can be successful either in your regular expressions or add a String Lenght Validator LowerBound 0 Upperbound 0 inside an OR composite validator along with the rest of your validations.

Currently this setup will give you pass for all nulls, the way I overcame this was to setup a Property Comparison Validator inside an And Composition Validator on my Last Name field having it compare to the SSN field set to NOT Equal. Which gives us a truth table similiar to:

LastName: “Smith” Pass -  SSN: “123%” Pass – Overall Pass

LastName: “” Pass -  SSN: “123%” Pass – Overall Pass

LastName: “Smith” Pass -  SSN: “” Pass – Overall Pass

LastName: “” Pass -  SSN: “” Pass – Overall FAIL which is what we want to happen.

There’s only one slight caveat to doing it this, entering exact same values with real text into the last name field and SSN field will generate the case that we have set for nulls.

LastName “123%” Fail – SSN “123%” Pass – Overall FAIL.

Overall i think this is an acceptable trade off, especially with the vastly different validation types. Now if you were going to use this method to compare First Name and Last Name, you would need to weigh if it would be worth making it impossible to search for a person with the same first name as last name. Of course if the search handles wild cards it could easily be worked around with just an explanation to take off 1 letter.

One last thing I needed to figure out was how to stop the property proxy validators from firing when I hit my reset button because it sets it to an valid state making every field null (not suprising since we just set the fields not accept all nulls). Maybe this more obvious to others or perhaps people that have just worked more using ASP.NET’s page validation but the only thing needed done to fix this was add to my button

<asp:button id=”btnReset” runat=”server” On_Click=”btnReset_Click” CausesValidation=”false” />

BloggingContext.ApplicationInstance.CompleteRequest();

The Shocking Blue Green Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 242 other followers

%d bloggers like this: