ASP.NET Web API之消息[攔截]處理
標(biāo)題相當(dāng)難取,內(nèi)容也許和您想的不一樣,而且網(wǎng)上已經(jīng)有很多這方面的資料了,我不過是在實踐過程中作下記錄。廢話少說,直接開始。
Exception
當(dāng)服務(wù)端拋出未處理異常時,most exceptions are translated into an HTTP response with status code 500, Internal Server Error.當(dāng)然我們也可以拋出一個特殊的異常HttpResponseException,它將被直接寫入響應(yīng)流,而不會被轉(zhuǎn)成500。
public Product GetProduct(int id) { Product item = repository.Get(id); if (item == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } return item; }
有時要對服務(wù)端異常做一封裝,以便對客戶端隱藏具體細(xì)節(jié),或者統(tǒng)一格式,那么可創(chuàng)建一繼承自System.Web.Http.Filters.ExceptionFilterAttribute的特性,如下:
public class APIExceptionFilterAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { //業(yè)務(wù)異常 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應(yīng)用到action或controller,或者GlobalConfiguration.Configuration.Filters.Add(new APIExceptionFilterAttribute());使之應(yīng)用于所有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());)。當(dāng)然,在上述代碼中,我們也可以在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.
.net還內(nèi)置了HttpError這個類,若想返回格式化對象(如json、xml等),用起來更方便。The HttpError class is actually a key-value collection (it derives from Dictionary<string, object>), so you can add your own key-value pairs.
以上知識主要來自Exception Handling in ASP.NET Web API。
ActionFilterAttribute、ApiControllerActionInvoker
有時要在action執(zhí)行前后做額外處理,那么ActionFilterAttribute和ApiControllerActionInvoker就派上用場了。比如客戶端請求發(fā)過來的參數(shù)為用戶令牌字符串token,我們要在action執(zhí)行之前先將其轉(zhuǎn)為action參數(shù)列表中對應(yīng)的用戶編號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)) { //參數(shù)列表中不存在userid,寫入日志 //…… var response = new HttpResponseMessage(); response.Content = new StringContent("用戶信息轉(zhuǎn)換異常."); response.StatusCode = HttpStatusCode.Conflict; //在這里為了不繼續(xù)走流程,要throw出來,才會立馬返回到客戶端 throw new HttpResponseException(response); } //userid系統(tǒng)賦值 actionContext.ActionArguments[UserID] = actionContext.Request.Properties["shumi_userid"]; base.OnActionExecuting(actionContext); } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { base.OnActionExecuted(actionExecutedContext); } }
ActionFilterAttribute如何應(yīng)用到action,和前面的ExceptionFilterAttribute類似。
ApiControllerActionInvoker以上述Exception為例:
public class ServerAPIControllerActionInvoker : ApiControllerActionInvoker { public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken) { //對actionContext做一些預(yù)處理 //…… 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進(jìn)行包裝處理,應(yīng)該優(yōu)先選擇ActionFilterAttribute。另外ApiControllerActionInvoker在ActionFilterAttribute之前處理。
DelegatingHandler
前面的攔截都發(fā)生在請求已被路由至對應(yīng)的action后發(fā)生,有一些情況需要在路由之前就做預(yù)先處理,或是在響應(yīng)流返回過程中做后續(xù)處理,這時我們就要用到DelegatingHandler。比如對請求方的身份驗證,當(dāng)驗證未通過時直接返回錯誤信息,否則進(jìn)行后續(xù)調(diào)用。
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("請求參數(shù)有重復(fù).", 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用于服務(wù)端,其實DelegatingHandler也可以在發(fā)起調(diào)用時使用,HttpClient可接收一個DelegatingHandler作為消息處理器。
參考資料:
- ASP.NET Web API Exception Handling
- Implementing message handlers to track your ASP.NET Web API usage
- MVC4 WebAPI(二)——Web API工作方式
- Asp.Net MVC及Web API框架配置會碰到的幾個問題及解決方案
- HTTP Message Handlers in ASP.NET Web API
轉(zhuǎn)載請注明原文出處:http://www.rzrgm.cn/newton/p/3238082.html

浙公網(wǎng)安備 33010602011771號