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

14.7k views Asked by At

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.

2

There are 2 answers

0
opensas On

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...

0
gcamp806 On

I, too, had issues with ReadAsync stopping short of the full content. My solution is similar to the one offered by opensas, however, I did it with a "using" so the StreamReader's dispose method would be called automatically. I also added the UTF8 encoding option to the StreamReader.

using StreamReader reader = new StreamReader (Request.Body, Encoding.UTF8);
string body = await reader.ReadToEndAsync ();