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:
- How these tools work,
- How to use them and the pre-built support offered for them in WPF, Silverlight and MVC, and, finally,
- 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:
- Data constraints can be defined in their natural place i.e in the business classes;.
- 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:
- 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.
- 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!
- 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.
- 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:
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: INotifyDataError, MVVM, Validation, Data Annotations, IDataErrorInfo