|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis is the first in a series of articles, code samples and presentations that deal with design (and architecture?) ‘Below’ the enterprise level. Enterprise patterns are valuable for applications that have requirements for scalability, availability, maintainability, security and manageability, but using them for applications with less strenuous requirements (over-engineering) can have a negative impact on both developability and maintainability. So I approached building this design sample in a different way. The primary requirement is that it does the job; the secondary requirement is that it is easy to explain/understand. Nothing else gets a look in. This has led to some interesting design decisions – it doesn’t look like anything I have built for a while. I’ll point these design points out as we go through it. If you download simplevalidation.zip from the source files link above, extract and open the SimpleValidation solution it contains using VS.NET 2003 (it works OK in VS.NET 2005 as well) you will see the following projects:
This solution implements a simple (passive – no eventing) way of performing business layer validation. The objective here is to implement validation of datasets, business object collections, XML documents or whatever else you are using as your data transfer objects as an aspect. If you don’t understand where this would fit in a layered service oriented design, I’ll cover ‘standard’ (simple?) layers and tiers in another article in a couple of weeks. To see what it does, run the ValidationTest (default) project. This exercises two different validation libraries, IntegerValidationRules and OrderValidationRules. Integer ValidatorWhen you click on the Validate button in the Integer test it ends up executing the following line of code: Dim results As IntegerValidationRules.ValidationResultCollection =
IntegerValidationRules.Validator.Validate(ii, -1)
This calls the Validate method of the The first part of the validate method (shown below) loads up the
IntegerValidationRules Validator – Part 1public class Validator
{
public static SortedList ValidationRules;
public static ValidationResultCollection Validate(
object objectToValidate, int maxValidationFailures)
{
if (ValidationRules == null)
{
// Add the validation rules from the current
// assembly to the set to use - sorted by Priority
ValidationRules = new SortedList();
Assembly vAss = Assembly.GetExecutingAssembly();
foreach (Type typ in vAss.GetTypes())
{
if (typ.BaseType == typeof(ValidationRuleBase)) {
ValidationRuleBase rule =
(ValidationRuleBase) vAss.CreateInstance(typ.FullName);
ValidationRules.Add(rule.RulePriority.ToString() +
rule.RuleName, rule);
}
}
}
The reason the Another option would have been just to populate a list of all the validation
rules in code. The reason I did it using reflection is because I feel it is more
obvious. The validation rules called by this assembly’s Validator’s
Once we have worked out what the validation rules are (or figured that they are already loaded) we go ahead and call the Validate methods of each rule. IntegerValidationRules Validator – Part 2// Perform Validation
ValidationResultCollection results = new ValidationResultCollection();
int failures = 0;
foreach (ValidationRuleBase rule in ValidationRules.Values)
{
ValidationResultCollection ruleResults = rule.Validate(objectToValidate);
if ((ruleResults != null) && (ruleResults.Count > 0))
{
results.AddRange(ruleResults);
if (maxValidationFailures > -1)
{
foreach (ValidationResult result in ruleResults)
{
if (result.ResultType == ResultType.Failed)
{
failures++;
if (failures >= maxValidationFailures)
{
return results;
}
}
}
}
}
}
The validate methods return a collection of As we return another interesting design decision is obvious. The types we are
using such as The bad thing about this is that we can’t for example easily combine the results of one validation library with another, each one stands alone with its own set of types. Again the reason this is done is for simplicity:
If you take a look at a ValidationRule such as
public override ValidationResultCollection Validate(object objectToValidate)
{
// This rule only checks integers
if (!(objectToValidate is int)) { return null; }
Normally I am a firm believer in typing everything, but objects are more
generic to start with and because we are sharing nothing between assemblies the
developer can change this in the Order ValidatorThe second example shows validation of a strongly typed dataset (STDS). This STDS would actually map to a couple of tables in the AdventureWorks sample database but I didn’t want to mess with SQL Server, so the dataset is constructed in code by the testbed’s form load method. The DataTransferObjects (DTO) assembly contains the definition for the
dataset. We are simulating code that would run in the business layer of an SOA
application, and the DTO should define the (serializable of course) messages we
are sending between layers – in this case When you click validate a call to the Dim results As OrderValidationRules.ValidationResultCollection =
OrderValidationRules.Validator.Validate(drOrder, -1)
This time we pass an Order datarow, which represents an order. Exactly what the individual validations rules do is very open, they can check stuff inside the object being validated (which the sample ones here do) or they can access a database for more information, or they might call a web service – the validation ‘plumbing’ doesn’t care at all. One thing the plumbing doesn’t do is muck around with the Instead we are using a more generic approach. The Eventually we get back to the caller which then has the option of iterating through the result collection and using the information available there to set the datatable errors collections (it doesn’t). Code Generation - LiteOK, well how would you use this yourself? If you download, unzip and run the exe from the template installer link at the top of this article, it will install a new project type (“Validation Rules Library”) and a new Code project item type (“Validation Rule”) for both VB and C#. Using the project types is a way to do code generation, and that is one of the things that is happening here – code generation (which is good). Well that's it (it's supposed to be 'Simple' after all). I hope that this sample is useful to somebody! Check my blog at http://endintiers.com/ for more 'simple' .NET designs.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||