How to do model validation in every method in ASP.NET Core Web API?

后端 未结 3 1359
孤城傲影
孤城傲影 2021-02-05 13:24

I am getting into ASP.NET Core 2.0 with Web API. One of my first methods are my login:

/// 
/// API endpoint to login a user
/// 
/         


        
相关标签:
3条回答
  • 2021-02-05 13:53

    I would Highly recommend using [ApiController] and other attributes that help ease validation in web API based projects.

    [ApiController] this attribute does all basic validation on the modal for you before it enters the method. So you only have to inspect the modal if your want to do some form of custom validation.

    0 讨论(0)
  • 2021-02-05 14:02

    To check if the model state is valid use the ModelState property (exposed by the ControllerBase class which the Controller class inherits from)

    ModelState.IsValid
    

    To get the errors from the ModelState you could filter out the errors from the dictionary and return them as a list

    var errors = ModelState
        .Where(a => a.Value.Errors.Count > 0)
        .SelectMany(x => x.Value.Errors)
        .ToList();
    

    One option is then to validate the state in every method/controller but i recommend you to implement the validation in a base class which validates the model in the
    OnActionExecuting method like this

    public class ApiController : Controller
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!ModelState.IsValid)
            {
                var errors = ModelState
                    .Where(a => a.Value.Errors.Count > 0)
                    .SelectMany(x => x.Value.Errors)
                    .ToList();
                context.Result = new BadRequestObjectResult(errors);
            }
            base.OnActionExecuting(context);
        }
    }
    

    Then every controller which should have automatic model state validation just inherit from the base class

    public class TokenController : ApiController
    {
        /// <summary>
        /// API endpoint to login a user
        /// </summary>
        /// <param name="data">The login data</param>
        /// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
        [AllowAnonymous]
        [Route("login")]
        [HttpPost]
        public IActionResult Login([FromBody]LoginData data)
        {
            var token = _manager.ValidateCredentialsAndGenerateToken(data);
            if (token == null)
            {
                return Unauthorized();
            }
            else
            {
                return Ok(token);
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-05 14:16

    How to check the model state?

    Check the controller's ModelState in the action to get the state of the model.

    getting a readable string out of all errors and return a BadRequest with this error?

    Use BadRequest(ModelState) to return HTTP bad request response which will inspect the model state and construct message using errors.

    Completed code

    /// <summary>
    /// API endpoint to login a user
    /// </summary>
    /// <param name="data">The login data</param>
    /// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
    [AllowAnonymous]
    [Route("login")]
    [HttpPost]
    public IActionResult Login([FromBody]LoginData data) {
        if(ModelState.IsValid) {
            var token = _manager.ValidateCredentialsAndGenerateToken(data);
            if (token == null) {
                return Unauthorized();
            } else {
                return Ok(token);
            }
        }
        return BadRequest(ModelState);
    }
    

    Of course I could write it all myself in a helper method... But I thought about a filter maybe?

    To avoid the repeated ModelState.IsValid code in every action where model validation is required you can create a filter to check the model state and short-circuit the request.

    For example

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

    Can be applied to the action directly

    [ValidateModel] //<-- validation
    [AllowAnonymous]
    [Route("login")]
    [HttpPost]
    public IActionResult Login([FromBody]LoginData data) {
        var token = _manager.ValidateCredentialsAndGenerateToken(data);
        if (token == null) {
            return Unauthorized();
        } else {
            return Ok(token);
        }    
    }
    

    or added globally to be applied to all request where model state should be checked.

    Reference Model validation in ASP.NET Core MVC

    0 讨论(0)
提交回复
热议问题