MVC Model Validation–Refactor (Part Deux)

by rhernandez 9. November 2010 10:36

This post enhances the functionality of the code in the Blog titled “MVC2 Validation and Testing” at the following link. 
http://blog.overridethis.com/blog/post/2010/04/22/MVC2-Model-Validation-and-Testing-Scenarios.aspx

 

A comment was made on one of my previous blogs requesting additional functionality for the extension method I wrote in April for testing controller action’s that rely on MVC2 Model Validation.  The request was simple, to be able to test class level validation attributes such as the ones found on the ChangePasswordModel in the default MVC2 project template.   Well, as requested!

 

public static class ControllerExtensions {

    public static ActionResult CallWithModelValidation<TController, TResult, TModel>(
            this TController controller, 
            Func<TController, TResult> action, 
            TModel model)
        where TController : Controller
        where TResult : ActionResult
        where TModel : class {

        var provider = new DataAnnotationsModelValidatorProvider();

        var metadata = new List<ModelMetadata>();
        metadata.Add(GetMetadataForClass(model));
        metadata.AddRange(GetMetadataForProperties(model));

        foreach (ModelMetadata modelMetadata in metadata) {
            ApplyValidatorsFromMetadata(model, provider, modelMetadata, controller);
        }        
        
        return action(controller);
    }

    private static ModelMetadata GetMetadataForClass<TModel>(TModel model) 
        where TModel : class {

        return ModelMetadataProviders
            .Current
            .GetMetadataForType(() => model, typeof (TModel));
    }

    private static IEnumerable<ModelMetadata> GetMetadataForProperties<TModel>(TModel model)
       where TModel : class {
        return ModelMetadataProviders
            .Current
            .GetMetadataForProperties(model, typeof(TModel));
    }

    private static void ApplyValidatorsFromMetadata<TModel, TController>(TModel model, 
        DataAnnotationsModelValidatorProvider provider, 
        ModelMetadata modelMetadata, 
        TController controller)
            where TController : Controller
            where TModel : class {
        
        IEnumerable<ModelValidator> validators = provider
            .GetValidators(modelMetadata, new ControllerContext());
            
        foreach (ModelValidator validator in validators) {
            IEnumerable<ModelValidationResult> results = validator.Validate(model);
            foreach (ModelValidationResult result in results)
                controller.ModelState.AddModelError(
                    modelMetadata.PropertyName ?? "Model", 
                    result.Message);
        }
    }
}

Comments

11/9/2010 3:38:36 PM #

alan

awesome!

i'm a relative newbie to C# so this helps greatly.

now i can get on w/ the business of my application with tests in hand.

thanks!

alan United States

Comments are closed

The Author



Roberto Hernández

 

Currently a Managing Consultant for Excella in Arlington, VA. I have been architecting and building software solutions using Microsoft technology for the past 14 years. I was awarded as a Microsoft MVP in C# in 2007,2008 and 2010. I am originally from the Dominican Republic, and the proud father of two beautiful daughters that make my life special. You can track me down on twitter (@hernandezrobert) and on this blog http://overridethis.com.


 

Stack Overflow profile for Roberto Hernandez at Stack Overflow, Q&A for professional and enthusiast programmers

INETA Community Speakers Program

Recent Posts