如何为属性路由创建响应包装器?
How to create a response wrapper for Attribute routing?
使用基于约定的路由时,我可以使用 DelegatingHandler 通过覆盖 SendAsync 方法来创建响应包装器。
DelegatingHandler[] handler = new DelegatingHandler[] {
new ResponseWrapper()
};
var routeHandler = HttpClientFactory.CreatePipeline(new HttpControllerDispatcher(config), handler);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}",
defaults: null,
constraints: null,
handler: routeHandler
);
但是,这种方法不适用于依赖属性路由的方法。在我的例子中,基于约定的路由不适用于所有场景,并且 routeHandler 不适用于基于属性的路由。
如何将响应包装器应用于所有基于属性的路由响应?
我能够添加适用于所有请求的全局消息处理程序。
config.MessageHandlers.Add(new ResponseWrapper());
由于我使用的是 swagger,因此我也不得不忽略 swagger 请求 URI。这是 ResponseWrapper class 的代码,如果它对某人有帮助的话。我还没有机会回顾它,所以肯定会有一些改进......
public class ResponseWrapper : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (request.RequestUri.ToString().Contains("swagger"))
{
return response;
}
return BuildApiResponse(request, response);
}
private static HttpResponseMessage BuildApiResponse(HttpRequestMessage request, HttpResponseMessage response)
{
object content = null;
string errorMessage = null;
response.TryGetContentValue(out content);
if (!response.IsSuccessStatusCode)
{
content = null;
var error = new HttpError(response.Content.ReadAsStringAsync().Result);
var data = (JObject)JsonConvert.DeserializeObject(error.Message);
errorMessage = data["message"].Value<string>();
if (!string.IsNullOrEmpty(error.ExceptionMessage) && string.IsNullOrEmpty(errorMessage))
{
errorMessage = error.ExceptionMessage;
}
}
var newResponse = request.CreateResponse(response.StatusCode, new ApiResponse(response.StatusCode, content, errorMessage));
foreach (var header in response.Headers)
{
newResponse.Headers.Add(header.Key, header.Value);
}
return newResponse;
}
}
使用基于约定的路由时,我可以使用 DelegatingHandler 通过覆盖 SendAsync 方法来创建响应包装器。
DelegatingHandler[] handler = new DelegatingHandler[] {
new ResponseWrapper()
};
var routeHandler = HttpClientFactory.CreatePipeline(new HttpControllerDispatcher(config), handler);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}",
defaults: null,
constraints: null,
handler: routeHandler
);
但是,这种方法不适用于依赖属性路由的方法。在我的例子中,基于约定的路由不适用于所有场景,并且 routeHandler 不适用于基于属性的路由。
如何将响应包装器应用于所有基于属性的路由响应?
我能够添加适用于所有请求的全局消息处理程序。
config.MessageHandlers.Add(new ResponseWrapper());
由于我使用的是 swagger,因此我也不得不忽略 swagger 请求 URI。这是 ResponseWrapper class 的代码,如果它对某人有帮助的话。我还没有机会回顾它,所以肯定会有一些改进......
public class ResponseWrapper : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (request.RequestUri.ToString().Contains("swagger"))
{
return response;
}
return BuildApiResponse(request, response);
}
private static HttpResponseMessage BuildApiResponse(HttpRequestMessage request, HttpResponseMessage response)
{
object content = null;
string errorMessage = null;
response.TryGetContentValue(out content);
if (!response.IsSuccessStatusCode)
{
content = null;
var error = new HttpError(response.Content.ReadAsStringAsync().Result);
var data = (JObject)JsonConvert.DeserializeObject(error.Message);
errorMessage = data["message"].Value<string>();
if (!string.IsNullOrEmpty(error.ExceptionMessage) && string.IsNullOrEmpty(errorMessage))
{
errorMessage = error.ExceptionMessage;
}
}
var newResponse = request.CreateResponse(response.StatusCode, new ApiResponse(response.StatusCode, content, errorMessage));
foreach (var header in response.Headers)
{
newResponse.Headers.Add(header.Key, header.Value);
}
return newResponse;
}
}