TL; DR質問:すべてのリクエストボディをコピーせずに、ASP.NET Coreの既存のExceptionTelemetryインスタンスにリクエストボディを取得する方法はありますか?ASP.NET InsightのExceptTelemetryをASP.NETコアのリクエストボディで強化する方法
私はアプリケーションの洞察のための例外テレメトリにリクエストボディを含めることができます。私。私は、例外が発生したときにのみ要求をしたい。
ASP.NET CoreとApplication Insightsの両方のドキュメントを参照すると、遠隔測定を豊かにする「正しい」方法がTelemetryProcessorsまたはTelemetryInitializersを使用しているように思われるため、カスタムテレメトリイニシャライザでリクエスト本体を取得してみましたリクエストボディストリームは、読みたいときに閉じられ/破棄されます(App Insightテレメトリ初期化ツールが実行されているときに、すでに巻き戻しが行われているため、巻き戻しは役立ちません)。
私はコピーが要求ストリームミドルウェア持つことによってそれを解決することになった:
public async Task Invoke(HttpContext context)
{
var stream = context.Request.Body;
try
{
using (var buffer = new MemoryStream())
{
// Copy the request stream and rewind the copy
await stream.CopyToAsync(buffer);
buffer.Position = 0L;
// Create another copy and rewind both
var otherBuffer = new MemoryStream();
await buffer.CopyToAsync(otherBuffer);
buffer.Position = 0L;
otherBuffer.Position = 0L;
// Replace the request stream by the first copy
context.Request.Body = buffer;
// Put a separate copy in items collection for other things to use
context.Items["RequestStreamCopy"] = otherBuffer;
context.Response.RegisterForDispose(otherBuffer);
await next(context);
}
}
finally
{
context.Request.Body = stream;
}
}
そして、私の初期化子:
public AiExceptionInitializer(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException("httpContextAccessor");
}
public void Initialize(ITelemetry telemetry)
{
var context = this.httpContextAccessor.HttpContext;
if (context == null)
{
return;
}
lock (context)
{
var request = context.Features.Get<RequestTelemetry>();
if (request == null)
{
return;
}
this.OnInitializeTelemetry(context, request, telemetry);
}
}
protected void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
{
if (telemetry is ExceptionTelemetry exceptionTelemetry)
{
var stream = platformContext.Items["RequestStreamCopy"] as MemoryStream;
try
{
if (stream?.Length <= 0)
{
return;
}
// Rewind the stream position just to be on the safe side
stream.Position = 0L;
using (var reader = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
{
string requestBody = reader.ReadToEnd();
exceptionTelemetry.Properties.Add("HttpRequestBody", requestBody);
}
}
finally
{
if (stream != null)
{
// Rewind the stream for others to use.
stream.Position = 0L;
}
}
}
}
しかし、これはそれぞれの要求ストリーム(2回)をコピーすることを要求では、それが失敗で使用されているだけでは、私にとってはかなり非効率的です。 このようなことをする他の方法があるのだろうかと思っています。ここでは、すべての要求のストリームをコピーして、失敗したものをシリアライズする必要はありません。
新しいExceptionTelemetryインスタンスを作成するミドルウェアを作成することはできますが、私が知っている限り(私は間違っているかもしれません)、アプリケーション・インサイトで2つの例外インスタンス(つまり、私と私の必要とする追加されたプロパティを持つただ一つの例外の代わりに、AI拡張によって生成されたもの)。
は、私はおそらく、代わりの機能ではわからないストリームを入れることができますが、それは問題には無関係であるI推測。 –
例外追跡ミドルウェアを書くことは可能ですが、それを使って要求の本文をコンテキストに取り込むだけですか? (言い換え:カスタム例外追跡ミドルウェアで依頼主体が依然として利用可能かどうか)はいの場合、この本体をその例外ミドルウェア内のコンテキストに書き込むことができます。その後、遠隔測定初期化子では、本体が存在しないかどうかを確認できますコンテキスト内でnullを返し、それを使用して例外プロパティを設定します。したがって、ミドルウェアをAIミドルウェアの前に注文することによって、イニシャライザが実行される前にコンテキストを生成することができます。 –
完全にはわかりませんが、私は試してみてお知らせします。 –