私の要件:後続の別のミドルウェア(Mvcなど)からの応答からすべての「悪い言葉」をフィルタリングするミドルウェアを作成します。
問題:応答のストリーミング。したがって、すでに応答に書き込んでいる後続のミドルウェアからFilterBadWordsMiddleware
に戻ると、パーティーには遅すぎます...応答がすでに送信を開始しているため、既知のエラーresponse has already started
...
これは多くのさまざまな状況での要件なので、どのように対処すればよいでしょうか?
送信を防ぐために、応答ストリームをMemoryStream
に置き換えます。応答が変更された後、元のストリームを返します。
public class EditResponseMiddleware
{
private readonly RequestDelegate _next;
public EditResponseMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var originBody = context.Response.Body;
var newBody = new MemoryStream();
context.Response.Body = newBody;
await _next(context);
newBody.Seek(0, SeekOrigin.Begin);
string json = new StreamReader(newBody).ReadToEnd();
context.Response.Body = originBody;
await context.Response.WriteAsync(modifiedJson);
}
}
これは回避策であり、パフォーマンスの問題を引き起こす可能性があります。私はここでより良い解決策を見たいと思っています。
私が使用したコードに基づく簡単なバージョン:
/// <summary>
/// The middleware Invoke method.
/// </summary>
/// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
/// <returns>A Task to support async calls.</returns>
public async Task Invoke(HttpContext httpContext)
{
var originBody = httpContext.Response.Body;
try
{
var memStream = new MemoryStream();
httpContext.Response.Body = memStream;
await _next(httpContext).ConfigureAwait(false);
memStream.Position = 0;
var responseBody = new StreamReader(memStream).ReadToEnd();
//Custom logic to modify response
responseBody = responseBody.Replace("hello", "hi", StringComparison.InvariantCultureIgnoreCase);
var memoryStreamModified = new MemoryStream();
var sw = new StreamWriter(memoryStreamModified);
sw.Write(responseBody);
sw.Flush();
memoryStreamModified.Position = 0;
await memoryStreamModified.CopyToAsync(originBody).ConfigureAwait(false);
}
finally
{
httpContext.Response.Body = originBody;
}
}