41

In the HttpApplication.BeginRequest event, how can I read the entire raw request body? When I try to read it the InputStream is of 0 length, leading me to believe it was probably already read by ASP.NET.

I've tried to read the InputStream like this:

using (StreamReader reader = new StreamReader(context.Request.InputStream))
{
    string text = reader.ReadToEnd();
}

But all I get is an empty string. I've reset the position back to 0, but of course once the stream is read it's gone for good, so that didn't work. And finally, checking the length of the stream returns 0.

Edit: This is for POST requests.

Josh M.
  • 26,437
  • 24
  • 119
  • 200
  • How are you reading the stream? – Oded Jun 15 '11 at 18:58
  • 2
    Your code works if I put it in Application_BeginRequest method in Global.asax – Pavel Chuchuva Jun 15 '11 at 23:01
  • 2
    If you put the code in Application_BeginRequest and you are using .Net 4.5 use the following constructor to keep the stream open so ASP.NET can read it after you: StreamReader(request.InputStream, Encoding.UTF8, true, 1024, true – samneric Dec 13 '16 at 15:36

6 Answers6

28

The request object is not populated in the BeginRequest event. You need to access this object later in the event life cycle, for example Init, Load, or PreRender. Also, you might want to copy the input stream to a memory stream, so you can use seek:

protected void Page_Load(object sender, EventArgs e)
{
    MemoryStream memstream = new MemoryStream();
    Request.InputStream.CopyTo(memstream);
    memstream.Position = 0;
    using (StreamReader reader = new StreamReader(memstream))
    {
        string text = reader.ReadToEnd();
    }
}
Pål Thingbø
  • 1,211
  • 1
  • 17
  • 17
19

Pål's answer is correct, but it can be done much shorter as well:

string req_txt;
using (StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream))
{
    req_txt = reader.ReadToEnd();
}

This is with .NET 4.6.

jpaugh
  • 6,634
  • 4
  • 38
  • 90
Ian
  • 4,169
  • 3
  • 37
  • 62
  • 4
    This will close the `InputStream` as currently written, which will throw an exception later in the ASP.NET pipeline. Pal's answer avoids that pitfall by making a copy. Your answer would work if you simply remove the `using` statement. – Lee Grissom Apr 16 '19 at 22:30
6

In ASP.NET Core 2:

using (var reader = new StreamReader(HttpContext.Request.Body)) {
    var body = reader.ReadToEnd();
}
4

It is important to reset position of InputStream.

var memstream = new MemoryStream();
Request.InputStream.CopyTo(memstream);
Request.InputStream.Position = 0;
using (StreamReader reader = new StreamReader(memstream)) {
    var text = reader.ReadToEnd();
    Debug.WriteLine(text);
}
Kasper Jensen
  • 548
  • 5
  • 12
jjaskulowski
  • 2,524
  • 3
  • 26
  • 36
  • 1
    If I recall correctly the problem is that you can only read the `InputStream` ONCE. I wanted to read it and allow normal processing to continue as well. – Josh M. Jan 08 '15 at 14:04
4

I had a similar requirement to get the raw content and struck the same issue. I found that calling Seek(0, SeekOrigin.Begin) solved the problem.

This is not a particularly good approach as it makes assumptions about how the underlying infrastructure operates, but it seems to work.

Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
Dale Anderson
  • 1,681
  • 16
  • 15
-9

Here's what I ended up doing:

//Save the request content. (Unfortunately it can't be written to a stream directly.)
context.Request.SaveAs(filePath, false);
Josh M.
  • 26,437
  • 24
  • 119
  • 200
  • i don't have VS installed on my computer at work or i'd post a real answer, but there IS a way to get the request "body" into a string. Your code in your OP doesn't work because it is using the InputStream which is empty for HTTP GET requests (but not empty for POSTS). A GET request really only has a query string and some headers. – Al W Jun 15 '11 at 20:50
  • Thanks for the down vote (assuming it was you). This is a POST request. I know the difference between GET and POST, thanks. – Josh M. Jun 15 '11 at 22:40
  • 3
    You should not use this approach, too much IO operation will be a trouble for you as the number of requests increase. Reading Request.InputStream and setting Position to 0 at the end works. – Feyyaz Apr 02 '13 at 08:18
  • 2
    @sahs - can you recommend a better alternative? This method is a last ditch effort. – Josh M. Apr 02 '13 at 12:42
  • @JoshM. As I stated Request.InputStream is the answer. StreamReader.ReadToEnd should give you the string. If it is an empty string, that means there is no "body" in the request. – Feyyaz Apr 02 '13 at 13:38
  • @sahs - This was a while back so I don't remember the specifics but if I run into it again, I'll certainly try everything first before what I ended up doing here. Thanks! – Josh M. Apr 02 '13 at 13:40
  • @Feyyaz, I also would like to see a better solution. Also try doing StreamReader.ReadToEnd for second time and you'll come out with an empty string. before downvoting, please study the case properly! – AaA Apr 11 '17 at 10:28