programming4us
programming4us
ENTERPRISE

Microsoft Enterprise Library : Banishing Validation Complication - Diving in With Some Simple Examples (part 4)

- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire
11/15/2013 6:56:52 PM

4. WCF Service Validation Integration

The Validation block allows you to add validation attributes to the parameters of methods defined in your WCF service contract, and have the values of these automatically validated each time the method is invoked by a client.

To use WCF integration, you edit your service contract, edit the WCF configuration to add the Validation block and behaviors, and then handle errors that arise due to validation failures. In addition to the other assemblies required by Enterprise Library and the Validation block, you must add the assembly named Microsoft.Practices.Enterprise Library.Validation.Integration.WCF to your application and reference them all in your service project.

The example, Validating Parameters in a WCF Service, demonstrates validation in a simple WCF service. It uses a service named ProductService (defined in the Example Service project of the solution). This service contains a method named AddNewProduct that accepts a set of values for a product, and adds this product to its internal list of products.

Defining Validation in the Service Contract

The service contract, shown below, carries the ValidationBehavior attribute, and each service method defines a fault contract of type ValidationFault.

[ServiceContract]
[ValidationBehavior]
public interface IProductService
{
[OperationContract]
[FaultContract(typeof(ValidationFault))]
bool AddNewProduct(
[NotNullValidator(MessageTemplate = "Must specify a product ID.")]
[StringLengthValidator(6, RangeBoundaryType.Inclusive,
6, RangeBoundaryType.Inclusive,
MessageTemplate = "Product ID must be {3} characters.")]
[RegexValidator("[A-Z]{2}[0-9]{4}",
MessageTemplate = "Product ID must be 2 letters and 4 numbers.")]
string id,
...
[IgnoreNulls(MessageTemplate = "Description can be NULL or a string value.")]
[StringLengthValidator(5, RangeBoundaryType.Inclusive,
100, RangeBoundaryType.Inclusive,
MessageTemplate = "Description must be between {3} and {5} characters.")]
string description,
[EnumConversionValidator(typeof(ProductType),
MessageTemplate = "Must be a value from the '{3}' enumeration.")]
string prodType,
...
[ValidatorComposition(CompositionType.Or,
MessageTemplate = "Date must be between today and six months time.")]
[NotNullValidator(Negated = true,
MessageTemplate = "Value can be NULL or a date.")]
[RelativeDateTimeValidator(0, DateTimeUnit.Day, 6, DateTimeUnit.Month,
MessageTemplate = "Value can be NULL or a date.")]
DateTime? dateDue);
}

You can see that the service contract defines a method named AddNewProduct that takes as parameters the value for each property of the Product class we've used throughout the examples. Although the previous listing omits some attributes to limit duplication and make it easier to see the structure of the contract, the rules applied in the example service we provide are the same as you saw in earlier examples of validating a Product instance. The method implementation within the WCF service is simple—it just uses the values provided to create a new Product and adds it to a generic List.

Editing the Service Configuration

After you define the service and its validation rules, you must edit the service configuration to force validation to occur. The first step is to specify the Validation block as a behavior extension. You will need to provide the appropriate version information for the assembly, which you can obtain from the configuration file generated by the configuration tool for the client application, or from the source code of the example, depending on whether you are using the assemblies provided with Enterprise Library or assemblies you have compiled yourself.

<extensions>
<behaviorExtensions>
<add name="validation"
type="Microsoft.Practices...WCF.ValidationElement,
Microsoft.Practices...WCF" />
</behaviorExtensions>
... other existing behavior extensions here ...
</extensions>

Next, you edit the <behaviors> section of the configuration to define the validation behavior you want to apply. As well as turning on validation here, you can specify a rule set name (as shown) if you want to perform validation using only a subset of the rules defined in the service. Validation will then only include rules defined in validation attributes that contain the appropriate Ruleset parameter (the configuration for the example application does not specify a rule set name here).

<behaviors>
<endpointBehaviors>
<behavior name="ValidationBehavior">
<validation enabled="true" ruleset="MyRuleset" />
</behavior>
</endpointBehaviors>
... other existing behaviors here ...
</behaviors>

Note

Note that you cannot use a configuration rule set with a WCF service—all validation rules must be in attributes.

Finally, you edit the <services> section of the configuration to link the ValidationBehavior defined above to the service your WCF application exposes. You do this by adding the behaviorConfiguration attribute to the service element for your service, as shown here.

<services>
<service behaviorConfiguration="ExampleService.ProductServiceBehavior"
name="ExampleService.ProductService">
<endpoint address="" behaviorConfiguration="ValidationBehavior"
binding="wsHttpBinding" contract="ExampleService.IProductService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
...
</services>

Using the Product Service and Detecting Validation Errors

At last you can use the WCF service you have created. The example uses a service reference added to the main project, and initializes the service using the service reference in the usual way. It then creates a new instance of a Product class, populates it with valid values, and calls the AddNewProduct method of the WCF service. Then it repeats the process, but this time by populating the product instance with invalid values. You can examine the code in the example to see this if you wish.

However, one important issue is the way that service exceptions are handled. The example code specifically catches exceptions of type FaultException<ValidationFault> . This is the exception generated by the service, and ValidationFault is the type of the fault contract we specified in the service contract.

Validation errors detected in the WCF service are returned in the Details property of the exception as a collection. You can simply iterate this collection to see the validation errors. However, if you want to combine them into a ValidationResults instance for display, especially if this is part of a multi-step process that may cause other validation errors, you must convert the collection of validation errors returned in the exception.

The example application does this using a method named ConvertToValidationResults, as shown here. Notice that the validation errors returned in the ValidationFault do not contain information about the validator that generated the error, and so we must use a null value for this when creating each ValidationResult instance.

// Convert the validation details in the exception to individual
// ValidationResult instances and add them to the collection.
ValidationResults adaptedResults = new ValidationResults();
foreach (ValidationDetail result in results)
{
adaptedResults.AddResult(new ValidationResult(result.Message, target,
result.Key, result.Tag, null));
}
return adaptedResults;

When you execute this example, you will see a message indicating the service being started—this may take a while the first time, and may even time out so that you need to try again. Then the output shows the result of validating the valid Product instance (which succeeds) and the result of validating the invalid instance (which produces the now familiar list of validation errors shown here).

The following 6 validation errors were detected:
+ Target object: Product, Member:
- Detected by: [none]
- Tag value: id
- Message: 'Product ID must be two capital letters and four numbers.'
...
+ Target object: Product, Member:
- Detected by: [none]
- Tag value: description
- Message: 'Description can be NULL or a string value.'
+ Target object: Product, Member:
- Detected by: [none]
- Tag value: prodType
- Message: 'Product type must be a value from the 'ProductType' enumeration.'
...
+ Target object: Product, Member:
- Detected by: [none]
- Tag value: dateDue
- Message: 'Date due must be between today and six months time.'

Again, we've omitted some of the duplication so that you can more easily see the result. Notice that there is no value available for the name of the member being validated or the validator that was used. This is a form of exception shielding that prevents external clients from gaining information about the internal workings of the service. However, the Tag value returns the name of the parameter that failed validation (the parameter names are exposed by the service), allowing you to see which of the values you sent to the service actually failed validation.

5. User Interface Validation Integration

The Validation block contains integration components that make it easy to use the Validation block mechanism and rules to validate user input within the user interface of ASP.NET, Windows Forms, and WPF applications. While these technologies do include facilities to perform validation, this validation is generally based on individual controls and values.

When you integrate the Validation block with your applications, you can validate entire objects, and collections of objects, using sets of rules you define. You can also apply complex validation using the wide range of validators included with the Validation block. This allows you to centrally define a single set of validation rules, and apply them in more than one layer and when using different UI technologies.

Note

The UI integration technologies provided with the Validation block do not instantiate the classes that contain the validation rules. This means that you cannot use self-validation with these technologies.

ASP.NET User Interface Validation

The Validation block includes the PropertyProxyValidator class that derives from the ASP.NET BaseValidator control, and can therefore take part in the standard ASP.NET validation cycle. It acts as a wrapper that links an ASP.NET control on your Web page to a rule set defined in your application through configuration, attributes, and self-validation.

To use the PropertyProxyValidator, you add the assembly named Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet to your application, and reference it in your project. You must also include a Register directive in your Web pages to specify this assembly and the prefix for the element that will insert the PropertyProxyValidator into your page.

<% @Register TagPrefix="EntLibValidators"
Assembly="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet"
Namespace="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet"
%>

Then you can define the validation controls in your page. The following shows an example that validates a text box that accepts a value for the FirstName property of a Customer class, and validates it using the rule set named RuleSetA.

<EntLibValidators:PropertyProxyValidator id="firstNameValidator"
runat="server" ControlToValidate="firstNameTextBox"
PropertyName="FirstName" RulesetName="RuleSetA"
SourceTypeName="ValidationQuickStart.BusinessEntities.Customer" />

One point to be aware of is that, unlike the ASP.NET validation controls, the Validation block PropertyProxyValidator control does not perform client-side validation. However, it does integrate with the server-based code and will display validation error messages in the page in the same way as the ASP.NET validation controls.

Windows Forms User Interface Validation

The Validation block includes the ValidationProvider component that extends Windows Forms controls to provide validation using a rule set defined in your application through configuration, attributes, and self-validation. You can handle the Validating event to perform validation, or invoke validation by calling the PerformValidation method of the control. You can also specify an ErrorProvider that will receive formatted validation error messages.

To use the ValidationProvider, you add the assembly named Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms to your application, and reference it in your project.

WPF User Interface Validation

The Validation block includes the ValidatorRule component that you can use in the binding of a WPF control to provide validation using a rule set defined in your application through configuration, attributes, and self-validation. To use the ValidatorRule, you add the assembly named Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WPF to your application, and reference it in your project.

As an example, you can add a validation rule directly to a control, as shown here.

<TextBox x:Name="TextBox1">
<TextBox.Text>
<Binding Path="ValidatedStringProperty" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<vab:ValidatorRule SourceType="{x:Type test:ValidatedObject}"
SourcePropertyName="ValidatedStringProperty"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

You can also specify a rule set using the RulesetName property, and use the Validation SpecificationSource property to refine the way that the block creates the validator for the property.

Other  
  •  Microsoft Enterprise Library : Banishing Validation Complication - How Do I Use The Validation Block?
  •  Microsoft Enterprise Library : Banishing Validation Complication - What Does the Validation Block Do? (part 2)
  •  Microsoft Enterprise Library : Banishing Validation Complication - What Does the Validation Block Do? (part 1)
  •  Microsoft Enterprise Library : A Cache Advance for Your Applications - How Do I Use the Caching Block (part 4) - Refreshing the Cache, Loading the Cache
  •  Microsoft Enterprise Library : A Cache Advance for Your Applications - How Do I Use the Caching Block (part 3) - Removing Items from and Flushing the Cache
  •  Microsoft Enterprise Library : A Cache Advance for Your Applications - How Do I Use the Caching Block (part 2)
  •  Microsoft Enterprise Library : A Cache Advance for Your Applications - How Do I Use the Caching Block (part 1) - Adding Items to and Retrieving Items from the Cache
  •  Microsoft Enterprise Library : A Cache Advance for Your Applications - How Do I Configure the Caching Block?
  •  Microsoft Visual Studio 2010 : Data Parallelism - Unrolling Sequential Loops into Parallel Tasks (part 4) - Handling Exceptions
  •  Microsoft Visual Studio 2010 : Data Parallelism - Unrolling Sequential Loops into Parallel Tasks (part 3) - Interrupting a Loop
  •  
    Top 10
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
    - Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
    - Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    programming4us programming4us
    programming4us
     
     
    programming4us