Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

June 2012 - Posts

Implementing an Interceptor Using NHibernate’s Built In Dynamic Proxy Generator

Updated: important correction, reported by Christoph; when the event is raised, the first argument should be info.Target, not this.Proxy. Thanks!

NHibernate 3.2 came with an included proxy generator, which means there is no longer the need – or the possibility, for that matter – to choose Castle DynamicProxy, LinFu or Spring. This is actually a good thing, because it means one less assembly to deploy. Apparently, this generator was based, at least partially, on LinFu.

As there are not many tutorials out there demonstrating it’s usage, here’s one, for demonstrating one of the most requested features: implementing INotifyPropertyChanged. This interceptor, of course, will still feature all of NHibernate’s functionalities that you are used to, such as lazy loading, and such.

We will start by implementing an NHibernate interceptor, by inheriting from the base class NHibernate.EmptyInterceptor. This class does not do anything by itself, but it allows us to plug in behavior by overriding some of its methods, in this case, Instantiate:

   1: public class NotifyPropertyChangedInterceptor : EmptyInterceptor
   2: {
   3:     private ISession session = null;
   4:  
   5:     private static readonly ProxyFactory factory = new ProxyFactory();
   6:  
   7:     public override void SetSession(ISession session)
   8:     {
   9:         this.session = session;
  10:         base.SetSession(session);
  11:     }
  12:  
  13:     public override Object Instantiate(String clazz, EntityMode entityMode, Object id)
  14:     {
  15:         Type entityType = Type.GetType(clazz);
  16:         IProxy proxy = factory.CreateProxy(entityType, new _NotifyPropertyChangedInterceptor(), typeof(INotifyPropertyChanged)) as IProxy;
  17:         
  18:         _NotifyPropertyChangedInterceptor interceptor = proxy.Interceptor as _NotifyPropertyChangedInterceptor;
  19:         interceptor.Proxy = this.session.SessionFactory.GetClassMetadata(entityType).Instantiate(id, entityMode);
  20:  
  21:         this.session.SessionFactory.GetClassMetadata(entityType).SetIdentifier(proxy, id, entityMode);
  22:  
  23:         return (proxy);
  24:     }
  25: }

Then we need a class that implements the NHibernate dynamic proxy behavior, let’s place it inside our interceptor, because it will only need to be used there:

   1: class _NotifyPropertyChangedInterceptor : NHibernate.Proxy.DynamicProxy.IInterceptor
   2: {
   3:     private PropertyChangedEventHandler changed = delegate { };
   4:  
   5:     public Object Proxy
   6:     {
   7:         get;
   8:         set;}
   9:  
  10:     #region IInterceptor Members
  11:  
  12:     public Object Intercept(InvocationInfo info)
  13:     {
  14:         Boolean isSetter = info.TargetMethod.Name.StartsWith("set_") == true;
  15:         Object result = null;
  16:  
  17:         if (info.TargetMethod.Name == "add_PropertyChanged")
  18:         {
  19:             PropertyChangedEventHandler propertyChangedEventHandler = info.Arguments[0] as PropertyChangedEventHandler;
  20:             this.changed += propertyChangedEventHandler;
  21:         }
  22:         else if (info.TargetMethod.Name == "remove_PropertyChanged")
  23:         {
  24:             PropertyChangedEventHandler propertyChangedEventHandler = info.Arguments[0] as PropertyChangedEventHandler;
  25:             this.changed -= propertyChangedEventHandler;
  26:         }
  27:         else
  28:         {
  29:             result = info.TargetMethod.Invoke(this.Proxy, info.Arguments);
  30:         }
  31:  
  32:         if (isSetter == true)
  33:         {
  34:             String propertyName = info.TargetMethod.Name.Substring("set_".Length);
  35:             this.changed(this.Target, new PropertyChangedEventArgs(propertyName));
  36:         }
  37:  
  38:         return (result);
  39:     }
  40:  
  41:     #endregion
  42: }

What this does for every interceptable method (those who are either virtual or from the INotifyPropertyChanged) is:

  • For methods that came from the INotifyPropertyChanged interface, add_PropertyChanged and remove_PropertyChanged (yes, events are methods Winking smile), we add an implementation that adds or removes the event handlers to the delegate which we declared as changed;
  • For all the others, we direct them to the place where they are actually implemented, which is the Proxy field;
  • If the call is setting a property, it fires afterwards the PropertyChanged event.

In order to use this, we need to add the interceptor to the Configuration before building the ISessionFactory:

   1: using (ISessionFactory factory = cfg.SetInterceptor(new NotifyPropertyChangedInterceptor()).BuildSessionFactory())
   2: {
   3:     using (ISession session = factory.OpenSession())
   4:     using (ITransaction tx = session.BeginTransaction())
   5:     {
   6:         Customer customer = session.Get<Customer>(100);    //some id
   7:         INotifyPropertyChanged inpc = customer as INotifyPropertyChanged;
   8:         inpc.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
   9:         {
  10:             //fired when a property changes
  11:         };
  12:         customer.Address = "some other address";    //will raise PropertyChanged
  13:         customer.RecentOrders.ToList();            //will trigger the lazy loading
  14:     }
  15: }

Any problems, questions, do drop me a line!

NDepend 4 – First Steps

Introduction

Thanks to Patrick Smacchia I had the chance to test NDepend 4. I can only say: awesome!

This will be the first of a series of posts on NDepend, where I will talk about my discoveries. Keep in mind that I am just starting to use it, so more experienced users may find these too basic, I just hope I don’t say anything foolish! Smile

I must say that I am in no way affiliated with NDepend and I never actually met Patrick.

Installation

No installation program – a curious decision, I’m not against it -, just unzip the files to a folder and run the executable. It will optionally register itself with Visual Studio 2008, 2010 and 11 as well as RedGate’s Reflector; also, it automatically looks for updates. NDepend can either be used as a stand-alone program (with or without a GUI) or from within Visual Studio or Reflector.

Getting Started

One thing that really pleases me is the Getting Started section of the stand-alone, with links to pages on NDepend’s web site, featuring detailed explanations, which usually include screenshots and small videos (<5 minutes). There’s also an How do I with hierarchical navigation that guides us to through the major features so that we can easily find what we want.

Usage

There are two basic ways to use NDepend:

  • Analyze .NET solutions, projects or assemblies;
  • Compare two versions of the same assembly.

I have so far not used NDepend to compare assemblies, so I will first talk about the first option.

After selecting a solution and some of its projects, it generates a single HTML page with an highly detailed report of the analysis it produced. This includes some metrics such as number of lines of code, IL instructions, comments, types, methods and properties, the calculation of the cyclomatic complexity, coupling and lots of others indicators, typically grouped by type, namespace and assembly.

The HTML also includes some nice diagrams depicting assembly dependencies, type and method relative proportions (according to the number of IL instructions, I guess) and assembly analysis relating to abstractness and stability. Useful, I would say.

Then there’s the rules; NDepend tests the target assemblies against a set of more than 120 rules, grouped in categories Code Quality, Object Oriented Design, Design, Architecture and Layering, Dead Code, Visibility, Naming Conventions, Source Files Organization and .NET Framework Usage. The full list can be configured on the application, and an explanation of each rule can be found on the web site. Rules can be validated, violated and violated in a critical manner, and the HTML will contain the violated rules, their queries – more on this later - and results. The HTML uses some nice JavaScript effects, which allow paging and sorting of tables, so its nice to use.

Similar to the rules, there are some queries that display results for a number (about 200) questions grouped as Object Oriented Design, API Breaking Changes (for assembly version comparison), Code Diff Summary (also for version comparison) and Dead Code. The difference between queries and rules is that queries are not classified as passes, violated or critically violated, just present results.

The queries and rules are expressed through CQLinq, which is a very powerful LINQ derivative specific to code analysis. All of the included rules and queries can be enabled or disabled and new ones can be added, with intellisense to help.

Besides the HTML report file, the NDepend application can be used to explore all analysis results, compare different versions of analysis reports and to run custom queries.

Comparison to Other Analysis Tools

Unlike StyleCop, NDepend only works with assemblies, not source code, so you can’t expect it to be able to enforce brackets placement, for example. It is more similar to FxCop, but you don’t have the option to analyze at the IL level, that is, other that the number of IL instructions and the complexity.

What’s Next

In the next days I’ll continue my exploration with a real-life test case.

References

The NDepend web site is http://www.ndepend.com/. Patrick keeps an updated blog on http://codebetter.com/patricksmacchia/ and he regularly monitors StackOverflow for questions tagged NDepend, which you can find on http://stackoverflow.com/questions/tagged/ndepend.

The default list of CQLinq rules, queries and statistics can be found at http://www.ndepend.com/DefaultRules/webframe.html. The syntax itself is described at http://www.ndepend.com/Doc_CQLinq_Syntax.aspx and its features at http://www.ndepend.com/Doc_CQLinq_Features.aspx.

Differences Between NHibernate and Entity Framework

Introduction

NHibernate and Entity Framework are two of the most popular O/RM frameworks on the .NET world. Although they share some functionality, there are some aspects on which they are quite different. This post will describe this differences and will hopefully help you get started with the one you know less. Mind you, this is a personal selection of features to compare, it is by no way an exhaustive list.

History

First, a bit of history. NHibernate is an open-source project that was first ported from Java’s venerable Hibernate framework, one of the first O/RM frameworks, but nowadays it is not tied to it, for example, it has .NET specific features, and has evolved in different ways from those of its Java counterpart. Current version is 3.3, with 3.4 on the horizon. It currently targets .NET 3.5, but can be used as well in .NET 4, it only makes no use of any of its specific functionality. You can find its home page at NHForge.

Entity Framework 1 came out with .NET 3.5 and is now on its second major version, despite being version 4. Code First sits on top of it and but came separately and will also continue to be released out of line with major .NET distributions. It is currently on version 4.3.1 and version 5 will be released together with .NET Framework 4.5. All versions will target the current version of .NET, at the time of their release. Its home location is located at MSDN.

Architecture

In NHibernate, there is a separation between the Unit of Work and the configuration and model instances. You start off by creating a Configuration object, where you specify all global NHibernate settings such as the database and dialect to use, the batch sizes, the mappings, etc, then you build an ISessionFactory from it. The ISessionFactory holds model and metadata that is tied to a particular database and to the settings that came from the Configuration object, and, there will typically be only one instance of each in a process. Finally, you create instances of ISession from the ISessionFactory, which is the NHibernate representation of the Unit of Work and Identity Map. This is a lightweight object, it basically opens and closes a database connection as required and keeps track of the entities associated with it. ISession objects are cheap to create and dispose, because all of the model complexity is stored in the ISessionFactory and Configuration objects.

As for Entity Framework, the ObjectContext/DbContext holds the configuration, model and acts as the Unit of Work, holding references to all of the known entity instances. This class is therefore not lightweight as its NHibernate counterpart and it is not uncommon to see examples where an instance is cached on a field.

Mappings

Both NHibernate and Entity Framework (Code First) support the use of POCOs to represent entities, no base classes are required (or even possible, in the case of NHibernate).

As for mapping to and from the database, NHibernate supports three types of mappings:

  • XML-based, which have the advantage of not tying the entity classes to a particular O/RM; the XML files can be deployed as files on the file system or as embedded resources in an assembly;
  • Attribute-based, for keeping both the entities and database details on the same place at the expense of polluting the entity classes with NHibernate-specific attributes;
  • Strongly-typed code-based, which allows dynamic creation of the model and strongly typing it, so that if, for example, a property name changes, the mapping will also be updated.

Entity Framework can use:

  • Attribute-based (although attributes cannot express all of the available possibilities – for example, cascading);
  • Strongly-typed code mappings.

Database Support

With NHibernate you can use mostly any database you want, including:

  • SQL Server;
  • SQL Server Compact;
  • SQL Server Azure;
  • Oracle;
  • DB2;
  • PostgreSQL;
  • MySQL;
  • Sybase Adaptive Server/SQL Anywhere;
  • Firebird;
  • SQLLite;
  • Informix;
  • Any through OLE DB;
  • Any through ODBC.

Out of the box, Entity Framework only supports SQL Server, but a number of providers exist, both free and commercial, for some of the most used databases, such as Oracle and MySQL. See a list here.

Inheritance Strategies

Both NHibernate and Entity Framework support the three canonical inheritance strategies: Table Per Type Hierarchy (Single Table Inheritance), Table Per Type (Class Table Inheritance) and Table Per Concrete Type (Concrete Table Inheritance).

Associations

Regarding associations, both support one to one, one to many and many to many. However, NHibernate offers far more collection types:

  • Bags of entities or values: unordered, possibly with duplicates;
  • Lists of entities or values: ordered, indexed by a number column;
  • Maps of entities or values: indexed by either an entity or any value;
  • Sets of entities or values: unordered, no duplicates;
  • Arrays of entities or values: indexed, immutable.

Querying

NHibernate exposes several querying APIs:

  • LINQ is probably the most used nowadays, and really does not need to be introduced;
  • Hibernate Query Language (HQL) is a database-agnostic, object-oriented SQL-alike language that exists since NHibernate’s creation and still offers the most advanced querying possibilities; well suited for dynamic queries, even if using string concatenation;
  • Criteria API is an implementation of the Query Object pattern where you create a semi-abstract conceptual representation of the query you wish to execute by means of a class model; also a good choice for dynamic querying;
  • Query Over offers a similar API to Criteria, but using strongly-typed LINQ expressions instead of strings; for this, although more refactor-friendlier that Criteria, it is also less suited for dynamic queries;
  • SQL, including stored procedures, can also be used;
  • Integration with Lucene.NET indexer is available.

As for Entity Framework:

  • LINQ to Entities is fully supported, and its implementation is considered very complete; it is the API of choice for most developers;
  • Entity-SQL, HQL’s counterpart, is also an object-oriented, database-independent querying language that can be used for dynamic queries;
  • SQL, of course, is also supported.

Caching

Both NHibernate and Entity Framework, of course, feature first-level cache. NHibernate also supports a second-level cache, that can be used among multiple ISessionFactorys, even in different processes/machines:

Out of the box, Entity Framework does not have any second-level cache mechanism, however, there are some public samples that show how we can add this.

ID Generators

NHibernate supports different ID generation strategies, coming from the database and otherwise:

  • Identity (for SQL Server, MySQL, and databases who support identity columns);
  • Sequence (for Oracle, PostgreSQL, and others who support sequences);
  • Trigger-based;
  • HiLo;
  • Sequence HiLo (for databases that support sequences);
  • Several GUID flavors, both in GUID as well as in string format;
  • Increment (for single-user uses);
  • Assigned (must know what you’re doing);
  • Sequence-style (either uses an actual sequence or a single-column table);
  • Table of ids;
  • Pooled (similar to HiLo but stores high values in a table);
  • Native (uses whatever mechanism the current database supports, identity or sequence).

Entity Framework only supports:

  • Identity generation;
  • GUIDs;
  • Assigned values.

Properties

NHibernate supports properties of entity types (one to one or many to one), collections (one to many or many to many) as well as scalars and enumerations. It offers a mechanism for having complex property types generated from the database, which even include support for querying. It also supports properties originated from SQL formulas.

Entity Framework only supports scalars, entity types and collections. Enumerations support will come in the next version.

Events and Interception

NHibernate has a very rich event model, that exposes more than 20 events, either for synchronous pre-execution or asynchronous post-execution, including:

  • Pre/Post-Load;
  • Pre/Post-Delete;
  • Pre/Post-Insert;
  • Pre/Post-Update;
  • Pre/Post-Flush.

It also features interception of class instancing and SQL generation.

As for Entity Framework, only two events exist:

Tracking Changes

For NHibernate as well as Entity Framework, all changes are tracked by their respective Unit of Work implementation. Entities can be attached and detached to it, Entity Framework does, however, also support self-tracking entities.

Optimistic Concurrency Control

NHibernate supports all of the imaginable scenarios:

  • SQL Server’s ROWVERSION;
  • Oracle’s ORA_ROWSCN;
  • A column containing date and time;
  • A column containing a version number;
  • All/dirty columns comparison.

Entity Framework is more focused on Entity Framework, so it only supports:

  • SQL Server’s ROWVERSION;
  • Comparing all/some columns.

Batching

NHibernate has full support for insertion batching, but only if the ID generator in use is not database-based (for example, it cannot be used with Identity), whereas Entity Framework has no batching at all.

Cascading

Both support cascading for collections and associations: when an entity is deleted, their conceptual children are also deleted. NHibernate also offers the possibility to set the foreign key column on children to NULL instead of removing them.

Flushing Changes

NHibernate’s ISession has a FlushMode property that can have the following values:

  • Auto: changes are sent to the database when necessary, for example, if there are dirty instances of an entity type, and a query is performed against this entity type, or if the ISession is being disposed;
  • Commit: changes are sent when committing the current transaction;
  • Never: changes are only sent when explicitly calling Flush().

As for Entity Framework, changes have to be explicitly sent through a call to AcceptAllChanges()/SaveChanges().

Lazy Loading

NHibernate supports lazy loading for

  • Associated entities (one to one, many to one);
  • Collections (one to many, many to many);
  • Scalar properties (thing of BLOBs or CLOBs).

Entity Framework only supports lazy loading for:

  • Associated entities;
  • Collections.

Generating and Updating the Database

Both NHibernate and Entity Framework Code First (with the Migrations API) allow creating the database model from the mapping and updating it if the mapping changes.

Extensibility

As you can guess, NHibernate is far more extensible than Entity Framework. Basically, everything can be extended, from ID generation, to LINQ to SQL transformation, HQL native SQL support, custom column types, custom association collections, SQL generation, supported databases, etc. With Entity Framework your options are more limited, at least, because practically no information exists as to what can be extended/changed. It features a provider model that can be extended to support any database.

Integration With Other Microsoft APIs and Tools

When it comes to integration with Microsoft technologies, it will come as no surprise that Entity Framework offers the best support. For example, the following technologies are fully supported:

Documentation

This is another point where Entity Framework is superior: NHibernate lacks, for starters, an up to date API reference synchronized with its current version. It does have a community mailing list, blogs and wikis, although not much used. Entity Framework has a number of resources on MSDN and, of course, several forums and discussion groups exist.

Conclusion

Like I said, this is a personal list. I may come as a surprise to some that Entity Framework is so behind NHibernate in so many aspects, but it is true that NHibernate is much older and, due to its open-source nature, is not tied to product-specific timeframes and can thus evolve much more rapidly. I do like both, and I chose whichever is best for the job I have at hands. I am looking forward to the changes in EF5 which will add significant value to an already interesting product.

So, what do you think? Did I forget anything important or is there anything else worth talking about? Looking forward for your comments!

ASP.NET MVC Validation Complete

OK, so let’s talk about validation. Most people are probably familiar with the out of the box validation attributes that MVC knows about, from the System.ComponentModel.DataAnnotations namespace, such as EnumDataTypeAttribute, RequiredAttribute, StringLengthAttribute, RangeAttribute, RegularExpressionAttribute and CompareAttribute from the System.Web.Mvc namespace. All of these validators inherit from ValidationAttribute and perform server as well as client-side validation. In order to use them, you must include the JavaScript files MicrosoftMvcValidation.js, jquery.validate.js or jquery.validate.unobtrusive.js, depending on whether you want to use Microsoft’s own library or jQuery. No significant difference exists, but jQuery is more extensible.

You can also create your own attribute by inheriting from ValidationAttribute, but, if you want to have client-side behavior, you must also implement IClientValidatable (all of the out of the box validation attributes implement it) and supply your own JavaScript validation function that mimics its server-side counterpart. Of course, you must reference the JavaScript file where the declaration function is. Let’s see an example, validating even numbers. First, the validation attribute:

   1: [Serializable]
   2: [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
   3: public class IsEvenAttribute : ValidationAttribute, IClientValidatable
   4: {
   5:     protected override ValidationResult IsValid(Object value, ValidationContext validationContext)
   6:     {
   7:         Int32 v = Convert.ToInt32(value);
   8:  
   9:         if (v % 2 == 0)
  10:         {
  11:             return (ValidationResult.Success);
  12:         }
  13:         else
  14:         {
  15:             return (new ValidationResult("Value is not even"));
  16:         }
  17:     }
  18:  
  19:     #region IClientValidatable Members
  20:  
  21:     public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
  22:     {
  23:         yield return (new ModelClientValidationRule() { ValidationType = "iseven", ErrorMessage = "Value is not even" });
  24:     }
  25:  
  26:     #endregion
  27: }

The iseven validation function is declared like this in JavaScript, using jQuery validation:

   1: jQuery.validator.addMethod('iseven', function (value, element, params)
   2: {
   3:     return (true);
   4:     return ((parseInt(value) % 2) == 0);
   5: });
   6:  
   7: jQuery.validator.unobtrusive.adapters.add('iseven', [], function (options)
   8: {
   9:     options.rules['iseven'] = options.params;
  10:     options.messages['iseven'] = options.message;
  11: });

Do keep in mind that this is a simple example, for example, we are not using parameters, which may be required for some more advanced scenarios.

As a side note, if you implement a custom validator that also requires a JavaScript function, you’ll probably want them together. One way to achieve this is by including the JavaScript file as an embedded resource on the same assembly where the custom attribute is declared. You do this by having its Build Action set as Embedded Resource inside Visual Studio:

image

Then you have to declare an attribute at assembly level, perhaps in the AssemblyInfo.cs file:

   1: [assembly: WebResource("SomeNamespace.IsEven.js", "text/javascript")]

In your views, if you want to include a JavaScript file from an embedded resource you can use this code:

   1: public static class UrlExtensions
   2: {
   3:     private static readonly MethodInfo getResourceUrlMethod = typeof(AssemblyResourceLoader).GetMethod("GetWebResourceUrlInternal", BindingFlags.NonPublic | BindingFlags.Static);
   4:  
   5:     public static IHtmlString Resource<TType>(this UrlHelper url, String resourceName)
   6:     {
   7:         return (Resource(url, typeof(TType).Assembly.FullName, resourceName));
   8:     }
   9:  
  10:     public static IHtmlString Resource(this UrlHelper url, String assemblyName, String resourceName)
  11:     {
  12:         String resourceUrl = getResourceUrlMethod.Invoke(null, new Object[] { Assembly.Load(assemblyName), resourceName, false, false, null }).ToString();
  13:         return (new HtmlString(resourceUrl));
  14:     }
  15: }

And on the view:

   1: <script src="<%: this.Url.Resource("SomeAssembly", "SomeNamespace.IsEven.js") %>" type="text/javascript"></script>

Then there’s the CustomValidationAttribute. It allows externalizing your validation logic to another class, so you have to tell which type and method to use. The method can be static as well as instance, if it is instance, the class cannot be abstract and must have a public parameterless constructor. It can be applied to a property as well as a class. It does not, however, support client-side validation. Let’s see an example declaration:

   1: [CustomValidation(typeof(ProductValidator), "OnValidateName")]
   2: public String Name
   3: {
   4:     get;
   5:     set;
   6: }

The validation method needs this signature:

   1: public static ValidationResult OnValidateName(String name)
   2: {
   3:     if ((String.IsNullOrWhiteSpace(name) == false) && (name.Length <= 50))
   4:     {
   5:         return (ValidationResult.Success);
   6:     }
   7:     else
   8:     {
   9:         return (new ValidationResult(String.Format("The name has an invalid value: {0}", name), new String[] { "Name" }));
  10:     }
  11: }

Note that it can be either static or instance and it must return a ValidationResult-derived class. ValidationResult.Success is null, so any non-null value is considered a validation error. The single method argument must match the property type to which the attribute is attached to or the class, in case it is applied to a class:

   1: [CustomValidation(typeof(ProductValidator), "OnValidateProduct")]
   2: public class Product
   3: {
   4: }

The signature must thus be:

   1: public static ValidationResult OnValidateProduct(Product product)
   2: {
   3: }

Continuing with attribute-based validation, another possibility is RemoteAttribute. This allows specifying a controller and an action method just for performing the validation of a property or set of properties. This works in a client-side AJAX way and it can be very useful. Let’s see an example, starting with the attribute declaration and proceeding to the action method implementation:

   1: [Remote("Validate", "Validation")]
   2: public String Username
   3: {
   4:     get;
   5:     set;
   6: }

The controller action method must contain an argument that can be bound to the property:

   1: public ActionResult Validate(String username)
   2: {
   3:     return (this.Json(true, JsonRequestBehavior.AllowGet));
   4: }

If in your result JSON object you include a string instead of the true value, it will consider it as an error, and the validation will fail. This string will be displayed as the error message, if you have included it in your view.

You can also use the remote validation approach for validating your entire entity, by including all of its properties as included fields in the attribute and having an action method that receives an entity instead of a single property:

   1: [Remote("Validate", "Validation", AdditionalFields = "Price")]
   2: public String Name
   3: {
   4:     get;
   5:     set;
   6: }
   7:  
   8: public Decimal Price
   9: {
  10:     get;
  11:     set;
  12: }

The action method will then be:

   1: public ActionResult Validate(Product product)
   2: {
   3:     return (this.Json("Product is not valid", JsonRequestBehavior.AllowGet));
   4: }

Only the property to which the attribute is applied and the additional properties referenced by the AdditionalFields will be populated in the entity instance received by the validation method. The same rule previously stated applies, if you return anything other than true, it will be used as the validation error message for the entity. The remote validation is triggered automatically, but you can also call it explicitly. In the next example, I am causing the full entity validation, see the call to serialize():

   1: function validate()
   2: {
   3:     var form = $('form');
   4:     var data = form.serialize();
   5:     var url = '<%: this.Url.Action("Validation", "Validate") %>';
   6:  
   7:     var result = $.ajax
   8:     (
   9:         {
  10:             type: 'POST',
  11:             url: url,
  12:             data: data,
  13:             async: false
  14:         }
  15:     ).responseText;
  16:  
  17:     if (result)
  18:     {
  19:         //error
  20:     }
  21: }

Finally, by implementing IValidatableObject, you can implement your validation logic on the object itself, that is, you make it self-validatable. This will only work server-side, that is, the ModelState.IsValid property will be set to false on the controller’s action method if the validation in unsuccessful. Let’s see how to implement it:

   1: public class Product : IValidatableObject
   2: {
   3:     public String Name
   4:     {
   5:         get;
   6:         set;
   7:     }
   8:  
   9:     public Decimal Price
  10:     {
  11:         get;
  12:         set;
  13:     }
  14:  
  15:     #region IValidatableObject Members
  16:     
  17:     public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
  18:     {
  19:         if ((String.IsNullOrWhiteSpace(this.Name) == true) || (this.Name.Length > 50))
  20:         {
  21:             yield return (new ValidationResult(String.Format("The name has an invalid value: {0}", this.Name), new String[] { "Name" }));
  22:         }
  23:         
  24:         if ((this.Price <= 0) || (this.Price > 100))
  25:         {
  26:             yield return (new ValidationResult(String.Format("The price has an invalid value: {0}", this.Price), new String[] { "Price" }));
  27:         }
  28:     }
  29:     
  30:     #endregion
  31: }

The errors returned will be matched against the model properties through the MemberNames property of the ValidationResult class and will be displayed in their proper labels, if present on the view.

On the controller action method you can check for model validity by looking at ModelState.IsValid and you can get actual error messages and related properties by examining all of the entries in the ModelState dictionary:

   1: Dictionary<String, String> errors = new Dictionary<String, String>();
   2:  
   3: foreach (KeyValuePair<String, ModelState> keyValue in this.ModelState)
   4: {
   5:     String key = keyValue.Key;
   6:     ModelState modelState = keyValue.Value;
   7:  
   8:     foreach (ModelError error in modelState.Errors)
   9:     {
  10:         errors[key] = error.ErrorMessage;
  11:     }
  12: }

And these are the ways to perform date validation in ASP.NET MVC. Don’t forget to use them!

More Posts