Validation Asp.Net MVC 2.0 avec Entlib 5.0

Asp.Net 2.0 est maintenant pourvu d’un système de validation des entités du modèle très puissant basé sur des attributs qu’il faut placer sur les propriétés d’une classe pour valider celle-ci.

 

Voir sur le site de Scott Guthrie : http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx

A priori ce dispositif est très pratique, mais à la moindre modification de règle de validation il faut recompiler le projet et mettre à jour l’application web pour que celle-ci soit prise en compte.

Les “géniaux” développeurs d’Asp.Net MVC 2.0 ont mis en place un Fournisseur de validation d’entité qu’il est possible d’étendre.

Je vais montrer ici comment utiliser le Validation Application Block d’Entlib 5.0 pour valider les entités du modèle et stocker les règles de validation dans un fichier de configuration xml a part.

Dans un premier temps il va falloir indiquer que l’on veut utiliser le Validation Application Block d’Entlib

	public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

}

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);

var validationFile = Context.Server.MapPath("/validations.config");

ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new EntLibValidatorProvider(validationFile));
}
}


Il faut donc effacer les validateurs standards, puis ajouter celui d’enlib, j’ai récupéré ce code sur le blog de Brad Wilson à l’adresse suivante :


http://bradwilson.typepad.com/blog/2009/10/enterprise-library-validation-example-for-aspnet-mvc-2.html


	public class EntLibValidatorProvider : ModelValidatorProvider
{
private string m_ConfigFileName;

public EntLibValidatorProvider(string configFileName)
{
m_ConfigFileName = configFileName;
}

public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
var configSource = new Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource(m_ConfigFileName);
var validator = ValidationFactory.CreateValidatorFromConfiguration(metadata.ModelType, "defaultRuleSets", configSource);

if (validator != null)
{
yield return new EntLibValidatorWrapper(metadata, context, validator);
}
}
}


a noter, la fabrique de validator possède une methode qui permet de charger les règles a partir d’un fichier (le chemin de celui-ci est passé en paramètre du constructeur)



voici le code du wrapper EntLibValidatorWrapper



	public class EntLibValidatorWrapper : ModelValidator
{
private Validator _validator;

public EntLibValidatorWrapper(ModelMetadata metadata, ControllerContext context, Validator validator)
: base(metadata, context)
{
_validator = validator;
}

public override IEnumerable<ModelValidationResult> Validate(object container)
{
return ConvertResults(_validator.Validate(Metadata.Model));
}

private IEnumerable<ModelValidationResult> ConvertResults(IEnumerable<ValidationResult> validationResults)
{
if (validationResults != null)
{
foreach (var validationResult in validationResults)
{
if (validationResult.NestedValidationResults != null)
{
foreach (var result in ConvertResults(validationResult.NestedValidationResults))
{
yield return result;
}
}

yield return new ModelValidationResult
{
Message = validationResult.Message,
MemberName = validationResult.Key
};
}
}
}
}




Pour l’exemple l’idée sera de valider une classe très simple Person



	public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}


On peut voir qu’elle ne possède aucun attribut (pure classe poco).



J’ajoute une règle qui interdit que le nom puisse être vide dans un fichier en racine du site web nommé “validations.config”



<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="validation" type="Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.ValidationSettings, Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<validation>
<type name="MvcEntlibValidation.Models.Person" defaultRuleset="defaultRuleSets"
assemblyName="MvcEntlibValidation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<ruleset name="defaultRuleSets">
<properties>
<property name="LastName">
<validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.NotNullValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
messageTemplate="Vous devez indiquer un nom" name="Not Null Validator" />
</property>
</properties>
</ruleset>
</type>
</validation>
</configuration>


Entlib 5.0 possède un editeur de configuration assez sympa, voici ce que ça donne :



image 


il ne reste plus qu’a mettre en place l’action d’edition d’une personne dans le controller :


		public ActionResult EditPerson()
{
ViewData.Model = new Models.Person();
return View();
}

[HttpPost]
public ActionResult EditPerson(Models.Person person)
{
ViewData.Model = person;

if (!ModelState.IsValid)
{
return View();
}

return View();
}


 



L’appel de la propriété ModelState.IsValid a pour effet de valider l’instance de la classe Person.



image



Voici le contenu de la vue :



    <h2>EditPerson</h2>

<% =Html.ValidationSummary() %>
<% Html.BeginForm(); %>

Nom : <%=Html.EditorFor(m => m.LastName) %><br />
<%=Html.ValidationMessageFor(m => m.LastName) %>
<br />

Prénom : <%=Html.EditorFor(m => m.FirstName) %><br />
<%=Html.ValidationMessageFor(m => m.FirstName) %>

<br />

<input type="submit" name="Valider" />

<% Html.EndForm(); %>





Il ne manque plus que la mise en place de la validation client à la volée pour que ce soit parfait, voici le code source de l’exemple :


Aucun commentaire: