ホームページ  >  記事  >  バックエンド開発  >  Asp.Net WebAPI でのフィルターの使用と実行シーケンス (お気に入り)

Asp.Net WebAPI でのフィルターの使用と実行シーケンス (お気に入り)

PHPz
PHPzオリジナル
2018-05-14 15:39:584235ブラウズ

WEB APIではアスペクト指向プログラミング(AOP)の考え方が導入されており、プロセスインターセプト処理のために特定の場所に特定のフィルターを挿入することができます。このメカニズムの導入により、フィルターを通じて、許可の検証、パラメーターの暗号化と復号化、パラメーターの検証などのいくつかの一般的なロジックを均一に処理できるようになり、DRY (Don't Reply Yourself) のアイデアをより適切に実装できるようになります。今日は、Filter の開発と使用法を紹介し、その実行シーケンスについて説明します。

1. Filter の開発と呼び出し

デフォルトの WebApi では、フレームワークは次の表に示す 3 種類の Filter を提供します。その機能と動作条件は次の表のとおりです。

タイプ IAuthorizationFilterIActionFilterIExceptionFilter

実装されたインターフェース

説明

Authorization

最初に実行するもの

Filter
、リクエスト許可の検証として使用

Action

Aアクション
前後の操作

Exception

例外が発生したときに実行します

まず、単純な権限を制御するために使用できる Authorizatoinfilter を実装します。

       
             (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute> verifyResult = actionContext.Request.Headers.Authorization!= &&  == ; 

             (!= HttpError(
ユーザー検証で使用される単純なフィルターが開発されます。これが渡されると、401 エラーが返され、コンテンツ内のトークンが返されます。は不正確になります。次に、このフィルターを登録する必要があります。フィルターを登録するには 3 つの方法があります:

1 つ目: アクセス許可を制御したいアクションに AuthFilterAttribute を配置します:

    public class PersonController : ApiController
    {
        [AuthFilter]        public CreateResult Post(CreateUser user)
        {            return new CreateResult() {Id = "123"};
        }
    }
この方法は、単一のアクションのアクセス許可の制御に適しています。 。

2 番目に、対応するコントローラーを見つけてこの属性を追加します:

    [AuthFilter]    public class PersonController : ApiController
    {        public CreateResult Post(CreateUser user)
        {            return new CreateResult() {Id = "123"};
        }
    }
このメソッドは、コントローラー全体を制御するのに適しています。この属性を追加すると、コントローラー全体のすべてのアクションにアクセス制御が適用されます。

3 番目の方法は、App_StartWebApiConfig.cs を見つけて、Register メソッドの下に Filter インスタンスを追加することです:

   { id =
このメソッドは、すべての API を制御するのに適しており、任意のコントローラーと任意のアクションがこの権限制御を受け入れます。

ほとんどのシナリオでは、各 API の権限検証ロジックは同じです。この前提では、フィルターのグローバル登録を使用するのが最も簡単で便利な方法ですが、明らかな問題があります。それは、特定の API が What ではない場合です。制御する必要があるもの(ログインなど)についてはどうですか?このような API でこれを行うことができます:

[AllowAnonymous]public CreateResult PostLogin(LoginEntity entity)
{      //TODO:添加验证逻辑
      return new CreateResult() {Id = "123456"};
}
アクションにAllowAnonymousAttributeをマークしましたが、検証ロジックは権限検証を実行せずにAPIを無視しました。

実際の開発では、ユーザーのログインを通じてトークンを取得し、後続の対話型 HTTP リクエストでこのトークンを含む Authorization ヘッダーを追加し、それをカスタム AuthFilterAttribute に設定するセッションのようなメカニズムを設計できます。トークンが検証され、標準トークンが生成されます。検証プロセスを実装できます。

次に、ActionFilter を紹介します。

ActionFilterAttrubute は、インターセプト用の 2 つのメソッド、OnActionExecuting と OnActionExecuted を提供します。どちらも同期メソッドと非同期メソッドを提供します。

OnActionExecutingメソッドはActionの実行前に実行され、OnActionExecutedメソッドはActionの実行後に実行されます。

アプリケーション シナリオを見てみましょう: MVC を使用したことがある学生は、MVC のモデル バインディングとモデル検証をよく理解している必要があります。エンティティを定義した後、検証が必要な箇所に対応する属性を追加できます。アクションの開始時に ModelState の IsValid プロパティを使用すると、検証が失敗した場合、フロント エンドが検証に失敗した理由を解析して表示できます。 Web API もこの便利な機能を継承しており、さらに使いやすくなっています:

 public class CustomActionFilterAttribute : ActionFilterAttribute
{    public override void OnActionExecuting(HttpActionContext actionContext)
    {        if (!actionContext.ModelState.IsValid)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,  actionContext.ModelState);
        }
    }
}
このフィルターはモデル検証の機能を提供し、モデル検証が失敗した場合は 400 エラーが返され、関連するエラー情報が引き継がれます。発信者に。使い方は AuthFilterAttribute と同じで、アクション、コントローラー、およびグローバルに使用できます。次の例を使用して検証できます:

コードは次のとおりです:

public class LoginEntity
{
    [Required(ErrorMessage = "缺少用户名")]    public string UserName { get; set; }

    [Required(ErrorMessage = "缺少密码")]    public string Password { get; set; }
}


[AllowAnonymous]
[CustomActionFilter]public CreateResult PostLogin(LoginEntity entity)
{     //TODO:添加验证逻辑
     return new CreateResult() {Id = "123456"};
}

もちろん、独自のニーズに応じて ModelState を解析し、独自の形式を使用して、 Request.CreateResponse() を通じてユーザーにエラー メッセージを送信します。

OnActionExecutedメソッドは実際の業務ではほとんど使ったことはありませんが、現時点では部分的な応答データを暗号化するシナリオでのみ使用しています。使用方法は同じで、既存の応答を読み取って暗号化したものを渡します。応答を actionContext.Response に割り当てるだけです。

デモを行います:

public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{        var key = 10;        var responseBody = await actionExecutedContext.Response.Content.ReadAsByteArrayAsync(); //以Byte数组方式读取Content中的数据

        for (int i = 0; i < responseBody.Length; i++)
        {
            responseBody[i] = (byte)(responseBody[i] ^ key); //对每一个Byte做异或运算        }

        actionExecutedContext.Response.Content = new ByteArrayContent(responseBody); //将结果赋值给Response的Content
        actionExecutedContext.Response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("Encrypt/Bytes"); //并修改Content-Type}

このメソッドを使用して、応答コンテンツの各バイトに対して XOR 演算を実行し、応答コンテンツに対して単純な暗号化を実行します。独自の方法に従って実行できます。 AES、DES、RSA など、より信頼性の高い暗号化が必要です。この方法は、アクションの結果を柔軟に処理でき、柔軟性が高く、アクションに関する多くの情報を取得できます。を入力し、その情報をもとに暗号化方式を選択したり、暗号化に必要なパラメータを取得したりすることができます。暗号化に使用されるパラメーターが現在実行されているアクションに依存しない場合は、HttpMessageHandler を使用して処理することもできます。これについては後続のチュートリアルで紹介します。

最後のフィルター: ExceptionFilter

顾名思义,这个Filter是用来进行异常处理的,当业务发生未处理的异常,我们是不希望用户接收到黄页或者其他用户无法解析的信息的,我们可以使用ExceptionFilter来进行统一处理:

public class ExceptionFilter : ExceptionFilterAttribute
{    public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {        //如果截获异常为我们自定义,可以处理的异常则通过我们自己的规则处理
        if (actionExecutedContext.Exception is DemoException)
        {            //TODO:记录日志
            actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(
                    HttpStatusCode.BadRequest, new {Message = actionExecutedContext.Exception.Message});
        }        else
        {            //如果截获异常是我没无法预料的异常,则将通用的返回信息返回给用户,避免泄露过多信息,也便于用户处理            //TODO:记录日志
            actionExecutedContext.Response =
                    actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError,                        new {Message = "服务器被外星人拐跑了!"});
        }
    }
}

我们定义了一个ExceptoinFilter用于处理未捕获的异常,我们将异常分为两类:一类是我们可以预料的异常:如业务参数错误,越权等业务异常;还有一类是我们无法预料的异常:如数据库连接断开、内存溢出等异常。我们通过HTTP Code告知调用者以及用相对固定、友好的数据结构将异常信息告诉调用者,以便于调用者记录并处理这样的异常。

 [CustomerExceptionFilter]public class TestController : ApiController
{    public int Get(int a, int b)
    {        if (a < b)
        {            throw new DemoException("A必须要比B大!");
        }        if (a == b)
        {            throw new NotImplementedException();
        }        return a*b;
    }
}

我们定义了一个Action:在不同的情况下会抛出不同的异常,其中一个异常是我们能够预料并认为是调用者传参出错的,一个是不能够处理的,我们看一下结果:

在这样的RestApi中,我们可以预先定义好异常的表现形式,让调用者可以方便地判断什么情况下是出现异常了,然后通过较为统一的异常信息返回方式让调用者方便地解析异常信息,形成统一方便的异常消息处理机制。

但是,ExceptionFilter只能在成功完成了Controller的初始化以后才能起到捕获、处理异常的作用,而在Controller初始化完成之前(例如在Controller的构造函数中出现了异常)则ExceptionFilter无能为力。对此WebApi引入了ExceptionLogger和ExceptionHandler处理机制,我们将在之后的文章中进行讲解。

二、Filter的执行顺序

在使用MVC的时候,ActionFilter提供了一个Order属性,用户可以根据这个属性控制Filter的调用顺序,而Web API却不再支持该属性。Web API的Filter有自己的一套调用顺序规则:

所有Filter根据注册位置的不同拥有三种作用域:Global、Controller、Action:

通过HttpConfiguration类实例下Filters.Add()方法注册的Filter(一般在App_Start\WebApiConfig.cs文件中的Register方法中设置)就属于Global作用域;

通过Controller上打的Attribute进行注册的Filter就属于Controller作用域;

通过Action上打的Attribute进行注册的Filter就属于Action作用域;

他们遵循了以下规则:

1、在同一作用域下,AuthorizationFilter最先执行,之后执行ActionFilter

2、对于AuthorizationFilter和ActionFilter.OnActionExcuting来说,如果一个请求的生命周期中有多个Filter的话,执行顺序都是Global->Controller->Action;

3、对于ActionFilter,OnActionExecuting总是先于OnActionExecuted执行;

4、对于ExceptionFilter和ActionFilter.OnActionExcuted而言执行顺序为Action->Controller->Global;

5、对于所有Filter来说,如果阻止了请求:即对Response进行了赋值,则后续的Filter不再执行。

关于默认情况下的Filter相关知识我们就讲这么一些,如果在文章中有任何不正确的地方或者疑问,欢迎大家为我指出。

以上がAsp.Net WebAPI でのフィルターの使用と実行シーケンス (お気に入り)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:Asp.net (3) Web表示次の記事:Asp.net (3) Web表示