1

Current code

if (!(context.Exception is exception))
    HttpContent requestContent = context.Request.Content;
    string jsonContent = requestContent.ReadAsStringAsync().Result;

Jsoncontent returns null here as well as

context.request = context.HttpRequestMessage

Seeing below output in local window

context.Request.Content.Headers {
    Content-Length: 1458
    Content-Type: application/json
    }
Allow: {}
ContentDisposition: null
ContentEncoding: {}
ContentLanguage: {}
ContentLength: 1458
ContentLocation: null
ContentMD5: null
ContentRange: null
ContentType: { application/json }
Expires: null
LastModified: null
Results View: Expanding the Results View will enumerate the IEnumerable
context.Request.Content { System.Net.Http.StreamContent }
Headers: {
    Content-Length: 1458
    Content-Type: application/json
}

How do I retrieve content from header?

Dovydas Šopa
  • 2,282
  • 8
  • 26
  • 34
  • what language is this? – frozen Jul 11 '17 at 19:14
  • C#.public override void OnException(HttpActionExecutedContext context) { if (!(context.Exception is ClientErrorException)) { HttpContent requestContent = context.Request.Content; string jsonContent = requestContent.ReadAsStringAsync().Result; } } – Naresh Garlapati Jul 11 '17 at 19:17
  • public override void OnException(HttpActionExecutedContext context) { if (!(context.Exception is ClientErrorException)) { HttpContent requestContent = context.Request.Content; string jsonContent = requestContent.ReadAsStringAsync().Result; } } – Naresh Garlapati Jul 11 '17 at 19:19

1 Answers1

0

If you want content-type and length as json string, you can use

 JsonConvert.SerializeObject(Request.Content.Headers);

 // Sample output 
 // "[{\"Key\":\"Content-Length\",\"Value\":[\"29\"]},{\"Key\":\"Content-Type\",\"Value\":[\"application/json\"]}]"

requestContent.ReadAsStringAsync() return empty string because body can only be read once. If you want to read body using ReadAsStringAsync then remove parameter from actions (this will prevent default model binding).

   // This will have Request.Content.ReadAsStringAsync as ""
   public async Task<IHttpActionResult>  Post(MyModel model)

Change it to

   // This will have Request.Content.ReadAsStringAsync as json string
   public async Task<IHttpActionResult>  Post()

Blog explains this in more detail https://blogs.msdn.microsoft.com/jmstall/2012/04/16/how-webapi-does-parameter-binding/

Hope this help

Update

If you need request details in exception filter then you can use following options

Options 1 (easier and I would advise to use this)

Use

       context.ActionContext.ActionArguments

Example

        var requestJson = $"RequestUrl: {context.Request.RequestUri} " +
                          $"ActionName: {context.ActionContext.ActionDescriptor.ActionName} " +
                          $"Arguments: {JsonConvert.SerializeObject(context.ActionContext.ActionArguments)}";

        Debug.WriteLine(requestJson);

Options 2 copy RequestStream to MemoryStream and reread from position 0 (copied from link)

        string request;
        using (var memoryStream = new MemoryStream())
        {
            var requestStream = await context.Request.Content.ReadAsStreamAsync();
            requestStream.Position = 0;
            requestStream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            using (StreamReader streamReader = new StreamReader(memoryStream))
            {
                request = streamReader.ReadToEnd();
            }
        }

        Debug.WriteLine(request)
Kaushal
  • 1,251
  • 1
  • 8
  • 8
  • Thank you kaushal. i need to have my model in post, is there any way to overcome this like by using seek or something else? – Naresh Garlapati Jul 12 '17 at 15:53
  • As far as I know, no you cannot read body stream twice in web api. Why you need to read content twice? If you already have model bounded, I am not sure why would you need to read it twice? If you need only content-type and content length, then you can get it from Request.Content.Headers (and its available without any restriction) – Kaushal Jul 12 '17 at 16:29
  • i want to read request body in global.asax global on exception method for logging purpose. Model is not available in global.asax. is there any other way to over come this situation? – Naresh Garlapati Jul 12 '17 at 16:44
  • I haven't tried it in global.asax however seems its possible. Please try solution from https://stackoverflow.com/q/6362781/7500843 using seek. If it doesn't work, I will try code and will update later – Kaushal Jul 12 '17 at 17:02
  • i have tried with streamreader. i am getting below error This "method or property is not supported after HttpRequest.GetBufferlessInputStream has been invoked" – Naresh Garlapati Jul 12 '17 at 20:53
  • tried this HttpRequest request = System.Web.HttpContext.Current.Request; StreamReader reader = new StreamReader(request.InputStream); try { string body = reader.ReadToEnd(); } finally { reader.BaseStream.Position = 0; } – Naresh Garlapati Jul 12 '17 at 21:35
  • tried below one also string data; using (var stream = context.Request.Content.ReadAsStreamAsync().Result) { if (stream.CanSeek) { stream.Position = 0; } data = context.Request.Content.ReadAsStringAsync().Result; } return data; stream.canseek coming as false and tream.position is only readable. – Naresh Garlapati Jul 12 '17 at 22:59
  • Please check update section of answer. Hope this help. – Kaushal Jul 13 '17 at 12:19