Click here to Skip to main content
Click here to Skip to main content

Tagged as

MVC Data Annotation Validators using Fluent Validation

, 29 Aug 2012
Rate this:
Please Sign up or sign in to vote.
Validating objects through metadata is the approach of Validation with the MVC Data Annotation concept.

Validating objects through metadata is the approach of Validation with the MVC Data Annotation concept. Metadata allows us to bind specific configurations to the business objects without changing or extending any of the objects implicit responsibilities. In ASP.NET MVC, the concept is to use a specialized view model for each view and to pass the data needed. In this approach, the validation attributes must be placed in view model class. If you have a separation between each layer of the application, and that separation implies that you have different projects for each layer. The model can be defined by the classes generated by the entity framework in you data access layer or by your business layer.

I have a database first approach using the Entity Framework and to use the MVC validation I could create a partial class with a MetadataType attribute to define the validator class. This is called a "buddy class". A simple example is:

[MetadataType(typeof(CustomerMetadata))]
public partial class Customer
{
    // Class generated by the Entity Framework designer
}

public class CustomerMetadata
{
   [Required]
   public object Id;

   [Required]
   [StringLength(250)]
   public object FirstName;
}

The above approach works great, but if you have service oriented architecture with WCF Services the validation attributes will be ignored by the WCF Serializer. The reason is obvious, the service and operation contracts are described by the Web Service Definition Language (WSDL), but the W3C specification doesn't support these attributes, so they are simple are ignored.

Possible solutions to this problem are:

  1. Using buddy classes for partial classes of the WCF proxy
  2. Share an assembly with your entities between your WCF client and WCF service and reuse those types

None of the above solutions are what I consider a good option and both will create tight coupling between your service and ASP.NET MVC application.

Another problem I face is that I have a project with all my service Proxies that is referenced by the MVC application or any client. Since you cannot have two partial classes referring to the same class in two different assemblies (projects) and I don't want to have MVC specific client side validation on my reusable proxy library, so another solution is in order.

Above all I think that if you want to have client side validation you should to it on the client side. The validation must be as simple as defining some rules that don't need to be associated directly with your model class.

I also wanted to take advantage of all the MVC validation infrastructure with client and server side validation. I don't want to reinvent the wheel and develop all that code manually.

The solution I found is to use Fluent Validation framework with an Inversion of Control container (IoC) to instantiate my validators. The Inversion of Control (IoC) pattern is all about removing dependencies from your code. Fluent Validation is a small validation library for .NET that uses a fluent interface and lambda expressions for building validation rules for your business objects.

The Fluent Validation framework is a validation engine that can be used in several scenarios. In this specific solution, I will be focusing in the integration with MVC without using any attributes. To use Fluent Validation with ASP.NET MVC I am going to use an Inversion of Control container to instantiate the validators.

The difference between an Inversion of Control (IoC) and any other kind of frameworks is that the control gets inverted. The objects in a application are controlled by the Inversion of Control Containers and the application is completely unaware of what the IoC does. A IoC container manages it's life-cycle, invokes methods and is fully autonomous form the application.

The solution implemented by Fluent Validation is to use a custom Validator Factory.

The process to implement can be described in the following steps:

  1. Create a Validator Factory for FluentValidation that inherits from ValidatorFactoryBase. Override the CreateInstance method to call the IoC container that is responsible for instantiating the validators.
  2. public class StructureMapValidatorFactory : ValidatorFactoryBase
    {
        public override IValidator CreateInstance(Type validatorType)
        {
            return ObjectFactory.TryGetInstance(validatorType) as IValidator;
        }
    }

    I am going to use StructureMap as the IoC Container.

  3. Create a StructureMap Controller Factory that inherits from the MVC DefaultControllerFactory.
  4. public class StructureMapValidatorFactory : ValidatorFactoryBase
    {
        public override IValidator CreateInstance(Type validatorType)
        {
            return ObjectFactory.TryGetInstance(validatorType) as IValidator;
        }
    }
  5. Register your validator types with StructureMap, using the FluentValidation AssemblyScanner. The AssemblyScanner automatically registers all of the validator classes in a particular assembly with a IoC container.
  6. public class MyRegistry : StructureMap.Configuration.DSL.Registry
    {
        public MyRegistry()
        {
            FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<CustomerValidator>()
                .ForEach(result =>
                {
                    For(result.InterfaceType)
                        .Singleton()
                        .Use(result.ValidatorType);
                });
    
        }
    }
  7. Configure MVC to use FluentValidation MVC integration in Global.asax Application_Start.
  8. protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
    
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    
        // Configure structuremap
        ObjectFactory.Configure(cfg => cfg.AddRegistry(new MyRegistry()));
        ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
    
        // Configure FluentValidation to use StructureMap
        var factory = new StructureMapValidatorFactory();
    
        // Tell MVC to use FluentValidation for validation
        ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(factory));
        DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
    }
  9. Now the real fun can begin. The FluentValidation library can be used in MVC.

Let's create a customer validator class, where the First Name and Last Name are mandatory and we also want to set a custom error message. Also perform the same validation on the email and guarantee that the email follows the basic rules.

The validation class must inherit from AbstractValidator. The rules are defined using lambda expressions.

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleFor(customer => customer.FirstName).NotEmpty().WithMessage("Please fill the first name.");
        RuleFor(customer => customer.LastName).NotEmpty().WithMessage("Please fill the last name.");
        RuleFor(customer => customer.EmailAddress).EmailAddress()
                                       .WithMessage("Please fill a valid email address.")
                                       .NotEmpty().WithMessage("Please fill the first email.");
    }
}

The FluentValidation has built in Validators or you can define your custom validators.

You can read more about the fluent validation here. Structuremap download and documentation can be found here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rui Inacio
Team Leader
Portugal Portugal
I am an Experienced Senior Microsoft Consultant responsible for developing and defining architectures for various projects in a Microsoft environment, using a Service-Oriented Architecture (SOA) and web based applications.
I am also a project manager using agile methodologies and SCRUM.
Software Quality Assurance is a mandatory in every project I am responsible.
As someone said:
“Anyone can program, but not everyone is a programmer...”
Follow on   Twitter

Comments and Discussions

 
GeneralGreat Article PinprofessionalBhavik_Patel8-Aug-14 1:08 
GeneralMy vote of 1 Pinmemberlmcpferreira13-Sep-13 7:44 
GeneralMy vote of 5 PinmemberMohammad Sepahvand23-May-13 10:36 
GeneralMy vote of 5 PinmemberChristian Amado29-Aug-12 10:58 
Questionexample for download Pinmembervm_728-Aug-12 1:38 
AnswerRe: example for download PinmemberRui Inacio28-Aug-12 23:19 
QuestionToo short I'm afraid PinmentorKeith Barrow22-Jul-12 23:31 
AnswerRe: Too short I'm afraid PinmemberRui Inacio23-Jul-12 4:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140827.1 | Last Updated 29 Aug 2012
Article Copyright 2012 by Rui Inacio
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid