Server side validation with custom DataAnnotationsModelValidatorProvider
Asked Answered
B

1

5

I have setup a custom provider to allow setting validation attributes from a data store instead of in static code. Works great with the client side validation in my .NET MVC 4 project, but I am unable to get the server side validation to work.

CustomModelValidatorProvider .cs:


    public class CustomModelValidatorProvider : DataAnnotationsModelValidatorProvider
    {
        protected override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable attributes)
        {
            // set attributes from datastore here

            return base.GetValidators(metadata, context, attributes);
        }
    }

In my Global.asax.cs I have:


    protected void Application_Start()
    {
        ModelValidatorProviders.Providers.Clear();
        ModelValidatorProviders.Providers.Add(new CustomModelValidatorProvider());
    }

And in a Web API method I have:


    var validationResultList = new List();
    bool valid = Validator.TryValidateObject(myModelObject, new ValidationContext(myModelObject, null, null), validationResultList, true);

Here, valid is always true. Even when the Jquery client side validation displays an error. On the server side my custom provider is not being used to apply the data annotations. When I set a breakpoint in GetValidators() it's called when the View is created and correctly displays the client side validators, but does not get called again when the model is bound to the controller.

Have I missed a step? Any help is greatly appreciated!

UPDATE

The custom validator works correctly when the object is posted to a Controller, but does not get fired when posted to an ApiController.

Baa answered 2/8, 2012 at 20:33 Comment(7)
sorry I posted a comment in the other question not realising this was your question! From what I know API controllers and standard controllers use separate model binders so the issue could stem from not correctly adding the validator to the correct model binder. Not currently at my PC but I will have a look into it later :)Barret
@HenryGarle Yes, I just tested this and the custom validation does work when posted to a Controller, but not the ApiController. Not sure how to register it correctly for the ApiController.Baa
Ok thats a good start, does inheriting from ModelValidatorProvider instead make any difference?Barret
Or perhaps something like this (In RegisterRoutes() global) GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(System.Web.Http.Validation.ModelValidatorProvider), new CustomModelValidatorProvider()); If any of this helps you I'll write it up as an answer if you dont mind :)Barret
@henry-garle No luck yet. I tried GlobalConfiguration.Configuration.Services.Add(typeof(System.Web.Mvc.DataAnnotationsModelValidator), new DAL.CustomModelValidatorProvider()); but get a run-time error The type CustomModelValidatorProvider must derive from DataAnnotationsModelValidator. Parameter name: service. Unfortunately I'm not finding much info when I search on this topicBaa
@HenryGarle Still haven't been able to figure this out... If you have any ideas it is greatly appreciated!Baa
Hi Dave, sorry for the incredibly slow reply I've been away. Glad you sorted it!Barret
B
3

I finally figured this out, it's a pretty simple answer. The ApiControllers only respond to the providers in the System.Web.Http.Validation namespace, not the System.Web.Mvc namespace that is used for regular Controllers and the client side validation.

I implemented both to achieve both the client side validation and server validation in the ApiControllers.

Baa answered 31/8, 2012 at 1:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.