Introduction
Validation block is used for validation purposes and supports technology specific integration features such WPF and WCF. It offers an easy and relatively simpler way
to validate data compared with the validation methods provided by most technologies. I will focus on how to integrate the validation block in Microsoft Enterprise Library 5.0 with WCF.
You can learn what the validation block is and how to use it in your projects from the following
article: Microsoft Enterprise Library 5.0 - Introduction to Validation Block.
Background
WCF employs its own validation methods through the implementation of the IParameterInspector
interface. You can find a good article showing how to consume the IParameterInspector
interface for validation from the following
address: How to: Perform Input Validation in WCF.
This method actually requires more effort and offers more complex ways than the validation block does. Through the validation block, you just focus on what to validate rather
than how to validate. This makes the validation block appeal. Also, it prevents you from complexities, writing your own validations and maintaining them.
How to configure
Although it saves you from complexities, I dream of a technology without configuration, but nice news, because you just need to put the following setting into the configuration of your WCF.
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="validation"
type="Microsoft.Practices.EnterpriseLibrary.
Validation.Integration.WCF.ValidationElement,
Microsoft.Practices.EnterpriseLibrary.
Validation.Integration.WCF,
Version=5.0.414.0,
Culture=neutral,
PublicKeyToken=31bf3856ad364e35" />
</behaviorExtensions>
</extensions>
.......
</system.serviceModel>
After porting the required setting, we need one more step to start. In addition to the validation and common assemblies,
we also need to add Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF
as a reference to our project.
Here is the structure of the references:
Developing our project
I developed a WCF service and a client WPF application. The WPF application will send the data from the UI to the WCF service and check the results.
Here is the project structure:
After configuration and building the project structure, we can write the WCF service and the WPF application. Let's start with the service part.
Service side
In the service side, we create a service named SalaryService
. This service exposes two methods: CalculatePartial
and CalculateFull
.
These two methods actually do the same thing, but in different ways.
[ServiceContract]
[ValidationBehavior]
public interface ISalaryService
{
[OperationContract]
[FaultContract(typeof(ValidationFault))]
string CalculatePartial(
[RangeValidator(2, RangeBoundaryType.Inclusive, 5,
RangeBoundaryType.Inclusive,
MessageTemplate =
"Education level must be between {3} and {5}")]
int EducationLevel,
[RangeValidator(0, RangeBoundaryType.Inclusive, 30,
RangeBoundaryType.Inclusive,
MessageTemplate =
"Your experience in years must be between {3} and {5}")]
int ExperienceInYears,
[NotNullValidator(MessageTemplate =
"You must supply your currency")]
[StringLengthValidator(1, RangeBoundaryType.Inclusive, 3,
RangeBoundaryType.Inclusive,
MessageTemplate =
"Currency code must be between {3} and {5} characters.")]
string Currency,
bool HasCertificate,
bool InvolvedInManagement
);
[OperationContract]
[FaultContract(typeof(ValidationFault))]
string CalculateFull(
[NotNullValidator(MessageTemplate =
"You must supply your education level")]
[TypeConversionValidator(typeof(int),
MessageTemplate =
"You must supply a valid level of your education")]
[RangeValidator("2", RangeBoundaryType.Inclusive, "5",
RangeBoundaryType.Inclusive,
MessageTemplate =
"Education level must be between {3} and {5}")]
string EducationLevel,
[NotNullValidator(MessageTemplate =
"You must supply your experience in years")]
[TypeConversionValidator(typeof(int),
MessageTemplate = "You must supply a valid
number of experience in years")]
[RangeValidator("0", RangeBoundaryType.Inclusive, "30",
RangeBoundaryType.Inclusive,
MessageTemplate = "Your experience in years
must be between {3} and {5}")]
string ExperienceInYears,
[NotNullValidator(MessageTemplate = "You must supply your currency")]
[StringLengthValidator(1, RangeBoundaryType.Inclusive, 3,
RangeBoundaryType.Inclusive,
MessageTemplate = "Currency code must
be between {3} and {5} characters.")]
string Currency,
[NotNullValidator(MessageTemplate =
"You must supply your certificate status")]
[TypeConversionValidator(typeof(bool),
MessageTemplate = "You must supply a valid
status for your certificate status")]
string HasCertificate,
[NotNullValidator(MessageTemplate =
"You must supply your status for management involvement")]
[TypeConversionValidator(typeof(bool),
MessageTemplate = "You must supply a valid
status for management involvement")]
string InvolvedInManagement
);
}
Above, you see the contract for SalaryService
. In order to make WCF service work with the validation block, we need to do two things:
- Decorate service contract (interface) with the
ValidationBehavior
attribute - Decorate operation with
[FaultContract(typeof(ValidationFault))]
By doing these items, we tell the validation block to check for validations and provide the validation errors to the client on failure. Let's see how clients get these error messages now.
Client side
SalaryServiceReference.SalaryServiceClient salaryClient;
private void btnSendDataPartial_Click(object sender, RoutedEventArgs e)
{
salaryClient = new SalaryServiceReference.SalaryServiceClient();
try
{
var result = salaryClient.CalculatePartial(
Convert.ToInt32(this.txtEducationLevel.Text),
Convert.ToInt32(this.txtExperienceInYears.Text),
this.txtCurrency.Text,
Convert.ToBoolean(this.txtHasCertificate.Text),
Convert.ToBoolean(this.txtInvolvedInManagement.Text));
MessageBox.Show(result);
}
catch (FaultException<ValidationFault> validationEx)
{
foreach (var validationError in validationEx.Detail.Details)
{
MessageBox.Show(String.Format("Invalid input for {0} - {1}",
validationError.Tag, validationError.Message));
}
salaryClient.Abort();
}
catch (Exception ex)
{
MessageBox.Show("Unhandled exception: " + ex.ToString());
salaryClient.Abort();
}
finally
{
if (salaryClient.State == CommunicationState.Opened)
{
salaryClient.Close();
}
}
}
private void btnSendDataFull_Click(object sender, RoutedEventArgs e)
{
salaryClient = new SalaryServiceReference.SalaryServiceClient();
try
{
var result = salaryClient.CalculateFull(
this.txtEducationLevel.Text,
this.txtExperienceInYears.Text,
this.txtCurrency.Text,
this.txtHasCertificate.Text,
this.txtInvolvedInManagement.Text);
MessageBox.Show(result);
}
catch (FaultException<ValidationFault> validationEx)
{
foreach (var validationError in validationEx.Detail.Details)
{
MessageBox.Show(String.Format("Invalid input for {0} - {1}",
validationError.Tag, validationError.Message));
}
salaryClient.Abort();
}
catch (Exception ex)
{
MessageBox.Show("Unhandled exception: " + ex.ToString());
salaryClient.Abort();
}
finally
{
if (salaryClient.State == CommunicationState.Opened)
{
salaryClient.Close();
}
}
}
Above, you see how the WCF service operations are consumed by the client. We get the exceptions as we do for other types of exceptions for WCF, with the help
of FaultException<>
. Remember that we decorated the service operations with ValidationFault
, which is a custom SOAP exception provided by
the validation block, so we can detect the validation exceptions with FaultException<ValidationFault>
.
After capturing the validation exception, it is easy to iterate over the error messages and the parameters which cause the validation exceptions. Let's see it in action now.
Sample
Here is a screen from the client WPF application:
After filling the input and clicking on one of the buttons, we see a similar screen, including the error message and the reason provided by the WCF service through the validation block.
Also, we have two methods, CalculatePartial
and CalculateFull
. The difference between these two methods is that the first one uses strongly typed
parameters while the latter uses string type as the base type for all the parameters and forces the validation block to validate the input type through the attribute
TypeConversionValidator
.
Final words
Validation block is impressive when it comes to validation and keeps its power through the support of technology specific features for WCF, WPF, WinForms, and ASP.NET.
It makes validations simpler and more maintainable compared with other solutions and make you focus on what to validate. I tried to explain how to integrate
the WCF features provided by the validation block in Microsoft Enterprise Library. Lastly, I want to mention a difference in the way in which validation block is used in the implementation
with WCF. There is no support to validate the parameters using a configuration file in WCF, so we must consider using code base validation.