簡単な質問です。答えは簡単ですが、見つけられません。
WebAPIを使用していますが、カスタムヘッダーをすべての応答(同期のために開発者から要求されたサーバーの日付/時刻)に送り返したいと思います。
現在、ある場所(global.asaxまたは別の中央の場所)で、すべての応答にカスタムヘッダーを表示する方法の明確な例を見つけるのに苦労しています。
回答は受け入れられました。ここに私のフィルター(ほぼ同じ)と、WebApi構成のRegister関数に追加された行があります。
注: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());
そのためには、カスタム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());
filtersConfig.csのRegisterGlobalFilters(GlobalFilterCollection filters)
メソッドに追加してから追加
public class AddCustomHeaderFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
actionExecutedContext.HttpContext.Response.Headers.Add("ServerTime", DateTime.Now.ToString());
}
}
この質問に対するこれまでの回答では、コントローラーアクションが例外をスローした場合の対処方法を説明していません。それを機能させるには、2つの基本的な方法があります。
例外フィルターを追加:
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()で利用可能なすべてのオーバーロードをチェックアウトし、ニーズに合ったものを選択してください。
Julianの答えは、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());
私の要件によると、以下の1行のコードが目的を果たします。
System.Web.HttpContext.Current.Response.Headers.Add("Key", "Value")
メッセージハンドラーで簡単に実行でき、OK応答と例外ケースの両方を処理します。
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());
1つのクラスに通常のパスと例外のパスを組み合わせました。
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);
}
}
}
派手なことは何もありませんが、少なくとも、追加のヘッダーを制御する1つの場所が得られます。今のところそれは単なる静的コンテンツですが、いつでも何らかの種類の辞書ジェネレーター/ファクトリーに接続できます。
コントローラ全体に新しいヘッダーを追加しようとしたときに同じ問題が発生しました。「services.AddHttpContextAccessor();」を追加するだけですstartup.csに移動して、コントローラーを作成します
public class EnController : Controller{
public EnController(IHttpContextAccessor myHttpAccessor)
{
myHttpAccessor.HttpContext.Response.Headers.Add("Content-Language", "en-US");
}
... more methods here...
}