Common extensions of ASP. net mvc: Filter and model binding, asp. netmvc

Source: Internet
Author: User

Common extensions of ASP. net mvc: Filter and model binding, asp. netmvc
1. Filter)

ASP. every request in. net mvc is allocated to a specific Action (hereinafter referred to as "method") under the corresponding Controller (hereinafter referred to as "Controller") for processing, under normal circumstances, you can directly write code in the method, but if you want to process some logic before or after the method is executed, you need to use the filter here.

There are three commonly used filters: Authorize (authorization filter), HandleError (exception filter), and ActionFilter (custom filter). The corresponding classes are AuthorizeAttribute, HandleErrorAttribute, and ActionFilterAttribute, inherit these classes and override the methods to implement different functions.

1. Authorize authorization Filter

An authorization filter is used as its name implies. The authorization filter is executed before the method is executed. It is used to restrict whether a request can enter this method and create a new method:

public JsonResult AuthorizeFilterTest(){    return Json(new ReturnModel_Common { msg = "hello world!" });}

Direct access to get the result:

Now, assume that the AuthorizeFilterTest method is a background method and you must have a valid token to access it. The general practice is to receive and verify the token in the AuthorizeFilterTest method, however, once there are too many methods, it is obviously impractical to write verification code in each method. In this case, the authorization filter should be used:

Public class TokenValidateAttribute: AuthorizeAttribute {/// <summary> /// logic of authorization verification. If true is returned, authorization is enabled, false indicates the opposite. // </summary> /// <param name = "httpContext"> </param> /// <returns> </returns> protected override bool AuthorizeCore (httpContextBase httpContext) {string token = httpContext. request ["token"]; if (string. isNullOrEmpty (token) {return false;} else {return true ;}}}

A new class that inherits AuthorizeAttribute is created, and the AuthorizeCore method is rewritten. This pseudo code returns true if the token has a value, and false if no value exists, mark the method that requires authorization before access:

[TokenValidate]public JsonResult AuthorizeFilterTest(){    return Json(new ReturnModel_Common { msg = "hello world!" })}

After TokenValidate is marked, The AuthorizeCore method is executed before AuthorizeFilterTest. If AuthorizeCore returns true, the authorization succeeds and the code in AuthorizeFilterTest is executed. Otherwise, the authorization fails. Do not pass the token:

Pass token:

The default unauthorized page of MVC is displayed when the authorization fails without passing the token. Here we will make an improvement: whether the authorization is successful or fails, the returned value format is consistent to facilitate frontend processing. At this time, rewrite the HandleUnauthorizedRequest method in the AuthorizeAttribute class:

/// <Summary> /// handle Authorization failure /// </summary> /// <param name = "filterContext"> </param> protected override void HandleUnauthorizedRequest (AuthorizationContext Context filterContext) {base. handleUnauthorizedRequest (filterContext); var json = new JsonResult (); json. data = new ReturnModel_Common {success = false, code = ReturnCode_Interface.Token expired or error, msg = "token expired or error"}; json. jsonRequestBehavior = JsonRequestBehavior. allowGet; filterContext. result = json ;}

Effect:

Practice: permission management systems are the most widely used authorization filters. After a user logs on to the server, the server outputs an encrypted token, which will be used for subsequent requests, the server unlocks the token in the AuthorizeCore method to obtain the user ID. Based on the user ID, check whether the database has the permission to request the current interface. If yes, true is returned. Otherwise, false is returned. In this way, the advantage of successfully logging on to cookies and sessions is that an interface is used by PC and App.

2. HandleError exception filter

The exception filter is used to handle code exceptions. It is executed when the system code throws an error. By default, MVC has implemented the exception filter and registered it to FilterConfig. cs under the App_Start directory:

filters.Add(new HandleErrorAttribute());

This takes effect for the entire system. If any interface or page reports an error, the default Exception Handling of MVC will be executed and a default error page will be returned: views/Shared/Error (this page is displayed only when the program sends an Error to the server. The local debugging permission is high and the specific Error message is displayed)

@ {Layout = null ;}<! DOCTYPE html> 

The default exception filter obviously cannot meet the usage requirements. Rewrite the exception filter to meet the actual needs of the project:

1) When an error is reported, you can record the controller and method of the error code, as well as the request parameters and time when the error is reported;

2) return JSON in a specific format to facilitate front-end processing. Because most of the system's ajax requests are now, an error is returned and the default error page of MVC is returned, which is not easy to handle at the front end.

Create a new class LogExceptionAttribute to inherit HandleErrorAttribute and override the internal OnException method:

Public override void OnException (ExceptionContext filterContext) {if (! FilterContext. exceptionHandled) {string controllerName = (string) filterContext. routeData. values ["controller"]; string actionName = (string) filterContext. routeData. values ["action"]; string param = Common. getPostParas (); string ip = HttpContext. current. request. userHostAddress; LogManager. getLogger ("LogExceptionAttribute "). error ("Location: {0}/{1} Param: {2} UserIP: {3} Exception: {4}", controllerName, actionName, param, ip, filterContext. exception. message); filterContext. result = new JsonResult {Data = new ReturnModel_Common {success = false, code = ReturnCode_Interface. the server throws an error. msg = filterContext. exception. message}, JsonRequestBehavior = JsonRequestBehavior. allowGet};} if (filterContext. result is JsonResult) filterContext. exceptionHandled = true; // If the returned result is JsonResult, The else base has been processed for the exception. onException (filterContext); // executes the logic of the base class HandleErrorAttribute and redirects to the error page}

The exception filter is not marked on the method like the authorization filter. It is directly registered with FilterConfig. cs under the App_Start directory, so that all interfaces can take effect:

filters.Add(new LogExceptionAttribute());

The NLog is used as the logging tool in the exception filter. The Nuget installation command is as follows:

Install-Package NLogInstall-Package NLog.Config

Compared with Log4net, NLog is easy to configure and can only contain a few lines of code. NLog. config:

<?xml version="1.0" encoding="utf-8" ?><nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">  <targets>    <target xsi:type="File" name="f" fileName="${basedir}/log/${shortdate}.log" layout="${uppercase:${level}} ${longdate} ${message}" />    <target xsi:type="File" name="f2" fileName="D:\log\MVCExtension\${shortdate}.log" layout="${uppercase:${level}} ${longdate} ${message}" />  </targets>  <rules>    <logger name="*" minlevel="Debug" writeTo="f2" />  </rules></nlog>

If an error is reported, the log is recorded in the MVCExtension directory under the log directory of the d disk. A project has a log directory for convenient management. The configuration is complete. Check the Code:

public JsonResult HandleErrorFilterTest(){    int i = int.Parse("abc");    return Json(new ReturnModel_Data { data = i });}

If the string type is strongly converted to int type, an error is inevitable. Page response:

At the same time, the log is recorded as follows:

3. ActionFilter custom filter

Custom filters are more flexible and can be precisely injected before, during, and after a request. Inherit the abstract class ActionFilterAttribute and override the method:

public class SystemLogAttribute : ActionFilterAttribute{    public string Operate { get; set; }    public override void OnActionExecuted(ActionExecutedContext filterContext)    {        filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnActionExecuted");        base.OnActionExecuted(filterContext);    }    public override void OnActionExecuting(ActionExecutingContext filterContext)    {        filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnActionExecuting");        base.OnActionExecuting(filterContext);    }    public override void OnResultExecuted(ResultExecutedContext filterContext)    {        filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnResultExecuted");        base.OnResultExecuted(filterContext);    }    public override void OnResultExecuting(ResultExecutingContext filterContext)    {        filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnResultExecuting");        base.OnResultExecuting(filterContext);    }}

This filter is suitable for logging system operations:

[SystemLog (Operate = "Add User")] public string CustomerFilterTest () {Response. write ("<br/> the Action is being executed... "); return" <br/> Action execution ended ";}

Check the result:

The execution sequence of the four methods: OnActionExecuting-> OnActionExecuted-> OnResultExecuting-> OnResultExecuted, which precisely controls the entire request process.

In practice, the logging process is like this: Write an operation log to the database in the OnActionExecuting method, store the primary key of the record in the global variable, and go to the OnResultExecuted method to indicate that the request has ended, at this time, you will naturally know whether this operation is successful and whether the operation log is successfully updated based on the primary key.

Additional reading:

ASP. net mvc Filter

MVC filter Use Case: Unified Exception Handling and streamlined code

Ii. Model binding)

Let's first look at a common method:

public ActionResult Index(Student student){    return View();}

The parameters accepted by this method are a Student object. The parameters passed by the front-end are kept consistent with the attributes in the Student object, so they are automatically bound to this object, you do not need to bind the new Student object to the method one by one. The binding process is completed by defamodelmodelbinder in MVC. defamodelmodelbinder inherits the IModelBinder interface at the same time, now we can use the IModelBinder interface and DefaultModelBinder to implement more flexible model binding.

Scenario 1: the front end uploads an encrypted string token. Some fields in the token need to be used in the method, so you have to receive the string, decrypt the string, and convert it into an object in the method, this method makes it easy to say that there are a lot of repeated code, even if the general method is extracted, it is still necessary to call this general method in the method, is there a way to encapsulate this object directly in the parameter?

Objects bound to the model:

Public class TokenModel {// <summary> // primary key // </summary> public int Id {get; set ;} /// <summary> /// Name /// </summary> public string Name {set; get ;} /// <summary> /// overview /// </summary> public string Description {get; set ;}}

Create a TokenBinder to inherit the IModelBinder interface and implement the BindModel method:

public class TokenBinder : IModelBinder{    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)    {        var token = controllerContext.HttpContext.Request["token"];        if (!string.IsNullOrEmpty(token))        {            string[] array = token.Split(':');            if (array.Length == 3)            {                return new TokenModel() { Id = int.Parse(array[0]), Name = array[1], Description = array[2] };            }            else            {                return new TokenModel() { Id = 0 };            }        }        else        {            return new TokenModel() { Id = 0 };        }    }}

This method receives a token parameter and parses and encapsulates the token parameter. After the code is complete, you need to register it in the Application_Start method:

ModelBinders.Binders.Add(typeof(TokenModel), new TokenBinder());

Now simulate this interface:

public JsonResult TokenBinderTest(TokenModel tokenModel){    var output = "Id:" + tokenModel.Id + ",Name:" + tokenModel.Name + ",Description:" + tokenModel.Description;    return Json(new ReturnModel_Common { msg = output });}

Call:

We can see that "1: Wang Jie: oppoic.cnblogs.com" has been bound to the tokenModel object. However, if you bind an IModelBinder to a more complex model, you will be powerless.

Scenario 2: remove the first space of an object attribute
public class Student{    public int Id { get; set; }    public string Name { get; set; }    public string Class { get; set; }}

If there is a space in the Name attribute sent from the front end, how can we remove it? Use defamodelmodelbinder for more flexible control

Public class TrimModelBinder: DefaultModelBinder {protected override object GetPropertyValue (ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) {var obj = base. getPropertyValue (controllerContext, bindingContext, propertyDescriptor, propertyBinder); if (obj is string & propertyDescriptor. attributes [typeof (Tr ImAttribute)]! = Null) // identifies the string type and has the [Trim] flag {return (obj as string). Trim () ;} return obj ;}}

Mark the entity for which the first attribute needs to be formatted:

[ModelBinder(typeof(TrimModelBinder))]public class Student{    public int Id { get; set; }    [Trim]    public string Name { get; set; }    public string Class { get; set; }}

Okay, test:

Public JsonResult TrimBinderTest (Student student) {if (string. isNullOrEmpty (student. name) | string. isNullOrEmpty (student. class) {return Json (new ReturnModel_Common {msg = "parameters not found"});} else {return Json (new ReturnModel_Common {msg = "Name:" + student. name + ", Length:" + student. name. length + "Class:" + student. class + ", Length:" + student. class. length });}}

It can be seen that the length of the Name marked with the Trim attribute is the length of Space removed: 7, and the length of the Class attribute not labeled is 6.

Additional reading:

Simple Application of ASP. net mvc Model binding

MVC extension (ModelBinder)

ASP. net mvc: use custom ModelBinder

ASP. net mvc: use custom ModelBinder to filter sensitive information

 

Crawlers shame, the original link: http://www.cnblogs.com/oppoic/p/6407896.html

Environment: Visual Studio 2013, ASP. net mvc 5.0 source code

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.