Bug Fix: ASP.Net Core with Entity Framework Data Annotation Validators
Today we fixed a problem that was causing users to create broken posts in the Rants and Raves category on this site. The problem was that we failed to add a line of code needed for validation to function properly. Without that line of code users were able to submit the form without selecting a required value. The bug was easy to identify and fix in a matter of minutes once we tested the form ourselves and noticed that we were not being given an error when we failed to select a value for Sentiment. We simply looked at the annotation we already had for the corresponding field in our Entity Framework model and compared it to other fields in other models that were also bound to select lists for other categories. When we did that we noticed that the Sentiment field in the Rants and Raves model was missing a required line of code. This led to two problem.
The first problem was that we had failed to add a range annotation that required the integer value submitted to be greater than 1. This is the value that ASP.Net Core uses to generate the code needed for the jQuery Unobtrusive Validation Plugin to know that the value submitted for that field must be greater than 1. Without that no error will be given to the user if the value they submit is 0. That was the case when users submitted the form without selecting a value for Sentiment because in addition to values from the Sentiment table the select list used to allow the user to select a value has a default option that does not correspond to anything in the database. It has a value of 0 and displays text which says "Select Sentiment." Since the default selected option technically had a numeric value of 0 it would pass the required field validation check because that simply checks to see if the value is null.
The second problem was that our database does not permit records to be created if they violate SQL Server referential integrity rules. Those rules are fairly simple in that they require a match between the value in the Rants and Raves table if it has a relationship with a value in a different table. This is called a primary and foreign key relationship. The primary key is typically the row id number in one table and the foreign key is typically a value in a second table related to that row id. In this case the primary key in the Sentiment table can be an integer of 1 or 2 because there are two rows in that table (1 for negative and 2 for positive). If someone tries to insert an integer in the Rants and Raves table column that has a relationship with the Sentiment table it must be 1 or 2 because a different number will not match any row id number in the Sentiment table. That is the case when the record submitted to the database has an integer value of 0 for Sentiment. SQL Server will not allow a record to be created in the Rants and Raves table that has a value of 0 for sentiment because it violates the referential integrity constraint. When that happens a records is created in the Posts table but not the Rants and Raves table. Since every entry in the Posts table must also have a corresponding entry in one of the category tables in order to render a valid result on a page the end results were pages displaying nothing but error messages.
Adding a range validation annotation is the best way to solve this problem. It prevents the form from submitting without a value of 1 or greater in the Sentiment field of the Rants and Raves table. Some might wonder why we would permit a record to be added to the Posts table but not the Rants and Raves table. The reason is that there is value in the Rants and Raves table that requires the Post ID number from the new row in the Posts table. A row must first be created in the Posts table before it can be added to the Rants and Raves table. That is necessary so that the database knows which record from the Rants and Raves table to retrieve for each specific entry in the Posts table.