Initial import!
This commit is contained in:
866
doc/reference/src/validation.xml
Normal file
866
doc/reference/src/validation.xml
Normal file
@@ -0,0 +1,866 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="validation">
|
||||
<title id="val-title">Validation Framework</title>
|
||||
|
||||
<section>
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Data validation is a very important part of any enterprise
|
||||
application. ASP.NET has a validation framework but it is very limited in
|
||||
scope and starts falling apart as soon as you need to perform more complex
|
||||
validations. Problems with the out of the box ASP.NET validation framework
|
||||
are well <ulink
|
||||
url="http://www.peterblum.com/VAM/ValMain.aspx">documented</ulink> by
|
||||
Peter Blum on his web site, so we are not going to repeat them here. Peter
|
||||
has also built a nice replacement for the standard ASP.NET validation
|
||||
framework, which is worth looking into if you prefer the standard ASP.NET
|
||||
validation mechanism to the one offered by Spring.NET for some reason.
|
||||
Both frameworks will allow you to perform very complex validations but we
|
||||
designed the Spring.NET validation framework differently for the reasons
|
||||
described below.</para>
|
||||
|
||||
<para>On the Windows Forms side the situation is even worse. Out of the
|
||||
box data validation features are completely inadequate as pointed out by
|
||||
Ian Griffiths in this <ulink
|
||||
url="http://pluralsight.com/wiki/default.aspx/Craig/WinFormsValidationBroken.html">article</ulink>.
|
||||
One of the major problems we saw in most validation frameworks available
|
||||
today, both open source and commercial, is that they are tied to a
|
||||
specific presentation technology. The ASP.NET validation framework uses
|
||||
ASP.NET controls to define validation rules, so these rules end up in the
|
||||
HTML markup of your pages. Peter Blum's framework uses the same approach.
|
||||
In our opinion, validation is not applicable only to the presentation
|
||||
layer so there is no reason to tie it to any particular technology. As
|
||||
such, the Spring.NET Validation Framework is designed in a way that
|
||||
enables data validation in different application layers using the same
|
||||
validation rules.</para>
|
||||
|
||||
<para>The goals of the validation framework are the following:</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Allow for the validation of any object, whether it is a UI
|
||||
control or a domain object.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Allow the same validation framework to be used in both Windows
|
||||
Forms and ASP.NET applications, as well as in the service layer (to
|
||||
validate parameters passed to the service, for example).</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Allow composition of the validation rules so arbitrarily complex
|
||||
validation rule sets can be constructed.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Allow validators to be conditional so they only execute if a
|
||||
specific condition is met.</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>The following sections will describe in more detail how these goals
|
||||
were achieved and show you how to use the Spring.NET Validation Framework
|
||||
in your applications.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Example Usage</title>
|
||||
|
||||
<para>Decoupling validation from presentation was the major goal that
|
||||
significantly influenced design of the validation framework. We wanted to
|
||||
be able to define a set of validation rules that are completely
|
||||
independent from the presentation so we can reuse them (or at least have
|
||||
the ability to reuse them) in different application layers. This meant
|
||||
that the approach taken by Microsoft ASP.NET team would not work and
|
||||
custom validation controls were not an option. The approach taken was to
|
||||
configure validation rules just like any other object managed by Spring -
|
||||
within the application context. However, due to possible complexity of the
|
||||
validation rules we decided not to use the standard Spring.NET
|
||||
configuration schema for validator definitions but to instead provide a
|
||||
more specific and easier to use custom configuration schema for
|
||||
validation. Note that the validation framework is not tied to the use of
|
||||
XML, you can use its API Programatically. The following example shows
|
||||
validation rules defined for the Trip object in the SpringAir sample
|
||||
application:</para>
|
||||
|
||||
<para><programlisting><objects xmlns="http://www.springframework.net" xmlns:v="http://www.springframework.net/validation">
|
||||
|
||||
<object type="TripForm.aspx" parent="standardPage">
|
||||
<property name="TripValidator" ref="tripValidator" />
|
||||
</object>
|
||||
|
||||
<v:group id="tripValidator">
|
||||
|
||||
<v:required id="departureAirportValidator" test="StartingFrom.AirportCode">
|
||||
<v:message id="error.departureAirport.required" providers="departureAirportErrors, validationSummary"/>
|
||||
</v:required>
|
||||
|
||||
<v:group id="destinationAirportValidator">
|
||||
<v:required test="ReturningFrom.AirportCode">
|
||||
<v:message id="error.destinationAirport.required" providers="destinationAirportErrors, validationSummary"/>
|
||||
</v:required>
|
||||
<v:condition test="ReturningFrom.AirportCode != StartingFrom.AirportCode" when="ReturningFrom.AirportCode != ''">
|
||||
<v:message id="error.destinationAirport.sameAsDeparture" providers="destinationAirportErrors, validationSummary"/>
|
||||
</v:condition>
|
||||
</v:group>
|
||||
|
||||
<v:group id="departureDateValidator">
|
||||
<v:required test="StartingFrom.Date">
|
||||
<v:message id="error.departureDate.required" providers="departureDateErrors, validationSummary"/>
|
||||
</v:required>
|
||||
<v:condition test="StartingFrom.Date >= DateTime.Today" when="StartingFrom.Date != DateTime.MinValue">
|
||||
<v:message id="error.departureDate.inThePast" providers="departureDateErrors, validationSummary"/>
|
||||
</v:condition>
|
||||
</v:group>
|
||||
|
||||
<v:group id="returnDateValidator" when="Mode == 'RoundTrip'">
|
||||
<v:required test="ReturningFrom.Date">
|
||||
<v:message id="error.returnDate.required" providers="returnDateErrors, validationSummary"/>
|
||||
</v:required>
|
||||
<v:condition test="ReturningFrom.Date >= StartingFrom.Date" when="ReturningFrom.Date != DateTime.MinValue">
|
||||
<v:message id="error.returnDate.beforeDeparture" providers="returnDateErrors, validationSummary"/>
|
||||
</v:condition>
|
||||
</v:group>
|
||||
|
||||
</v:group>
|
||||
|
||||
</objects></programlisting>There are a few things to note in the example
|
||||
above:<itemizedlist>
|
||||
<listitem>
|
||||
<para>You need to reference the validation schema by adding a
|
||||
<literal>xmlns:v="http://www.springframework.net/validation"</literal>
|
||||
namespace declaration to the root element.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>You can mix standard object definitions and validator
|
||||
definitions in the same configuration file as long as both schemas
|
||||
are referenced.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The Validator defined in the configuration file is identified
|
||||
by and id attribute and can be referenced in the standard Spring
|
||||
way, i.e. the injection of tripValidator into TripForm.aspx page
|
||||
definition in the first <object> tag above.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The validation framework uses Spring's powerful expression
|
||||
evaluation engine to evaluate both validation rules and
|
||||
applicability conditions for the validator. As such, any valid
|
||||
Spring expression can be specified within the test and when
|
||||
attributes of any validator.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>The example above shows many of the features of the framework, so
|
||||
let's discuss them one by one in the following sections.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Validator Groups</title>
|
||||
|
||||
<para>Validators can be grouped together. This is important for many
|
||||
reasons but the most typical usage scenario is to group multiple
|
||||
validation rules that apply to the same value. In the example above there
|
||||
is a validator group for almost every property of the Trip instance. There
|
||||
is also a top-level group for the Trip object itself that groups all other
|
||||
validators.</para>
|
||||
|
||||
<para>There are three types of validator groups each with a different
|
||||
behavior:</para>
|
||||
|
||||
<para>While the first type (AND) is definitely the most useful, the other
|
||||
two allow you to implement some specific validation scenarios in a very
|
||||
simple way, so you should keep them in mind when designing your validation
|
||||
rules.</para>
|
||||
|
||||
<table>
|
||||
<title>Validator Groups</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec align="left" colname="c1" colwidth="1*" />
|
||||
|
||||
<colspec colname="c2" colwidth="5*" />
|
||||
|
||||
<colspec colname="c3" colwidth="18*" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Type</entry>
|
||||
|
||||
<entry>XML Tag</entry>
|
||||
|
||||
<entry>Behavior</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>AND</entry>
|
||||
|
||||
<entry><literal>group</literal></entry>
|
||||
|
||||
<entry>Returns <emphasis role="bold"><emphasis
|
||||
role="bold"><emphasis>true</emphasis></emphasis></emphasis> only
|
||||
if all contained validators return <emphasis
|
||||
role="bold"><emphasis>true</emphasis></emphasis>. This is the most
|
||||
commonly used validator group.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>OR</entry>
|
||||
|
||||
<entry><literal>any</literal></entry>
|
||||
|
||||
<entry>Returns <emphasis
|
||||
role="bold"><emphasis>true</emphasis></emphasis> if one or more of
|
||||
the contained validators return <emphasis
|
||||
role="bold"><emphasis>true</emphasis></emphasis>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>XOR</entry>
|
||||
|
||||
<entry><literal>exclusive</literal></entry>
|
||||
|
||||
<entry>Returns true if only one of the contained validators return
|
||||
true.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>One thing to remember is that a validator group is a validator like
|
||||
any other and can be used anywhere validator is expected. You can nest
|
||||
groups within other groups and reference them using validator reference
|
||||
syntax (described later), so they really allow you to structure your
|
||||
validation rules in the most reusable way.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Validators</title>
|
||||
|
||||
<para>Ultimately, you will have one or more validator definitions for each
|
||||
piece of data that you want to validate. Spring.NET has several built-in
|
||||
validators that are sufficient for most validations, even fairly complex
|
||||
ones. The framework is extensible so you can write your own custom
|
||||
validators and use them in the same way as the built-in ones.</para>
|
||||
|
||||
<section>
|
||||
<title>Condition Validator</title>
|
||||
|
||||
<para>The condition validator evaluates any logical expression that is
|
||||
supported by Spring's evaluation engine. The syntax is</para>
|
||||
|
||||
<programlisting><v:<emphasis role="bold">condition</emphasis> id="id" test="testCondition" when="applicabilityCondition" parent="parentValidator">
|
||||
actions
|
||||
</v:<emphasis role="bold">condition</emphasis>></programlisting>
|
||||
|
||||
<para>An example is shown below</para>
|
||||
|
||||
<programlisting><v:condition test="StartingFrom.Date >= DateTime.Today" when="StartingFrom.Date != DateTime.MinValue">
|
||||
<v:message id="error.departureDate.inThePast" providers="departureDateErrors, validationSummary"/>
|
||||
</v:condition></programlisting>
|
||||
|
||||
<para>In this example the StartingFrom property of the Trip object is
|
||||
compared to see if it is later than the current date, i.e. DateTime but
|
||||
only when the date has been set (the initial value of StartingFrom.Date
|
||||
was set to DateTime.MinValue).</para>
|
||||
|
||||
<para>The condition validator could be considered "the mother of all
|
||||
validators". You can use it to achieve almost anything that can be
|
||||
achieved by using other validator types, but in some cases the test
|
||||
expression might be very complex, which is why you should use more
|
||||
specific validator type if possible. However, condition validator is
|
||||
still your best bet if you need to check whether particular value
|
||||
belongs to a particular range, or perform a similar test, as those
|
||||
conditions are fairly easy to write.</para>
|
||||
|
||||
<para><note>
|
||||
<para>Keep in mind that Spring.NET Validation Framework typically
|
||||
works with domain objects. This is after data binding from the
|
||||
controls has been performed so that the object being validated is
|
||||
strongly typed. This means that you can easily compare numbers and
|
||||
dates without having to worry if the string representation is
|
||||
comparable.</para>
|
||||
</note></para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Required Validator</title>
|
||||
|
||||
<para>This validator ensures that the specified test value is not empty.
|
||||
The syntax is</para>
|
||||
|
||||
<programlisting><v:<emphasis role="bold">required</emphasis> id="id" test="requiredValue" when="applicabilityCondition" parent="parentValidator">
|
||||
actions
|
||||
</v:<emphasis role="bold">required</emphasis>></programlisting>
|
||||
|
||||
<para>An example is shown below</para>
|
||||
|
||||
<programlisting><v:required test="ReturningFrom.AirportCode">
|
||||
<v:message id="error.destinationAirport.required" providers="destinationAirportErrors, validationSummary"/>
|
||||
</v:required></programlisting>
|
||||
|
||||
<para>The specific tests done to determine if the required value is set
|
||||
is listed below</para>
|
||||
|
||||
<table>
|
||||
<title>Rules to determine if required value is valid</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec align="center" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>System.Type</entry>
|
||||
|
||||
<entry>Test</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>System.Type</entry>
|
||||
|
||||
<entry>Type exists</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>System.String</entry>
|
||||
|
||||
<entry>not null or an empty string</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para></para>
|
||||
|
||||
<para>Required validator is also one of the most commonly used ones, and
|
||||
it is much more powerful than the ASP.NET Required validator, because it
|
||||
works with many other data types other than strings. For example, it
|
||||
will allow you to validate <literal>DateTime</literal> instances (both
|
||||
<literal>MinValue</literal> and <literal>MaxValue</literal> return
|
||||
<literal>false</literal>), integer and decimal numbers, as well as any
|
||||
reference type, in which case it returns <literal>true</literal> for a
|
||||
non-null value and <literal>false</literal> for
|
||||
<literal>{{null}}</literal>s.</para>
|
||||
|
||||
<para>The test attribute for the required validator will typically
|
||||
specify an expression that resolves to a property of a domain object,
|
||||
but it could be any valid expression that returns a value, including a
|
||||
method call.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Regular Expression Validator</title>
|
||||
|
||||
<para>The syntax is</para>
|
||||
|
||||
<programlisting><v:<emphasis role="bold">regex</emphasis> id="id" test="valueToEvaluate" when="applicabilityCondition" parent="parentValidator">
|
||||
<<emphasis role="bold">v:property name="Expression" value="regularExpressionToMatch"</emphasis>/>
|
||||
<v:property name="Options" value="regexOptions"/>
|
||||
actions
|
||||
</v:<emphasis role="bold">regex</emphasis>></programlisting>
|
||||
|
||||
<para>An example is shown below</para>
|
||||
|
||||
<programlisting><v:regex test="ReturningFrom.AirportCode">
|
||||
<v:property name="Expression" value="[A-Z][A-Z][A-Z]"/>
|
||||
<v:message id="error.destinationAirport.threeCharacters" providers="destinationAirportErrors, validationSummary"/>
|
||||
</v:regex></programlisting>
|
||||
|
||||
<para>Regular expression validator is very useful when validating values
|
||||
that need to conform to some predefined format, such as telephone
|
||||
numbers, email addresses, URLs, etc.</para>
|
||||
|
||||
<para>One major difference of the regular expression validator compared
|
||||
to other built-in validator types is that you need to set a required
|
||||
<literal>Expression</literal> property to a regular expression to match
|
||||
against.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Generic Validator</title>
|
||||
|
||||
<para>The syntax is</para>
|
||||
|
||||
<programlisting><v:<emphasis role="bold">validator</emphasis> id="id" test="requiredValue" when="applicabilityCondition" type="validatorType" parent="parentValidator">
|
||||
actions
|
||||
</v:<emphasis role="bold">validator</emphasis>></programlisting>
|
||||
|
||||
<para>An example is shown below</para>
|
||||
|
||||
<programlisting><v:validator test="ReturningFrom.AirportCode" type="MyNamespace.MyAirportCodeValidator, MyAssembly">
|
||||
<v:message id="error.destinationAirport.invalid" providers="destinationAirportErrors, validationSummary"/>
|
||||
</v:required></programlisting>
|
||||
|
||||
<para>Generic validator allows you to plug in your custom validator by
|
||||
specifying its type name. Custom validators are very simple to
|
||||
implement, because all you need to do is extend
|
||||
<literal>BaseValidator</literal> class and implement abstract
|
||||
<literal>bool Validate(object objectToValidate)</literal> method. Your
|
||||
implementation simply needs to return <literal>true</literal> if it
|
||||
determines that object is valid, or <literal>false</literal>
|
||||
otherwise</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Conditional Validator Execution</title>
|
||||
|
||||
<para>As you can see from the examples above, each validator (and
|
||||
validator group) allows you to define its applicability condition by
|
||||
specifying a logical expression as the value of the when attribute. This
|
||||
feature is very useful and is one of the major deficiencies in the
|
||||
standard ASP.NET validation framework, because in many cases specific
|
||||
validators need to be turned on or off based on the values of the object
|
||||
being validated.</para>
|
||||
|
||||
<para>For example, when validating a Trip object we need to validate
|
||||
return date only if the Trip.Mode property is set to the
|
||||
TripMode.RoundTrip enum value. In order to achieve that we created
|
||||
following validator definition:</para>
|
||||
|
||||
<programlisting><v:group id="returnDateValidator" when="Mode == 'RoundTrip'">
|
||||
// nested validators
|
||||
</v:group></programlisting>
|
||||
|
||||
<para>Validators within this group will only be evaluated for round
|
||||
trips.</para>
|
||||
|
||||
<note>
|
||||
<para>You should also note that you can compare enums using the string
|
||||
value of the enumeration. You can also use fully qualified enum name,
|
||||
such as:</para>
|
||||
|
||||
<para><literal>Mode == TripMode.RoundTrip</literal></para>
|
||||
|
||||
<para>However, in this case you need to make sure that alias for the
|
||||
TripMode enum type is registered using Spring's standard type aliasing
|
||||
mechanism.</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Validator Actions</title>
|
||||
|
||||
<para>Validation actions are executed every time the containing validator
|
||||
is executed. They allow you to do anything you want based on the result of
|
||||
the validation. By far the most common use of the validation action is to
|
||||
add validation error message to the errors collection, but theoretically
|
||||
you could do anything you want. Because adding validation error messages
|
||||
to the errors collection is such a common scenario, Spring.NET validation
|
||||
schema defines a separate XML tag for this type of validation
|
||||
action.</para>
|
||||
|
||||
<section>
|
||||
<title>Error Message Action</title>
|
||||
|
||||
<para>The syntax is</para>
|
||||
|
||||
<programlisting><v:message id="messageId" providers="errorProviderList" when="messageApplicabilityCondition">
|
||||
<v:param value="paramExpression"/>
|
||||
</v:message></programlisting>
|
||||
|
||||
<para>An example is shown below</para>
|
||||
|
||||
<programlisting><v:message id="error.departureDate.inThePast" providers="departureDateErrors, validationSummary">
|
||||
<v:param value="StartingFrom.Date.ToString('D')"/>
|
||||
<v:param value="DateTime.Today.ToString('D')"/>
|
||||
</v:message></programlisting>
|
||||
|
||||
<para>There are several things that you have to be aware of when dealing
|
||||
with error messages:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>id</literal> is used to look up the error message in
|
||||
the appropriate Spring.NET message source.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>providers</literal> specifies a comma separated list
|
||||
of "error buckets" particular error message should be added to.
|
||||
These "buckets" will later be used by the particular presentation
|
||||
technology in order to display error messages as necessary.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>a message can have zero or more parameters. Each parameter is
|
||||
an expression that will be resolved using current validation context
|
||||
and the resolved values will be passed as parameters to
|
||||
<literal>IMessageSource.GetMessage</literal> method, which will
|
||||
return the fully resolved message.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Generic Actions</title>
|
||||
|
||||
<para>The syntax is</para>
|
||||
|
||||
<programlisting><v:action type="actionType" when="actionApplicabilityCondition">
|
||||
properties
|
||||
</v:action></programlisting>
|
||||
|
||||
<para>An example is shown below</para>
|
||||
|
||||
<programlisting><v:action type="Spring.Validation.Actions.ExpressionAction, Spring.Core" when="#page != null">
|
||||
<v:property name="Valid" value="#page.myPanel.Visible = true"/>
|
||||
<v:property name="Invalid" value="#page.myPanel.Visible = false"/>
|
||||
</v:action></programlisting>
|
||||
|
||||
<para>Generic actions can be used to perform all kinds of validation
|
||||
actions. In simple cases, such as in the example above where we turn
|
||||
control's visibility on or off depending on the validation result, you
|
||||
can use the built-in <literal>ExpressionAction</literal> class and
|
||||
simply specify expressions to be evaluated based on the validator
|
||||
result.</para>
|
||||
|
||||
<para>In other situations you may want to create your own action
|
||||
implementation, which is fairly simple thing to do – all you need to do
|
||||
is implement <literal>IValidationAction</literal> interface:</para>
|
||||
|
||||
<programlisting>public interface IValidationAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the action.
|
||||
/// </summary>
|
||||
/// <param name="isValid">Whether associated validator is valid or not.</param>
|
||||
/// <param name="validationContext">Validation context.</param>
|
||||
/// <param name="contextParams">Additional context parameters.</param>
|
||||
/// <param name="errors">Validation errors container.</param>
|
||||
void Execute(bool isValid, object validationContext, IDictionary contextParams, ValidationErrors errors);
|
||||
}</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Validator References</title>
|
||||
|
||||
<para>Sometimes it is not possible (or desirable) to nest all the
|
||||
validation rules within a single top-level validator group. For example,
|
||||
if you have an object graph where both ObjectA and ObjectB have a
|
||||
reference to ObjectC, you might want to set up validation rules for
|
||||
ObjectC only once and reference them from the validation rules for both
|
||||
ObjectA and ObjectB, instead of duplicating them within both
|
||||
definitions.</para>
|
||||
|
||||
<para>The syntax is shown below</para>
|
||||
|
||||
<programlisting><v:ref name="referencedValidatorId" context="validationContextForTheReferencedValidator"/></programlisting>
|
||||
|
||||
<para>An example is shown below</para>
|
||||
|
||||
<programlisting><v:group id="objectA.validator">
|
||||
<v:ref name="objectC.validator" context="MyObjectC"/>
|
||||
// other validators for ObjectA
|
||||
</v:group>
|
||||
|
||||
<v:group id="objectB.validator">
|
||||
<v:ref name="objectC.validator" context="ObjectCProperty"/>
|
||||
// other validators for ObjectB
|
||||
</v:group>
|
||||
|
||||
<v:group id="objectC.Validator">
|
||||
// validators for ObjectC
|
||||
</v:group></programlisting>
|
||||
|
||||
<para>It is as simple as that — you define validation rules for ObjectC
|
||||
separately and reference them from within other validation groups.
|
||||
Important thing to realize that in most cases you will also want to
|
||||
"narrow" the context for the referenced validator, typically by specifying
|
||||
the name of the property that holds referenced object. In the example
|
||||
above, ObjectA.MyObjectC and ObjectB.ObjectCProperty are both of type
|
||||
ObjectC, which objectC.validator expects to receive as the validation
|
||||
context.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Progammatic usage</title>
|
||||
|
||||
<para>You can also create Validators programmatically using the API. An
|
||||
example is shown below</para>
|
||||
|
||||
<programlisting>UserInfo userInfo = new UserInfo(); // has Name and Password props
|
||||
|
||||
ValidatorGroup userInfoValidator = new ValidatorGroup();
|
||||
|
||||
userInfoValidator.Validators
|
||||
.Add(new RequiredValidator("Name", null));
|
||||
|
||||
userInfoValidator.Validators
|
||||
.Add(new RequiredValidator("Password", null));
|
||||
|
||||
ValidationErrors errors = new ValidationErrors();
|
||||
bool userInfoIsValid = userInfoValidator.Validate(userInfo, errors);
|
||||
</programlisting>
|
||||
|
||||
<para>No matter if you create your validators programmatically or
|
||||
declaratively, you can invoke them in service side code via the 'Validate'
|
||||
method shown above and then handle error conditions. Spring provides AOP
|
||||
parameter validation advice as part of ithe <link
|
||||
linkend="aop-aspect-library">aspect library</link> which may also be
|
||||
useful for performing server-side validation.</para>
|
||||
</section>
|
||||
|
||||
<section id="validation-aspnet-usage">
|
||||
<title>Usage tips within ASP.NET</title>
|
||||
|
||||
<para>Now that you know how to configure validation rules, let's see what
|
||||
it takes to evaluate those rules within your typical ASP.NET application
|
||||
and to display error messages.</para>
|
||||
|
||||
<para>The first thing you need to do is inject validators you want to use
|
||||
into your ASP.NET page, as shown in the example below:</para>
|
||||
|
||||
<programlisting><objects xmlns="http://www.springframework.net" xmlns:v="http://www.springframework.net/validation">
|
||||
|
||||
<object type="TripForm.aspx" parent="standardPage">
|
||||
<property name="TripValidator" ref="tripValidator" />
|
||||
</object>
|
||||
|
||||
<v:group id="tripValidator">
|
||||
// our validation rules
|
||||
</v:group>
|
||||
|
||||
</objects></programlisting>
|
||||
|
||||
<para>Once that's done, you need to perform validation in one or more of
|
||||
the page event handlers, which typically looks similar to this:</para>
|
||||
|
||||
<programlisting>public void SearchForFlights(object sender, EventArgs e)
|
||||
{
|
||||
if (Validate(Controller.Trip, tripValidator))
|
||||
{
|
||||
Process.SetView(Controller.SearchForFlights());
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>Keep in mind that your ASP.NET page needs to extend
|
||||
Spring.Web.UI.Page in order for the code above to work.</para>
|
||||
</note>
|
||||
|
||||
<para>Finally, you need to define where validation errors should be
|
||||
displayed by adding one or more
|
||||
<literal><spring:validationError/></literal> and
|
||||
<literal><spring:validationSummary/></literal> controls to the
|
||||
ASP.NET form:</para>
|
||||
|
||||
<programlisting><%@ Page Language="c#" MasterPageFile="~/Web/StandardTemplate.master" Inherits="TripForm" CodeFile="TripForm.aspx.cs" %>
|
||||
<%@ Register TagPrefix="spring" Namespace="Spring.Web.UI.Controls" Assembly="Spring.Web" %>
|
||||
|
||||
<asp:Content ID="head" ContentPlaceHolderID="head" runat="server">
|
||||
|
||||
<script language="javascript" type="text/javascript">
|
||||
<!--
|
||||
function showReturnCalendar(isVisible)
|
||||
{
|
||||
document.getElementById('<%= returningOnDate.ClientID %>').style.visibility = isVisible? '': 'hidden';
|
||||
document.getElementById('returningOnCalendar').style.visibility = isVisible? '': 'hidden';
|
||||
}
|
||||
-->
|
||||
</script>
|
||||
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="body" ContentPlaceHolderID="body" runat="server">
|
||||
<div style="text-align: center">
|
||||
<h4><asp:Label ID="caption" runat="server"></asp:Label></h4>
|
||||
<emphasis role="bold"><spring:ValidationSummary ID="validationSummary" runat="server" /></emphasis>
|
||||
<table>
|
||||
<tr class="formLabel">
|
||||
<td>&nbsp;</td>
|
||||
<td colspan="3">
|
||||
<spring:RadioButtonGroup ID="tripMode" runat="server">
|
||||
<asp:RadioButton ID="OneWay" onclick="showReturnCalendar(false);" runat="server" />
|
||||
<asp:RadioButton ID="RoundTrip" onclick="showReturnCalendar(true);" runat="server" />
|
||||
</spring:RadioButtonGroup>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="formLabel" align="right">
|
||||
<asp:Label ID="leavingFrom" runat="server" /></td>
|
||||
<td nowrap="nowrap">
|
||||
<asp:DropDownList ID="leavingFromAirportCode" AutoCallBack="true" runat="server" />
|
||||
<emphasis role="bold"><spring:ValidationError id="departureAirportErrors" runat="server" /></emphasis>
|
||||
</td>
|
||||
<td class="formLabel" align="right">
|
||||
<asp:Label ID="goingTo" runat="server" /></td>
|
||||
<td nowrap="nowrap">
|
||||
<asp:DropDownList ID="goingToAirportCode" AutoCallBack="true" runat="server" />
|
||||
<emphasis role="bold"><spring:ValidationError id="destinationAirportErrors" runat="server" /></emphasis>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="formLabel" align="right">
|
||||
<asp:Label ID="leavingOn" runat="server" /></td>
|
||||
<td nowrap="nowrap">
|
||||
<spring:Calendar ID="leavingFromDate" runat="server" Width="75px" AllowEditing="true" Skin="system" />
|
||||
<emphasis role="bold"><spring:ValidationError id="departureDateErrors" runat="server" /></emphasis>
|
||||
</td>
|
||||
<td class="formLabel" align="right">
|
||||
<asp:Label ID="returningOn" runat="server" /></td>
|
||||
<td nowrap="nowrap">
|
||||
<div id="returningOnCalendar">
|
||||
<spring:Calendar ID="returningOnDate" runat="server" Width="75px" AllowEditing="true" Skin="system" />
|
||||
<emphasis role="bold"><spring:ValidationError id="returnDateErrors" runat="server" /></emphasis>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="buttonBar" colspan="4">
|
||||
<br/>
|
||||
<asp:Button ID="findFlights" runat="server"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script language="javascript" type="text/javascript">
|
||||
if (document.getElementById('<%= tripMode.ClientID %>').value == 'OneWay')
|
||||
showReturnCalendar(false);
|
||||
else
|
||||
showReturnCalendar(true);
|
||||
</script>
|
||||
|
||||
</asp:Content></programlisting>
|
||||
|
||||
<section>
|
||||
<title>Rendering Validation Errors</title>
|
||||
|
||||
<para>Spring.NET allows you to render validation errors within the page
|
||||
in several different ways, and if none of them suits your needs you can
|
||||
implement your own validation errors renderer. Implementations of the
|
||||
<literal>Spring.Web.Validation.IValidationErrorsRenderer</literal> that
|
||||
ship with the framework are:</para>
|
||||
|
||||
<table>
|
||||
<title>Validation Renderers</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec colname="c1" colwidth="1*" />
|
||||
|
||||
<colspec colname="c2" colwidth="5*" />
|
||||
|
||||
<colspec colname="c3" colwidth="10*" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="left">Name</entry>
|
||||
|
||||
<entry align="center">Class</entry>
|
||||
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Block</entry>
|
||||
|
||||
<entry><literal>Spring.Web.Validation.DivValidationErrorsRenderer
|
||||
</literal></entry>
|
||||
|
||||
<entry>Renders validation errors as list items within a
|
||||
<literal><div></literal> tag. Default renderer for
|
||||
<literal><spring:validationSummary></literal>
|
||||
control.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Inline</entry>
|
||||
|
||||
<entry><literal>Spring.Web.Validation.SpanValidationErrorsRenderer
|
||||
</literal></entry>
|
||||
|
||||
<entry>Renders validation errors within a
|
||||
<literal><span></literal> tag. Default renderer for
|
||||
<literal><spring:validationError></literal>
|
||||
control.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Icon</entry>
|
||||
|
||||
<entry><literal>Spring.Web.Validation.IconValidationErrorsRenderer</literal></entry>
|
||||
|
||||
<entry>Renders validation errors as error icon, with error
|
||||
messages displayed in a tooltip. Best option when saving screen
|
||||
real estate is important.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>These three error renderers should be sufficient for most
|
||||
applications, but in case you want to display errors in some other way
|
||||
you can write your own renderer by implementing
|
||||
<literal>Spring.Web.Validation.IValidationErrorsRenderer</literal>
|
||||
interface:</para>
|
||||
|
||||
<programlisting>namespace Spring.Web.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface should be implemented by all validation errors renderers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Validation errors renderers are used to decouple rendering behavior from the
|
||||
/// validation errors controls such as <see cref="ValidationError"/> and
|
||||
/// <see cref="ValidationSummary"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This allows users to change how validation errors are rendered by simply plugging in
|
||||
/// appropriate renderer implementation into the validation errors controls using
|
||||
/// Spring.NET dependency injection.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public interface IValidationErrorsRenderer
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders validation errors using specified <see cref="HtmlTextWriter"/>.
|
||||
/// </summary>
|
||||
/// <param name="page">Web form instance.</param>
|
||||
/// <param name="writer">An HTML writer to use.</param>
|
||||
/// <param name="errors">The list of validation errors.</param>
|
||||
void RenderErrors(Page page, HtmlTextWriter writer, IList errors);
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<section>
|
||||
<title>Configuring which Error Renderer to use.</title>
|
||||
|
||||
<para>The best part of the errors renderer mechanism is that you can
|
||||
easily change it across the application by modifying configuration
|
||||
templates for <literal><spring:validationSummary></literal> and
|
||||
<literal><spring:validationError></literal> controls:</para>
|
||||
|
||||
<programlisting><!-- Validation errors renderer configuration -->
|
||||
<object id="Spring.Web.UI.Controls.ValidationError" abstract="true">
|
||||
<property name="Renderer">
|
||||
<object type="Spring.Web.Validation.IconValidationErrorsRenderer, Spring.Web">
|
||||
<property name="IconSrc" value="validation-error.gif"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object id="Spring.Web.UI.Controls.ValidationSummary" abstract="true">
|
||||
<property name="Renderer">
|
||||
<object type="Spring.Web.Validation.DivValidationErrorsRenderer, Spring.Web">
|
||||
<property name="CssClass" value="validationError"/>
|
||||
</object>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
|
||||
<para>It's as simple as that!</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
Reference in New Issue
Block a user