Как напрямую установить тело ответа для потока файлов в промежуточном программном обеспечении ASP.NET Core? - PullRequest
0 голосов
/ 01 ноября 2019

Пример кода ниже для записи потока файлов в Response.Body в промежуточном программном обеспечении ASP.NET Core не работает (выдает пустой ответ):

public Task Invoke(HttpContext context)
{
    context.Response.ContentType = "text/plain";

    using (var fs = new FileStream("/valid-path-to-file-on-server.txt", FileMode.Open)
    using (var sr = new StreamReader(fs))
    {
        context.Response.Body = sr.BaseStream;
    }

    return Task.CompletedTask;
}

Любые идеи, что может быть не так с этим подходомпрямой настройки context.Response.Body?

Примечание: любое следующее промежуточное ПО в конвейере пропускается для дальнейшей обработки.

Обновление (другой пример): простой MemoryStream назначение также не работает (пустой ответ):

context.Response.Body = new MemoryStream(Encoding.UTF8.GetBytes(DateTime.Now.ToString()));

1 Ответ

1 голос
/ 04 ноября 2019
  1. Нет. Вы никогда не можете сделать это напрямую.

    Обратите внимание, что context.Response.Body является ссылкой на объект (HttpResponseStream), который инициализирован до , он становитсядоступно в HttpContext. Предполагается, что все байты записаны в этот оригинальный поток. Если вы измените Body на ссылку ( указывает на ) нового объекта потока на context.Response.Body = a_new_Stream, исходный Stream вообще не изменится.

    Кроме того, если вы посмотритев исходный код ASP.NET Core вы всегда найдете команду скопировать поток-обертку в исходный основной поток в конце, а не с простой заменой (если только они не тестируются модулем сиздевательский поток). Например, промежуточное программное обеспечение SPA Prerendering , исходный код:

        finally
        {
            context.Response.Body = originalResponseStream;
            ...
    

    и исходный код ResponseCachingMiddleware:

        public async Task Invoke(HttpContext httpContext)
        {
            ...
            finally
            {
                UnshimResponseStream(context);
            }
            ...
        }
    
        internal static void UnshimResponseStream(ResponseCachingContext context)
        {
            // Unshim response stream
            context.HttpContext.Response.Body = context.OriginalResponseStream;
    
            // Remove IResponseCachingFeature
            RemoveResponseCachingFeature(context.HttpContext);
        }
    
  2. Как обходной путь, вы можете скопировать байтов в необработанный поток, как показано ниже:

    public async Task Invoke(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        using (var fs = new FileStream("valid-path-to-file-on-server.txt", FileMode.Open))
        {
            await fs.CopyToAsync(context.Response.Body);
        }
    }
    

    Или, если вам нравится угон необработанный HttpResponseStream с вашей собственной оберткой потока:

        var originalBody = HttpContext.Response.Body;
        var ms = new MemoryStream();
        HttpContext.Response.Body = ms;
        try
        {
            await next();
            HttpContext.Response.Body = originalBody;
            ms.Seek(0, SeekOrigin.Begin);
            await ms.CopyToAsync(HttpContext.Response.Body);
        }
        finally
        {
            response.Body = originalBody;
        }
    
...