I am starting to write a series of blog articles, each varying in complexity, highlighting how we use can the Validation Application Blocks within the Microsoft Enterprise Library to do really neat validation. Extremely flexible and configurable at runtime. Although we will slowly build towards that.
In this first part let me just give a brief introduction to what the VAB actually is some simple ways of using it within a WCF service.
While writing WCF services we often cannot guarantee the data we get passed in, let it be simple data like integers or complex business objects such as Customers or even worse, process definitions. Although, as developers we have to design some sort of clever program which can intelligently sorting out good data from bad data. Good data is often derived from pages of use cases and business rules. These rules tend to change often so it’s only advisable that we allow for this by allowing our program (in this case a WCF service) to read this rules at runtime. This is our end goal.
In the early days I used to do simple checks on data to determine its validity. Although strenuous and naive, it worked. For e.g. if you have a service which finds the square root of a number then we know for a fact that it cannot accept a negative number. So a developer has the following options:
- Don’t care about the erroneous input
- Cater for error scenarios (number being less than 0) and return a exception
- Cater for error scenarios (number being less than 0) and return a message
- Return an exception which has the message
Yes, the last option does look the most tempting but a bit harder to implement. Let us try and work through the other options first, for all our scenarios we will have the same interface and client definition:
Interface:
namespace VABService
{
[ServiceContract]
public interface IMyService
{
[OperationContract]
double SquareRoot(double number);
}
}
Client:
namespace VABServiceClient
{
class Program
{
static void Main(string[] args)
{
service.MyServiceClient client = null;
try
{
client = new VABServiceClient.service.MyServiceClient();
double result = client.SquareRoot(4);
}
catch (Exception e)
{
}
finally
{
if (client != null && client.State != System.ServiceModel.CommunicationState.Faulted)
{
try
{
client.Close();
}
catch (Exception e)
{
// don't care
}
}
}
}
}
}
Don’t care about the erroneous input With this approach our implementation looks simple and we end up with:
namespace VABService
{
public class MyService : IMyService
{
#region IMyService Members
public double SquareRoot(double number)
{
return Math.Sqrt(number);
}
#endregion
}
}
This service implementation will allow for the correct square root to be returned but say instead of passing in a positive integer we pass in a negative integer: –4; can the service guarantee a deterministic result? I don’t think so, the most the developer can say is that it will do whatever the .Net environment is set up to do. Left as is the result coming back will be NaN.
If the client was a high risk financial application and the service returned this value, the result would be quite catastrophic unless both the client and the service came to some sort of prior agreement about this returned value. Although wouldn’t it be nice if we raised an exception or an error of some kind sighting the problem?
Cater for error scenarios (with an Exception) To allow for an exception to be raised we have to slightly change the service implementation as shown below:
namespace VABService
{
public class MyService : IMyService
{
#region IMyService Members
public double SquareRoot(double number)
{
if (number < 0)
throw new ArgumentOutOfRangeException(string.Format("Square root of negative numbers cannot be determined:{0}.", number));
return Math.Sqrt(number);
}
#endregion
}
}
Now with the same client as before if we pass in a negative number we get a exception although the client is nonetheless wiser than it was before:
You see the above exception because of an attempt to hide the implementation details of the service from the clients calling it. Just as the exception states, if we set the flag IncludeExceptionDetailsInFaults to be true, we will actually see why the exception occurred:
Although this is opening up our service unnecessarily and clients can get a clear view of our implementation when things go wrong and lets face it, things always can go wrong! So we want to avoid setting IncludeExceptionDetailsInFaults to true in a production environment.
Cater for error scenarios (with a message) To allow for this we have to add even more code to the implementation and also add another parameter to our interface which we can use to pass back the error message, which in this case is the exception text. We all know how this is going to look, yes UGLY! We don’t want to do that!!! This brings us to our last option and the most elegant solution.
Return an exception which has the message This is where Geers Blog comes in handy. WCF exposes really neat things which can be used to do all sorts of validation but why do this when we can go one step further and use an already well thought and designed framework wrapper. Yes, the VAB is exactly that.
The Meat
Yes so far all you have seen is bones and why, what…and blah blah, boring stuff. The meat of the post is now here…let us use the VAB to do simple validation while finding the square root of a number.
First step would be to install the enterprise library and add a reference to (within your service project):
Microsoft.Practices.EnterpriseLibrary.Validation.integration.WCF
Microsoft.Practices.EnterpriseLibrary.Validation.dll
Microsoft.Practices.EnterpriseLibrary.Common.dll
After doing so we’ll need to make 3 changes…
- Service interface change
Our service interface will now contain the following code.
using System;
using System.ServiceModel;
using Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
namespace VABService
{
[ServiceContract]
public interface IMyService
{
[OperationContract]
[FaultContract(typeof(ValidationFault))]
double SquareRoot(
[RangeValidator(0, RangeBoundaryType.Inclusive, Double.MaxValue, RangeBoundaryType.Inclusive)]
double number);
}
}
Note that we now have a rangevalidator for the parameter “number” and also declare that this particular interface method has a fault contract of type ValidationFault associated to it - Config file
Note that we have only added new a endpoint behaviour, a behaviour extension and mapped our already existing endpoint to the newly added endpoint behaviour. - Client change
static void Main(string[] args)
{
service.MyServiceClient client = null;
try
{
client = new VABServiceClient.service.MyServiceClient();
double result = client.SquareRoot(-4);
}
catch (FaultExceptionfe)
{
}
catch (Exception e)
{
}
finally
{
if (client != null && client.State != System.ServiceModel.CommunicationState.Faulted)
{
try
{
client.Close();
}
catch (Exception e)
{
// don't care
}
}
}
}
With this change in the client, now instead of getting simply exceptions without any message we get a particular type of exception which we can catch and investigate as shown in the image below:
We’ll look at other validators in Part 2.
Got more information about Microsoft Enterprise Library VAB with WCF services.
ReplyDeleteConvert VB to C#
VB6 to VB.Net Migration
Convert ASP to ASP.Net