Apr 9 2024

Software Architecture with C# 12 and .NET 8 is out!

The fourth edition of my book is out! You can buy it on Amazon

fourthedition

If you are a an aspiring .NET software architect, or a C# developer wishing to jump into the world of enterprice applications and cloud, this is the right book for you!

Software Architecture with C# 12 and .NET 8 puts high-level design theory to work in a .NET context, teaching you the key skills, technologies, and best practices required to become an effective .NET software architect.

This fourth edition puts emphasis on a case study that will bring your skills to life. You'll learn how to choose between different architectures and technologies at each level of the stack. You'll take an even closer look at Blazor and explore OpenTelemetry for observability, as well as a more practical dive into preparing .NET microservices for Kubernetes integration.

Divided into three parts, this book starts with the fundamentals of software architecture, covering C# best practices, software domains, design patterns, DevOps principles for CI/CD, and more. The second part focuses on the technologies, from choosing data storage in the cloud to implementing frontend microservices and working with Serverless. You'll learn about the main communication technologies used in microservices, such as REST API, gRPC, Azure Service Bus, and RabbitMQ. The final part takes you through a real-world case study where you'll create software architecture for a travel agency.

What’s new in this edition?

Topics are analyzed in greater detail and updated for .NET 8 and the latest Azure components. We have also added a new practical chapter on developing .NET applications for Kubernetes.

Finally, the book has been organized into three parts, creating a flow that will guide you in your journey to becoming a software architect: architectural fundamentals, .NET technologies, and practical coding with a great case study.

Highlights from the World Wide Travel Club case study:

  • Code examples in past editions restructured and re-organized into a case study
  • Examining user needs and managing requirements with Azure DevOps
  • Understanding the application domains and choosing cloud data storage
  • Implementing worker microservices with gRPC and RabbitMQ

How does this book differ from other books on C# 12 and .NET 8?

Although we are using .NET 8, the current Long Term Support version of .NET, and the book’s programming language is C# 12, we don’t only talk about technology. We connect different modern topics needed to design an enterprise application, and we enable you to understand how these techniques work together. This means the book focuses more on architectures, patterns, and design techniques, than on the syntax of the language and its features.

In a few words, the book assumes you already have basic knowledge of .NET and C#, driving you toward their usage for implementing cutting-edge applications based on microservices and modern architectures and design techniques.

Table of Contents

  1. Understanding the Importance of Software Architecture
  2. Non-Functional Requirements
  3. Managing Requirements
  4. Best Practices in Coding C# 12
  5. Implementing Code Reusability in C# 12
  6. Design Patterns and .NET 8 Implementation
  7. Understanding the Different Domains in Software Solutions
  8. Understanding DevOps Principles and CI/CD
  9. Testing Your Enterprise Application
  10. Deciding on the Best Cloud-Based Solution
  11. Applying a Microservice Architecture to Your Enterprise Application
  12. Choosing Your Data Storage in the cloud
  13. Interacting with Data in C# - Entity Framework Core
  14. Implementing Microservices with .NET
  15. Applying Service-Oriented Architectures with .NET
  16. Working with Serverless - Azure Functions
  17. Presenting ASP.NET Core
  18. Implementing Frontend Microservices with ASP.NET Core
  19. Client Frameworks: Blazor
  20. Kubernetes
  21. Case Study
  22. Case Study Extension: Developing .NET Microservices for Kubernetes

DO NOT MISS IT!

Francesco

    Tags: , , , , , ,

    Apr 1 2022

    Software Architecture with C# 10 and .NET 6 is out!

    The third edition of my book is out! You can buy it on Amazon

    imagebook3_thumb[1]

    If you are a C# developer wishing to jump into the world of enterprice applications and cloud, this is the right book for you!

    From how to collect requirements, and how to master DevOps, selecting the right cloud resources, Web API, front-end frameworks (ASP.Net MVC and Blazor) to microservices design principles and practice,. This new edition updates all subjects to the last cloud and .Net features and adds new chapters:

    • A detailed description of gRPC and of how to use it from .NET
    • A new chapter that explains in detail how to implement a worker microservice with  ASP.NET + gRPC, and .NET hosted services + RabbitMQ
    • An introduction to Artificial Intelligence and Machine Learning
    • An introduction to native clients (including a short review of .NET MAUI)

    Most of chapters give enough details to cover 90% of all practical applications and give all links and pointers to get more details.The only exceptions are the chapters about artificial intelligence and native clients that are just introductions to big subjects. However,  also there you will find complete learning paths to follow to become an expert.

    The first three chapters describe modern development processes, and how to collect and document functional and not-functional requirements. Example of requirement collection and management with Azure DevOps are given.

    Then the books moves to the basic cloud concepts and describes how to select the right cloud resources for each application.

    Chapter 5 explains the whole therory behind Microservices design, and lists .NET resources that plays a foundamental role in the .NET implementation of Microservices. A self-contained description of Docker, is given, too.

    Chapter 6 is dedicated to Kubernetes. There you will find all basic concepts and enough details to cover 90% of all practial applications.

    Chapter 7 and 8 are dedicated to data storage and how to interact with them with Entity Framework Core and other clients. There, you will find .the whole theory behind distributed databases, how to maximize read and write parallelism and how to choose between SQL and Not-SQL databases.

    Chapter 9 is about serverless and Azure functions. There, you  will find enough details to cover simple-middle complexity functions, and pointers on how to implement more complex functions.

    Chapter 10 is dedicated to  the concept of pattern and describes various patterns used throghout the book.

    Chapter 11 describes Domain Driven Design, that is the most used design methodology for microservices. Related patterns and their practical usage in .NET layered applications are given, too.

    Chapter 12 describes typical patterns of code reusability used in .NET applications.

    Chapter 14 gives a detailed description of gRPC and of its usage in .NET applications. Then, a complete implementation of a worker microservice with gRPC and ASP.NET CORE is given. Finally the same example is implemented with a .NET worker service and RabbitMQ.

    Further chapters describe SOA architectures  and their implementation with ASP-NET Core (13), ASP.NET Core and ASP.NET Core MVC(15) and Blazor (17).

    Chapter 16 puts in practice all concepts learned with ASP.NET Core MVC and Domain Driven Design with the implementation of a front-end microservice.

    Chapter 18 is a introduction to native .NET clients that includes also a first look to .NET MAUI. The description is not detailed since a detailed description would require another complete book, but native clients are compared with browser-based clients and frameworks (like Blazor) and complete learning paths are given.

    Chapter 19 is an introduction to artificial intelligence and machine learning. The basic principles of the main AI techniques are described, without going deep into the implementation details.Also. the basic theory about machine learning is given. Here the focus is on understanding which problems can be solved with machine learning and how many examples they require. A practical example of supervised learning is given.

    Chapter 20 is dedicated to best practices and code metrics.

    Chapter 21 and 22 are dedicated to DevOps and to the usage of Azure DevOps and GitHub actions.

    Finally chapter 23 is dedicated to testing, test-driven design, unit-tests and functional/acceptance tests.The chapter gives the complete theory and describes in detail xUnit, and Moq.Practical examples of functional tests based on AngleSharp and Selenium are given, too.

    DO NOT MISS IT!

    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: , , ,

    Dec 11 2010

    Silverlight…without Ria Services

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

    Something More about Ria Services

    Ria Services offer an easy solution to the main problems of a typical Business Silverlight application, specifically:

    1. Data Validation. As discussed in a previous post, Ria Services offer support for a data validation based on Data Annotations defined on the server side classes.
    2. Communication with the server and remote validation. Several configuration details of the web service definitions are automatically handled by Ria Services. Moreover, as discussed previously, if the definition of some custom validation attribute is not available on the client side, validation is performed remotely on the server (please refer to the above post for more information).
    3. Ria services automatically set up Asp.net Authentication, Authorization and User Profile Web Services for the Silverlight client.

    Unluckily, it is not always possible to use Ria Services, because the Web Services created by Ria Services are specific for Silverlight. Therefore, if one needs a interoperable general purpose service layer that is compatible with various technologies Ria services can not be used.

    In such a case the only acceptable option should be the configuration of a Silverlight specific endpoint in a general purpose Web Services. However, often I see developers that do a partial duplication of code implementing a parallel Ria Services Layer specific for the Silverlight clients just to take advantage of the opportunities  offered by Ria Services.

    In this post I will show a simple alternative way to obtain the same advantages offered by Ria Services with general purpose Web Services.

    Let start with the support for Data Annotations.We can proceed as follows ( I assume  knowledge of the Data Annotations issues discussed in my previous posts here and here.) :

    1. When we define the meta classes of our business classes we  furnish a complete implementation of those classes with the right property types. Moreover, in order to make them serializable we decorate them with the [DataContract] attribute and their properties with the [DataMember ] attribute, since we want they be compatible with Silverlight that has no implementation of the [Serializable] attribute.
    2. We use the above meta classes as View Models or as part of the View Models, both in the server and in Silverlight projects. I advice just linking the same code to both the Silverlight  and  the server projects.
    3. We define our Web Services according to general design constraints, and not only according to Silverlight needs.
    4. We generate the Silverlight proxy, with the option to use already existing classes. This way, we use the original View Models we have linked to the Silverlight project instead of View Models provided automatically by Visual studio during proxy generation.
    5. Once in Silverlight, we wrap the View Model with the Validation Toolkit for Wpf & Silverlight wrapper, in order to furnish it support for both Data Annotations and INotifyPropertyChanged.

    With the above procedure we have View Models with Data Validation support without duplicating code, and with the same effort required by the definition of a Ria Domain Service.

    The Validation Toolkit for Wpf & Silverlight offers also all tools needed to perform the Remote Validation. On the server we pack all validation errors into an IEnumerable<ValidationErrorInfo> and then we throw a fault Exception: FaultException<IEnumerable<ValidationErrorInfo>> containing the above IEnumerable.

    The exception is passed to the client if we decorate the Wcf interface definition with the FaultContract<IEnumerable<ValidationErrorInfo>>] attribute.This is enough for all clients but Silverlight to receive the validation errors. In fact Silverlight is a browser plug-in and as all browser plug-ins it can receive the details of a response only if the status code of the response is either 200(OK) or 404(Not Found), and the status code associated with a fault error normally is not one of them. To overcome this problem we apply the SilverlightFaultBehavior defined in the BindToolkit.Behaviors namespace of the Validation Toolkit for Wpf & Silverlight to the endpoint specific for Silverlight. This endpoint behavior change the status code of the Wcf error response from whatever it is into a 200 status code, thus allowing Silverlight to receive the FaultException.

    Once the FaultException is available to the silverlight client,we need just to call the AddValidationFaultExceptionContent(IEnumerable<ValidationErrorInfo> errors) method of the top level wrapper, to send all error messages in their adequate places in the User Interface.

    The binary distribution of the Validation Toolkit for Wpf & Silverlight contains a Silverlight example that shows both how to use the wrapper and how to handle remote validation.

    Finally, the set up of  Asp.net Authentication, Authorization and User Profile Web Services for the Silverlight client is easy because Asp.net has standard implementations for these Web Service.

    For the authentication service we just need to add to our web project an .svc file containing just:

    <%@ ServiceHost 
      Language="C#"
      Service="System.Web.ApplicationServices.AuthenticationService" 
      Factory="System.Web.ApplicationServices.ApplicationServicesHostFactory" %>

    No code behind or explicit implementation needs to be furnished since the Asp.net class  System.Web.ApplicationServices.AuthenticationService offers a standard implementation of the Authentication Service. However, we need to configure a Membership provider on our Web Site.

    In the configuration file we must enable the Authentication Service:

    <system.web.extensions>
      <scripting>
        <webServices>
          <authenticationService enabled="true" 
             requireSSL = "true"/>
        </webServices>
      </scripting>
    </system.web.extensions>

    and we must configure it to use basicHttpBinding(for Silverlight compatibility) and Https:

    <services>
        <service name="System.Web.ApplicationServices.AuthenticationService"
            behaviorConfiguration="AuthenticationServiceTypeBehaviors">
          <endpoint contract=
            "System.Web.ApplicationServices.AuthenticationService"
            binding="basicHttpBinding"
            bindingConfiguration="userHttps" 
            bindingNamespace="http://asp.net/ApplicationServices/v200"/>
          </service>
      </services>
      <bindings>
            <basicHttpBinding>
                <binding name="userHttps">
                    <security mode="Transport" />
                </binding>
            </basicHttpBinding>
      </bindings>

    A detailed reference is here.

    Analogously, for the Authorization service we have:

    <%@ ServiceHost 
      Language="C#"
      Service="System.Web.ApplicationServices.RoleService" 
      Factory="System.Web.ApplicationServices.ApplicationServicesHostFactory" %>
    <system.web.extensions>
      <scripting>
        <webServices>
          <roleService enabled="true"/>
        </webServices>
      </scripting>
    </system.web.extensions>
    <services>
        <service name="System.Web.ApplicationServices.RoleService"
            behaviorConfiguration="ApplicationServiceTypeBehaviors">
          <endpoint contract=
            "System.Web.ApplicationServices.RoleService"
            binding="basicHttpBinding"
            bindingConfiguration="userHttps" 
            bindingNamespace="http://asp.net/ApplicationServices/v200"/>
        </service>
      </services>
      <bindings>
    <basicHttpBinding>
    <binding name="userHttps">
    <security mode="Transport" />
    </binding>
    </basicHttpBinding>

    a Detailed reference is here.

    While for the User Profile we have:

    <%@ ServiceHost Language="C#"
    Service="System.Web.ApplicationServices.ProfileService" 
    Factory="System.Web.ApplicationServices.ApplicationServicesHostFactory" %>
    <system.web.extensions>
      <scripting>
        <webServices>
          <profileService enabled="true"
            readAccessProperties="Birthday, FavoriteColor"
            writeAccessProperties="Birthday, FavoriteColor" >
        </webServices>
      </scripting>
    </system.web.extensions>

    As you can see, while enabling the profile service we need to specify read and write permissions for each property.

    The service configuration is quite standard:

    <services>
        <service name="System.Web.ApplicationServices.ProfileService"
          behaviorConfiguration="MyServiceTypeBehaviors">
          <endpoint contract=
            "System.Web.ApplicationServices.ProfileService"
            binding="basicHttpBinding" 
            bindingNamespace="http://asp.net/ApplicationServices/v200"/>
        </service>

    A detailed Reference is here.

    Well. As you can see, the set up of a Silverlight application with all features described in points 1), 2), and 3) is quite easy and can be carried out quickly also without the use of Ria Services. Therefore, there is no need to force the use of Ria Services also when a different solutions should be more adequate.

    That’s all for now!. But…..

                                                                                      Stay Tuned !

                                                                                      Francesco

    For more information or consulences feel free to contact me

    Tags: , , , , , , , ,

    Oct 21 2010

    …Something More about Ria Services

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

    Silverlight…without Ria Services

    In my previous post about data validation I spoke quite enough about Ria Services. I spoke about its kind of validation and how it is achieved, and also how to share classes among a Silverlight project and its hosting web site project (it is enough to put the share.cs or share.vb extension to a file on the server).

    Discussing with people I discovered that there are a lot of  false beliefs about Ria services. For instance, a lot of developers think they can use Ria services only in conjunction with Entity Framework classes. This is simply false. Ria services allow you to define a context similar to the one of the EF entities also with general classes provided by the programmers: just follows the wizard that let you define your services…and will see it give you also this option.

    If your classes are interconnected, you can benefit of Linq to Objects for your queries in a way completely analogous to EF objects.

    With Ria services you can benefit of some pre-defined endpoints that have been adequately configured to fit well the needs of Silverlight users: you have a binary endpoint for intranet applications (its default), a soap endpoint for Internet applications and also a JSon endpoint. Moreover, you have also the option to expose OData (there is a check box in the wizard for the service definition). Instructions on how to define the endpoints in the configuration file are reported here. The bad news are that you cannot configure the features of the endpoints like in normal WCF services using the configuration file, but if you need features that are not contained in the standard configuration of the standard endpoints you have to define new endpoints in code.

    Requiring a secure session is quite easy and can be done just by putting this attribute on the class that defines the service: [EnableClientAccess(RequiresSecureEndpoint = true)].Secure messages protocols are not supported by Silverlight. Don’t forget to give an https Url to a secured soap endpoint!

    Requiring authentication and Role based authorizations are both easily achieved with attributes as explained here: http://msdn.microsoft.com/it-it/library/ee707361(en-us,VS.91).aspx. The above link explain also how to login and how to handle login errors.

    Another, important thing that is worth to mention about Ria services concerns the return value of the Query methods of the service. According to the official documentation Query methods may return an IEnumerable<T>, an IQueryable<T> or a single object. However, what is not reported in the documentation is that only by returning an IQueryable one can  have an efficient filtering of data based on criteria passed by the Silverlight client to the server. For instance, suppose the Silverlight client needs to filter the customers returned by a Query method .GetCustomersQuery() defined on the server according to a user provided name. One can achieve this with the instruction:

     domainContext.Load(domainContext.GetCustomersQuery().Where(c => c.Name == "John").OrderBy(c => c.Age))

    One could thing that all data returned by the server are then filtered by the Silverlight client. NO: behind the scene the Silverlight client build an IQueryable<T> and pass it to the server.Now, if also the server side method GetCustomerQuery() returns an IQueryable<T> the two queries are combined and either passed to the the Database or to Linq to Object to get the needed results efficiently! Therefore,  if you need to perform filtering based on client side defined criteria, please, always return an IQueryable<T>!

    I thanks Gius that helped me clarifying well this point by speaking directly with a member of the WCF data services team.

    Before concluding this short review post about Ria Services I would like to mention two more alternatives well suited for Silverlight clients: WCF Data Services, and WCF Rest Services. The WCF Rest Service Application template is not available in Visual Studio 2010 but it can be downloaded directly from Visual Studio 2010 by searching it in the Extension Manager(tool menu).

    WCF Data Services are very similar to Ria services, The way you use it from Silverlight is quite the same. The main difference is that they don’t have any simple mechanism to share code with Silverlight and to handle validation. Moreover, you have to generate the proxy in Silverlight with Visual Studio and your context need to be specified by code(you need just to substitute a generic with an actual class…), and not with a simple wizard. The context may involve either EF entities or normal classes as in the case of Ria Services. This means some more job to be done but more flexibility because all things that Ria Services do in a standard way can now be customized! The only big loss is validation, but you can use my Validation Toolkit for WPF & Silverlight that is more flexible than the standard mechanism of Ria Services. However, it is important to mention that WCF Data Services just have one type of endpoint! The Rest endpoint! With a Rest endpoint queries are specified by adequately writing an URL, and the results are returned in the OData format that is a generalization of the Atom feed format. This means, you can send query not only with Silverlight but also with a simple browser! This is a very useful help in debugging the application. Obviously if you work with Silverlight all this details are hidden to you that just may use data contexts and IQueryables like with Ria Services.

    WCF rest services use the same Rest protocol as the WCF Data Services but they are not connected to EF or classes, they are generic WCF services based on the Rest protocol. Parameters for the services are specified by the structure of the Url with the help of Routing tables defined in the Global.asax in a similar way to MVC Web applications. They are an interesting option to be considered for complex services that do more sophisticated computations than simply retrieving data from a Database.

    Next post of this series will be again on validation, but on the server side…

     

                                                                                      Stay Tuned !

                                                                                      Francesco

    For more information or consulences feel free to contact me

    Tags: , ,

    Oct 6 2010

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

    Category: WCF | WPF | Silverlight | Entity Frameworkfrancesco @ 01:06

    Data Validation 1

    Data Validation 2: Enriching WPF with Data Annotations Support

    Something More about Ria Services

    Silverlight…without Ria Services

    In my previous post I discussed how to enrich WPF with support for Data Annotations and for receiving asynchronous validation error from web services. What about Silverlight? In my first post of this series I already said that Silverlight already offers some support for Data Annotations. However, this support is not native of the silverlight presentation layer but is conveyed by other tools.

    In Silverlight data controls, such as the Data Form, the support for data annotations has been injected through the specific way this controls are implemented: the Data Control evaluates itself  the data annotations once it receives input from the user. However this doesn’t solve the general problem.

    A better solution is offered by the Ria services that offer their support for Data Annotation through the INotifyDataError interface whose support is native in the Silverlight presentation layer: this way if you use Ria services you have support for Data Annotations for ALL Silverlight controls.

    Ria services use an approach that is similar to the wrapper approach of the  Validation Toolkit for WPF & Silverlight. However, they don’t need a wrapper around the class for supplying it an adequate implementation of the INotifyDataError interface: when you define a class to be used with a Ria Web Service, Visual Studio automatically creates an analogous class in the Silverlight project with the same data annotations and put inside it the needed implementation of the INotifyDataError interface.

    Moreover, Visual Studio provides also automatic support for asynchronous errors coming from Web Services after the class has been submitted to the server. Such asynchronous errors come from those validation attribute that are defined on the server side version of the class but are not defined on the client side version of the class…..Yes, there might be attributes that are not copied on the client side version of the class! In fact, an attribute is copied on the client side only if the code that defines that attribute is available on the client side. This happens only if the attribute has been defined on the server side in a file with the .shared.cs (or .shared.vb)  extension: only in this case visual studio creates automatically a client side version of the attribute!

    Why should one create an attribute definition without the .shared. extension? There are two possible reasons:

    1. The attribute definition requires libraries that are available in .Net but are not available in Silverlight.
    2. However, the most important reason is that you DON’T WANT that attribute be used on the client side because the validation it performs requires data that are available only on the sever such as data coming from a database.

    Now it is clear that Ria services obtain the same objective of the Validation Toolkit for WPF & Silverlight with a slightly different technique.

    Then, why should one use use the Validation Toolkit for WPF & Silverlight? For two main reasons:

    1. The Web Services cannot be implemented as a Ria Web Services(also called Domain Web Services)
    2. To keep the compatibility with WPF that cannot take advantage of the same type of support offered by Ria services to Silverlight.

     

    The INotifyDataErrors interface and its advantages on the IDataErrorInfo interface

    The INotifyDataError interface is defined as:

    public interface INotifyDataErrorInfo

    {

          bool HasErrors { get; }

         event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

         IEnumerable GetErrors(string propertyName);

    }

    GetErrors has essentially the same role that the indexer in the IDataErrorInfo interface, however it returns a list of errors instead that a single error. This is more correct because there might be several errors for each Control: since WPF only supports the IDataErrorInfo one is forced to concatenate all errors into a single string! Moreover, if one pass to GetErrors the empty string it is supposed to return the object level errors. Also the HasErros property represents an evolution: one is not forced to count the errors by firing the validation routed event to verify if the View Model is valid.

    However, the really cool new feature is the ErrorsChanged event. Silverlight UI subscribes to this event and is able to update the error status of the interface also asynchronously when new errors are returned as a result of asynchronous call to web services. This behavior is not possible with WPF since WPF only supports the IDataErrorInfo interface.

    The Validation Toolkit for WPF & Silverlight is able to update the error status of the UI in response to asynchronous events just because it renounces to delivery the error to its exact target control, but it just renders asynchronous errors as if they all were object level errors. It is worth to point out that this doesn’t mean all asynchronous errors are delivered to the root of the view model but only that they are delivered to the father object of the property they refers to. Since most of remote errors are actually object level errors this behavior is acceptable…but in any case the right behavior…is better. The examples you find in the binary distribution of the Validation Toolkit for WPF and Silverlight shows this difference in the behavior between the Silverlight and the WPF versions.

    How to use the Validation Toolkit for WPF & Silverlight with Silverlight

    The use of the Silverlight version of the  Validation Toolkit for WPF and Silverlight is almost identical to use of the WPF version:

    1. First, you have to enable ValidatesOnNotifyDataErrors in Silverlight 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 of IEnumerables 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. In the Silverlight version you need to enclose in square brackets the names of the properties in your Bindings, because Silverlight doesn't support dynamic object and I was forced to use a dictionary. For instance, [Age] instead of Age.
    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 theValidateWholeObject 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.

    In the next post I will say something more on how to handle validation errors on the server side.

                                         Stay Tuned!

                                          Francesco

    For more information or consulences feel free to contact me

    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 25 2010

    Defining MVC Controls 1

    Category: MVCfrancesco @ 22:35

    Defining MVC Controls 2: Using the DataGrid

    Defining MVC Controls 3: Datagrid, Sorting, and Master-Detail Views

    Data Filtering, in the New Mvc 3 Version of the Mvc Controls Toolkit

    This is the first of a series of posts where I will describe the features of the MVCControlsToolkit Library for MVC that can be found here. The MVC Controls Toolkit contains some Controls for MVC, and a toolset for defining easily new controls. In this first post I describe the needs that lead me to develop the MVCControlsToolkit, and its foundations.

    One of the main foundational principles of MVC is the separation of concerns between the Controller that specifies what to show and the View that specifies How to show it. In the View you have access to all data that the Controller want to display through the View Model, and you can take advantage of the full power of the .Net framework to manipulate the data contained in the View Model to give to your web page the look that you prefer and also a structure that is quite different from the way data are organized in the View Model. For instance you can decide to display a date as 3 separate inputs, one for the Year, one for the Month and the other for the Day, instead of using a single TextBox for the whole date. Unluckily, if you do this the Data Binder will not be able to recompose this three separate fields into the original DateTime object when the View is posted back.

    From one side you have the maximum freedom in rendering the View Model in the View and you can define helper methods to handle complex rendering tasks, but from the other side if there isn’t a one to one correspondence between the elements to post back in the model and the properties of the View Model, and a one to one correspondence between the hierarchical structure of the input fields names and the hierarchical structure of the model, the Model Binder isn’t able to reconstruct the View Model from the data posted by the View. Clearly this is not a design error but a conceptual problem: the Model Binder  has simply no information about how map one structure into the other!

    The example of the date can be solved by defining a custom Model Binder for the DateTime type. There, you can put the information on how to recompose the three separate fields into the original DateTime. However, this will be a poor choice for the following reasons:

    1. All DateTime properties will be mapped in the same way! We have not gained freedom in the Map between the View and the View Model! We have simply moved from a standard map to another standard map! The way a property is displayed may depend on the context, so we need the freedom to specify dynamically this map for each instance of a type.
    2. The right place where to specify information about this map is the same place where we defined what map to use: the View! Not the Global.asax where we add the custom Model Binders.
    3. Conceptually the only information that is needed to reconstruct the View Model is the way the two structures are mapped one into the other. By contrast to write a model binder we are required to handle MVC specific data structure. This means two things:
      • More code to write
      • Difficulties in the testing because of the dependencies from complex data structures that needs to be simulated by the test classes

    Conceptually, the only way to solve the above problems is by putting references to the descriptions of the maps used in the Html pages. This way, we can define dynamically the maps when we render the involved elements in the View.

    The MVC Controls Toolkit uses a default Model Binder that is able to retrieve this map references and to use them to rebuild the View Model. The programmer is only required to write the code that furnishes the minimum information possible for the reconstruction of the model: the map!

    The map is defined by providing an implementation of the  IDisplayModel interface:

    
    namespace MVCControlsToolkit.Core
    {
        public interface IDisplayModel:ISafeCreation
        {
            object ExportToModel(Type TargetType, params object[] context);
            void ImportFromModel(object model, params object[] context);
            
        }
    }

    The ImportFromModel method is called by the method that renders the control. The original data structure to be transformed is passed in the model parameter.

    The ExportToModel function, instead, is called by the Data Binder to reconstruct the original data structure after that the class implementing the interface has been filled with the data extracted from the View that was posted back.

    The programmer may invoke the transformation defined by the interface implementation with the use of the InvokeDisplay helper method. The class returned by this method invocation can be chained with another transformation by calling another overload of the InvokeDispaly helper that accepts as parameters the newly created class and the interface implementation of the other transformation. At the end the transformed data are rendered into a template by passing them to the RenderIn helper.

    The use of the InvokeDisplay helper ensure that the inverse transformation will be applied by the Model Binder when the View is posted back.

    Let go see the details of the process described above with the example of the DateTime field that we already referenced before. Obviously, you don’t need to actually implement a DateTime control because the MVCControlsToolkit already comes with a sophisticate DateTimeInput control. This is just a simple example to help the understanding of the concepts exposed.

    In this case a possible simple implementation of the IDisplayModel interface is:

    public class TestDateTimeDisplay : IDisplayModel
    {
     
            [Range(1000, 3000, ErrorMessage = "wrong year")]
            
            public Nullable<int> Year { get; set; }
    
            [Range(1, 12, ErrorMessage = "wrong month")]
            public Nullable<int> Month { get; set; }
    
            [Range(1, 31, ErrorMessage = "wrong day")]
            public Nullable<int> Day { get; set; }
    
            public object ExportToModel(Type targetType, params object[] context)
            {
                if (Year == 0 && Month == 0 && Day == 0) return null;
                if (!Year.HasValue && !Month.HasValue && !Day.HasValue) return null;
                try
                {
                    return new DateTime(Year.Value, Month.Value, Day.Value);
                }
                catch (Exception ex)
                {
                    throw (new Exception(" {0} has an incorrect date format", ex));
                    
                }
            }
    
            public void ImportFromModel(object model, params object[] context)
            {
                Nullable<DateTime> date = model as Nullable<DateTime>;
                if(date.HasValue && date.Value != DateTime.MinValue)
                {
                    Year = date.Value.Year;
                    Month = date.Value.Month;
                    Day = date.Value.Day;
                }
    
            }
        }

    The call to the ImportFromModel  call is used to fill the values of the of the Year, Month and Day properties from the original DateTime. This three properties will be rendered instead of the original DateTime property. When the View is posted back, the Model Binder first fill the Year, Month and Day properties with its normal algorithm for extracting a model from the post back data and then calls the ExportToModel method of the interface to recover the initial DateTime property. 

    The exception thrown when the date format is wrong is intercepted by the Model Binder and its message is used to produce a validation error associate to the initial DateTime property.

    The code to put in the View for rendering our control is;

    <%: Html.RenderIn("YearMonthDayDate", Html.InvokeTransform(m => m.BirthDate, new TestDateTimeDisplay()))  %>

    YearMonthDayDate is a name of a strongly typed template for the type TestDateTimeDisplay.

    In order to test this example and to do other experiments you can use a generic template for rendering classes, like this one:

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
    <table cellpadding="0" cellspacing="0" border="0">
        <% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm))) { %>
            <% if (prop.HideSurroundingHtml) { %>
                <%= Html.Editor(prop.PropertyName) %>
            <% } else { %>
                <tr>
                    <td>
                        <div class="editor-label" style="text-align: right;">
                            <%= prop.IsRequired ? "*" : "" %>
                            <%= Html.Label(prop.PropertyName) %>
                        </div>
                    </td>
                    <td>
                        <div class="editor-field">
                            <%= Html.Editor(prop.PropertyName) %>
                            <%= Html.ValidationMessage(prop.PropertyName, "*") %>
                        </div>
                    </td>
                </tr>
            <% } %>
        <% } %>
        </table>

    The template can be put either on the Shared folder or in the folder for a specific controller. However if you put it either within a Display or Edit folder the template will not be retrieved,

    In order to test the example you need just:

    1. Download the MVCControlsToolkit from the CodePlex site here
    2. Create a new MVC 2 project
    3. Add the interface implementation to the project
    4. Add the above template or a specific template as explained above
    5. Add a DateTime property to one of the View Models of the predefined pages that you find into a newly created project. I have chosen the RegisterModel model in the AccountModels.cs file, that is rendered into the Register.aspx View.
    6. Add the code for rendering the control into the adequate View, in my case the Register.aspx View. Add also a reference to the namespace where you defined your interface implementation.
    7. Put a breakpoint in the controller method that handles the post back of the View. In my case, the Register method of the AccountController.cs file, to see how the separated Year, Month, Day fields you insert are recomposed into the original DateTime Property, in my case the BirthDate property.

    In the next post I will analyze more advanced features of the MVCControlsToolkit.

                                                                         Stay Tuned!

                                                                          Francesco

    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: , , , ,