1. 程式人生 > >ASP NET Web API之訊息 攔截 處理

ASP NET Web API之訊息 攔截 處理

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

標題相當難取,內容也許和您想的不一樣,而且網上已經有很多這方面的資料了,我不過是在實踐過程中作下記錄。廢話少說,直接開始。

Exception


當服務端丟擲未處理異常時,most exceptions are translated into an HTTP response with status code 500, Internal Server Error.當然我們也可以丟擲一個特殊的異常HttpResponseException,它將被直接寫入響應流,而不會被轉成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.ExceptionFilterAttribute的特性,如下:

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,或者GlobalConfiguration.Configuration.Filters.Add(new APIExceptionFilterAttribute());使之應用於所有action(If you use the "ASP.NET MVC 4 Web Application" project template to create your project, put your Web API configuration code inside the WebApiConfig class, which is located in the App_Start folder:config.Filters.Add(newProductStore.NotImplExceptionFilterAttribute());)。當然,在上述程式碼中,我們也可以在OnException方法中直接丟擲HttpResponseException,效果是一樣的。

Note: Something to have in mind is that the ExceptionFilterAttribute will be ignored if the ApiController action method throws a HttpResponseException;If something goes wrong in the ExceptionFilterAttribute and an exception is thrown that is not of type HttpResponseException, a formatted exception will be thrown with stack trace etc to the client.

如果要返回給客戶端的不僅僅是一串字串,比如是json物件,那麼可以使用HttpError這個類。

以上知識主要來自Exception Handling in ASP.NET Web API

ActionFilterAttribute、ApiControllerActionInvoker 


有時要在action執行前後做額外處理,那麼ActionFilterAttribute和ApiControllerActionInvoker就派上用場了。比如客戶端請求發過來的引數為使用者令牌字串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);    }}

ActionFilterAttribute如何應用到action,和前面的ExceptionFilterAttribute類似。

ApiControllerActionInvoker以上述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;    }}

然後註冊至GlobalConfiguration.Configuration.Services中。由於ApiControllerActionInvoker乃是影響全域性的,所以若要對部分action進行包裝處理,應該優先選擇ActionFilterAttribute。 

DelegatingHandler


前面的攔截都發生在請求已被路由至對應的action後發生,有一些情況需要在路由之前就做預先處理,或是在響應流返回過程中做後續處理,這時我們就要用到DelegatingHandler。比如對請求方的身份驗證,當驗證未通過時直接返回錯誤資訊,否則進行後續呼叫。

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);    }}

 參考資料:

轉載請註明原文出處:http://www.cnblogs.com/newton/p/3238082.html


           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述