Using ModelState for Validation with Vue.js in ASP.Net Core
Controllers in ASP.Net Core can keep track of the validation state of your models/view models through their ModelState property. While it’s very easy to do client-side validation in Vue js, server-side validation is a much stronger way to prevent data errors, and the built in ModelState capabilities provide this. Through a few steps and the right components, we can make this happen in a concise, repeatable way.
Step 1: ModelState Helper
Under the hood, the controller’s ModelState property is nothing more than a dictionary of attribute names and validation error messages. We can convert this to a JSON format that we can pass back to our Vue components. We could use a static helper extension function that looks like this:
Step 2: The Components
While you could certainly build your own Vue components to react to ModelState, Vuetify (https://vuetifyjs.com/) provides some excellent material design themed Vue components that are already set up to handle error messages in a way that jives perfectly with our ModelState output. Vuetify has excellent documentation for utilizing their components, and we’ll assume from this point forward we are working with them.
Step 3: Putting it all together
Now we are ready to make our Vue components react to ModelState. For this example, we’ll work with a login form and validate that you’ve entered the required username and password to log in.
The Vue code for our login page using Vuetify components looks like this:
Which results in a simple login form that looks like this:
Notice that one of the page’s data elements is an empty object called “modelstate”. This is what we will set our ModelState JSON into if the ModelState in our controller is invalid. When we POST our login form data, if we catch a 400 (Bad Request) coming back, we set the modelstate element. We bind the :error-messages attributes of our Vuetify v-text-field components to the element in our ModelState JSON that would have that error (named the same as the property in the view model we are using). If this property is set in the ModelState object, the error message for that field will show.
Next we have our LoginVewModel with attributes ensuring Email and Password are required:
Note that we could do additional validation in this view model – for example an attribute with a regex validating that the email entered is in the correct format.
Finally, we have the login controller action:
First thing we do in the controller is check the validity of the model state – if it isn’t valid, we utilize our ModelState helper to get the errors from the ModelState in a JSON structure and return a 400 (Bad Request) to the Vue page with the error data. It’ll then be set to the modelstate data element on the page which is bound to the error-messages attributes of our Vuetify components.
With all of that in place… if the login form is submitted without entering the email and password, we now see this:
We get the exact error messages provided by the ModelState showing when we don’t satisfy our view model’s requirements
Bonus: Generic/Non-field specific Errors
You can also use ModelState to specify an error that is not associated with one of your fields. Using our login example, maybe there is some error in the controller and we want to show a message about it to the user. We can specify our own ModelState error in this case and use another component to show it. We might add this to the top of our login vue:
Here we bind an alert box to a property of modelstate just called “Error”.
Then we could modify our controller to look like this:
We just assign the “Error” property of ModelState with our custom error message, and then if we log in and that case hits, we see this:
David Glick’s ModelState with Vue blog for some initial inspiration on this approach: https://daveaglick.com/posts/using-aspnet-modelstate-with-vuejs
Vuetify Components for being awesome: https://vuetifyjs.com/