在 NetCore Web 应用程序中异步正确读取 HttpRequest 正文

Tom*_*ica 6 c# iis-express asp.net-core

我正在尝试像string在 C# 中一样获取 POST 请求正文。我是这样写的:

    protected async Task<string> readBodyAsync(HttpRequest req)
    {
        // turns out this is always false...
        if(req.Body.CanSeek)
            req.Body.Seek(0, SeekOrigin.Begin);
        // string buffer
        string str = "";
        // I wouldn't expect to have to do this in 2017
        byte[] buffer = new byte[255];
        int offset = 0;
        int lastLen = 0;
        // On second iteration, CanRead is true but ReadAsync throws System.ArgumentException
        while ( req.Body.CanRead && (lastLen = await req.Body.ReadAsync(buffer, offset, buffer.Length))!=0)
        {
            offset += lastLen;
            // This also adds all the \0 characters from the byte buffer, instead of treating like
            // normal C string
            str += System.Text.Encoding.UTF8.GetString(buffer);
        }
        // This never executes due to the System.ArgumentException
        return str;
    }
Run Code Online (Sandbox Code Playgroud)

问题:

  • 在第二次迭代中,req.Body.CanReadis true,但调用 read 原因System.ArgumentException
  • 已经在第一次迭代时读取了所有内容。不仅如此,System.Text.Encoding.UTF8.GetString还将缓冲区中所有剩余的零添加到字符串中。

我处理这样的请求:

    app.Run(async (context) =>
    {
        if(context.Request.Method.ToLower() == "post" && context.Request.Path.ToString().EndsWith("/ajax"))
        {
            string requestText = await readBodyAsync(context.Request);
            /// Parsing of the JSON in requestText should be here
               // but I can't get that text
            await context.Response.WriteAsync("{data: \"AJAX TEST\"}");
        }
        else
        {
            await context.Response.WriteAsync("Hello World! And go away. Invalid request.");
        }  
    });
Run Code Online (Sandbox Code Playgroud)

Tim*_*ria 12

    private async Task<string> StreamToStringAsync(HttpRequest request)
    {
        using (var sr = new StreamReader(request.Body))
        {
            return await sr.ReadToEndAsync();
        }
    }
Run Code Online (Sandbox Code Playgroud)


Tom*_*ica 4

显然还有一种更优雅的方法也有效:

    protected async Task<string> readBodyAsync(HttpRequest req)
    {
        StreamReader r = new StreamReader(req.Body);
        return await r.ReadToEndAsync();
    }
Run Code Online (Sandbox Code Playgroud)

  • `StreamReader` 在使用后应该被丢弃。请注意,处置 StreamReader 也会关闭其底层流。 (3认同)