MODEL VALIDATION in ASP.NET Core | Getting Started With ASP.NET Core Series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone welcome back to another video in my asp.net core series if you're new here my name is rahul and i'm a microsoft azure mvp working as a software consultant in brisbane australia if you're not subscribed to this channel kindly press the subscribe button below the video to subscribe and help me grow this channel validating user input is an important part of application development in this video let's learn more about the built-in mechanisms that asp.net core provides to validate user input let's head off to the console and create a new.net web api application using the.net cli and specifying new and web api for the web api template this will create a new asp.net web api in the current folder let's open this up in an ide i will choose rider for this video you can do this in any ide of your choice i have the application opened up here this has the program.cs the startup.cs and a controller to start with let's head off into the weather forecast controller and start modifying the code in here to see model validation in action let's clean up this class to remove the code that we don't require for this video so let's remove the read-only list the constructor and the logger and also clean up the method get let's make this to return a public string instead of the i enumerable and also pass in two parameters let's start with an id and also a bool is test let's return back a string so we'll use string interpolation and we'll specify the id and the value that comes in here and also is test and the value associated with that so we now have a controller that has a get method which takes in two parameters and returns back that value as a string let's run and make sure everything is working as expected as expected it returns a message with the id and the is test since id is not passed in here in the request this is null the is test being a boolean takes in a default value which is false if we want to pass in an id let's use query parameters and specify question mark id is equal to 10 so this is going to start returning a 10 in place of the id if you want to know the actual value of the boolean and know when it is null in the request you can go back to the source code and make the boolean field nullable so let's stop this and let's make this a nullable of boolean running this again and if we refresh this now we are going to get the id 10 and its test is null it no longer shows the default value if you want to explicitly pass in a value for s test let's use the ampersand and also specify the is test is equal to true so this is starting to return the is test value as well as part of the response let's imagine we have a requirement that mandates the is test value so anytime this api is to be hit it should be executed only if a value is provided for us test so if the is test is not provided it's considered an invalid request so let's say if not is test dot hash value which means any time the s test doesn't have a value let's return a bad request in this case so we have to return a bad request and specify is test is required since we are returning a bad request we now need to modify the return type of the method so instead of just returning a string let's start returning an action result of string so we can specify action result and the type string so anytime this value is test is not provided it's going to return it as a bad request otherwise we'll get the string interpolated text as before so let's run this to make sure this is working as expected we get back the message is test is required if we inspect the network request and run this application again we can see that it's now returning a 404 which says a bad request we can also see if you were to look at the response that this is now returning and his test is required message if we specify the is test alone so let's say is test is equal to true this is now responding with the string interpreted text and also the response is a 200 okay if you now want to make sure that the id value is also provided we'll have to start adding in that so to capture all the error messages of the request let's create a new variable which is a new string list so let's create a list of strings to capture all the errors and in this case instead of returning right away we can add this message to the list so let's say errors.add and add in that is test is required we can also check for id so let's check if string dot is null or empty of id in this case let's also add id is required so now we have both the errors now that we have the error list populated let's check the errors.length and return back a bad request if its count is greater than zero so let's do that and say return bad request and return back the error list if not it's going to return the string interpolated text as before let's run this application to see this in action let's make a request again so we get back the 400 as before and we also see both the error messages is test is required and id is required so if we were to pass one of these values let's say id is equal to 10 we just get back is test is required to make this to work let's also pass this test to be true so now we have the string interpolated message returned as before instead of creating your own errors list and managing your errors as part of that you can use the model state property that's available as part of your controller so let's see how we can do that so let's remove the error list instead of errors dot add we can use model state dot add model error and specify the name of the field in this case it's is test so let's use name of s test and specify the error message similarly we can also modify this to make this model state dot add model error and specify the name of id and the error message that is associated instead of checking the errors.com let's check if this is not valid so we can specify not model state of valid so in this case whenever the model state is invalid it's going to return a bad request instead of errors let's return the model state itself let's run this and see this in action let's refresh this and see the request we still get a 400 so if we were to examine the request we have a json object which represents the errors for each of those properties so here it says id is required and also is test is required let's make the request with the valid parameters so let's say id is equal to 10 and this test is equal to true this now returns a 200 and also the string interpolated text as before if you ask me this is still a lot of verbose code to just check whether a value exists or not so let's clean this up to make it better so let's remove all this which is checking for the values that's required and also explicitly sending the model state as valid so let's remove that and go and specify that these fields are required so right next to the string where we are specifying the parameter let's open up the brackets to specify an attribute and say this is required so this is coming from the system.component model dot data annotations namespace let's also specify required for the is test parameter we can return this back to be a string but let's keep this as action result of string let's run it and see how this works now let's clear the network request and refresh the application in this case we get a 200 because we are passing back the id and the s test let's make a request with just the id and now we get back a 400 response as before so if you were to expand that this now returns a json object with an errors property that contains the same error object that we saw before if we were to make a request without the id and the s test it's now going to return errors for id and the s-test value by adding the required attributes we have considerably reduced the amount of code that we need to write to make sure that our id and s-test is always passed in as part of the request if you have nullable reference types turned on you can then avoid adding the required attributes for those kind of types so let's say for this example let's remove both the required attributes which makes them as optional and this is still going to return null let's go back and turn on the nullable reference types to do that we can specify hash nullable on a file and say enabled alternatively you can also enable this in the cs project file so if we go to the cs project file we can add in a property which is called nullable and make that as enabled as well this will enable nullable reference type across your project and in the other case it's specific to that particular file let's save this go back to the file and remove it from here and then run this to see how this is working now let's make a request and we will get back a 400 on the weather forecast in the errors we see that the id is required is getting returned back however note the is test value is not validated in this case this is because a boolean is not a reference type only a string is note in this case we did not add any required attribute for the string but still it is returning that asp.net core is automatically applying a required attribute for non-nullable reference types if you don't like this behavior you can suppress this in the startup class go to the startup.cs class we can suppress this when we are adding the controllers in the configure services method so let's say options and specify options dot suppress implicit required attribute for non-nullable reference types so that's going to suppress the implicitly adding of required attributes to non-nullable reference types as the name suggests let's set that to be true let's run this again to see how this is working now let's refresh this request which doesn't have an id or a test and we now get back the string interpolated text as before so now we don't have the automatic required getting added to the non-nullable type id let's go back to the startup class and remove this extra code that we have written the errors that we have seen till now are all model validation errors however there can be errors at the model binding step itself let's say the is test which is to be a boolean here is not a boolean value from the request check out my earlier video to learn more about model binding and how it works in asp.net core let's run this application again to see how model binding errors affects the responses by default this just has the id is required error being returned let's add in the is test parameter in this case so let's specify is test and specify an invalid value for the boolean let's say hello this now returns an additional error message for the is test field as well it says the value hello is not valid this is an error that's returned from the model binding system when it tries to convert hello into a boolean it finds an exception and adds that to the model state as well so model state represents errors from two subsystems the model binding and the model validation errors that generate in the model byting are generally data conversion errors so what is causing these requests to return back an error response we did not explicitly handle this and return a bad request in any of our controller code here the api controller attribute is automatically doing this for us so any controller that's decorated with this attribute are configured with features and behaviors targeted at improving the developer experience for building apis so automatically returning the error types is one of them so if we were to remove the api controller attribute and run this application this is not going to return an error any longer even though we didn't specify the id attribute this is still returning back the id is test even if we were to pass and his test is equal to hello this is still going to return back the response as expected however note the model binding is still not applicable and the value is still a null if we now want to return the error we'll need to explicitly handle this in the controller method so similar to what we did initially when we added the multiple arrays so we can explicitly say if not model state dot is valid then return a bad request like before and specify the model state itself if you were to run this again we now start getting the error responses as before so if we pass the is test with an invalid value hello it's also going to respond with that error message so note the api controller attribute is what was automatically enabling these error responses let's remove this additional code and add back in the api controller attribute to the class we can also override the api controller behavior to not return the error automatically to do that let's go back to the startup.cs under the configure services method let's configure the api behavior options so using services and the configure method we can specify in api behavior options take in the options and suppress the model state invalid filter so set this to true so this is going to stop the api controller attribute from automatically returning model errors so let's run this to see this in action so there's no model validation happening right now even though we have the api controller on the controller class so this is because we suppressed it using the api behavior options so let's go back and comment this out so that it doesn't happen in further request let's see more validation attributes that's available as part of the data annotations library let's go to the solution explorer and add in a new class so let's call this my data i already have a class written out so let me copy paste that in here this class has a few properties and also a few annotations already applied so we have name age email and phone you can see i have the required attribute on the name and also on the age and also a range which specifies that the age must be greater than 18 for the email i use email address attribute and for the phone i use the phone attribute all of these are coming from the system.componentmodel.data annotations namespace to make use of this new mydata class let's add a post method onto the controller i have this already written out we have a post method which takes in the my data class that we just wrote it looks in the body for this particular object it returns back the name age email and phone from this object let's run this to see this in action since this is a post request i cannot make this from the web browser so let me open up a tool called postman this is available for free download and the link is there in the description below i have a request already written out for the model validation so i have a post request going to the weather forecast endpoint it specifies a body and specifies the name age and email which is very similar to the properties that we have in the my data class since phone and email is optional i have only provided the value for email so let's go back to postman this is a post request and it also sends in a json request so let's make the request and this returns back the name age and email as expected phone is empty because we didn't pass one we had a restriction on the age attribute that it should be greater than 18 so let's make this 3 and try sending this again this now returns the field age must be between 18 and the maximum value that we provided for it we also have email validations so if we were to make this an invalid email by adding in one more dot or by removing the ad and make a request it's also going to return that the email field is not a valid email address the data annotations that we added for the properties in my data is automatically applying these validations for us so these are the built-in attributes that's available as part of asp.net core you can see a list in the documentation that's linked in the description below there's also a lot more that you can find in the data annotations namespace the whole list is available there if you have scenarios that the built-in attributes does not handle you can also write a custom attribute for yourself to create a new custom attribute let's go back to the source code and add in a new class let's name this custom name attribute to use this as a data annotation attribute you need to inherit this from the class validation attribute so let's do that so let's say we want to add a validation for a name that starts with a particular letter so we can take in the letter as part of this attribute so let's create a constructor and specify a name string starts with let's save this as part of this class variable to perform the validation we need to override a method from the validation attribute class so let's specify overwrite and choose the is valid method to override so let's choose that which gives us the value and the validation context in this case since we just want to check the value we can use that so let's first check if the value is string and use that as a variable value string and if the value string does not start with so let's specify a not and say starts with so we have the starts with property saved as part of our class so if this does not start with that let's return back a validation result so let's say return new validation result and specify the error message if you want the name of the property that this is applicable to we can specify validation context dot the member name and we can say this member name does not start with this particular value that we expect if not we can return a validationresult.success so basically here we are looking whether the value string is a string and then checking if it starts with this value that we want to and if it does not we return back a validation result with the appropriate error message to use this let's go back to the my data class and add this to the name property so let's say the custom name and specify the starts with as r so if the name does not start with r it's going to return an error message so let's run this to see this in action the application is running so let's go back to postman and make a valid request so let's specify 30 and also make the email as valid this is returning as expected because the name starts with r let's remove the starting r and make a request again this is now returning the error message that we wrote from the custom attribute it says the name does not start with r this custom attribute that we wrote is generic enough that it can be applied to any property but let's say you have a validation that's very specific to the my data class maybe in this case since both email and phone is nullable we want to ensure that at least one of them is provided to do that instead of writing custom attributes we can also implement an interface on this model class so we need to say a validatable object and implement this interface so let's implement the missing members which basically returns an i enumerable of validation result from the validate method so in here let's check if the string is null or empty on the phone and the string is not or empty on the email in this case we want to return a validation message since we need to return back an enumerable let's use the yield to return a new validation result we can specify the message either phone or email must be specified we can also pass in the properties that this message associated with passing in a new array of strings so in this case this is going to be the phone and also the name of the email so this is going to return back the phone and the email properties as being invalid let's run this to see this in action the application is running so let's go back to postman and make a request here let's make sure the name starts with r and send in a request this returns as expected but if you were to remove the email from the request body and make a request it's now returning an error message which specifies either phone or email must be specified note since we passed both the properties it's a getting applied for both email and phone based on your application needs you can choose how to validate and what properties to return this against if you were to pass just the phone as well so let's say if we pass in a valid phone number it's still going to return back a response because only a phone or an email is mandatory fluent validation is a library that's available for building strongly typed validation rules this library also works well with asp.net core so you can use a new get package fluentvalidation.asp.net core and configure it as shown in this link here i'll put this in the description below once you have registered you can create validators that's different from your model classes so you don't have to implement any interface if you don't like that so you can specify the class like this in here a person and also specify a person validator which has the rules that's applicable for that particular class by convention these values are getting automatically added into services and checked as part of the request you can check out the documentation here to learn more about that i hope this helps you to understand more about model validation in asp.net code we saw how to use model state how to specify data annotation attributes the built-in attributes that's available and also how to write custom validations on the objects that you create if you like this video please make sure to hit the like button and if you want to be notified of future such videos please make sure to subscribe thank you and see you soon
Info
Channel: Rahul Nath
Views: 7,991
Rating: undefined out of 5
Keywords: asp.net core model validation attributes, asp.net core model binding validation, model validation in asp.net core, asp.net core email validation, asp.net core required validation, asp.net core validation regular expression, asp.net core custom validation attribute, custom validation attribute in asp net core, modelstate in asp.net mvc, dataannotations .net core, dataannotations in mvc, model validation in asp.net web api, model validation in asp.net core web api
Id: 1QHq_sqzQCo
Channel Id: undefined
Length: 22min 16sec (1336 seconds)
Published: Wed Sep 09 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.