Objective
Parameter verification is a common problem, whether the front-end or the background, it is necessary to verify the user input, so as to ensure the correctness of the system data. For the web, some people may take it for granted that the front-end verification is OK, but this is a very wrong way, the front-end code for the user is transparent, a little bit of technology can bypass this authentication, directly submit data to the background. Whether it is the interface of the front-end Web page submission or the interface provided to the external, parameter validation is ubiquitous and essential. In short, all user input is not trustworthy.
There are a number of ways to verify parameter validation, and the following is an example of MVC, which lists several common authentication methods, assuming that there is a user registration method
[HttpPost]
Public ActionResult Register (registerinfo info)
First, through the If-if judgment
if (string. IsNullOrEmpty (info. UserName) { return Failjson ("User name cannot be empty"); } if (string. IsNullOrEmpty (info. Password) { return Failjson ("User password cannot be empty") }
It was the most brutal way to validate the parameters one after the other, but it was really used under WebForm. For the method of few parameters is OK, if more than one parameter, it is necessary to write n more if-if, rather cumbersome, more importantly, this part of the judgment can not be reused, another method is such a judgment.
Second, through the dataannotation
MVC provides dataannotation to validate the model of the action, in the final analysis Dataannotation is a series of inherited Validationattribute features, such as Rangeattribute, RequiredAttribute and so on. Validationattribute's virtual method IsValid is used to determine whether the object being tagged conforms to the current rule. When the model binding is carried out, ASP. NET MVC takes the Validationattribute of the tag through reflection, then calls IsValid to determine whether the current parameter conforms to the rule, and if the validation does not pass, the error message is collected. This is why we can determine whether the model validation passed through Modelstate.isvalid in action, and modelstate to obtain the reason for the validation failure information. For example, the above example:
public class Registerinfo { [Required (errormessage= "User name cannot be empty")] public string Username{get;set; [Required (errormessage= "Password cannot be empty")] public string Password {get; set;} }
In fact, it is possible to implement this process in webform with the implementation of MVC. The advantages of this approach are very elegant and flexible, and if you have multiple actions that share a model parameter, it is enough to write in one place, and the key is that it makes our code look very concise.
However, this approach also has shortcomings, usually our project may have a lot of interfaces, such as dozens of interfaces, some interface only two or three parameters, for each interface to define a class wrapper parameters a bit extravagant, and actually naming this class is a very headache.
Third, dataannotation can also be marked on the parameters
By validating the AttributeUsage of an attribute, you can see that it can be marked not only on attributes and fields, but also on parameters. In other words, we can also write:
Public ActionResult Register ([Required (errormessage= "User name cannot be empty")]string userName, [Required (errormessage= "Password cannot be empty")] String password)
This is OK, but it is clear that this is a bad way to write a parameter, especially if there are multiple parameters, or there are multiple validation rules for the parameter.
Iv. Custom ValidateAttribute
We know that we can use filters to do some processing before the action of MVC, such as authentication, authorization processing. Similarly, this can also be used to validate parameters. FilterAttribute is a common filter that allows us to do something before and after the action, and what we do here is to validate the parameters before the action, and if the validation does not pass, it will not be executed anymore.
Define a Basevalidateattribute base class as follows:
public class Basevalidateattribute:filterattribute { protected virtual void HandleError ( ActionExecutingContext context) {for (int i = ValidateHandlerProviders.Handlers.Count; i > 0; i--) { Validatehandlerproviders.handlers[i-1]. Handle (context); if (context. Result! = null) {break ; } }}
HandleError is used to process results when validation fails, and here validatehandlerproviders ivalidatehandler for processing results, which can be registered externally. Ivalidatehandler is defined as follows:
Public interface Ivalidatehandler { void Handle (ActionExecutingContext context);
Validatehandlerproviders is defined as follows, it has a default processor.
public class Validatehandlerproviders {public static list<ivalidatehandler> handlers {get; private set;} static validatehandlerproviders () { handlers = new List<ivalidatehandler> () { new Defaultvalidatehandler () }; } public static void Register (Ivalidatehandler handler) { handlers.add (handler); } }
The purpose of this is that, since we may have a lot of specific validateattribute, we can separate the module, and give the final processing to the external decision, for example, we can define a processor in the project:
public class Standervalidatehandler:ivalidatehandler {public void Handle (ActionExecutingContext Filtercontext) { Filtercontext.result = new Standerjsonresult () { Result = Faststatnderresult.fail ( "Parameter validation failed", 555) };}}
Then register when the application starts: ValidateHandlerProviders.Handlers.Add (new Standervalidatehandler ());
Give me two chestnuts:
Validatenullttribute:
public class Validatenullattribute:basevalidateattribute, iactionfilter {public bool Validateempty {get; Set public string Parameter {get; set;} Public Validatenullattribute (string parameter, bool Validateempty = false) {Validateempty = Validateemp Ty Parameter = Parameter; } public void OnActionExecuting (ActionExecutingContext filtercontext) {string[] validates = Para Meter. Split (', '); foreach (Var p in validates) {string value = Filtercontext.httpcontext.request[p]; if (validateempty) {if (string. IsNullOrEmpty (value)) {base. HandleError (Filtercontext); }} else {if (value = = null) { Base. HandleError (Filtercontext); } }}} public void onactionexecuted (ActionExecutedContext filtercontext) { } }
Validateregexattribute:
public class Validateregexattribute:basevalidateattribute, Iactionfilter { private Regex _regex; public string Pattern {get; set;} public string Parameter {get; set;} Public Validateregexattribute (string parameter, string pattern) { _regex = new Regex (pattern); Parameter = Parameter; } public void onactionexecuting (ActionExecutingContext filtercontext) { string[] validates = Parameter.split (', '); foreach (Var p in validates) { String value = Filtercontext.httpcontext.request[p]; if (!_regex. IsMatch (value)) { base. HandleError (Filtercontext); }}} public void onactionexecuted (ActionExecutedContext filtercontext) { } }
More validation can be done in the same vein.
In this way, our above-mentioned wording becomes:
[Validatenull ("Username,password")] Public ActionResult Register (string userName, string password)
Synthesis looks, still OK, with the above dataannotation can weigh the choice to use, here we can expand more useful information, such as error description and so on.
Summarize
Of course, each method has its shortcomings, this is depending on the circumstances of the choice. General parameters too many suggestions are wrapped with one object.
Several ways to validate background parameters