Home Validation in Asp.Net Core 2 Web Api
Post
Cancel

Validation in Asp.Net Core 2 Web Api

Alt text

Looking back at our two endpoints in our AccountController class I hope you remember that we didn’t do too much to insure that the client sends us correct data. In fact, as it stands right now, if a client sent us bad or missing data, our Api would just throw an application exception and we get back an ugly IIS 500 error. Not even a nice http 500 error.

We need to add some validation here and catch any bad data coming in and perhaps let the client know what they did wrong.

I will take the Validation Attribute approach here. I like this, straight forward and covers most scenarios that I have run into.

We start by adding some attributes to the two view models that we send in as arguments to our endpoints. They are the LoginViewModel and the RegisterViewModel if you remember.

First up is the..

RegisterViewModel:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class RegisterViewModel
{
  [Required]
  [EmailAddress]
  [StringLength(256, ErrorMessage = "{0} character limit of {1} exceeded.")]
  public string Email { get; set; }

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

  [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
  public string ConfirmPassword { get; set; }
}

Looking at the attributes on the Email property, we notice that our Email property will be required by the validation filter. Also, the [EmailAddress] attribute will ensure that the text going into our Email property is, in fact, a valid email string. Last here we check the length of the string coming into our property. I have kept this the same as the database and limited it to 256 characters. Now, should our property fail the Required and EmailAddress validations, the filter will return built-in error messages designating what validation was not met. These values are good enough for me.

Custom Error Message

I would like the error message on a StringLength violation to be custom however. For StringLength violations, the text returned will the custom message that I have in the ErrorMessage parameter. The first format parameter is the name of the property and the second format parameter will be the length that we designated. Our error message should look something like “Email character limit of 256 exceeded.”.

“Compare” Validation Attribute

Continuing on to our ConfirmPassword property, we notice a Compare attribute along with a ErrorMessage parameter. Here, we are saying, compare this property to another property. We have designated to compare the ConfirmPassword property to the Password property. Should this validation fail I want custom text returned instead of what may be the built-in error message for this situation. We have set the ErrorMessage parameter with our custom message and the Validation Filter will return this message when the client sends in passwords that don’t match.

LoginViewModel

1
2
3
4
5
6
7
8
9
10
public class LoginViewModel
{
  [Required]
  [EmailAddress]
  [StringLength(256, ErrorMessage = "{0} character limit of {1} exceeded.")]
  public string Email { get; set; }

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

Here again we see the Required attribute, and EmailAddress attribute, and a StringLength attribute. Nothing too new here.

Creating The Filter

Now we must create a validation filter to trigger the object validations for us. I have added a new folder called “Filter” to the project and also added a new class called “ApiValidationFilterAttribute”.

Alt text

ApiValidationFilterAttribute

1
2
3
4
5
6
7
8
9
10
11
12
public class ApiValidationFilterAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContext context)
  {
    if (!context.ModelState.IsValid)
    {
      context.Result = new BadRequestObjectResult(new BadRequestObjectResult(context.ModelState));
    }

    base.OnActionExecuting(context);
  }
}

Our new class needs to inherit from the ActionFilterAttribute and we need to override just one method here…OnActionExecuting. Here we can check the validity of our model via the attributes that we have placed on them and then return a nice http 400 BadRequest message back to the client. We even send along a nice error message letting the client know what was wrong with the request.

Putting It To Use

In order to use the validation attribute that we just created, we just need to add it, as an attribute, to our controller methods that we want to validate. This way, we don’t have to add the extra code at the top of these methods to do the model check and creating the return message, etc. This just adds noise to our code. Instead, the attribute code will do this for us!

1
2
3
4
[HttpPost]
[ApiValidationFilter]
[Route("Register")]
public async Task<IActionResult> TempRegister([FromBody] RegisterViewModel model)
1
2
3
4
5
[HttpPost]
[AllowAnonymous]
[ApiValidationFilter]
[Route("Token")]
public async Task<IActionResult> CreateToken([FromBody] LoginViewModel login)

Try It Out

Back to Postman! If I add a couple of characters to my email address in a Register call, we can see that we get a 400 error back not and not a generic 500 server error. In addition, we even get a message on what went wrong.

Alt text

Next Steps

Next up I would like to add just a couple of new http response objects and standardize the http responses that our Api returns. This way, the client will always know how our messages will be formatted for 200 respones, 400 and 401 responses, and also the dreaded 500 response.

Hope to see you then!

This post is licensed under CC BY 4.0 by the author.