How to avoid calling ModelState.IsValid on every PostBack?

泪湿孤枕 提交于 2020-01-11 11:25:12

问题


I pretty much always want to check if ModelSate.IsValid is called when I do a postback. And having to check at the start of every post back violates the DRY principle, is there a way to have it checked automatically?

Example:

[HttpPost("RegisterUser")]
[AllowAnonymous]
public async Task<IActionResult> RegisterUser([FromBody] UserRegisterViewModel vmodel)
{
    if(!ModelState.IsValid)          // This code is repeated at every postback
        return ModelInvalidAction(); // Is there a way to avoid having to write it down?

    // do other things

    return StatusCode(201);
}

回答1:


The framework provides an abstract ActionFilterAttribute that you can subclass.

You can use an action filter to automatically validate model state and return any errors if the state is invalid:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
    }
}

You can either then use it on individual actions or register it globally

Reference Asp.Net Core : Action Filters




回答2:


You can try something like this:

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.ModelState.IsValid)
        {
            filterContext.Result = new BadRequestResult();
        }
    }
}

You can request any registered service like this filterContext.HttpContext.RequestServices.GetService<ILogger>(). You can decorate by action filter your action or controller:

[HttpPost("RegisterUser")]
[AllowAnonymous]
[ValidateModel]
public async Task<IActionResult> RegisterUser([FromBody] UserRegisterViewModel vmodel)
{
    ...
}



回答3:


I've researched this and found the best answer I think. Even if I implement what's mentioned in the other answers, I'll still be repeating myself by having to put a [ValidateModel] attribute on each POST and PUT request, that's something I want to avoid, I would also like to log things if a model is invalid, other answers don't really allow for this. So here is my answer:

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class ValidateViewModelAttribute : Attribute, IFilterFactory
{
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        var logger = serviceProvider.GetService<ILogger>();

        return new InternalValidateModel(logger);
    }

    private class InternalValidateModel : IActionFilter
    {
        private ILogger _log;

        public InternalValidateModel(ILogger log)
        {
            _log = log;
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            if (IsInvalidModelState(context))
            {
                _log.Information("Invalid ModelState: {Model}", context.ModelState.ErrorMessages());
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
        }

        private bool IsInvalidModelState(ActionExecutingContext context)
        {
            var method = context.HttpContext.Request.Method;
            return (method == "POST" ||
                    method == "PUT") &&
                   !context.ModelState.IsValid;
        }
    }

    public bool IsReusable => true;
}

I don't want to repeat myself by having to add a [ValidateViewModel] on every POST and PUT. So I do the following:

        services.AddMvc(config =>
        {
            config.Filters.Add(new ValidateViewModelAttribute());
        });

Now all POST and PUT methods are validated!!



来源:https://stackoverflow.com/questions/48832195/how-to-avoid-calling-modelstate-isvalid-on-every-postback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!