Adding Validation6:10 with James Churchill
Web API gives us a way to check if our model state is in a valid state, and if it's not in a valid state, we can return an appropriate error response to the client, letting them know how to correct the problem.
To follow along committing your changes to this course, you'll need to fork the aspnet-fitness-frog-spa repo. Then you can clone, commit, and push your changes to your fork like this:
git clone <your-fork> cd aspnet-fitness-frog-spa git checkout tags/v3.6 -b adding-validation
The Fitness Frog client app already includes some validation. 0:00 For example, it won't allow the user to submit the add entry form 0:04 until they've supplied all the required values. 0:07 Notice that the Save button is disabled and can't be clicked. 0:10 If we supply all the required values, The client app will enable the Save button. 0:15 Having client-side validation doesn't mean that we can 0:24 skip implementing server-side validation. 0:27 In fact, if you had to choose between implementing client-side and service-side 0:30 validations, it's always best to implement your validations on the server. 0:34 Client-side validations are just too easy for users to circumvent. 0:39 Currently, the post method just accepts an entry object and 0:56 adds it to the database by calling the entries repositories add method. 0:59 We're just assuming that the provided entry object is in a valid state. 1:05 Meaning, that each of its properties that should have a value has a value. 1:09 And that all property values meet our expectation as to what valid 1:13 values should be. 1:18 Luckily, we don't have to assume anything. 1:20 Web API gives us a way to check if our model state is in a valid state. 1:23 And if it's not in a valid state, we can return an appropriate 1:27 error response to the client, letting them know how to correct a problem. 1:31 If you've worked with the ASP.NET MVC Framework before, 1:35 you'll feel right at home with how Web API implements model validation. 1:38 The API controller-based class provides a model state property that we can 1:43 use to check if the model state is in a valid state or not. 1:47 Here at the top of our action method, let's add an if statement. 1:53 If not |ModelState.IsValid. 1:56 And if the model state is in an invalid state, we can call the bad request method, 2:05 which will return a response with a 400 bad request HTTP status code. 2:10 The bad request method also provides an overload that allows us to pass in 2:16 the model state property. 2:20 Doing this will cause the error messages in the model state dictionary object to be 2:25 serialized to the response message body. 2:29 That will give the client the information that they'll need to correct any 2:32 issues with the data, before they try sending in another request. 2:35 Set a breakpoint just inside of the Post method, and press F5 to start debugging, 2:40 so we can test our method using Post method. 2:44 Let's start with posting an object with no values to the entry's endpoint. 2:56 I already have a post request here in my history, so 3:01 I'll click on it to load up the request. 3:03 Let's remove the exclude in notes properties as they're not required. 3:10 Then, let's set date, activityId, 3:15 duration and intensity to null. 3:20 Then click the Send button. 3:29 Here we are at our breakpoint. 3:33 Let's press F10 to step through our code. 3:35 If we hover over the ModelState.IsValid property, we can see that it was false. 3:40 So our if statement evaluated to true. 3:44 That means that we're going to return a call to the bad request method, 3:47 passing in our model state. 3:51 Press F5 to continue execution. 3:54 Scroll down to see the response body. 3:58 So the request wasn't successful. 4:02 We can see that we received back a 400 bad request HTTP status code. 4:05 But the error messages that we received, telling us that the provided values 4:10 couldn't be converted to the expected types, aren't very user friendly. 4:15 Now, let's try sending an empty object. 4:20 Just remove all of the properties and send a set of curly braces. 4:26 Click the Send button. 4:32 Here we are at our breakpoint again, just inside of the post action method. 4:35 Press F10 to step through our code, and look at that. 4:39 The ModelState.IsValid property is true. 4:44 How is that possible when we didn't supply any values? 4:48 Hover over the Entry parameter and expand it so 4:52 that you can see the Entry object's property values. 4:54 All of our required properties are defined in the Entry class as non-nullable types. 4:58 During a parameter binding process, non-nullable 5:03 types will be set to their default values if there isn't a value to bind to. 5:06 For example the date property, which is of type daytime will 5:10 be set to the static value daytime.meanvalue. 5:14 ActivityId which is of type int will be set to 0. 5:18 Duration which is of type decimal, will also be set 0. 5:22 And intensity, which is of type intensity level. 5:27 An enumeration defined in entry class will also be set to 0. 5:30 If we continue execution, we'll encounter an exception. 5:35 This is happening because the date properties daytime minimum value can't be 5:43 persisted to the database's daytime data column type. 5:47 Not providing all of an objects available properties is called under-posting. 5:54 As you can from this example, 5:59 Web API by default, doesn't prevent a client from under-posting. 6:01 We need a strategy for preventing under-posting for breaking our validation. 6:06
You need to sign up for Treehouse in order to download course files.Sign up