C# – How to get the http body into a String in dot net core 2.0 using ReadAsync

.net core.net-core-2.0asp.net-corecstream

I'm receiving and http post request, with raw body, and I'm trying to read the http body Stream into a String.

I'm using the basic Hello World web project generated by the dotnet web command. According to the documentation:

In the .NET Framework 4 and earlier versions, you have to use methods
such as BeginRead and EndRead to implement asynchronous I/O
operations. These methods are still available in the .NET Framework
4.5 to support legacy code; however, the new async methods, such as ReadAsync, WriteAsync, CopyToAsync, and FlushAsync, help you implement
asynchronous I/O operations more easily.

So I tried with the ReadAsync method with something like this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // _controller = controller;
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.Run(async (context) =>
    {

        using (Stream Body = context.Request.Body) {
            byte[] result;
            result = new byte[context.Request.Body.Length];
            await context.Request.Body.ReadAsync(result, 0, (int)context.Request.Body.Length);

            String body = System.Text.Encoding.UTF8.GetString(result).TrimEnd('\0');

            _log.LogInformation($"Body: {body}");
        }
        await context.Response.WriteAsync("Hello World!");
    });
}

But I'm getting the following error:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost1
Request starting HTTP/1.1 POST http://localhost:5000/json/testing?id=2342&name=sas application/json
82 fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HL7ISBH941G6", Request id "0HL7ISBH941G6:00000001": An unhandled exception was thrown by the
application. System.NotSupportedException: Specified method is not
supported. at
Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.FrameRequestStream.get_Length()
at mtss.ws.Startup.<b__4_0>d.MoveNext() in
/home/inspiron/devel/apps/dotnet/mtss-ws/Startup.cs:line 47

— update

I could get something working setting the size of the buffer to Int16.MaxValue, but that way I can't read bodies larger that 32k.

Best Answer

I found this question at SO that helped my find the following solution:

app.Run(async (context) =>
{

    string body = new StreamReader(context.Request.Body).ReadToEnd();
    _log.LogInformation($"Body: {body}");
    _log.LogInformation($"Body.Length: {body.Length}");

    await context.Response.WriteAsync("Hello World!");
});

and the async version is pretty much alike:

    string body = await new StreamReader(context.Request.Body).ReadToEndAsync();

Not sure if this is the best way to do it...