Стратегия и как создавать каналы запросов и ответов в промежуточном программном обеспечении .net core 3.0 - PullRequest
0 голосов
/ 08 апреля 2019

Я занимаюсь разработкой промежуточного программного обеспечения ядра .net (api) и собираюсь использовать каналы со следующим потоком. Может кто-нибудь сказать мне, что это хороший подход и соответствует передовым методам, или я должен использовать другую стратегию.

  1. Запрос приходит к API
  2. Канал авторизации подтверждает запрос.
  3. Канал запроса регистрирует запрос в БД.
  4. Запрос идет в API и выполняет действие и возвратрезультат.
  5. Канал ответа получает ответ, регистрируется в db и возвращает результат клиенту.

Я знаю, что мы можем читать поток только по времени (точка 3), но я понялэто уже, и после прочтения я снова прикрепил его к потоку запросов.

Итак, путаница - это где написать ответ?В апи?или в отдельном канале.

Если я делаю это в отдельном канале, тогда я обрабатываю свой ответ два раза (один создает ответ в API, второй читает ответ в отдельном канале), что является ударом по производительности.

Могу ли я передать данные из точек с 4 по 5, например, из API в мой канал, и оттуда этот ответ должен быть добавлен в поток ответов, и если он верный, то как я могу передать данные из API в канал?

1 Ответ

0 голосов
/ 09 апреля 2019

Да, поток ответов может быть прочитан только один раз. Вы можете использовать MemoryStream для загрузки ответа, ссылочный товар :

  • Сначала прочитайте запрос и отформатируйте его в строку.

  • Затем создайте фиктивный MemoryStream для загрузки нового ответа.

  • Затем подождите, пока сервер вернет ответ.

  • Наконец, скопируйте фиктивный MemoryStream (содержащий фактический ответ) в исходный поток, который возвращается клиенту.

Пример кода:

public class RequestResponseLoggingMiddleware
{
    private readonly RequestDelegate _next;

    public RequestResponseLoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        //First, get the incoming request
        var request = await FormatRequest(context.Request);

        //Copy a pointer to the original response body stream
        var originalBodyStream = context.Response.Body;

        //Create a new memory stream...
        using (var responseBody = new MemoryStream())
        {
            //...and use that for the temporary response body
            context.Response.Body = responseBody;

            //Continue down the Middleware pipeline, eventually returning to this class
            await _next(context);

            //Format the response from the server
            var response = await FormatResponse(context.Response);

            //TODO: Save log to chosen datastore

            //Copy the contents of the new memory stream (which contains the response) to the original stream, which is then returned to the client.
            await responseBody.CopyToAsync(originalBodyStream);
        }
    }

    private async Task<string> FormatRequest(HttpRequest request)
    {
        var body = request.Body;

        //This line allows us to set the reader for the request back at the beginning of its stream.
        request.EnableRewind();

        //We now need to read the request stream.  First, we create a new byte[] with the same length as the request stream...
        var buffer = new byte[Convert.ToInt32(request.ContentLength)];

        //...Then we copy the entire request stream into the new buffer.
        await request.Body.ReadAsync(buffer, 0, buffer.Length);

        //We convert the byte[] into a string using UTF8 encoding...
        var bodyAsText = Encoding.UTF8.GetString(buffer);

        //..and finally, assign the read body back to the request body, which is allowed because of EnableRewind()
        request.Body = body;

        return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
    }

    private async Task<string> FormatResponse(HttpResponse response)
    {
        //We need to read the response stream from the beginning...
        response.Body.Seek(0, SeekOrigin.Begin);

        //...and copy it into a string
        string text = await new StreamReader(response.Body).ReadToEndAsync();

        //We need to reset the reader for the response so that the client can read it.
        response.Body.Seek(0, SeekOrigin.Begin);

        //Return the string for the response, including the status code (e.g. 200, 404, 401, etc.)
        return $"{response.StatusCode}: {text}";
    }
}

И зарегистрируйте промежуточное ПО:

app.UseMiddleware<RequestResponseLoggingMiddleware>();
...