Ajouter un en-tête personnalisé à toutes les réponses dans Web API

Une question simple, et je suis sûr que sa réponse est simple mais je ne la trouve pas.

J’utilise WebAPI et j’aimerais renvoyer un en-tête personnalisé à toutes les réponses (date / heure du serveur demandée par un développeur à des fins de synchronisation).

Je me bats actuellement pour trouver un exemple clair de la façon dont, dans un endroit (via le global.asax ou un autre emplacement central), je peux obtenir un en-tête personnalisé pour toutes les réponses.


Réponse acceptée, voici mon filtre (à peu près le même) et la ligne que j’ai ajoutée à la fonction Register de la configuration WebApi.

NOTE: Le contenu de DateTime est NodaTime, aucune raison réelle n’était simplement intéressée à le regarder.

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { actionExecutedContext.Response.Content.Headers.Add("ServerTime", Instant.FromDateTimeUtc(DateTime.Now.ToUniversalTime()).ToSsortingng()); } 

Ligne de configuration:

 config.Filters.Add(new ServerTimeHeaderFilter()); 

Pour cela, vous pouvez utiliser un ActionFilter personnalisé ( System.Web.Http.Filters )

 public class AddCustomHeaderFilter : ActionFilterAtsortingbute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { actionExecutedContext.Response.Headers.Add("customHeader", "custom value date time"); } } 

Vous pouvez ensuite appliquer le filtre à toutes les actions de votre contrôleur en ajoutant ceci dans la configuration de Global.asax, par exemple:

 GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderFilter()); 

Vous pouvez également appliquer l’atsortingbut de filtre à l’action souhaitée sans la ligne de cofiguration globale.

La réponse de Julian m’a amené à créer le filtre, mais uniquement à l’aide de l’espace de noms System.Web (v4) et System.Web.Http (v5) (les packages MVC ne faisaient pas partie de ce projet particulier.)

 using System.Web; using System.Web.Http.Filters; ... public class AddCustomHeaderActionFilterAtsortingbute : ActionFilterAtsortingbute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { base.OnActionExecuted(actionExecutedContext); actionExecutedContext.ActionContext.Response.Headers.Add("name", "value"); } } 

Et l’append au global.asax pour l’avoir utilisé sur chaque contrôleur / action

  GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderActionFilterAtsortingbute()); 

Les réponses précédentes à cette question n’abordent pas la procédure à suivre si votre action de contrôleur génère une exception. Il existe deux méthodes de base pour que cela fonctionne:

Ajoutez un filtre d’exception :

 using System.Net; using System.Net.Http; using System.Web.Http.Filters; public class HeaderAdderExceptionFilter : ExceptionFilterAtsortingbute { 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"); } } 

et dans votre configuration WebApi:

 configuration.Filters.Add(new HeaderAdderExceptionFilter()); 

Cette approche fonctionne car le gestionnaire d’exceptions par défaut de WebApi envoie le message HttpResponseMessage créé dans un filtre au lieu de créer le sien.

Remplacez le gestionnaire d’exceptions par défaut:

 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); } } 

et dans votre configuration WebApi:

 configuration.Services.Replace(typeof(IExceptionHandler), new HeaderAdderExceptionHandler()); 

Vous ne pouvez pas utiliser les deux ensemble. Bon, vous le pouvez, mais le gestionnaire ne fera jamais rien car le filtre a déjà converti l’exception en réponse.

Il est très important de noter que, tel qu’écrit, ce code enverra tous les détails de l’exception au client . Vous ne voulez probablement pas faire cela en production, alors vérifiez toutes les surcharges disponibles sur CreateErrorResponse () et choisissez celle qui correspond à vos besoins.

Aucune des deux solutions ci-dessus n’a fonctionné pour moi. Ils ne comstackraient même pas. Voici ce que j’ai fait. Ajoutée:

 filters.Add(new AddCustomHeaderFilter()); 

à la méthode RegisterGlobalFilters(GlobalFilterCollection filters) dans FiltersConfig.cs, puis ajouté

 public class AddCustomHeaderFilter : ActionFilterAtsortingbute { public override void OnActionExecuted(ActionExecutedContext actionExecutedContext) { actionExecutedContext.HttpContext.Response.Headers.Add("ServerTime", DateTime.Now.ToSsortingng()); } } 

Selon mes exigences, une seule ligne de code remplit cette fonction.

 System.Web.HttpContext.Current.Response.Headers.Add("Key", "Value") 

J’ai combiné le chemin normal et le chemin d’exception dans une classe:

 public class CustomHeaderAtsortingbute : FilterAtsortingbute, IActionFilter, IExceptionFilter { private static ssortingng HEADER_KEY { get { return "X-CustomHeader"; } } private static ssortingng HEADER_VALUE { get { return "Custom header value"; } } public Task ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func> 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: ActionFilterAtsortingbute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Response != null) { actionExecutedContext.Response.Content.Headers.Add(HEADER_KEY, HEADER_VALUE); } } } private class CustomHeaderException : ExceptionFilterAtsortingbute { 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); } } } 

Rien de compliqué mais au moins cela me donne un endroit pour contrôler mes en-têtes supplémentaires. Pour l’instant, il ne s’agit que d’un contenu statique, mais vous pouvez toujours le connecter à une sorte de générateur / fabrique de dictionnaires.

J’ai eu le même problème en essayant d’append un nouvel en-tête à l’ensemble du contrôleur, ajoutez simplement “services.AddHttpContextAccessor ();” à startup.cs puis créez votre contrôleur

 public class EnController : Controller{ public EnController(IHttpContextAccessor myHttpAccessor) { myHttpAccessor.HttpContext.Response.Headers.Add("Content-Language", "en-US"); } ... more methods here... }