Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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

/// <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);
    }
}

My LoginData using DataAnnotations:

public class LoginData
{
    [Required]
    [MaxLength(50)]
    public string Username { get; set; }

    [Required]
    public string Password { get; set; }

    [Required]
    [MaxLength(16)]
    public string IpAddress { get; set; }
}

So my ModelState is well filled automatically when the login happens and e.g. the password is empty (of course on client side there should be a validation too for it later).

What is the best way to

  • check the model state,
  • getting a readable string out of all errors and
  • return a BadRequest with this error?

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

like image 756
PassionateDeveloper Avatar asked May 23 '18 06:05

PassionateDeveloper


People also ask

Is validation handled differently in Web API than in MVC?

We can perform model validation in MVC in an easy way. In API, when sending the request by the client or user to web API, then before doing the next process, it checks the empty validation and handles the validation error using data annotation in WEB API.

How can validation errors be handled in Web API?

Handling Validation Errors Web API does not automatically return an error to the client when validation fails. It is up to the controller action to check the model state and respond appropriately. If model validation fails, this filter returns an HTTP response that contains the validation errors.


2 Answers

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.

like image 184
Hawkzey Avatar answered Oct 07 '22 20:10

Hawkzey


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

like image 22
Nkosi Avatar answered Oct 07 '22 19:10

Nkosi