Page 21 - MSDN Magazine, March 2019
P. 21
The shared logic that validates business rules will be demonstrated on a new registration form. Figure 2 shows a simple form with fields for First Name, Last Name, Email and Phone. In this sample, it will validate that all the fields are required, that the name fields have a maximum length, and that the e-mail and phone number fields are in the correct format. It will display an error message under each field, and those messages will update as the user types. Last, the Register button will only be enabled if there are no errors.
Shared Library
All of the code that needs to be shared between the server and Blazor client will be placed in a separate shared library project. The shared library will contain the model class and a very simple validation engine. The model class will hold the data fields on the registration form. It looks like this:
public class RegistrationData : ModelBase {
if there are validation errors for a specific field and to retrieve the error messages quickly. Here’s the code:
private Dictionary<String, Dictionary<String, String>> _errors = new Dictionary<string, Dictionary<string, string>>();
Now I’ll add the AddError method for entering errors into the internal errors dictionary. AddError has parameters for fieldName, ruleName and errorText. It searches the internal errors dictionary and removes entries if they already exist, then adds the new error entry, as shown in this code:
private void AddError(String fieldName, String ruleName, String errorText) {
if (!_errors.ContainsKey(fieldName)) { _errors.Add(fieldName, new Dictionary<string, string>()); }
if (_errors[fieldName].ContainsKey(ruleName)) { _errors[fieldName].Remove(ruleName); }
_errors[fieldName].Add(ruleName, errorText);
OnModelChanged(); }
Finally, I’ll add the RemoveError method, which accepts the field- Name and ruleName parameters and searches the internal errors dictionary for a matching error and removes it. Here’s the code:
private void RemoveError(String fieldName, String ruleName) {
if (!_errors.ContainsKey(fieldName)) { _errors.Add(fieldName, new Dictionary<string, string>()); }
if (_errors[fieldName].ContainsKey(ruleName)) { _errors[fieldName].Remove(ruleName);
OnModelChanged(); }
}
The next step is to add the CheckRules functions that does the work of finding the validation rules attached to the model and executing them. There are two different CheckRules functions: One that lacks a parameter and checks all rules on all fields, and a second that has a fieldName parameter and only validates a specific field. This second function is used when a field is updated, and the rules for that field are validated immediately.
The CheckRules function uses reflection to find the list of attri- butes attached to a field. Then, it tests each attribute to see if it’s a type of IModelRule. When an IModelRule is found, it calls the Validate method and returns the result, as shown in Figure 3.
Next, I add the Errors function. This function takes a field name as a parameter and returns a string that contains the list of errors
[RequiredRule]
[MaxLengthRule(50)]
public String FirstName { get; set; }
[RequiredRule]
[MaxLengthRule(50)]
public String LastName { get; set; }
[EmailRule]
public String Email { get; set; }
[PhoneRule]
public String Phone { get; set; }
The RegistrationData class inherits from a ModelBase class, which contains all of the logic that can be used to validate the rules and return error messages that are bound to the Blazor page. Each field is decorated with attributes that map to validation rules. I chose to create a very simple model that feels a lot like the Entity Framework (EF) Data Annotations model. All of the logic for this model is contained in the shared library.
The ModelBase class contains methods that can be used by the Blazor client application or the server application to deter- mine if there are any validation errors. It will also fire an event when the model is changed, so the client can update the UI. Any model class can inherit from it
and get all of the validation engine
logic automatically.
}
I’ll start by first creating a new ModelBase class inside of the SharedLibrary project, like so:
public class ModelBase {
}
Errors and Rules
Now I’ll add a private dictionary to the ModelBase class that con- tains a list of validation errors. The _errors dictionary is keyed by the field name and then by the rule name. The value is the actual error message to be displayed. This setup makes it easy to determine msdnmagazine.com
Figure 2 Registration Form
March 2019 15