WEB API Series (ii) Use of filter and order of execution

Source: Internet
Author: User

Http://www.cnblogs.com/UliiAn/p/5402146.html

In the Web API, the idea of aspect-oriented programming (AOP) is introduced, in which specific filter can be inserted for process interception processing. The introduction of this mechanism can better practice the dry (Don ' t Repeat yourself) thought, through the filter can be unified to some common logic processing, such as: Permission check, parameter and decryption, parameter verification, etc. we can use this feature for unified processing, Today we present the development, use, and discussion of the filter's execution sequence.

First, the development and invocation of filter

In the default WEBAPI, the framework provides three filters, and their functionality and operating conditions are shown in the following table:

Filter type

The implemented interface

Describe

Authorization

Iauthorizationfilter

The first filter to run is used as the request permission check

Action

Iactionfilter

Run before and after the action is run

Exception

Iexceptionfilter

Run when an exception occurs

First, we implement a authorizatoinfilter that can be used for simple permission control:

    public class Authfilterattribute:authorizationfilterattribute    {public        override void Onauthorization ( Httpactioncontext actioncontext)        {            //If the user is bearing an action with Allowanonymousattribute, no authorization validation if            ( Actioncontext.actiondescriptor.getcustomattributes<allowanonymousattribute> (). Any ())            {                return;            }            var verifyresult = actioncontext.request.headers.authorization!=null &&  //request requires a Authorization header                               ActionContext.Request.Headers.Authorization.Parameter = = "123456";//and the Authorization parameter is 123456 validates            through if ( !verifyresult)            {                //If the validation does not pass, a 401 error is returned, and the reason for writing the error in body                actioncontext.response = ActionContext.Request.CreateErrorResponse (httpstatuscode.unauthorized,new httperror ("Token incorrect"));}        }
}

A simple filter for user authentication has been developed, this filter requires the user's request with the authorization header and the parameter is 123456, if passed, pass through, return 401 error, and in the content to prompt token is incorrect. Below, we need to register this filter, there are three ways to register the filter:

The first: Authfilterattribute this attribute on the action that we want to have permission to control:

    public class Personcontroller:apicontroller    {        [AuthFilter] public        createresult Post (CreateUser user)        {            return new Createresult () {Id = "123"};        }    }

This approach is appropriate for the permission control of a single action.

Second, find the appropriate controller and hit this attribute:

    [AuthFilter]    public class Personcontroller:apicontroller    {public        createresult Post (CreateUser user)        {            return new Createresult () {Id = "123"};        }    }

This method is suitable for controlling the entire controller, after this attribute, all actions in the controller have access control.

Third, find App_start\webapiconfig.cs and add the filter instance under the Register method:

public static void Register (Httpconfiguration config) {
Config. Maphttpattributeroutes ();
   Register the global Filter CONFIG. Filters.add (New Authfilterattribute ());
Config. Routes.maphttproute ( name: "Defaultapi", routetemplate: "Api/{controller}/{id}", defaults:new {id = Routeparameter.optional} );}

In this way, it is appropriate to control all the APIs, and any controller and any action accept this permission control.

In most scenarios, the authorization logic for each API is the same, and the easiest and easiest way to use global registration filter is to have an obvious question: what if a few APIs don't need to be controlled (such as login)? We can do this with this API:

[Allowanonymous]public Createresult Postlogin (loginentity entity) {      //todo: Add validation logic      return new Createresult () { Id = "123456"};}

I have allowanonymousattribute this action, and the validation logic has spared this API without permission checking.

In the actual development, we can design a similar session mechanism, through the user login to obtain token, in the subsequent interactive HTTP request to add authorization head and take this token, Tokens are validated in a custom authfilterattribute, and a standard token verification process can be implemented.

Next we introduce Actionfilter:

Actionfilterattrubute provides two ways to intercept: OnActionExecuting and onactionexecuted, both of which provide synchronous and asynchronous methods.

The OnActionExecuting method executes before the action executes, and the OnActionExecuted method executes after the action execution completes.

Let's take a look at an application scenario: a classmate who has used MVC is not unfamiliar. MVC model binding and model validation, it is very convenient to use, after the definition of the entity, in need to verify the place can play the corresponding attribute, The IsValid property of the Modelstate is checked at the start of the action, and if the checksum is not returned directly to view, the front end resolves and displays the reason for the failure to pass the checksum. This convenient feature is also inherited in the Web API, which is more convenient to use:

public class customactionfilterattribute:actionfilterattribute{public    override void OnActionExecuting ( Httpactioncontext actioncontext)    {        if (!actioncontext.modelstate.isvalid)        {            Actioncontext.response = ActionContext.Request.CreateErrorResponse (Httpstatuscode.badrequest,  actioncontext.modelstate);}}}    

This filter provides the function of model validation, and returns a 400 error if the model check is not passed, and gives the caller the relevant error information. He uses the same method as Authfilterattribute, which can be used for action, Controller, global use. We can use one of the following examples to verify:

The code is as follows:

public class loginentity{    [Required (errormessage = "Missing user name")] public    string UserName {get; set;}    [Required (errormessage = "Missing password")]    public string Password {get; set;}}
[AllowAnonymous] [Customactionfilter]public Createresult Postlogin (loginentity entity) {     //todo: Add validation logic     return new Createresult () {Id = "123456"};}

Of course, you can also parse modelstate according to your own needs and then return the error message to the user in your own format via Request.createresponse ().

OnActionExecuted method I used in the actual work less, currently only in a partial response to the data encryption scenario is used, using the same method, read the existing response, and encrypt and then give the encrypted response to the actioncontext.response can be assigned.

Let me give you a demo:

public override Async Task Onactionexecutedasync (Httpactionexecutedcontext actionexecutedcontext, CancellationToken CancellationToken) {        var key = ten;        var responsebody = await actionExecutedContext.Response.Content.ReadAsByteArrayAsync (); Reads the data in the content in a byte array for        (int i = 0; i < responsebody.length; i++)        {            responsebody[i] = (byte) ( Responsebody[i] ^ key); Make an XOR operation for each byte        }        actionExecutedContext.Response.Content = new Bytearraycontent (responsebody); Assign the result to Response's Content        actionExecutedContext.Response.Content.Headers.ContentType = Mediatypeheadervalue.parse ("Encrypt/bytes"); and modify Content-type}

In this way we will respond to the content of each byte has made an XOR operation, the response to a simple encryption, you can rely on their own needs for more reliable encryption, such as AES, DES or RSA ... This approach gives you the flexibility to process the processed results of an action, and the flexibility and versatility of responding to content encryption via filter allows him to get a lot of information about the current action, then choose how to encrypt it, get the parameters needed for encryption, and so on. If the parameters used by the encryption are not dependent on the currently executing action, you can also take httpmessagehandler for processing, which I'll cover later in the tutorial.

One last Filter:exceptionfilter.

As the name implies, this filter is used for exception handling, when the business has an unhandled exception, we do not want users to receive the yellow pages or other users cannot parse the information, we can use Exceptionfilter for unified processing:

public class exceptionfilter:exceptionfilterattribute{public    override void Onexception ( Httpactionexecutedcontext actionexecutedcontext)    {        //If the Intercept exception is customized for us, the exception that can be handled is handled by our own rules if        ( Actionexecutedcontext.exception is demoexception)        {            //todo: logging            actionexecutedcontext.response = ActionExecutedContext.Request.CreateResponse (                    httpstatuscode.badrequest, new {Message = ActionExecutedContext.Exception.Message});        }        else        {            //If the Intercept exception is an exception that I don't anticipate, return the generic return information to the user, avoid revealing too much information, and ease the user's handling of            //todo: Logging            Actionexecutedcontext.response =                    ActionExecutedContext.Request.CreateResponse ( Httpstatuscode.internalservererror,                        new {Message = "The server was abducted by aliens!" "});        }    }}

We define a exceptoinfilter to handle uncaught exceptions, and we divide the exceptions into two categories: one is the exception we can anticipate: business exceptions such as business parameter errors, ultra vires, and a class of exceptions that we cannot anticipate: exceptions such as database disconnection, memory overflow, and so on. We tell the caller through HTTP code and use a relatively fixed, friendly data structure to inform the caller of the exception, so that the caller can record and handle such an exception.

[Customerexceptionfilter]public class testcontroller:apicontroller{public    int Get (int a, int b)    {        if (a &L T b)        {            throw new Demoexception ("A must be bigger than B! ");        }        if (a = = b)        {            throw new notimplementedexception ();        }        return a*b;}    }

We define an action: Different exceptions are thrown in different situations, one of which we can anticipate and think is an error in the caller's argument, one that cannot be handled, and we look at the result:

In such a restapi, we can pre-define the abnormal expression, so that the caller can easily determine what the situation is abnormal, and then through a more uniform return of the exception information to allow the caller to easily parse the exception information, forming a unified and convenient exception message processing mechanism.

However, Exceptionfilter can only catch and handle exceptions after the controller's initialization has been successfully completed. The exceptionfilter can do nothing until controller initialization is complete, such as when an exception occurs in the Controller's constructor. This webapi introduces the Exceptionlogger and exceptionhandler processing mechanisms, which we will explain in a later article.

Second, the order of execution of the filter

When using MVC, Actionfilter provides an order property that allows the user to control the order in which the filter is called, while the Web API no longer supports that property. The filter for the WEB API has its own set of call order rules:

All filter has three scopes depending on the registration location: Global, Controller, action:

The filter registered by the Filters.add () method under the Httpconfiguration class instance (typically set in the Register method in the App_start\webapiconfig.cs file) belongs to the global scope;

The filter that is registered by the attribute that is played by the controller belongs to the controller scope;

The filter that is registered by the attribute that is played on the action is the action scope;

They followed the following rules:

1. Under the same scope, Authorizationfilter is executed first and then executed Actionfilter

2. For Authorizationfilter and actionfilter.onactionexcuting, if there is more than one filter in the life cycle of a request, the order of execution is global->controller- >Action;

3, for actionfilter,onactionexecuting always precedes onactionexecuted execution;

4. For Exceptionfilter and actionfilter.onactionexcuted, the order of execution is action->controller->global;

5. For all filter, if the request is blocked: The response is assigned, the subsequent filter is no longer executed.

About filter knowledge By default we're talking about this, and if there's any wrong place or question in the article, you're welcome to point it out for me.

WEB API Series (ii) Use of filter and order of execution

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.