May 9 2017

Customization And Localization Of ASP.NET Core MVC Default Validation Error Messages

Category: MVC | Asp.net core | Asp.netFrancesco @ 00:25

This time my post has been published on the MSDN Blog! Enjoy it!.

………Moreover, the new validation provider architecture made it easy to override the default messages built-in, in the .Net validation attributes with customized default messages defined in resource files. This way, the user can provide global custom messages once and for all, thus avoiding the burden of having to specify an error message in each occurrence, of each attribute.This article goes into detail about how to customize both all ASP.NET MVC specific error messages, and all default messages coming from validation attributes……Read full article

Tags: , , , , ,

Jan 2 2017

Defining Custom Client Validation Rules in Asp.net Core MVC

Category: Asp.net | Asp.net core | MVCFrancesco @ 22:15

This time my post has been published on the MSDN Blog! Enjoy it!

……..The way Asp.net MVC handles client side validation has relied on unobtrusive validation since Asp.net MVc 3. All client validation rules for each input field are extracted from various sources, including validation attributes, and the type of property to be rendered and encoded in the content of Html5 data…….Read full article

Tags: , , , ,

Jan 17 2012

Customizing Error Messages in Asp.Net MVC

Category: MVC | Asp.netFrancesco @ 07:07

 

Error messages that are automatically displayed by Asp.Net Mvc in response to user wrong inputs come from 3 sources:

  • Errors that the developer adds manually to the ModelState. Such errors are under the full control of the user since they are handled manually, so there is not too much to say about them: I just advice to put them in a resource file, instead of mixing them with the code. This way the application can be easily globalized, and all messages can be easily changed without putting the fingers in the code.
  • Errors added automatically by the Model Binder during the Model Binding process. The Model Binder adds substantially two kind of error messages:
    • Wrong Format Error messages: they are added when the Model Binder is not able to parse an input string coming from the client into its destination type. This happens, for instance, when the user inserts alphabetic characters into an integer field. The standard error message used in this case by the Model Binder is taken from an internal resource file, and it is used just for the server side validation. Client Side validation uses a messages taken from a different source.
    • Implicit Required Field Error Message: properties that can’t have a null value, such as integers or floats properties are considered Required also if they are not explicitely marked as Required with a RequiredAttribute. On the server side this check is automatically performed by the Model Binder. The standard error message used in this case is taken from an internal resource file, and it is used for both server side and client side validation.
  • Error Messages coming from different Validator Providers:

Summing up, the messages automatically provided by the framework that we might want to customize are:

  1. Messages coming from validation attributes. In this case the same message is used on both the Client Side and the Server Side.
  2. Implicit Required Field Error Message. In this case the same message is used on both the Client Side and the Server Side.
  3. Wrong Format Error message on the Server Side
  4. Wrong Format Error message on the Client Side

All the above messages share a common format: they are not simple strings, but the are format strings with an hole {0}, that is automatically filled with the DisplayName of the property they refer to. Accordingly, when we customize them, we may put the same hole in our customized messages to ensure a better user experience.

The DisplayName is taken from the Name property of the DisplayAttribute, or from the DisplayNameAttribute.if the ViewModel property is decorated with any of these attributes. In the case of the DisplayAttribute if the ResourceType property is null the string contained in Name is used directly as DisplayName otherwise the Name string is used as a key to retrieve the value of the DisplayName from the resource file specified in ResourceType. The DisplayNameAttribute.instead, is more “primitive” and doesn’t allow the use of resource files, but just a simple string that must be passed as parameter. However, the DisplayNameAttribute is the only one supported in Mvc 2.

If the ViewModel property is not decorated with either the DisplayAttribute or the DisplayNameAttribute the DisplayName is set to the name of the ViewModel property.

Customizing error messages coming from validation attributes.

All validation attributes inherits from the ValidationAttribute class. Accordingly, they all have three properties that enable the developer to customize their error messages: ErrorMessage, ErrorMessageResourceType, and ErrorMessageResourceName. ErrorMessage can be set directly to a custom error message (with a hole for the DisplayName). The other two properties are useful if we prefer to store the custom message in a resource file;  ErrorMessageResourceType specifies the type associated to the resource file (typically the type name is equal to the the file name), and ErrorMessageResourceName is the key to lookup in the resource to get the error message.

Below two examples using the ErrorMessage:

[Required(ErrorMessage="Please insert a valid {0}") ]
[DisplayName("User name")]
public string UserName { get; set; }

or without the “hole”:

[Required(ErrorMessage="Please insert a valid user name") ]
[DisplayName("User name")]
public string UserName { get; set; }

and an example that uses a resource file:

[Required(ErrorMessageResourceType=typeof(Resource1), ErrorMessageResourceName="fieldRequired") ]
[DisplayName("User name")]
public string UserName { get; set; }

Customizing the Implicit Required Field Error message and the Wrong Format Error message on the Server Side

These messages can be customized by defining them in a Resource file and then assigning the name of the resource file into the static string property ResourceClassKey of the class DefaultModelBinder. The Implicit Required Field custom error message has to be put under a key named DefaultModelBinder_ValueRequired and the Wrong Format custom error message under a key named DefaultModelBinder_ValueInvalid. While the Implicit Required Field custom error message is used on both client side and server side the Wrong Format custom error message is used just on the server side.

The message has two “holes” {0} is for the value and {1} for the DisplayName of the field. The standard message for the English is: The value '{0}' is not valid for {1}.

A good place where to assign a value to the ResourceClassKey property is the global.asax:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    DefaultModelBinder.ResourceClassKey = "MyResources";
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Customizing the Wrong Format Error messages on the Client Side

This messages are provided by the ClientDataTypeModelValidatorProvider, and have just one “hole” for the DisplayName of the property in contrast with its server side counterpart that has two holes, one for the value and the other for the DisplayName. The reason of this difference is simple: the “holes” are filled on the server side when the value is still unknown.

Before Mvc4 the ClientDataTypeModelValidatorProvider had no extension point to customize the error message. Accordingly, the only clean way to customize this message is by substituting the ClientDataTypeModelValidatorProvider. Starting from  Mvc 4 the ClientDataTypeModelValidatorProvider  was enriched with a ResourceClassKey static string property that may be filled with the name of a custom resource class, that works similarly works as   the ResourceClasseKey property of the DefaultModelBinder. In this case the wrong numeric format error and the wrong date format errors must be provided respectively under the FieldMustBeNumeric and FieldMustBeDate keys.

In the Mvc Controls Toolkit we have substituted the ClientDataTypeModelValidatorProvider with another provider called ClientDataTypeModelValidatorProviderExt that works properly also with Mvc versions before version 4. It has extension points for specifying errorr message for both the Wrong Numeric Format error and another for the Wrong Date and Time Format error, and specifies the resource class as a type instead instead of as a string in order to increase the maintainability of the code. The customization may be performe by passing both a Resource file type and the key for the two error messages to static properties of the ClientDataTypeModelValidatorProviderExt class as shown below:

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            MVCControlsToolkit.Core.ClientDataTypeModelValidatorProviderExt.ErrorMessageResources = typeof(MVCNestedModels.Models.Resource1);
            MVCControlsToolkit.Core.ClientDataTypeModelValidatorProviderExt.NumericErrorKey = "NumericError";
            MVCControlsToolkit.Core.ClientDataTypeModelValidatorProviderExt.DateTimeErrorKey = "DateError";
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }

for more details see here.

 

That’s all!

Stay Tuned

Francesco

Tags: , ,

Apr 13 2011

Data Dictionary And Data Annotations

Category: MVC | WPF | Silverlightfrancesco @ 07:07

Very often I am involved in discussions about “the right place” where to perform Data Validation. A lot of people do not approve the use of tools that checks automatically Data Validation attributes in the UI. This happens in Mvc, Silverlight +Ria services and in both Silverlight and Wpf if you use the Validation Toolkit for Wpf & Silverlight.

The main criticism is that, according to them, Validation needs to be performed in the Business Layer, not in the Presentation Layer. Performing validation in the presentation layer enforces a duplication of the procedure that needs to be repeated in other layers. Taken literally this  observation appears fair. However, behind the above words there is the danger of confusing some concepts:

  1. Where performing the validation is different from when performing the validation. Moreover, we needs also to understand well what does where mean in object programming. For sure the Presentation layer is not where to perform the validation. However, the best time when to perform validation is when the flux of control is in the Presentation Layer, that is, immediately after the user input: this way we are able to help the user with an immediate feedback, and we eliminate immediately potentially dangerous requests that might be used for a denial of service attack.
    Thus, the best solution is performing data validation when the flux of control is in the Presentation Layer by using rules defined in other Layers(where), and that the Presentation Layer is not aware of(it just enforces them, it doesn’t need to know anything about them). This is exactly what all tools that verify Data Annotations in the Presentation Layer do!
  2. Performing validation when the flux of control is in the Presentation Layer may force to perform a second validation control at a later time either because immediately after the user input we might miss some information that is necessary to perform the validation, or because of security related issues. However, there is nothing bad in performing two validation controls if we are able to do this without duplicating code. Code duplication has a negative impact on software modifiability, but the duplication of the validation control creates no problems. Below I will show how we can avoid code duplication.

Once we cleared the way from sources of possible confusion and mistakes we can try an answer to the question: what is the best place where to define data validation rules?

Actually there is not a unique place where to put them! There are rules, whose best place is the Data Layer, other the Business Layer, and also the Presentation Layer. Data Layer scoped constraints are the ones imposed by some consistency rules of the database that might be not relevant to the application, Business Layer level constraints are all constraints imposed by Business rules(some of them are also encoded within the consistency rules of the data base). Maybe someone is surprised that there might be also Presentation Level Validation rules: later on I will show some examples.

However, before it is worth to point out that there are rules involving the very conceptual nature of data. Such rules cross the boundaries of layers and remain attached to the different representations that the same conceptual entity has in each layer. For instance, the E-Mail address of a Customer has always the same structure that is independent on how this conceptual entity is represented in the different layers. Maybe in the Presentation Layer we have no object representing a single customer and that the customer data are mixed with the ones of another conceptual entity…but notwithstanding this, if there is a Customer E-Mail it has the same structure it has in the Data or Business Layer.

Such rules can be defined in a common place and used by all Layers they are relevant to, avoiding code duplication.However, where do this cross Layers rules come from and how we can identify them?

In the  Analysys stage of an application we typically prepare a Data Dictionary containing the definition of all terms and Data that are relevant to the application.Such definitions need to be considered in all Layers to ensure the coherence of the overall application. Thus, for instance, once we have defined the structure of an Address we need to use this structure in all Layers, otherwise we will not be able to translate it from the representation it has in one Layer to the representation it has into another Layer.

Well, now we have the answer: the cross Layers validation rules just translate the Data Dictionary property types definitions into procedures that enforce their structure. In other terms such Validation rules just translate constraints that are intrinsic in the data themselves, not Business rules: the structure of an E-Mail Address is independent of the use we do and is implicit in its definition. Such properties are typically property level validation rules, while Business rule more often involve constraints spanning several properties of an object.

To understand better how to proceed in practice let consider the case of the Address. We use the definition of address to write validation rules for different representations an address might have: 1) a single rule to be used when the address is represented as a single string and a some other rules for the case the address is represented as a complex structure(Country, street, etc). For the second representation we probably need several rules, one for each field, and a final check rule for the overall complex structure.

All validation rules obtained this way may be translated into validation attributes and put in a separate dll that is referenced by all Layers.

In a well structured application the Data Dictionary not only defines the structure of all conceptual entities but also name conventions, in order to make easier “to put the fingers” in the software, and to enforce coherence among all Layers. I suggest a convention for the name of the objects of the type Customer, CustomerBusiness, CustomerView, and the use of the same property names across all Layers.

Using the same property names for all properties related to the same conceptual entities allows the definition of common meta-classes to be used in all Layers. Thus, if we have a Data Layer Customer class and a DetailCustomer, and ShortCustomer classes passed from the Business Layer to the Presentation Layer, they can both take their property level Validation attributes from the same meta-class defined once and for all in the same dll that contains also the common Validation Attributes reference by all Layers. Properties defined in the meta-class that are not used in one of the target classes are simply not validated by the validation engine. The previous assertion is true for all property level attributes but the [Required] attribute that fails the Validation if it is not defined in the target class. Therefore I advice of avoiding to include it in the common meta-classes.

As a matter of fact the required attribute doesn’t translate an intrinsic constraint on the property it is applied to, but a requirement on the whole object that contains that property. For this reason we are not able to fit it among the common validation rules shared among all Layers. For instance, the fact that an OrderDate property is required in the business Layer doesn’t imply that it is necessarely required also in the Presentation Layer, because it might be provided from a source different from the user, for instance another procedure, or the computer clock.

Often the best time to check a Required attribute is when we are sure the object has been completely filled. However, this is not a general rule because we might want the user to insert a start and stop OrderDate to list all orders included in a time interval. This is an example of Presentation Layer scoped validation rule! In such a case we can use the [Required] attribute directly on some ViewModel property.In the cases where the Required check just translate an integrity constraint of the whole object that contains the property I propose to use an object level validation attribute that checks all required fields. Accordingly, I defined a similar object level attribute in my Mvc Controls Toolkit(see the RequiredFieldsAttribute here).

I promised to show some examples of Presentation Layer scoped validation rules. I already provided the example of the dates that defines the Orders to list. In general Validation rules on data that are used to define filtering criteria are often Presentation Layer scoped Validation rules.

Tags: , , ,

Oct 5 2010

Data Validation 2: Enriching WPF with Data Annotations Support

Category: Silverlight | WPFfrancesco @ 05:51

Data Validation 1

Data Validation 3: Silverlight, INotifyDataErrors, Ria Services and The Validation Toolkit for WPF & Silverlight

As I discussed in my previous post the only Validation tool available in WPF that is worth to be used is the support for the interface IDataErrorInfo. On the other hand the more effective way to specify constraints is Data Annotations. Data Annotations are a declarative way to specify validation rules by decorating properties and classes with attributes, so the code defining the validation rules and the business logic are kept completely separate.

In this post I will explain how to use IDataErrorInfo as a bridge between Data Annotations and WPF. More specifically I will show how to provide an implementation of IDataErrorInfo that uses Data Annotations and Validation Exceptions generated on the server side by some web service as source for the validation rules.The code can be found on Codeplex here.

My implementation of IDataErrorInfo is able to control the input against the Data Annotations defined on the Vie Model on the client side and also against constraints defined on the server-side.  The server side constraints may come either from Data Annotations defined on classes that are not available on the client side or directly from  the data sources (for instance database fields).

The only way to communicate validation errors through web service without intermixing them with the business objects is by embedding them into  web exceptions(Fault Contract), since  in the web services protocols arena there is no standard that is specific for validation errors. Therefore a global architecture for handling validation errors need to deal with validation exceptions returned by, possibly asynchronous, calls to web services.

A Short Review of Validation attributes.

The pre-defined validation attributes available in the System.ComponentModel.DataAnnotations namespace are:

  • RangeAttribute: It can be applied to any property or field that implements IComparable. It requires the value be within a constant interval
  • RequiredAttribute: It can be applied to any property, field or parameter. It requires that the value be not null or white spaces in case of a string
  • StringLegthAttribute: It can be applied only to strings. It specifies minimum and maximum number of characters allowed in the string.
  • RegularExpressionAttribute: It can be applied only to strings. I requires that the string conforms with a regular expression.

You can define custom validation rules in two ways:

  1. By using the CustomValidationAttribute. You can apply it to class, properties, fields or parameters of any type. Then you pass it a Type and the name of a static method of that Type. The method is called passing it the value to be validated. The method must return a ValidationResult. if the value returned is ValidationResult.Success the validation is considered successful, otherwise the error information contained in the ValidationResult are used by the layer in charge for displaying the validation errors.
  2. By inheriting from ValidationAttribute to define a new validation attribute. Your custom attribute needs essentially to override the IsValid method.

Attributes applied on a whole class definition are used to perform a global validation involving all values inserted for that class, while attributes applied to individual members validate only that member.

Sometime your business class is generated by some design tool such as the one of the Entity data model and you can not apply attributes to the members that have been defined by that design tool. In such cases you can define a partial class where you can apply class level attributes. In order to specify validation attributes also for the single properties you define a meta class associated to the initial partial class through the MetadataTypeAttribute, and you define properties with the same name of the properties of the initial class that you want to apply validation annotations too, and then apply the validation attributes to the newly defined properties of the meta class. See the official Microsoft documentation here for a simple example.

A Short Review of the IDataErrorInfo interface and of its support in WPF.

IDataErrorInfo is defined as:

public interface IDataErrorInfo { string this[string columnName] { get; } string Error { get; } }

The first member is required to return the error associated with the columnName property passed as parameter, while Error is required to return an object level validation error. null or string.Empty Return values are interpreted as success. The first member is called as soon as the WPF binder pass a value from the UI to a property, Errors returned are inserted into the Validation.Errors attached property of the control that is an array containing all errors associated with the control. When the Validation.Errors property is not empty the Validation.HasError is set to true.

The above properties can be used to change the look of the controls in error. Below a typical way to show errors in a TextBox(similar techniques apply also to other controls):

<ControlTemplate x:Key="validationTemplate">
  <DockPanel>
    <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
    <AdornedElementPlaceholder/>
  </DockPanel>
</ControlTemplate>
<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="ToolTip"
        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
    </Trigger>
  </Style.Triggers>
</Style>

When the error is removed it is automatically deleted from the Validation.Errors collection.

In order to enable the support to IDataErrorInfo you have to set the  property ValidatesOnDataErrors of the binding to true. If you set also the  NotifyOnValidationError to true, the RoutedEvent BindingValidationError is triggered when the error state of the binding changes. Such RoutedEvent can be intercepted by an higher level control (exploiting RoutedEvent bubbling) to update a Validation Summary.

The IDataErrorInfo.Error is not called automatically but you can bind it to a control that shows object level validation errors.If you use it this way, don’t forget to fire the PropertyChanged event when the object level error state changes.

The Validation Toolkit for WPF & Silverlight

The Validation Toolkit for WPF and Silverlight you can download freely from Codeplex here do the job of furnishing a IDataErrorInfo implementation that uses annotations attributes to validate data. Data are validated against validation attributes by using the static methods Validator.TryValidateProperty and Validator.TryValidateObject of the Validator class.

In order to supply an implementation of IDataErrorInfo that works with all classes the only solution is to wrap the original object into another object that implements the interface. I have chosen to implement the wrapper with a dynamic object that inherit from DynamicObject, this way,  thanks to the .net 4.0 support for dynamic objects you can interact with the wrapper as it were the original object: you can set and get the properties of the original object just by setting and getting properties of the wrapper with the same name. The wrapper implements also the INotifyPropertyChanged interface so you don’t need to implement it on your class.

Using the Validation Toolkit for WPF & Silverlight is easy:

  1. First, you have to enable ValidatesOnDataErros for the bindings you want to apply validation to. 
  2. Then, you need to wrap your View Model into the dynamic object BindWrapper with the instruction: new BindWrapper(ViewModel, true, true); Setting the second parameter to true causes all son objects of the View Model be recursively wrapped, too. Recursive wrapping will continue also through the boundaries ofIEnumerables if the third parameter is set to true .
  3. If  there is no top level View Model class but your top level structure is either a simple enumerable or a dictionary you can wrap recursively through them by calling respectively:
    static ObservableCollection<BindWrapper> WrapEnumerable(IEnumerable source, bool wrapDeep = false, bool wrapEnumerables=false)
    or
    public static ObservableDictionary<string, BindWrapper> WrapDictionary<TValue>(IDictionary<string, TValue> source, bool wrapDeep = false, bool wrapEnumerables = false)
    The result is respectively either an observable collection or an observable dictionary(the observable dictionary type is implemented in the toolkit). The meaning of the parameters is the same as  the ones of the BindWrapper constructor.
  4. Use the wrapper in place of your original object. You can get or set a  property of your original View Model by getting or setting a property of the wrapper with the same name: It is a dynamic object it will accept it, and it will retrieve or update the original property of your View Model while triggering the adequate events to update the interface and to perform validation.
  5. Bind the wrapper to your user interface. You can  write the names of the properties as if they would come from your original View Model.
  6. Validation of the simple properties is done automatically. When you want to trigger object level validation on the whole View Model or on a part of it, you call the ValidateWholeObject method of the relative wrapper. If Some Validation Exceptions are already available you can pass them to ValidateWholeObject as a parameter.
  7. Each time Validation Exceptions comes from a web service you can call AddRemoteErrors(IEnumerable<ValidationException> remoteErrors)  to update the interface.
  8. If for some reason you need to reset the interface from object level validation errors you can call ResetGlobalEvaluation(), but normally you don't need to do it.

The download on Codeplex contains also a simple WPF example where you can see how all this works in practice.

In the next posts we will see the how INotifyDataErrorInfo interface works in Silverlight, and how the Validation Toolkit for WPF & Silverlight takes advantage of it to implement a wrapper similar to the one of WPF.

                                      Stay Tuned!

                                      Francesco

For more information or consulences feel free to contact me

Tags: , , , , , , , ,

Sep 3 2010

Data Validation 1

Category: WPF | Silverlight | MVC | Entity Frameworkfrancesco @ 22:48

Data Validation 2: Enriching WPF with Data Annotations Support

Data Validation 3: Silverlight, INotifyDataErrors, Ria Services and The Validation Toolkit for WPF & Silverlight

Both Dot Net and Silverlight offer support for data validation through  various “ad hoc” tools. However, the supported tools and the way validation errors are propagated to and handled by the user interface depend on the kind of projects involved in the solution. For instance Silverlight supports automatically the INotifyDataErrors interface that is not available in WPF. It also supports data annotations on the business class but only if RIA services or DataForm control are used. (Don’t worry, I am going to explain all these tools!). Moreover, it is not obvious how to select each time the right tool.

This is the first of a series of posts where I shall explain:

  1. How these tools work, 
  2. How to use them and the pre-built support offered for them in WPF, Silverlight and MVC, and, finally,
  3. How to use and combine them in complex scenarios.

The problem solved by the Data Validation tools is the separation between the normal flow of control and the flow of validation errors. This is a labour-saving strategy whose aim is to allow the programmer to concentrate mainly in implementing his business logic. The programmer only needs to define data validation errors and the associated message errors. Then some standard mechanism  automatically propagate them to the UI interface. In this way the plumbing logic to propagate data errors to the UI is implemented once and for all in a standard way and it is not mixed with the code implementing the business logic.  In this series of  posts we shall see how most of this plumbing logic is already taken care of by the pre-built engines used in various type of applications (MVC, WPF, Silverlight, and dynamic data). RIA services also allow this pre-built plumbing logic propagate through the boundaries of web Services. This way data validation constraints that are defined directly on the business classes on the server  can reach the UI of the Silverlight client.

I summarize what I said in a couple of statements:

  1. Data constraints can be defined in their natural place i.e in the business classes;.
  2. Pre-built plumbing logic allows such a definitions to propagate till the UI with a minimum programming effort.

Let now move describing the Data Validation tools. They are:

  1. Data Annotations. Attributes that decorate either the members or the classes themselves and that state in a declarative way the constraints imposed either on each single member or on the whole  instantiation of the class. There are standard constraints such as [Range(a, b)] that constraint the member value to be within a and b, but also custom constraints that specify user defined code to be executed to verify the constraints.This is the simplest and more effective way to specify constraints, because the code to handle them is completely separated by the code of the class also in the case of custom constraints and can be reused all over the application. Since constraints are stated in a declarative way they are self-documented and they can be easily changed to fit new specifications.
  2. Interfaces IDataErrorInfo and INotifyDataErrors.  The business class may expose validation errors in a standard way by implementing the members of one of these interfaces. Other modules such as the pre-built error handling UI modules of Silverlight, WPF and MVC can query these interfaces to handle the errors. The disadvantage of this approach is that the implementation of the interfaces and hence the error validation code is mixed with the code handling normal operations of the class. However  it takes advantage of standard plumbing logics to propagate errors in the same way as Data Annotations. The better use of these interfaces is letting error defined with Data Annotations propagate to other modules in case the other modules are not able to handle directly Data Annotations: this way it is possible to build easily the plumbing logics to propagate errors through several layers in complex scenarios. Ria services do this! Errors defined on the server-side business classes are propagated to the UI of the client through a INotifyDataErrors interface implementation on the client-side business class that is generated automatically by Visual Studio. INotifyDataErrors has the advantage of exposing errors through events, specifically,event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged ,  while IDataErrorInfo do the same job with the only help of the indexer: string this[ string memberName] { get; }.The event solution is more attractive because it allows asynchronous data validation, for instance with the help of a web service that performs server-side verifications. When the asynchronous call to the web service returns, the UI is updated by raising the event. Obviously also INotifyDataErrors expose directly the errors through the GetErrors methods, and it has also a Boolean member HasErrors that can be used to enable/disable some UI logics. Unluckily, INotifyDataErrors is only available in Silverlight!
  3. Validation Rules. Validation rules are only available in WPF and are defined on the UI, not on the business classes! Therefore a discourage their use and i will not discuss them further.
  4. Exceptions. Exceptions are not a specific tool to handle data validation but sometimes they are useful to help other tools, such as Data Annotations, to propagate validation errors easily through several layers.

The table below summarizes the main properties of the above tools, and it is an useful start point in the design of data validation logic:

  WPF
built-in UI  support
Silverlight
built-in UI  support
MVC
built-in UI  support
Namespaces
IDataErrorInfo yes yes yes System.ComponentModel
INotifyDataErrors absent in .net yes absent in .net System.ComponentModel
Data Annotations no only with RIA or data controls yes System.ComponentModel.DataAnnotations
(need to add reference to assembly with the same name)

As already hinted INotifyDataErrorInfo is available only in Silverlight, while Data Annotations have only a limited built-in support.Silverlight native binding class offers no support for data annotations but data controls such as the DataForm control know how to use the data annotations of the object that is bound to them. Moreover, Ria services offer support for data annotations because Visual Studio wraps the automatically generated client-side business class within a  INotifyDataErrorInfo interface implementation that extracts validation errors from the data annotations. Ria services are able to perform data validation directly on the client-side if all custom data validation attributes are made available on the client side, otherwise they do the validation with the help of the server-side copy of the business object.

For what concerns Asp.net applications while the dynamic data engine relies on data annotations for data validations ad for defining the way data are presented to the user, standard Asp.net applications have no built-in mechanism to take advantage of the above described validation techniques. However, It is worth to point out that also in case of lack of built-in support for data annotations it is easy to validate either single members or whole objects by using the static validation methods of the Validator class in the System.ComponentModel.DataAnnotations namespace. Validations errors extracted this way can be made available to the UI by implementing either INotifyDataErrorInfo or IDataErrorInfo, or, in case of Asp.net applications, by a custom presentation logic.

In the next posts we will see how to use in practice INotifyDataErrorInfo, IDataErrorInfo, and data annotations.

Stay Tuned!

Francesco

Tags: , , , ,