Asp.net full stack development tutorial: using server verification method in MVC

Time:2019-10-30

Preface

In the previous chapter, we basically learned how fluent validation is simple and elegant in the console. Today, we will apply it in the actual project.

First, we create an asp.net MVC project. My environment is vs2017.

After the creation is successful, install fluent validation by using install package Fluent validation – version 7.6.104 in nuget.

Add two entities address and person in the model folder


public class Address
 {
 public string Home { get; set; }

 public string Phone { get; set; }
 }
public class Person
 {
 /// <summary>
 // / name
 /// </summary>
 public string Name { get; set; }
 /// <summary>
 // / age
 /// </summary>
 public int Age { get; set; }
 /// <summary>
 // / sex
 /// </summary>
 public bool Sex { get; set; }

 /// <summary>
 // / address
 /// </summary>
 public Address Address { get; set; }
 }

The validator that creates the entity next

public class AddressValidator : AbstractValidator<Address>
 {
 public AddressValidator()
 {
 this.RuleFor(m => m.Home)
 .NotEmpty()
 . withmessage ("home address cannot be empty");

 this.RuleFor(m => m.Phone)
 .NotEmpty()
 . withmessage ("mobile number cannot be empty");
 }
 }
public class PersonValidator : AbstractValidator<Person>
 {
 public PersonValidator()
 {
 this.RuleFor(p => p.Name)
 .NotEmpty()
 . withmessage ("name cannot be empty");

 this.RuleFor(p => p.Age)
 .NotEmpty()
 . withmessage ("age cannot be empty");

 this.RuleFor(p => p.Address)
 .SetValidator(new AddressValidator());

 }
 }

To better manage validators, I recommend that you use a manager to manage all instances of validators. Such as validatorhub


public class ValidatorHub
 {
 public AddressValidator AddressValidator { get; set; } = new AddressValidator();

 public PersonValidator PersonValidator { get; set; } = new PersonValidator();
 }

Now we need to create a page and add two action: validator tests under the default homecontroller controller. One of them is used to show the page and the other is used to submit.


[HttpGet]
 public ActionResult ValidatorTest()
 {
 return View();
 }

 [HttpPost]
 public ActionResult ValidatorTest(Person model)
 {
 return View();
 }

Add view for validator test, select create template, entity is person

Delete all the default @ HTML, because we don’t need it in this introduction. Our goal is to build a front-end and back-end separated project instead of relying on MVC too much.

Finally, we changed the form to

@using (Html.BeginForm())
{
 @Html.AntiForgeryToken()

 <div>
 <h4>Person</h4>
 <hr />
 @Html.ValidationSummary(true, "", new { @class = "text-danger" })
 <div>
 < label for = "name" > name < / label >
 <div>
 <input type="text" name="Name" />
 </div>
 </div>

 <div>
 < label for = "age" > age < / label >
 <div>
 <input type="text" name="Age" />
 </div>
 </div>

 <div>
 < label for = "home" > address < / label >
 <div>
 <input type="text" name="Address.Home" />
 </div>
 </div>

 <div>
 < label for = "phone" > phone < / label >
 <div>
 <input type="text" name="Address.Phone" />
 </div>
 </div>

 <div>
 < label for = "sex" > gender < / label >
 <div>
 <div>
 <input type="checkbox" name="Sex" />
 </div>
 </div>
 </div>

 <div>
 <div>
 <input type="submit" value="Create" />
 </div>
 </div>
 </div>
}

Be carefulBecause there is a complex type address in our entity person, we all know that the form submission is in the form of key: value by default, but in the traditional form key: value, we can’t make the value a complex object when the key is address, because input can only carry one value at a time, and it must be a string. In fact, there is model binding in MVC, which is not covered here (because I also forgot – | – |).

In short, it can help us automatically convert as much as possible according to the type you need. At present, as long as we know how to use it correctly, there are home property and phone property in address. We can set the name of the form to address.home, and MVC model binding will resolve address.home to the home property on the object address.

I can’t tell you more about the simple verification method. In the previous chapter, we have learned to create an entity verifier to verify the entity, and then judge whether the verification is successful through isvalid property. Yes, that’s right. It’s too easy for everyone. But does it seem a bit cumbersome for us to create a verifier every time we check? Don’t forget that we just created a validatorhub. We know that the controller inherits from the controller by default. What if we want to extend some capabilities for the controller? Now I’m going to create a controllerex and inherit it from the controller.


public class ControllerEx : Controller
 {
 protected Dictionary<string, string> DicError { get; set; } = new Dictionary<string, string>();

 protected ValidatorHub ValidatorHub { get; set; } = new ValidatorHub();

 protected override void OnActionExecuted(ActionExecutedContext filterContext)
 {
 base.OnActionExecuted(filterContext);
 ViewData["Error"] = DicError;
 }

 protected void ValidatorErrorHandler(ValidationResult result)
 {
 foreach (var failure in result.Errors)
 {
 if (!this.DicError.ContainsKey(failure.PropertyName))
 {
  this.DicError.Add(failure.PropertyName, failure.ErrorMessage);
 }
 }
 }
 }

In controllerex, I created a validatorhub attribute, just like its name, which contains various validator entities. With it, we can use this. Validatorhub. Concrete verifier in the action that needs to be verified to complete the concrete verification work, instead of going to the new verifier every time.

I also defined a key value pair set of dicerror, whose key and value type are string. Key is the attribute name of the validation failure, and value is the error message after the validation failure. It is used to exist the validation results.

Here I also define a validator errorhandler method. One of its parameters is the validation result. We have roughly guessed the function through the name. The processing of validation error, traversing the error information of the validation result, and adding the error information to the dicerror collection.

In the end, I need to pass this dicerror to view. The simple way is to view data [“error”], but I don’t want to do this on every page, because it makes me write this line of code repeatedly, and I will be tired of it. What’s great is that MVC framework provides us with filter (also known as function hook, aspect programming and filter in some places), which is convenient for us to control in different stages of life cycle. Obviously, my requirement is to add a sentence of viewdata [“error”] = dicerror at the end of each action. So I rewrite the onactionexecuted method, adding only viewdata [“error”] = dicerror;

Now I just need to inherit the homecontroller from controllerex to enjoy all the above functions.

Now the basic work has been basically completed, but we still ignore a problem. My error is that I passed it to view in viewdata [“error”], but do we display an error list on the page when verifying the error? Like Li? This is obviously not what we want. We also need a function to help us display error information reasonably. In razor, we can extend htmlhelper. So I extended a method validatormessage for htmlhelper

public static class ValidatorHelper
 {
 public static MvcHtmlString ValidatorMessageFor(this HtmlHelper htmlHelper, string property, object error)
 {
 var dicError = error as Dictionary<string, string>;

 If (dicerror = = null) // no error
 {
 //Not equal to null
 }
 else
 {
 if (dicError.ContainsKey(property))
 {
  return new MvcHtmlString(string.Format("<p>{0}</p>", dicError[property]));
 }
 }
 return new MvcHtmlString("");
 }
 }

Two parameters, property and error, are required in validator mesaegfor

The former is the error attribute name to be displayed, and the latter is the error object, viewdata [“error”]. The function is very simple. When the key in the error object is found to be the error attribute name, wrap the value with a p tag and return it. Value is the error prompt message corresponding to the error attribute.

Now we need to add a sentence under each input of view, such as @ HTML. Validatormessage for (“name”, viewdata [“error”)).

@using (Html.BeginForm())
{
 @Html.AntiForgeryToken()

 <div>
 <h4>Person</h4>
 <hr />
 @Html.ValidationSummary(true, "", new { @class = "text-danger" })
 <div>
 < label for = "name" > name < / label >
 <div>
 <input type="text" name="Name" />
 @Html.ValidatorMessageFor("Name", ViewData["Error"])
 </div>
 </div>

 <div>
 < label for = "age" > age < / label >
 <div>
 <input type="text" name="Age" />
 @Html.ValidatorMessageFor("Name", ViewData["Error"])
 </div>
 </div>

 <div>
 < label for = "home" > address < / label >
 <div>
 <input type="text" name="Address.Home" />
 @Html.ValidatorMessageFor("Address.Home", ViewData["Error"])
 </div>
 </div>

 <div>
 < label for = "phone" > phone < / label >
 <div>
 <input type="text" name="Address.Phone" />
 @Html.ValidatorMessageFor("Address.Phone", ViewData["Error"])
 </div>
 </div>

 <div>
 < label for = "sex" > gender < / label >
 <div>
 <div>
  <input type="checkbox" name="Sex" />
 </div>
 </div>
 </div>

 <div>
 <div>
 <input type="submit" value="Create" />
 </div>
 </div>
 </div>
}

All our basic work has been completed here


[HttpPost]
 public ActionResult ValidatorTest(Person model)
 {
 var result = this.ValidatorHub.PersonValidator.Validate(model);
 if (result.IsValid)
 {
 return Redirect("https://www.baidu.com");
 }
 else
 {
 this.ValidatorErrorHandler(result);
 }
 return View();
 }

Verify the entity person by using the validator hub of controllerex. If the verification is successful… There is nothing to do here, it should be represented as a jump. Otherwise, call the validator errorhandler in ex to bind the error message to viewdata [“error”], so that the error message can be displayed when the front-end view is rendered.

Next we will run the program.

As you can see, when I click Submit, although only the phone is not input, the other three forms are cleared. Maybe we will feel unhappy. Of course, if you need it, I believe you can solve the problem after reading the above error information binding, but in fact, we don’t need it, \ (^ o ^)/~

Why? Because we also need front-end verification. When the current end verification fails, it can’t be sent to the back-end at all, so we don’t need to worry about the form data that the user has filled out when some of the verification fails.

It is mentioned here that the front-end verification is required when the form is submitted. Since there is a front-end verification, why do we need to do the back-end verification? Didn’t you take off your pants and fart? In fact, the function of front-end verification is to optimize the user experience, reduce the pressure of the server, and prevent the gentleman, but never prevent the villain. Because of the uncertainty of the web client, anything can be simulated. If you don’t do server-side verification, if your system involves money, you may wake up that day and find yourself bankrupt.

One that’s proven.

summary

The above is the whole content of this article. I hope that the content of this article has a certain reference learning value for everyone’s study or work. If you have any questions, you can leave a message and exchange. Thank you for your support for developepaar.