When creating a business object, the object also has to be
validated. The data entered into a form needs to be checked for accuracy and
correctness. What means should we use? Should the object be stored in the
business layer if there is an error anyway? Where should validation be
performed and how?
In most instances, data is entered into a web or windows
form and a button is clicked to add the information to the repository. At this
point, the object representing this record has not yet been created, so
validation is a perfect time to occur here. However, some applications require
a different approach. They are very dynamic in that they tie together multiple
resources from many places. For instance, there is a form that contains many
fields; it is common to break this up into several forms, or to use a tab
control of some sort. However, some of the information related to this object
may only be created after the primary record is saved to the database and the
user has had time to review the information. A better solution would be to
save the object, even though in error, to the repository and come back to it
later.
For instance, additional properties for the object may only
be able to set up after the object is created. This object would be saved, but
it would not be considered correct, through the use of some sort of status property,
and any additional changes could be made later. In the windows world, this is
easily taken care of; but in the web world persisting these objects to a data
store has to occur often because the web is stateless and knows nothing about
the objects created in the previous page lifecycle. An external means, such as
a database or cache, can be used to persist the object and must be weighed
against how many people will use the application. Caching and session
mechanism only store the objects for so long, so error handling must be used to
ensure that if the object doesn't exist, the application can still work.
Another consideration is the actual validation of the fields
that are input. For instance, you can make use of the built-in validation
features within windows and web applications, or you can make use of the
Enterprise Library 3 Validation block. This new application block has the
ability to validate business applications through attributes or configuration
files established for a business class. An example of a business object is
shown below:
Listing 8
public class User
{
[StringLengthValidator(5, RangeBoundaryType.Inclusive, 7,
RangeBoundaryType.Inclusive,
"The authorization code is outside the range of valid values", Ruleset =
"primary"), AuthorizationCodeValidator(Ruleset = "primary")]
public string AuthorizationCode
{
get
{
return _authorizationCode;
}
set
{
_authorizationCode = value;
}
}
[StringLengthValidator(7, RangeBoundaryType.Inclusive, 150,
RangeBoundaryType.Inclusive,
"Email address must be between 7 and 150 characters", Ruleset = "primary"),
ContainsCharactersValidator("@.", ContainsCharacters.All,
"The email must have at least an @ and at least one decimal", Ruleset =
"primary"), EmailDomainValidator(".com", ".net", ".edu", ".gov", ".biz",
".tv", Ruleset = "primary")]
public string Email
{
get
{
return _email;
}
set
{
_email = value;
}
}
}
The Enterprise Library Validation block also has integration
features into ASP.NET with a new PropertyProxyValidator that performs server-side
validation using the validation attributes/configuration. It is also
customizable to include additional custom validators for whatever your needs
may be. Below is a definition of that validator:
Listing 9
<el:PropertyProxyValidator ID="ppvName" runat="server"
SourceTypeName="Mains.Examples.User,App_Code"
PropertyName="Name" RulesetName="primary" ControlToValidate="txtName">*</el:PropertyProxyValidator>
The repository or factory you build could validate a
business object using the validation block, and if in error, store this error
state in a flag within the object. That way, any erroring objects are not
persisted to the data store, and our new SaveChanges method (modified from
above) is below:
Listing 10
public virtual int SaveChanges()
{
int savedItems = 0;
foreach (T item in this.Items)
{
if (item.IsDirty)
{
if (Validation.Validate < T > (item).IsValid)
{
this.SaveItem(item);
item.ClearDirtyStatus();
}
else
item.IsValid = false;
savedItems++;
}
}
return savedItems;
}