将自定义标题添加到Web API中的所有响应
简单的问题,我相信它有一个简单的答案,但我找不到它。
我正在使用WebAPI,并且想要将自定义标题发送回所有响应(由开发人员为同步目的而请求的服务器date/时间)。
我目前正在努力寻找一个清晰的例子,在一个地方(通过global.asax或另一个中心位置),我可以得到一个自定义标题出现所有的响应。
接受的答案,这里是我的filter(几乎相同)和我添加到WebApiconfiguration的注册function的行。
注意:DateTime的东西是NodaTime,没有真正的理由只是有兴趣的看着它。
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { actionExecutedContext.Response.Content.Headers.Add("ServerTime", Instant.FromDateTimeUtc(DateTime.Now.ToUniversalTime()).ToString()); }
configuration线:
config.Filters.Add(new ServerTimeHeaderFilter());
为此,您可以使用自定义的ActionFilter( System.Web.Http.Filters
)
public class AddCustomHeaderFilter : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { actionExecutedContext.Response.Headers.Add("customHeader", "custom value date time"); } }
然后,您可以通过在Global.asax中的configuration中添加此filter来将filter应用于所有控制器的操作,例如:
GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderFilter());
您也可以将filter属性应用于所需的操作,而不使用全局configuration行。
此问题的以前的答案不解决如果您的控制器操作引发exception如何处理。 有两个基本的方法来实现它的工作:
添加一个例外filter :
using System.Net; using System.Net.Http; using System.Web.Http.Filters; public class HeaderAdderExceptionFilter : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { if (context.Response == null) context.Response = context.Request.CreateErrorResponse( HttpStatusCode.InternalServerError, context.Exception); context.Response.Content.Headers.Add("header", "value"); } }
并在您的WebApi设置:
configuration.Filters.Add(new HeaderAdderExceptionFilter());
这种方法是有效的,因为WebApi的默认exception处理程序将发送在filter中创build的HttpResponseMessage,而不是构build它自己的。
replace默认的exception处理程序:
using System.Net; using System.Net.Http; using System.Web.Http.ExceptionHandling; using System.Web.Http.Results; public class HeaderAdderExceptionHandler : ExceptionHandler { public override void Handle(ExceptionHandlerContext context) { HttpResponseMessage response = context.Request.CreateErrorResponse( HttpStatusCode.InternalServerError, context.Exception); response.Headers.Add("header", "value"); context.Result = new ResponseMessageResult(response); } }
并在您的WebApi设置:
configuration.Services.Replace(typeof(IExceptionHandler), new HeaderAdderExceptionHandler());
你不能同时使用这两个。 好的,你可以,但是处理程序永远不会做任何事情,因为filter已经将exception转换为响应。
需要注意的是, 按照书面forms,此代码将向客户端发送所有exception详细信息 。 您可能不想在生产环境中执行此操作,因此请检查CreateErrorResponse()上的所有可用重载,然后select适合您的需求的重载。
Julian的回答让我不得不创buildfilter,但只使用System.Web(v4)和System.Web.Http(v5)命名空间(MVC包不是这个特定项目的一部分)。
using System.Web; using System.Web.Http.Filters; ... public class AddCustomHeaderActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { base.OnActionExecuted(actionExecutedContext); actionExecutedContext.ActionContext.Response.Headers.Add("name", "value"); } }
并将其添加到global.asax以使其用于每个控制器/操作
GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderActionFilterAttribute());
上述两种解决scheme都不适合我。 他们甚至不会编译。 这是我做的。 添加:
filters.Add(new AddCustomHeaderFilter());
到FiltersConfig.cs中的RegisterGlobalFilters(GlobalFilterCollection filters)
方法,然后添加
public class AddCustomHeaderFilter : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext actionExecutedContext) { actionExecutedContext.HttpContext.Response.Headers.Add("ServerTime", DateTime.Now.ToString()); } }
我在一个类中组合了常规和exceptionpath:
public class CustomHeaderAttribute : FilterAttribute, IActionFilter, IExceptionFilter { private static string HEADER_KEY { get { return "X-CustomHeader"; } } private static string HEADER_VALUE { get { return "Custom header value"; } } public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { return (new CustomHeaderAction() as IActionFilter).ExecuteActionFilterAsync(actionContext, cancellationToken, continuation); } public Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) { return (new CustomHeaderException() as IExceptionFilter).ExecuteExceptionFilterAsync(actionExecutedContext, cancellationToken); } private class CustomHeaderAction: ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Response != null) { actionExecutedContext.Response.Content.Headers.Add(HEADER_KEY, HEADER_VALUE); } } } private class CustomHeaderException : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { if (context.Response == null) { context.Response = context.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, context.Exception); } context.Response.Content.Headers.Add(HEADER_KEY, HEADER_VALUE); } } }
没有什么奇特的,但至less它给了我一个地方来控制我的额外的标题。 现在,它只是静态的内容,但你总是可以挂钩到某种字典发生器/工厂。