Validation from WCF layer through to MVC

 

First off, why would you want to perform validation in the WCF layer?

After a vigorous PEN test, it was noted that the validation was mainly happening at the client browser and the application required validation to occur at the business logic layer, in our case the WCF layer.

In general, when working with an MVC/ASP.NET web application, you would typically want to do validation on the client-side as well as on the server side. Whilst the custom validation is simple enough, you’d have to duplicate it on the client and server, which is annoying – now you have two places to maintain a single validation routine.

Lets look at different validation options that will assist us in solving the issues over validation.

There are five validation approaches which you can prefer during validations. Each one has advantages and disadvantages over each other. Also, it is possible to apply multiple approaches at the same time. For example, you can implement self validation and data annotation attributes approaches at the same time, which gives you much flexibility.

  1. Rule sets in configuration
  2. Validation block attributes
  3. Data annotation attributes
  4. Self-validation
  5. Validators created programmatically

Rule sets in Configuration

In this approach, we put our validation rules into the configuration file (web.config in ASP.NET and app.config in Windows applications). Here is an example showing how to define validation rules:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="validation" type="Microsoft.Practices.EnterpriseLibrary.
	Validation.Configuration.ValidationSettings, 
	Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0, 
	Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
  </configSections>
  <validation>
    <type name="ELValidation.Entities.BasicCustomer" 
		defaultRuleset="BasicCustomerValidationRules"
      assemblyName="ELValidation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
      <ruleset name="BasicCustomerValidationRules">
        <properties>
          <property name="CustomerNo">
            <validator type="Microsoft.Practices.EnterpriseLibrary.
		Validation.Validators.NotNullValidator, 
		Microsoft.Practices.EnterpriseLibrary.Validation"
              negated="false" messageTemplate="Customer must have valid no"
              tag="CustomerNo" name="Not Null Validator" />
            <validator type="Microsoft.Practices.EnterpriseLibrary.
		Validation.Validators.StringLengthValidator, 
		Microsoft.Practices.EnterpriseLibrary.Validation"
              upperBound="5" lowerBound="5" lowerBoundType="Inclusive" 
		upperBoundType="Inclusive"
              negated="false" messageTemplate="Customer no must have {3} characters."
              tag="CustomerNo" name="String Length Validator" />
            <validator type="Microsoft.Practices.EnterpriseLibrary.
		Validation.Validators.RegexValidator, 
		Microsoft.Practices.EnterpriseLibrary.Validation"
              pattern="[A-Z]{2}[0-9]{3}" options="None" patternResourceName=""
              patternResourceType="" 
		messageTemplate="Customer no must be 2 capital letters and 3 numbers."
              messageTemplateResourceName="" messageTemplateResourceType=""
              tag="CustomerNo" name="Regex Validator" />
          </property>
        </properties>
      </ruleset>
    </type>
  </validation>
</configuration>

Validation Block Attributes

In this approach, we define our validations through the attributes defined in Enterprise Library validation block.

[NotNullValidator(MessageTemplate = "Customer must have valid no")]
[StringLengthValidator(5, RangeBoundaryType.Inclusive, 
		5, RangeBoundaryType.Inclusive, 
		MessageTemplate = "Customer no must have {3} characters.")]
[RegexValidator("[A-Z]{2}[0-9]{3}", 
	MessageTemplate = "Customer no must be 2 capital letters and 3 numbers.")]
public string CustomerNo { get; set; }

Message template is a good way to provide meaningful messages on failure with the flexibility to be replaced by Enterprise Library validation block for brackets.

Data Annotation Attributes

In this approach, we define our validations through the attributes defined within System.ComponentModel.DataAnnotations assembly.

[Required(ErrorMessage = "Customer no can not be empty")]
[StringLength(5, ErrorMessage = "Customer no must be 5 characters.")]
[RegularExpression("[A-Z]{2}[0-9]{3}", 
	ErrorMessage = "Customer no must be 2 capital letters and 3 numbers.")]
public string CustomerNo { get; set; }

This approach is widely used in conjunction with Entity Framework, MVC and ASP.NET validations.

Self-validation

This approach gives much flexibility to us in order to create and execute complex validation rules.

In order to implement this approach, we first decorate HasSelfValidation attribute with the object type as shown in the following example:

[HasSelfValidation]
public class AttributeCustomer
{
    …
}

 

Then, we write our validation logic by putting SelfValidation attribute on the top of the method which executes the validations.

[SelfValidation]
public void Validate(ValidationResults validationResults)
{
    var age = DateTime.Now.Year - DateTime.Parse(BirthDate).Year;

    // Due to laws, only customers older than 18 can be registered 
    // to system and allowed to order products
    if (age < 18)
    {
        validationResults.AddResult(
            new ValidationResult("Customer must be older than 18",
                this,
                "BirthDate",
                null,
                null));
    }
}

Validators Created Programmatically

This approach is different from the others because validation rules are created programmatically and executed independent of the type.

First, we define our validation rules:

Validator[] validators = new Validator[] 
{ 
    new NotNullValidator(false, "Value can not be NULL."),
    new StringLengthValidator(5, RangeBoundaryType.Inclusive, 
	5, RangeBoundaryType.Inclusive,  "Value must be between {3} and {5} chars.")
};

Then, we add them into one of the composite validators depending on your preference.

var validator = new AndCompositeValidator(validators);

In this example, we check Value to be tested… if it is not null and it has five exact characters.

Finally, I want to mention about the validations against collections. Actually, it is similar to the validations for objects.

// Initialize our object and set the values
var customer = new AttributeCustomer();
            
FillCustomerInfo(customer);

// Create a list of objects and add the objects to be tested to the list
List<AttributeCustomer> customers = new List<AttributeCustomer>();
customers.Add(customer);

// Initialize our validator by providing the type of objects in the list and validate them
Validator cusValidator = new ObjectCollectionValidator(typeof(AttributeCustomer));
ValidationResults valResults = cusValidator.Validate(customers);

// Show our validation results
ShowResults(valResults);

 

First thought was to use the MVC answer to validation – DataAnnotations, so why can’t we do this?

WCF is technology for exposing services and it does it in interoperable way. Data contract exposed by the service is just create for data. It doesn’t matter how many fancy attributes you use on the contract or how many custom logic you put inside get and set methods of the property. On the client side you always see just the properties.

The reason for this is that once you expose the service it exposes all its contracts in interoperable way – service and operation contracts are described by WSDL and data contracts are described by XSD. XSD can describe only structure of data but no logic. The validation itself can be in some limited way be described in XSD but .NET XSD generator doesn’t do this. Once you add service reference to your WCF service the proxy generator will take WSDL and XSD as a source and create your classes again without all that attributes.

If you want to have client side validation you should in the first place implement that validation on the client side – it can be done by using buddy classes for partial classes used by WCF proxy. If you want to have a maintenance nightmare and you don’t want to use this way you must share assembly with your entities between your WCF client and WCF service and reuse those types when adding service reference. This will create tight coupling between your service and ASP.NET MVC application.

What about Microsoft.Practices.EnterpriseLibrary.Validation.Validators?

This is a possible solution to the WCF layer, but what this does not provide is a process to pass the validation back to the UI for JavaScript validation, which you get from DataAnnotations.

It may be worth using both the DataAnnotations and the Enterprise Library validation block together.

One question still to remain, is if the validation fails in the Services layer (WCF) how does the validation message get passed to the calling WCF client?

In general, when working with an MVC/ASP.NET web application, you would typically want to do validation on the client-side as well as on the server side. Whilst the custom validation is simple enough, you’d have to duplicate it on the client and server, which is annoying – now you have two places to maintain a single validation routine.

So what else can we use?

First of all, do not throw Exceptions as a way of validating data – that’s a way too expensive operation, instead of graceful handling of invalid data.

If you would like to see some sample code take a look at Microsoft Enterprise Library 5.0 – Introduction to Validation Block by Ercan Anlama

ELValidation_src.zip (772.17 kb)

 

We’ve looked at all possible validation options, now the searching question is how do pass the validation over WCF to the WCF client for validation?  to be continued……

MVC running on IIS8

After a number of 500 errors coming up from IIS8 under Windows Server 2012, I final found the solution.

The solution was to go back to the Microsoft Server 2012 Dashboard and select the “Add Roles” feature. Scroll down to the root “Web Server (IIS)”, expand “Web Server”, expand “Application Development” and select “ASP.NET 3.5” and “ASP.NET 4.5” and “Install”.

What confused me originally was I hadn’t expanded “Application Development”, but selected IIS and continued. On the next step, “Features”, “.NET Framework 4.5 Features” was selected by default so I selected “.NET Framework 3.5 Features” and thought all would be fine.