Как мне прочитать и обновить тело HttpResponse с помощью PipeWriter? - PullRequest
0 голосов
/ 07 октября 2019

На самом деле это вопрос из двух частей, связанный непосредственно с .net core 3.0 и, в частности, с PipeWriter: 1) Как мне читать в теле HttpResponse? 2) Как я могу обновить HttpResponse? Я задаю оба вопроса, потому что я чувствую, что решение, вероятно, будет включать в себя то же понимание и код.

Ниже показано, как я получил эту работу в .net core 2.2 - обратите внимание, что здесь используются потоки вместо PipeWriter идругие "некрасивые" вещи, связанные с потоками - например. MemoryStream, Seek, StreamReader и т. Д.

public class MyMiddleware
{
    private RequestDelegate Next { get; }
    public MyMiddleware(RequestDelegate next) => Next = next;

    public async Task Invoke(HttpContext context)
    {
        var httpResponse = context.Response;
        var originalBody = httpResponse.Body;
        var newBody = new MemoryStream();
        httpResponse.Body = newBody;

        try
        {
            await Next(context);
        }
        catch (Exception)
        {
            // In this scenario, I would log out the actual error and am returning this "nice" error
            httpResponse.StatusCode = StatusCodes.Status500InternalServerError;
            httpResponse.ContentType = "application/json"; // I'm setting this because I might have a serialized object instead of a plain string
            httpResponse.Body = originalBody;
            await httpResponse.WriteAsync("We're sorry, but something went wrong with your request.");
            return;
        }

        // If everything worked
        newBody.Seek(0, SeekOrigin.Begin);
        var response = new StreamReader(newBody).ReadToEnd(); // This is the only way to read the existing response body
        httpResponse.Body = originalBody;
        await context.Response.WriteAsync(response);
    }
}

Как это будет работать при использовании PipeWriter? Например. Кажется, что работа с каналами вместо базового потока предпочтительнее, но я пока не могу найти примеров того, как использовать это для замены моего кода выше?

Есть ли сценарий, в котором мне нужно ждатьпоток / канал, чтобы закончить запись, прежде чем я смогу прочитать его обратно и / или заменить на новую строку? Я никогда не делал этого лично, но, глядя на примеры PipeReader, кажется, указывает на то, что нужно читать вещи порциями и проверять IsComplete.

1 Ответ

0 голосов
/ 17 октября 2019

Для обновления HttpRepsonse есть

 private  async Task WriteDataToResponseBodyAsync(PipeWriter writer, string jsonValue)
        {
            // use an oversized size guess
            Memory<byte> workspace = writer.GetMemory();
            // write the data to the workspace
            int bytes = Encoding.ASCII.GetBytes(
               jsonValue, workspace.Span);
            // tell the pipe how much of the workspace
            // we actually want to commit
            writer.Advance(bytes);
            // this is **not** the same as Stream.Flush!
            await writer.FlushAsync();
        }
...