Tuesday, April 14, 2009

Spring.NET Short Circuiting Validators - The Finally

I really like what I do, I love the internet and love hearing other's ideas. After posting part 2 of this topic I noticed someone had actually commented on one of my very few posts. Mark Pollack suggested a great interim solution to the problem of easily configuring short circuiting validators. I say interim because the ability to do something like <v:group fastValidate=true> is planned fro Spring 2.0. Mark's solution allows me to preserve the initial rules layout that was presented in part 1. Here it is a again

    1 <objects xmlns="http://www.springframework.net"

    2         xmlns:v="http://www.springframework.net/validation">

    3   <v:group id="UserValidator">

    4     <v:group id="UserNameValidator">

    5       <v:required id="UserNameRequired" test="UserName">

    6         <v:message id="Errors.UserName.Required"  providers="UserNameError"/>

    7       </v:required>

    8 

    9       <v:regex id="UserNameMinmumComplexity" test="UserName">

   10         <v:property name="Expression" value="^.{5,20}$"/>

   11         <v:message id="Errors.UserName.MinimumComplexity" providers="UserNameError"/>

   12       </v:regex>

   13 

   14       <v:validator id="UserNameIsUnique" test="UserName" type="XXX.Infrastructure.Validation.IsUniqueUserNameValidator, XXX.Infrastructure">

   15         <v:property name="UserRepository" ref="UserRepository"/>

   16         <v:message id="Errors.UserName.IsUnique" providers="UserNameError"/>

   17       </v:validator>

   18     </v:group>

   19 

   20   ....

   21   </v:group

   22 

   23  ....

   24 </objects>



His suggestion is to use IObjectPostProcessor to set the FastValidate property. Since I don't want to set the property on every ValidatorGroup I adopted a naming convention for those groups I do desire the behavior and so I can easily identify them in the post processor. For example, In the configuration above I changed UserNameValidator to UserNameFastValidator. The post processor looks like,

    1     public class FastValidatePostProcessor

    2         : IObjectFactoryPostProcessor

    3     {

    4         public void PostProcessObjectFactory(IConfigurableListableObjectFactory factory)

    5         {

    6             string[] validatorGroupNames = factory.GetObjectNamesForType(typeof(ValidatorGroup));

    7             foreach (string validatorGroupName in validatorGroupNames)

    8             {

    9 

   10                 if (validatorGroupName.EndsWith("FastValidate"))

   11                 {

   12                     IObjectDefinition definition = factory.GetObjectDefinition(validatorGroupName);

   13                     definition.PropertyValues.Add("FastValidate", true);

   14                 }

   15             }

   16         }

   17     }



All that is left is to add the object to the configuration file something like

    1 <object type="XXX.Infrastructure.Validation.FastValidatePostProcessor, XXX.Infrastructure"/>



Thanks Mark!

Spring.NET Short Circuiting Validators - Part 2

Yesterday I gave a possible solution to the problem of easily configurable short circuiting validators in Spring.NET. Several hours later another possiblity struck me. One can use the existing ValidatorGroup class with the <v:validator> tag and set FastValidate in the <v:property> tag instead using the <v:group> tag which doesn't let you set that property. The configuration would look like this


    1 <objects xmlns="http://www.springframework.net"

    2         xmlns:v="http://www.springframework.net/validation">

    3   <v:group id="UserValidator">

    4     <v:validator id="UserNameValidator" type="Spring.Validation.ValidatorGroup, Spring.Core">

    5       <v:property name="FastValidate" value="true"/>

    6       <v:property name="Validators">

    7         <list>

    8           <ref object="UserNameRequired"/>

    9           <ref object="UserNameMinimumComplexity"/>

   10           <ref object="UserNameIsUnique"/>

   11         </list>

   12       </v:property>

   13     </v:validator>

   14 

   15     <!-- ...more validators -->

   16   </v:group>

   17 

   18   <v:required id="UserNameRequired" test="UserName">

   19     <v:message id="Errors.UserName.Required"  providers="UserNameError"/>

   20   </v:required>

   21 

   22   <v:regex id="UserNameMinimumComplexity" test="UserName">

   23     <v:property name="Expression" value="^.{5,20}$"/>

   24     <v:message id="Errors.UserName.MinimumComplexity" providers="UserNameError"/>

   25   </v:regex>

   26 

   27   <v:validator id="UserNameIsUnique" test="UserName" type="XXX.Infrastructure.Validation.IsUniqueUserNameValidator, HSN.Infrastructure">

   28     <v:property name="UserRepository" ref="UserRepository"/>

   29     <v:message id="Errors.UserName.IsUnique" providers="UserNameError"/>

   30   </v:validator>

   31 

   32   <!-- ...more validators -->

   33 </objects>

Monday, April 13, 2009

Spring.NET Short Circuiting Validators - Part 1

One of the features I've come to like in Spring.NET is the validation library, but it does come up short on at least one basic need. That is a straight forward way to configure short circuiting for <v:group>'s. Meaning a validator group that quits validating and returns false on the first failed validator and returns true otherwise. Out of the box if you wanted to setup a group to, let's say, validate the User.UserName property you might write something like,

    1 <objects xmlns="http://www.springframework.net"

    2         xmlns:v="http://www.springframework.net/validation">

    3   <v:group id="UserValidator">

    4     <v:group id="UserNameValidator">

    5       <v:required id="UserNameRequired" test="UserName">

    6         <v:message id="Errors.UserName.Required"  providers="UserNameError"/>

    7       </v:required>

    8 

    9       <v:regex id="UserNameMinmumComplexity" test="UserName">

   10         <v:property name="Expression" value="^.{5,20}$"/>

   11         <v:message id="Errors.UserName.MinimumComplexity" providers="UserNameError"/>

   12       </v:regex>

   13 

   14       <v:validator id="UserNameIsUnique" test="UserName" type="XXX.Infrastructure.Validation.IsUniqueUserNameValidator, XXX.Infrastructure">

   15         <v:property name="UserRepository" ref="UserRepository"/>

   16         <v:message id="Errors.UserName.IsUnique" providers="UserNameError"/>

   17       </v:validator>

   18     </v:group>

   19 

   20   ....

   21   </v:group

   22 

   23  ....

   24 </objects>



However when User.UserName is validated every validator will fire. There are many reasons why it makes sense to abandon validation on the first failed validator: some rules maybe more expensive than others to evaluate, maybe executing every action due to failed rules produces less than desirable results.

The approach I took was to create a custom validator that inherits from ValidatorGroup.

    1     public class ShortCircuitingValidatorGroup

    2         : ValidatorGroup

    3     {

    4         public ShortCircuitingValidatorGroup()

    5         {}

    6 

    7         public ShortCircuitingValidatorGroup(string when)

    8             : base(when)

    9         {}

   10 

   11         public ShortCircuitingValidatorGroup(IExpression when)

   12             : base(when)

   13         {}

   14 

   15         /// <summary>

   16         /// The non-shortcircuiting validator group

   17         /// </summary>

   18         public ValidatorGroup GroupToShortCircuit { get; set; }

   19 

   20 

   21         public override bool Validate(object validationContext,

   22                                       System.Collections.IDictionary contextParams,

   23                                       IValidationErrors errors)

   24         {

   25             GroupToShortCircuit.FastValidate = true;

   26             return GroupToShortCircuit.Validate(validationContext, contextParams, errors);

   27         }

   28 

   29     }



As you can see the class holds a reference to the group we want to short circuit and sets the FastValidate property, invoking the behavior I want, to true. The custom validator is setup in xml for the User.UserName property like this

    1 <objects xmlns="http://www.springframework.net"

    2         xmlns:v="http://www.springframework.net/validation">

    3   <v:group id="UserValidator">

    4     <v:validator id="UserNameValidator"

    5                 type="XXX.Infrastructure.Validation.ShortCircuitingValidatorGroup, XXX.Infrastructure">

    6       <v:property name="ValidatorGroup" ref="UserNameValidatorGroup"/>

    7     </v:validator>

    8     ...

    9   </v:group>

   10 

   11   <v:group id="UserNameValidatorGroup">

   12     <v:required id="UserNameRequired" test="UserName">

   13       <v:message id="Errors.UserName.Required"  providers="UserNameError"/>

   14     </v:required>

   15 

   16     <v:regex id="UserNameMinmumComplexity" test="UserName">

   17       <v:property name="Expression" value="^.{5,20}$"/>

   18       <v:message id="Errors.UserName.MinimumComplexity" providers="UserNameError"/>

   19     </v:regex>

   20 

   21     <v:validator id="UserNameIsUnique" test="UserName" type="XXX.Infrastructure.Validation.IsUniqueUserNameValidator, XXX.Infrastructure">

   22       <v:property name="UserRepository" ref="UserRepository"/>

   23       <v:message id="Errors.UserName.IsUnique" providers="UserNameError"/>

   24     </v:validator>

   25   </v:group>

   26   ...

   27 </objects>

Sunday, April 12, 2009

Unit Testing a Custom Membership Provider

Wow, it's been awhile since I've blogged here. I don't want to bore you with my regret so I'll get to it. Today I was attempting to test drive a custom membership provider

    1 [Test]

    2 public void CanCreateNewUser()

    3 {

    4     TestProvider.Initialize(ProviderName, DefaultConfig);

    5     MembershipCreateStatus Status;

    6     ApplicationUser UserToSave =

    7         new ApplicationUser(CorrectUserName,

    8                             CorrectPassword,

    9                             CorrectEmail)

   10                         {

   11                             PasswordQuestion = ThePasswordQuestion,

   12                             PasswordAnswer = ThePasswordAnswer

   13                         };

   14     UserRepository.Expect(x => x.Save(UserToSave))

   15         .IgnoreArguments();

   16 

   17     MembershipUser NewUser =

   18         TestProvider.CreateUser(CorrectUserName,

   19                                 CorrectPassword,

   20                                 CorrectEmail,

   21                                 ThePasswordQuestion,

   22                                 ThePasswordAnswer,

   23                                 false,

   24                                 null,

   25                                 out Status);

   26 

   27     Assert.AreEqual(MembershipCreateStatus.Success, Status);

   28     UserRepository.VerifyAllExpectations();

   29 }



I hit run in my NUnit test runner and bam, I got this error

Tests.UnitTests.CustomMembershipProviderTestCase.CanCreateNewUser: System.ArgumentException : The membership provider name specified is invalid. Parameter name: providerName

At the top of the stack trace was the MembershipUser constructor so that's where I started my search. O how I love Reflector. I fired it up and examined the constructor for the MembershipUser class and spotted the following check

    1 if ((providerName == null) ||

    2     (Membership.Providers[providerName] == null))

    3 {

    4     throw new ArgumentException(

    5         SR.GetString("Membership_provider_name_invalid"), "providerName");

    6 }



There's the culprit : Membership.Providers[providerName] == null. So I tried setting the provider programmatically in my test, but the provider's collection is read only. I know that the provider's collection is populated according to what is in the web.config so I added the necessary section to the app.config of my test project.

    1   <system.web>

    2     <membership defaultProvider="CustomMembershipProvider">

    3       <providers>

    4         <remove name="AspNetSqlMembershipProvider"/>

    5         <add applicationName="UnitTests"

    6             name="CustomMembershipProvider"

    7             type="XXX.Infrastructure.Authentication.CustomMembershipProvider, XXX.Infrastructure"/>

    8       </providers>

    9     </membership>

   10   </system.web>



I reran my test and I saw green, but I wasn't totally satisfied. The one thing I don't like about this solution is I can't control what's in the providers collection on a test by test basis.

In the back of my mind I knew I could use reflection, but I was avoiding it because I really wanted to move on. I quickly poked around the Membership and MembershipProvderCollection classes with reflector knowing, like many things, that somebody has probably solved this problem. Within minutes I found Colin Bowern's post describing the same exact issue. The code below to programmatically populate the provider's collection is to his credit. Thanks Colin.

    1 private void InjectProvider(ProviderCollection Collection, ProviderBase Provider)

    2 {

    3     typeof(ProviderCollection).GetField("_ReadOnly", BindingFlags.Instance | BindingFlags.NonPublic)

    4                               .SetValue(Collection, false);

    5 

    6     Hashtable Hash = (Hashtable)typeof(ProviderCollection).GetField("_Hashtable", BindingFlags.Instance | BindingFlags.NonPublic)

    7                                                           .GetValue(Collection);

    8 

    9     if (Hash[Provider.Name] == null)

   10     {

   11         Hash.Add(Provider.Name, Provider);

   12     }

   13     else

   14     {

   15         Hash[Provider.Name] = Provider;

   16     }

   17 }



Now the top two lines of my test look like

    1 TestProvider.Initialize(ProviderName, DefaultConfig);

    2 InjectProvider(Membership.Providers, TestProvider);



And my test still passes.