Integrating The Spring.NET Validation Framework And ASP .NET MVC

I recently completed a very successful project for a client using ASP .NET MVC, Spring.NET and jQuery. One of the technical requirements of the solution was that we wanted to have an advanced validation mechanism that would allow us to move all our validation rules out of theUI layer, and business logic, and into a dynamically configurable rule engine. Spring.NET’s validation framework is ideally suited for this challenging task.

Spring.NET’s validation framework is based on a hierarchy of validation groups, conditions, and actions. I refer those unfimiliiar with Spring.NET’s validation framework, to their well composed documentation.

What I’ll propose here is a way to integrate Spring.NET’s validation with ASP MVC, and some issues you might encounter alng the way.

Spring.NET Validation Is From Mars, and ASP MVC Is From Venus

Okay, so you’ve covered the validation framework’s documentation. You can create new validation rules, pass through an object (in the MVC space this would be the model), and get back a boolean result to tell you whether the object passed (true) or failed (false). As I’ve mentioned this process is made very clear in the help documentation of the validation framework, so I’m going to jump straight into the juicy complexities.

Spring.NET’s validation rules apply themselves directly to a POCO’s (Plain Old C# Object) schema. For instance, say I’ve got a class Customer that I pass through as the validationContext, and I wanted to validate his CellPhone ContactNumber (Customer.ContactNumbers.CellPhone), the validation rule might look something like this:

<v:regex when="ContactNumbers.CellPhone != null and ContactNumbers.CellPhone != ''"
test="ContactNumbers.CellPhone">

When we’re talking about MVC, our Customer will serve as the model sent to a ViewPage by a Controller action.

ASP’s Controller all have a ViewData.ModelState.AddModelError(…), that takes in a key, and an error message. To get MVC to highlight the input element, the key must match its name. To get MVC to automatically bind the HTML control to a model property, the name of the control in turn should be the same as the path to the Property that provides its value. For example, say I want ASP MVC to automatically display his CellPhone number, then I’d use “Customer.ContactNumbers.CellPhone” as the input control’s name. To flag this control as an error source, I’ll use a key with the exact same name.

<%= Html.TextBox( "Customer.ContactNumbers.HomeDialCode" )%>
-
<%= Html.TextBox( "Customer.ContactNumbers.HomePhone" )%>
<%= Html.ValidationMessage( "Customer.ContactNumbers.HomeDialCode" )%>
<%= Html.ValidationMessage( "Customer.ContactNumbers.HomePhone" )%>

The important point is that the naming convention of the ViewPage’s HTML controls, is based on the model’s schema or graph, and so are the validation rules. The trick is then to relate a Spring.NET validation error (and specifically the error message) to the current node in the schema to which it’s being applied.

Spring.NET’s message or ErrorMessageAction has the concept of “providers“. A provider is just a fancy name for an IDictionary<string,IList> of key-values, where the provider name serves as the key, and the list is a list of ErrorMessages. The idea is that each provider name relates to a Spring validation web server control, that will display it’s error. For ASP MVC we’d rather like to generate the correct ModelError key, so MVC can automatically take care of displaying the error message in its own way.

So at this point we have 3 tasks that we need to complete to successfully integrate ASP MVC and Spring.NET Validation:

1. Tell each Spring.NET validation rule where in the object graph it’s currently executing.
2. Generate the correct error key from the validation rule’s location or context.
3. Convert the validation error to a ModelError and add it to the Controller’s ModelState.

Validation Rules: “I Know What I’m Doing, But Not Where I’m Doing It!”

One of the problems of Spring.NET’s validation rules are that they do not know where in the schema they’re executing. Put a another way, they do not know the path that lead to the current rule being executed – henceforth being referred to as their context. Why is this important? It is important because, as explained previously, the MVC’s input field names and error keys are based on the full path of underlying model-object property.

The most straightforward way to provide this contextual information for a validation rule is to embed it directly inside its definition, probably using a custom IValidationAction:

<v:regex id="homeDialCodeValidator" when="HomeDialCode != null and HomeDialCode != ''" test="HomeDialCode">
<v:property name="Expression" value="&#91;0-9&#93;{3}"/>
  <v:action type="Shinobido.GhostBlade.Validation.ModelValidationAction, Shinobido.GhostBlade.Core">
    <v:property name="CurrentError">
      <object id="homeDialCodeError" type="Shinobido.GhostBlade.Validation.ModelError, Shinobido.GhostBlade">
<property name="Key" value="Customer.ContactNumbers.HomeDialCode" />
<property name="Message" value="3 numbers expected." />
      </object>
    </v:property>
  </v:action>
</v:regex>

The problem with the aforementioned approach is that it reduces the re-usability of validation rules. For instance, lets say we have the following classes:

public class ContactNumbers
{
    public string HomeDialCode { get; set; }
    public string HomePhone { get; set; }
}

public class Customer
{
    public string Name { get; set; }
    public ContactNumbers ContactNumbers { get; set; }
    public Spouse Spouse { get; set; }
    public NextOfKin NextOfKin { get; set; }
}

public class Spouse
{
    public ContactNumbers ContactNumbers { get; set; }
}

public class NextOfKin
{
    public ContactNumbers ContactNumbers { get; set; }
}

Ideally we want to create one contactNumbersValidator rule-group, that can be referenced from other validators, wherever ContactNumbers need to be validated:

<v:ref name="contactNumbersValidator" context="Spouse.ContactNumbers" />

The problem with specifying the context information or error key, in the rule, as that it only caters for a single context. For instance, in the above example we would like to validate ContactNumbers from three different contexts: Customer.ContactNumbers, Customer.Spouse.ContactNumbers, and Customer.NextOfKin.ContactNumbers. All three will use the same validation rule, but from different contexts or schema paths. If we specify a context of Customer.ContactNumbers.HomeDialCode, then we are unable to accommodate any other path, such as those for NextOfKin and Spouse.

What we can infer from this exercise is that we need to specify a rule’s context outside of the rule, in a parent group or rule. A validation rule itself cannot contain the context, because it does not know from where it’s referenced. So how do we set the rule’s current context, from its parent?

One of the ValidatorGroup‘s overloads for the Validate(…) method, has an input argument called contextParams of type IDictionary. The significance of this argument is that we can write and read values to it – programmatically and from the config file. This allows us to make variables available to validation groups, validators or actions.

So how do we set a variable from the rule configuration? For this we use the “#variableName” syntax of Spring.NET’s expression language. When Spring.NET encounters the following command “#SomeVariable=’SomeValue‘” a new entry is made in the contextParams dictionary with a key name of “SomeVariable” and value of “SomeValue”.

What we’re going to do is write a magic little custom class that allow us to navigate up and down the object graph, as validation rules are evaluated:

public class ObjectContext
{
    private IList<string> contextPath = new List<string>();
    private string finalContext;
    private readonly StringBuilder pathBuilder = new StringBuilder();

    public bool StepIn( params string[] path )
    {
        for ( var i = 0; path != null && i < path.Length; ++i )
        {
            contextPath.Add( path&#91;i&#93; );
        }
        return true;
     }

    public bool FinalStepIn( params string&#91;&#93; path )
    {
        for ( var i = 0; path != null && i < path.Length; ++i )
        {
            if ( i == path.Length - 1 )
            {
                finalContext = path&#91;i&#93;;
            }
            else
            {
                contextPath.Add( path&#91;i&#93; );
            }
        }
        return true;
    }

    public bool StepOut( params string&#91;&#93; path )
    {
        // Reverse list so we can start deleting from index 0
        var reversedContextPath = contextPath.Reverse().ToList();
        for ( var i = 0; i < reversedContextPath.Count(); ++i )
        {
            // Just remove the same number of items in "path"
            // from "contextPath"
            reversedContextPath.RemoveRange( 0, path.Length );
        }

        // Revert back to original order and assign back to "contextPath"
        reversedContextPath.Reverse();
        contextPath = reversedContextPath;

        return true;
    }

    public string ContextPath
    {
        get
        {
            if ( pathBuilder.Length > 0 ) pathBuilder.Remove( 0, pathBuilder.Length );

            for ( var i = 0; i < contextPath.Count; ++i )
            {
                pathBuilder.Append( contextPath&#91;i&#93; );

                // If don't have a leaf node, and this is the last
                // intermediate/branch node, then do not add a "."
                if ( string.IsNullOrEmpty( finalContext ) &&
                     i == contextPath.Count - 1 )
                {
                    continue;
                }

                pathBuilder.Append( "." );
            }
            pathBuilder.Append( finalContext );
            return pathBuilder.ToString();
        }
     }
 }

&#91;/sourcecode&#93;

Let's first explain some of the <strong>logic behind ObjectContext</strong>. When it comes to object schemas or graphs we can distinguish between three types of contexts: <strong>the root context</strong>, <strong>several intermediate sub contexts</strong>, and a <strong>final leaf context</strong> (containing the "test" expression). The <strong>root context </strong><em>serves as the starting point for the evaluation path</em>, and is similar to MVC's concept of a binding prefix. <strong>Sub contexts</strong> <em>refer to those that navigate from the root down to a final leaf context</em>. A <strong>leaf context</strong> <em>is a validation rule end-point, that does not have any children, and contains the actual "test" expression</em>.

<strong>ObjectContext </strong>has three methods <strong>StepIn</strong>, <strong>FinalStepIn</strong>, and <strong>StepOut</strong>. <strong>StepIn </strong><em>allows us to step into a child context</em>, like when we move from Customer into Spouse. <strong>FinalStepIn </strong><em>is used when we move from a parent context into a final leaf context</em>, like we'd do if we moved from ContactNumbers to HomePhone. Lastly we have <strong>StepOut</strong>, <em>that takes us from a child context back up to a parent one</em>, such as when we move back from Spouse to Customer.

All we need to do now, is <strong>add a new instance of ObjectContext to contextParams</strong> and call the relevant methods as we move through the object graph's nodes. I wrote a <strong>ValidatorGroup extension</strong> method to automatically add a new ObjectContext instance to contextParams:


public static class ValidatorGroupExtensions
{
    public static bool Validate( this ValidatorGroup validatorGroup, object validationContext, IValidationErrors errors, bool hasContext )
    {
        var contextParams = hasContext ? new Dictionary<string,object> { { "ObjectContext", new ObjectContext() } } : new Dictionary<string,object>();
        return validatorGroup.Validate( validationContext, contextParams, errors );
    }
}

At this point it should be clear how to add a new instance of ObjectContext to contextParams. What we haven’t discussed is how we’re going to retrieve our ObjectContext instance from contextParams, and invoke one of its methods in the validation configuration. The answer to this question lies in the fact that Spring.NET’s IExpression interface allows multiple independent commands to be executed in the same expression. What’s also important is that we realize that the validation configuration schema’s “when” and “test” attributes are actually IExpression properties. Therefore we can use any of the validation framework’s attributes/properties that is an IExpression to use variables from contextParams:

<v:group id="customerValidator" when="#ObjectContext.StepIn( 'Customer' )">

    <v:condition when="#ObjectContext.FinalStepIn( 'Name' )" test="Name != null and Name != ''" />

    <v:group when="( #ObjectContext.StepIn( 'Spouse', 'ContactNumbers' ); Employer != null )">
        <v:ref name="contactNumbersValidator" context="Spouse.ContactNumbers" />
    </v:group>

    <v:group when="( #ObjectContext.StepOut( 'Spouse', 'ContactNumbers' ); #ObjectContext.StepIn( 'ContactNumbers' ) )">
        <v:ref name="contactNumbersValidator" context="ContactNumbers" />
    </v:group>
</v:group>

<!-- contactNumbersValidator -->
<v:group id="contactNumbersValidator">

    <!-- CellPhone validator -->
    <v:regex when="( #ObjectContext.FinalStepIn( 'CellPhone' ); CellPhone != null and CellPhone != '' )" test="CellPhone">
        <v:property name="Expression" value="&#91;0-9&#93;{10}"/>
        <v:action type="Shinobido.GhostBlade.ErrorMessageContextAction, Shinobido.GhostBlade">
            <v:property name="Message" value="Unexpected format for cellphone number." />
        </v:action>
    </v:regex>

</v:group>

The first “when” validation statement on the group element tells Spring.NET to fetch the value of the DictionaryEntry with key “ObjectContext”. To execute multiple commands in a single IExpression we place the entire expression in brackets, and separate the each sub-expression with a semi-colon. When multiple statements are specified like this, Spring.NET always returns the last statement’s value. This is why our navigation methods all return true: So that the groups are executed by default, relieving us from the burden to add a last additional expression that returns true.

The next step is to create a custom IValidationAction that inherits from BaseValidationAction, that will store our validation rule’s error message, and build the current context’s full path info:

public class ErrorMessageContextAction: BaseValidationAction
{
    /// <summary>
    /// Gets or sets the error message.
    /// </summary>
    public string Message { get; set; }

    protected override void OnInvalid( object validationContext, IDictionary contextParams, IValidationErrors errors )
    {
        var objContext = contextParams["ObjectContext"] as ObjectContext;

        if ( objContext == null ) return;

        var error = new ErrorMessage( null, Message );
        errors.AddError( objContext.ContextPath, error );
     }
 }

BaseValidationAction provides two virtual methods OnInvalid and OnValid, that are called when a rule fails or passes. ErrorMessageContextAction has one property called Message, that is set to the actual error message we wish to display. Our override of OnInvalid uses ObjectContext.ContextPath to build the full path of the current context. This full path will be used as our ‘provider’. ASP MVC’s built-in error message handling magic fulfills the role of validation errors renderer using this ‘provider’.

The last piece of the puzzle is a custom IValidationErrors implementation that will add validation errors to a MVC Controller’s ViewData.ModelState:

public class ModelStateErrors: IValidationErrors
{
    ModelStateDictionary modelState;

    public ModelStateErrors( ModelStateDictionary modelState )
    {
        this.modelState = modelState;
    }

    public void AddError( string provider, ErrorMessage message )
    {
        if ( message != null &&
             message.Parameters != null &&
             message.Parameters.Length > 0 &&
             message.Parameters[0] != null &&
             message.Parameters[0] is string )
        {
            modelState.AddModelError( provider, message.Parameters[0].ToString() );
        }
    }

    public void MergeErrors( ValidationErrors errorsToMerge )
    {
        throw new System.NotImplementedException();
    }

    public IList GetErrors( string provider )
    {
        var modelStateDict = modelState[provider];
        return modelStateDict == null ? null : modelStateDict.Errors;
    }

    public IList GetResolvedErrors(string provider, IMessageSource messageSource)
    {
        throw new System.NotImplementedException();
    }

    public bool IsEmpty
    {
        get { return modelState.Count == 0; }
    }

    public IList Providers
    {
        get
        {
            return modelState.Keys.ToList();
        }
    }
}

Class ModelStateErrors internally wraps a ViewData‘s ModelStateDictionary, and automatically adds Spring.NET validation errors to it. The provider name is used as the key for AddModelError, because this is the ‘bucket’ that we’d like to sink the message to. The ErrorMessage‘s first parameter is expected to be the message text.

Usage and Conclusion

An important point to remember when specifying the context in Spring’s validation configuration, is to always provide a complete path from the current node to a final leaf node. It is important to StepIn and StepOut of contexts in-sync with the validation rules. If a context is skipped, our we don’t StepOut of a previous one, we will not get the correct path. When you get the wrong context, check that you’ve SteppedOut as many times as you’ve SteppedIn, to bring you back to the current node or level. Also check that you’ve specified the correct context names when you StepInto a context.

All we need to do is make sure our context navigation correctly follows our validation rules. Apart from this we don’t really need to do anything else to get Spring.NET to add its validation errors and messages to ViewData’s ModelState:

1. Import the namespace where the ValidatorGroupExtensions is defined:

using Shinobido.GhostBlade.Extensions;

2. Get the desired ValidatorGroup from Spring.NET’s objects configuration.
3. Call ValidatorGroup.Validate with ModelStateErrors as the IValidationErrors implementation, and hasContext as true.

Just obtain the desired ValidatorGroup from the objects configuration, ModelStateErrors as the IValidationErrors implementation in a Controller’s Action method:

public partial class CustomerController: Controller
{
    public ActionResult EditPersonalAssessment( int id )
    {
        var customer = ObjectManager.New<ICustomer>();
        customer.ContactNumbers = new ContactNumbers
                                  {
                                      CellPhone = "djsk"
                                  };
        customer.Spouse = new Spouse
                          {
                              ContactNumbers = new ContactNumbers
                                               {
                                                   CellPhone = "kasjd"
                                               }
                          };
        var validator = ObjectManager.New<ValidatorGroup>( "customerValidator" );
        var result = validator.Validate( sampleObj, new ModelStateErrors( ViewData.ModelState ), true );
    }
}

From the final usage we observe that it’s a pretty neat way of integrating Spring.NET’s Validation Framework with ASP .NET MVC’s ModelState and error handling magic. The only part that’s a bit weird is the way we specify the context in Spring.NET’s validation configuration. It abuses the IExpression attributes a little in a way that they weren’t originally designed for. But I believe this is a small price to pay to gain the huge benefit of automatic integration of Spring.NET’s Validation Framework and ASP MVC’s validation and error handling and display.

In the next Spring.NET post I’ll be covering how to use Spring.NET’s Aspect Oriented Programming (AOP) to create an impersonation aspect. Happy Springing until then!


Web Service HTTP-407 Proxy Access Denied Error

Summary
When calling a web service operation you get the following error: “The request failed with HTTP status 407: Proxy Access Denied.”Conditions:

  1. When you inspect System.Security.Principal.WindowsIdentity.GetCurrent() the returned WindowIdentity is the current user’s Windows account.
  2. The web service proxy’s Proxy is null: “webService.Proxy == null” I true.
  3. The web service’s Credentials might be set or not. You get the above error even though you’ve set the web service proxy’s Credentials from System.Net.CredentialCache.DefaultCredentials: “webService.Credentials = System.Net.CredentialCache.DefaultCredentials”.

Solution
If the web service proxy’s Proxy property is null, then assign the default WebProxy to it:

if ( webService.Proxy == null )
{
webService.Proxy = System.Net.WebProxy.GetDefaultProxy();
webService.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
}