ASP.NET Web APIのメッセージ[ブロック]処理

16239 ワード

タイトルはかなり取りにくいです。内容はあなたの考えと違っているかもしれません。そして、ネット上にはすでにこの方面の資料がたくさんあります。余計なことは言わないで、直接始めます。
Exception
サービスが異常を処理していない場合、most exceptions are translated into an HTTP reponse with status code 500、Internal Server Errorを投げ出すことができます。もちろん、私たちも特殊な異常HttpResponse Exceptionを捨てれます。これは直接に応答ストリームに書き込みます。500に回されません。
public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return item;
}
クライアントに対して具体的な詳細を隠すために、または統合されたフォーマットを実装する場合、System.Web.Http.Filters.Exception FilterAttributeから継承された特性を作成することができます。
public class APIExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        //    
        if (context.Exception is BusinessException)
        {
            context.Response = new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.ExpectationFailed };
            BusinessException exception = (BusinessException)context.Exception;
            context.Response.Headers.Add("BusinessExceptionCode", exception.Code);
            context.Response.Headers.Add("BusinessExceptionMessage", exception.Message);
        }
        //    
        else
        {
            context.Response = new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.InternalServerError };
        }
    }
}
その後、このAttributeをactionまたはcontroller、またはGlobal Configrations.figrations.Filters.Addに適用します。 API Exception FilterAttribute();すべてのaction(If you use the"ASP.NET MVC 4 Web Apple"project template to create your project,putyour Web API configration code inside theに適用させます。  WebApiConfig class、which is located in the Apple.config.Filters.Add(newProdStore.NotImpl Exception FilterAttribute))。もちろん、上記のコードでは、OnException方法で直接にHttpResonseExceptionを投げることもできます。効果は同じです。
Note:Something to have in mind is that the Exception FilterAttribute will be ignored if the AppniController action methrows a HttpResonseException;If something goes wrong in the Exception FilterAttribute and an exception is thrown that is not of type HttpResonse Exception、a formated exception will be thrown with stack trace etc to the client.
ネットにはHttpErrerという種類が内蔵されていますが、もしフォーマットの対象に戻りたいなら、(Json、xmlなど)、より便利に使えます。
以上の知識は主にException Handling in ASP.NET Web APIから来ています。
アクションFilterAttribute、AppniController Action Invoker 
action実行前後に追加処理をする場合もありますが、アクションFilterAttributeとAppniController Action Invokerが役に立ちます。例えば、クライアント要求から送られてきたパラメータは、ユーザトークン文字列tokenであり、action実行前にactionパラメータリストに対応するユーザ番号IDに変換します。 
public class TokenProjectorAttribute : ActionFilterAttribute
{
    private string _userid = "userid";
    public string UserID
    {
        get { return _userid; }
        set { _userid = value; }
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!actionContext.ActionArguments.ContainsKey(UserID))
        {
            //        userid,    
            //……
            var response = new HttpResponseMessage();
            response.Content = new StringContent("        .");
            response.StatusCode = HttpStatusCode.Conflict;
            //           , throw  ,          
            throw new HttpResponseException(response);
        }
        //userid    
        actionContext.ActionArguments[UserID] = actionContext.Request.Properties["shumi_userid"];
        base.OnActionExecuting(actionContext);
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);
    }
}
アクションFilterAttributeはどのようにactionに適用しますか?前のException FilterAttributeと似ています。
Apple Controller Action Invokerは上記のExceptionを例にしている:
public class ServerAPIControllerActionInvoker : ApiControllerActionInvoker
{
    public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        // actionContext      
        //……
        var result = base.InvokeActionAsync(actionContext, cancellationToken);
        if (result.Exception != null && result.Exception.GetBaseException() != null)
        {
            var baseException = result.Exception.GetBaseException();

            if (baseException is BusinessException)
            {
                return Task.Run<HttpResponseMessage>(() =>
                {
                    var response = new HttpResponseMessage(HttpStatusCode.ExpectationFailed);
                    BusinessException exception = (BusinessException)baseException;
                    response.Headers.Add("BusinessExceptionCode", exception.Code);
                    response.Headers.Add("BusinessExceptionMessage", exception.Message);
                    return response;
                });
            }
            else
            {
                return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError));
            }
        }
        return result;
    }
}
その後Global Configrations.Servicesに登録します。Apple Controller Action Invokerは全体に影響を与えるので、部分actionに対して包装処理を行うなら、アクションFilterAttributeを優先的に選ぶべきです。また、Apple Controller Action Invokerは、アクションFilterAttributeの前に処理します。
DelegatingHandler
前のブロックは、対応するactionにルーティングされた要求後に発生します。ルーティングの前に予め処理したり、応答ストリームの返却中に後処理したりする場合があります。例えば、要求側のアイデンティティを検証し、検証が通過しない場合は、エラー情報を直接返します。そうでなければ、後続の呼び出しを行います。
public class AuthorizeHandler : DelegatingHandler
{
    private static IAuthorizer _authorizer = null;

    static AuthorizeHandler()
    { }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Method == HttpMethod.Post)
        {
            var querystring = HttpUtility.ParseQueryString(request.RequestUri.Query);
            var formdata = request.Content.ReadAsFormDataAsync().Result;
            if (querystring.AllKeys.Intersect(formdata.AllKeys).Count() > 0)
            {
                return SendError("       .", HttpStatusCode.BadRequest);
            }
        }
        //       
        AuthResult result = _authorizer.AuthRequest(request);
        if (!result.Flag)
        {
            return SendError(result.Message, HttpStatusCode.Unauthorized);
        }
        request.Properties.Add("shumi_userid", result.UserID);
        return base.SendAsync(request, cancellationToken);
    }

    private Task<HttpResponseMessage> SendError(string error, HttpStatusCode code)
    {
        var response = new HttpResponseMessage();
        response.Content = new StringContent(error);
        response.StatusCode = code;

        return Task<HttpResponseMessage>.Factory.StartNew(() => response);
    }
}
ここのDelegatingHandlerはサービスのために使われていますが、実はDelegating Handlerも起動時に使用できます。HttpClientはDelegating Handlerをメッセージプロセッサとして受信することができます。
参考資料:
  • AS.NET Web API Exception Handling
  • Implementing message handlers to trocyour ASP.NET Web API usage
  • MVC 4 WebAPI(二)——Web APIの働き方
  • Asp.Net MVCおよびWeb APIの枠組み構成は、いくつかの問題と解決策に出会う。
  • HTTP Message Handlers in ASP.NET Web API
  • 転載は原文の出所を明記してください。http://www.cnblogs.com/newton/p/3238082.html