Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Manually validate the model. #2078

Closed
phillip-haydon opened this issue Feb 25, 2015 · 5 comments
Closed

Manually validate the model. #2078

phillip-haydon opened this issue Feb 25, 2015 · 5 comments

Comments

@phillip-haydon
Copy link

Because WebAPI sets parameters to null when there's no arguments to satisfy the creation of the object, I have to create the model itself in an Action Filter.

I tried to do it in a Model Binder but implementing that is far too complicated when all I need is binding to be implemented, as is, with the exception that it doesn't return null.

As a result validation wont work because its done before Action Filters are executed.

So how can I manually do validation after the model has been fixed?

@yishaigalatzer
Copy link
Contributor

This sounds like a Web API 2.X question. This repository tracks MVC 6.
I suggest you open a question in the forums or stackoverflow.

in MVC 6 we will create an object rather than return null by default, so your issue is resolved in this framework. If you change the object in an action filter, you can always call TryValidate on it. This wasn't supported in Web API 2.x

@yishaigalatzer
Copy link
Contributor

In Web API 2 you can call Validate<T>(model) in the action body

        /// <summary>
        /// Validates the given entity and adds the validation errors to the <see cref="ApiController.ModelState"/>
        /// under the empty prefix, if any.
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity to be validated.</typeparam>
        /// <param name="entity">The entity being validated.</param>
        public void Validate<TEntity>(TEntity entity)
        {
            Validate(entity, keyPrefix: String.Empty);
        }

@phillip-haydon
Copy link
Author

@yishaigalatzer cannot, this is done at a filter.

I had to add an action filter to fix the broken design of WebAPI giving null objects, but because that happens after model binding and validation I have to do validation in a action filter myself.

I just rewrote the validation myself just lacking support for complex models, since we don't have anything complex.

Plan is to move to MVC 6 when it's released with VS 2015. Cannot run beta at work.

@yishaigalatzer
Copy link
Contributor

Here is how you can do it very simply

using System.ComponentModel.DataAnnotations;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace WebApplication5.Controllers
{
    public class ValuesController : ApiController
    {
        [SetData]
        public string Get(Foo foo)
        {
            string result = null;
            if (foo == null)
            {
                result += "Was Null\r\n";
            }

            if (ModelState.IsValid)
            {
                result += "Was Valid\r\n";
            }
            else
            {
                result += "Invalid Keys: " + string.Join(", ", ModelState.Keys);
            }

            return result;
        }
    }

    public class SetData : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var foo = new Foo();
            actionContext.ActionArguments["foo"] = foo;

            ((ApiController)(actionContext.ControllerContext.Controller)).Validate(foo);
        }
    }

    public class Foo
    {
        [Required]
        public string Name { get; set; }
    }
}

or alternatively just use the code from the Validate method on the controller in your filter like this:

    public class SetData : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var foo = new Foo();
            actionContext.ActionArguments["foo"] = foo;

            Validate(foo, actionContext);
        }

        public void Validate<TEntity>(TEntity entity, HttpActionContext actionContext)
        {
            var configuration = actionContext.ControllerContext.Configuration;

            var validator = configuration.Services.GetBodyModelValidator();
            if (validator != null)
            {
                var metadataProvider = configuration.Services.GetModelMetadataProvider();

                validator.Validate(entity, typeof(TEntity), metadataProvider, actionContext, keyPrefix: string.Empty);
            }
        }
    }

@phillip-haydon
Copy link
Author

@yishaigalatzer I have a global action to fix up the null parameters.

The validate stuff is helpful tho. Thanks a lot.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants