Добавить пользовательский заголовок для всех ответов в Web API
Простой вопрос, и я уверен, что он имеет простой ответ, но я не могу его найти.
Я использую WebAPI, и я хотел бы отправить обратно настраиваемый заголовок для всех ответов (дата/время сервера, запрошенное разработчиком для синхронизации).
В настоящее время я пытаюсь найти ясный пример того, как в одном месте (через global.asax или в другом центральном месте) я могу получить настраиваемый заголовок для всех ответов.
Ответ принят, вот мой фильтр (почти такой же) и строка, добавленная в функцию Register конфигурации WebApi.
ПРИМЕЧАНИЕ. Материал DateTime - это NodaTime, и никакая реальная причина просто не заинтересована в его просмотре.
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Content.Headers.Add("ServerTime", Instant.FromDateTimeUtc(DateTime.Now.ToUniversalTime()).ToString());
}
Конфигурация:
config.Filters.Add(new ServerTimeHeaderFilter());
Ответы
Ответ 1
Для этого вы можете использовать пользовательский 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, например:
GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderFilter());
Вы также можете применить атрибут фильтра к действию, которое вы хотите, без линии глобальной конфигурации.
Ответ 2
Ни один из двух вышеперечисленных решений не работал у меня. Они даже не собирались. Вот что я сделал. Добавлено:
filters.Add(new AddCustomHeaderFilter());
to RegisterGlobalFilters(GlobalFilterCollection filters)
в FiltersConfig.cs, а затем добавлен
public class AddCustomHeaderFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
actionExecutedContext.HttpContext.Response.Headers.Add("ServerTime", DateTime.Now.ToString());
}
}
Ответ 3
Джулианский ответ заставил меня создать фильтр, но только с использованием пространства имен 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());
Ответ 4
Предыдущие ответы на этот вопрос не касаются того, что делать, если действие вашего контроллера вызывает исключение. Есть два основных способа заставить это работать:
Добавить фильтр исключений:
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 отправит HttpResponseMessage, созданный в фильтре, вместо того, чтобы создавать свои собственные.
Заменить обработчик исключений по умолчанию:
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());
Вы не можете использовать оба эти метода вместе. Хорошо, ну, вы можете, но обработчик никогда ничего не сделает, потому что фильтр уже преобразовал исключение в ответ.
Самое главное отметить, что, как написано, этот код отправит все детали исключения клиенту. Вероятно, вы не хотите делать это на производстве, поэтому проверьте все доступные перегрузки на CreateErrorResponse() и выберите, какой из них подходит вашим потребностям.
Ответ 5
Согласно моему требованию, ниже одной строки кода служит цели.
System.Web.HttpContext.Current.Response.Headers.Add("Key", "Value")
Ответ 6
Я объединил обычный путь и исключение в одном классе:
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);
}
}
}
Ничего необычного, но по крайней мере это дает мне одно место для контроля над моими дополнительными заголовками. Пока что это просто статический контент, но вы всегда можете подключить его к некоторому генератору словарей/ factory.
Ответ 7
У меня возникла та же проблема при попытке добавить новый заголовок ко всему контроллеру, просто добавьте "services.AddHttpContextAccessor();" в startup.cs, затем создайте свой контроллер
public class EnController : Controller{
public EnController(IHttpContextAccessor myHttpAccessor)
{
myHttpAccessor.HttpContext.Response.Headers.Add("Content-Language", "en-US");
}
... more methods here...
}
Ответ 8
Это может быть легко сделано обработчиком сообщений, он будет обрабатывать как нормальный ответ, так и исключительный случай.
public class CustomHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// add header to request if you want
var response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("cutomKey", "cutomValue");
return response;
}
}
Добавьте его в конфиг
config.MessageHandlers.Add(new CustomHeaderHandler());