Замена потока ответов в промежуточном программном обеспечении ASP.NET Core 1.0
Я хочу написать пользовательское промежуточное программное обеспечение в моем проекте ASP.NET Core 1.0, который заменит поток Http Response исходного фреймворка на мой собственный, поэтому я смогу выполнять над ним операции чтения / поиска / записи (первые 2 невозможны на оригинальном поток) в следующем коде, т.е. в действиях или фильтрах.
Я начал со следующего кода:
public class ReplaceStreamMiddleware
{
protected RequestDelegate NextMiddleware;
public ReplaceStreamMiddleware(RequestDelegate next)
{
NextMiddleware = next;
}
public async Task Invoke(HttpContext httpContext)
{
using (var responseStream = new MemoryStream())
{
var fullResponse = httpContext.Response.Body;
httpContext.Response.Body = responseStream;
await NextMiddleware.Invoke(httpContext);
responseStream.Seek(0, SeekOrigin.Begin);
await responseStream.CopyToAsync(fullResponse);
}
}
}
Проблема со следующим кодом заключается в том, что иногда fullResponse
поток уже закрыт на момент вызова await responseStream.CopyToAsync(fullResponse);
поэтому выдает исключение. Не удается получить доступ к закрытому потоку.
Это странное поведение легко наблюдать, когда я загружаю страницу в браузере, а затем обновляю ее до полной загрузки.
Я бы хотел знать:
- почему это происходит?
- как это предотвратить?
- мое решение хорошая идея или есть другой способ заменить поток ответа?
1 ответ
Исключение не исходит от вашего CopyToAsync
, Это от одного из абонентов вашего кода:
Вы не восстанавливаете исходный поток ответов в HttpContext
, Поэтому тот, кто вызывает ваше промежуточное ПО, получит обратно закрытое MemoryStream
,
Вот некоторый рабочий код:
app.Use(async (httpContext, next) =>
{
using (var memoryResponse = new MemoryStream())
{
var originalResponse = httpContext.Response.Body;
try
{
httpContext.Response.Body = memoryResponse;
await next.Invoke();
memoryResponse.Seek(0, SeekOrigin.Begin);
await memoryResponse.CopyToAsync(originalResponse);
}
finally
{
// This is what you're missing
httpContext.Response.Body = originalResponse;
}
}
});
app.Run(async (context) =>
{
context.Response.ContentType = "text/other";
await context.Response.WriteAsync("Hello World!");
});