Mon exigence: écrire un middleware qui filtre tous les "mauvais mots" d'une réponse provenant d'un autre middleware ultérieur (par exemple Mvc).
Le problème: le streaming de la réponse. Donc, quand nous revenons à notre FilterBadWordsMiddleware
à partir d'un middleware suivant, qui a déjà écrit dans la réponse, nous sommes trop en retard pour le parti ... car la réponse a déjà commencé à envoyer, ce qui donne l'erreur bien connue response has already started
...
Donc, puisque c'est une exigence dans de nombreuses situations différentes - comment y faire face?
Remplacez un flux de réponse par MemoryStream
pour empêcher son envoi. Renvoyez le flux d'origine une fois la réponse modifiée:
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);
}
}
C'est une solution de contournement et cela peut causer des problèmes de performances. J'espère voir une meilleure solution ici.
Une version plus simple basée sur le code que j'ai utilisé:
/// <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;
}
}