Validating WCF Service Messages with Validation Application Block

This post is one of a post series about WCF Integration in Enterprise Library 3.0.

This is the first post that I am writing about the integration between Windows Communication Foundation and Validation Application Block in Enterprise Library 3.0. This post will focus on what you should do in order to declare the validation on parameters of service operations.

When you want to make sure that the service operation receives valid parameters, you can achieve that in two ways:

1. Validating Parameters on a service operation

If your service operation received parameters with primitive types, such as:

[OperationContract]

int CreateOrder(string currency, double amount);

and you still want to validate them, you can use the parameter-level validation in the service contract:

[ServiceContract]

public interface IOrdersService

    [OperationContract]

    int CreateOrder(

        [NotNullValidator] string currency,

        [RangeValidator(1.0, RangeBoundaryType.Inclusive, 2.0, RangeBoundaryType.Inclusive)] double amount);

}

Notice the usage of the validation attributes before each of the parameters of the service operation.

2. Validating Message Contracts or Data Contracts passed to a service operation

If your service operation received Data Contract parameter or a
Message Contract parameter, you actually use the validation logic
specified above them. For example, this a Data Contract of order data
that has validation logic that make sure that the input currency is one
of a pre-defined domain of values.

[DataContract]

public class OrderData

    [DataMember]

    public double Amount

    {

        get { return amount; }

        set { amount = value; }

    }

 

    [DataMember]

    [DomainValidator("USD","EUR","JPY")]

    public string Currency

    {

        get { return currency; }

        set { currency = value; }

    }

}

Now, when you use it in a service contract definition, you don’t
have to specify the validation for the input parameters, since it will
be taken from the Data Contract definition.

[OperationContract]

OrderInfo CreateOrder(OrderData orderData);

Keep in mind that in order to validate an object, using attributes
is not the only way to do so. If you need more flexibility you can do
it using the configuration file.

The Validation Application Block Integration with WCF is implemented by a Parameter Inspector.
I’ll talk about this in details in a later post, but for now I’ll say
that the Validation Application Block inspector intercepts calls to
service operations and performs logic for validating the parameters
passed to that operation. What happens if the parameters are found
invalid is that the actual service operation is never get executed, and
an exception (actually a Fault) is thrown back to the client.

Validation Results

When using the standard code to validate on object, we usually use
the following code snippet. We validate the target object, receive back
a ValidationResults object that contains the list of validation results that were returned by the validators.

Validator validator = ValidationFactory.CreateValidator<OrderData>();

ValidationResults results = validator.Validate(myOrderData);

foreach (ValidationResult result in results)

{

    … 

}

With WCF Services things are a little but different, since we do not
validate the objects, but the Parameter Inspector does. If the
parameters are found invalid, the Parameter Inspector throws a FaultException<ValidationFault> which is translated to a Soap Fault on the wire. The ValidationFault class (similar to ValidationResults) contains an array of ValidationDetails items which are similar to ValidationResult items that contain the validation message, key and tag.
The
WCF Fault Handling is a basic subject that one should be familiar with
and it is not part of this post, but what is important to mention is
that if you want to be able to catch this exception in the client, and
 get the details about the validation errors, there are two things that
you want to do:

1. Specify the FaultContract attribute foreach service operation that has a validation attached to it (or its parameters), and give the ValidationFault class as the type of the fault:

[ServiceContract]

public interface IOrdersService

{

    [FaultContract(typeof(ValidationFault))]

    [OperationContract]

    OrderInfo CreateOrder(OrderData orderData);

}

2. Use the following code to catch the validation exception and investigate the validation details.

try

{

    // Call the service operation

}

catch (FaultException<ValidationFault> ex)

{

    // Extract the Detail node from the Fault Exception. This details is the

    // ValidationFault class

    ValidationFault fault = ex.Detail;

 

    // Iterate through the list of validation errors

    Console.WriteLine("Fault Occurred:");

    foreach (ValidationDetail validationResult in faults.Details)

    {

        Console.WriteLine(string.Format("Message={0} Key={1} Tag={2}",

            validationResult.Message, validationResult.Key, validationResult.Tag));

    }

}

As I will discuss in more details later, the Validation Application Block extension to WCF is done using a ValidationBehavior.
A WCF behavior is a component that controls various run-time aspects of
a service, an endpoint, a particular operation, or a client, and can be
configured via attributes or configuration. Same goes for the
Validation Behavior:

Using attributes to Configure Validation

One
way to add the validation behavior to the service is to set the
[ValidationBehavior] attribute above the service contract. This
attribute adds a ValidationParametersInspector to the each operation runtime definition in order to be executed each time a service operation is called.

[ServiceContract]

[ValidationBehavior]

public interface IOrdersService

{

    …

}

Configuring Validation using Configuration File

The first thing you should do in order to configure the validation application block extension to WCF is to declare the Validation Behavior Extension:

<configuration>

  <system.serviceModel>

 

    <extensions>

      <behaviorExtensions>

        <add name="validation"

             type="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.ValidationElement,
Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF,
Version=3.0.0.0, Culture=neutral, PublicKeyToken=null
" />

      </behaviorExtensions>

    </extensions>

 

  </system.serviceModel>

</configuration>

This
declaration in the configuration file allows you to configure an
Endpoint Behavior that uses definitions in a configuration element
specified in that extension. In our case, this is the ValidationElement, which has two attributes: enabled (true/false) and ruleset (string).

The definition of this endpoint behavior will look like this:

 

<configuration>

  <system.serviceModel>

 

    <behaviors>

      <endpointBehaviors>

        <behavior name="Validation">

          <validation enabled="true" ruleset="myruleset"/>

        </behavior>

      </endpointBehaviors> 

    </behaviors>

 

  </system.serviceModel>

</configuration>

While
using the [ValidationBehavior] attribute adds a service-level behavior
to the service, using the configuration approach adds an endpoint-level
behavior. This way, if you expose multiple endpoints for you service
you have more flexibility in changing the validation rules between the
endpoint, but basically, the affect is same in both approaches.

In
order to relate an endpoint to the above behavior, you have to add the
behaviorConfiguration attribute to the endpoint definition.

Here
is a complete configuration snippet that shows all the configuration
needed in order to add the validation to the service endpoints.

 

<configuration>

  <system.serviceModel>

    <services>

      <service name="Bursteg.Samples.WCFIntegration.Services.OrdersService">

 

        <endpoint address="http://localhost:8080/OrdersService"

                  binding="basicHttpBinding"

                  behaviorConfiguration="Validation"

                  contract="Bursteg.Samples.WCFIntegration.ServiceContracts.IOrdersService" />

      </service>

    </services>

 

    <behaviors>

      <endpointBehaviors>

        <behavior name="Validation">

          <validation enabled="true" ruleset="myruleset"/>

        </behavior>

      </endpointBehaviors>

  

    <extensions>

      <behaviorExtensions>

        <add name="validation"

            type="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.ValidationElement,
Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF,
Version=3.0.0.0, Culture=neutral, PublicKeyToken=null
" />

      </behaviorExtensions>

    </extensions>

 

  </system.serviceModel>

</configuration>

In this post I talked about the steps one should follow in order to enable the validation of a WCF Service.

I hope that by now you have enough information to get started with WCF and Validation Application Block together. You can download a sample project that contains a WCF Service with some validation parameters and configuration settings.

This entry was posted in Best Practices. Bookmark the permalink.

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s