请任何人给我一些想法,以下三个模块在asp.net Web API 2.1中一起工作
> Owin中间件
> HttpMessageHandler(或DelegatingHandler)
> ExceptionHandler
我想要做的是开发和提供一个不变格式的json数据的web api,意味着如果实际的数据是
- {"Id":1,"UserName":"abc","Email":"abc@xyz.com"}
然后我喜欢提供json
- {__d:{"Id":1,"Email":"abc@xyz.com"},code:200,somekey: "somevalue"}
为此,我尝试使用自定义ActionFilterAttribute,但我觉得(仍然不能确认),如果代码遇到异常,这样做不能提供类似的格式数据
请建议我最好的方向.
这是我的简短的自定义属性代码片段.还建议我是自定义属性是好的目的
- [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,Inherited = true,AllowMultiple = false)]
- public class ResponseNormalizationAttribute : ActionFilterAttribute
- {
- public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
- {
- base.OnActionExecuted(actionExecutedContext);
- var response = actionExecutedContext.Response;
- object contentValue;
- if (response.TryGetContentValue(out contentValue))
- {
- var nval = new { data=contentValue,status = 200 };
- var newResponse = new HttpResponseMessage { Content = new ObjectContent(nval.GetType(),nval,new JsonMediaTypeFormatter()) };
- newResponse.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
- actionContext.Response = newResponse;
- }
- }
- }
解决方法
如果您不使用Owin中间件,则可以全局包装所有响应,以便使用委托处理程序返回常量格式的json数据.
编写一个继承自DelegatingHandler的自定义处理程序:
- public class ApiResponseHandler : DelegatingHandler
- {
- protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
- {
- var response = await base.SendAsync(request,cancellationToken);
- return BuildResponse(request,response);
- }
- private static HttpResponseMessage BuildResponse(HttpRequestMessage request,HttpResponseMessage response)
- {
- object content;
- string errorMessage = null;
- if (response.TryGetContentValue(out content) && !response.IsSuccessStatusCode)
- {
- HttpError error = content as HttpError;
- if (error != null)
- {
- content = null;
- errorMessage = error.Message;
- }
- }
- var newResponse = request.CreateResponse(response.StatusCode,new ApiResponse((int)response.StatusCode,content,errorMessage));
- foreach (var header in response.Headers)
- {
- newResponse.Headers.Add(header.Key,header.Value);
- }
- return newResponse;
- }
- }
- //ApiResponse is your constant json response
- public class ApiResponse
- {
- public ApiResponse(int statusCode,object content,string errorMsg)
- {
- Code = statusCode;
- Content = content;
- Error = errorMsg;
- Id = Guid.NewGuid().ToString();
- }
- public string Error { get; set; }
- //your actual data is mapped to the Content property
- public object Content { get; set; }
- public int Code { get; private set; }
- public string Id { get; set; }
- }
在WebApiConfig.cs中注册处理程序:
- public static void Register(HttpConfiguration config)
- {
- // Web API routes
- config.MapHttpAttributeRoutes();
- ...
- config.MessageHandlers.Add(new ApiResponseHandler());
- config.Routes.MapHttpRoute(
- name: "DefaultApi",routeTemplate: "{controller}/{id}",defaults: new { id = RouteParameter.Optional }
- );
- ...
- }
我在SO中发布了一个类似的答案,但这是在.NET Core中,并被实现为一个OWIN中间件(因为DelegatingHandler在.NET Core中). How can I wrap Web API responses(in .net core) for consistency?