Elmah: How to get JSON HTTP request body from error report
Asked Answered
I

3

15

I'm using Elmah to log exceptions. Elmah is great at logging request bodies if the request is a Form-based request (i.e. Content-Type: application/x-www-form-urlencoded), but with JSON based requests where the content type is application/json, the request body is nowhere to be found in the error reports. Anyone know where I can find this request body so that I can properly diagnose my exceptions?

UPDATE: 2012-01-03

As a clarification on what I mean by JSON based requests, here's an example raw HTTP request with JSON as the request body:

PUT http://mycompany.com/api/v1.0/me HTTP/1.1
Host: mycompany.com
Content-Length: 20
Content-Type: application/json

{"city":"Vancouver"}
Iroquois answered 31/12, 2011 at 5:18 Comment(2)
What do you mean with JSON based requests? Are they recieving via GET or POST? If you enter a details page and click "Raw/Source data in XML", can you see the body there?Pastelist
@alexn, the requests are sent via PUT and POST. Raw/Source data in XML does not show the request body for JSON based requests. Please see my updated info above for a clarification on what I mean by JSON based requests.Iroquois
T
19

ELMAH so far only logs the context or information that is peripheral to the request and which can be conveniently captured in a standard way. Forms are arguably a special treatment because ASP.NET already does the job of decoding and memorizing request entities when the MIME type is application/x-www-form-urlencoded. JSON requests on the other hand are prolematic because at the time an exception occurs, the input stream (HttpRequest.InputStream) may have been partially or completely consumed by a JSON decoder. ELMAH would not be able to get a second crack at it for the purpose of logging. You will therefore have to make sure that you buffer the input stream or text before passing it through any JSON decoder and stash it away somewhere like HttpContext.Items. You could then try to recover the buffered data and attach it to an outgoing mail at the time of an error. ELMAH currently does not support attaching arbitrary data to a logged error. There is however the ErrorLogModule that has a Logged event and which supplies the Id of the logged error. This could be used to store the input data elsewhere (perhaps in another table if you are using a back-end database for the error logs) but tie it back to the logged error by maintaining an association via the Id.

Tamatave answered 5/1, 2012 at 10:53 Comment(4)
Thanks Atif for your detailed answer. Regarding the outgoing mail option (i.e. inside ErrorMail_Mailing), I don't have access to the HttpContext, so I can't access HttpContext.Items. If I could access HttpContext, then I can try to recover the request body from HttpRequest.InputStream if it's still available. Is it possible to access HttpContext from ErrorMail_Mailing?Iroquois
You should have access to the Context property inside of the event handler. It is inherited from HttpApplication by Global.asax. Try this.Context or just type this then period (.) and it should show up in IntelliSense in the IDE.Tamatave
this.Context is null and this.Request throws an exception because it's no longer available. HttpContext.Current is null as well. It seems that ErrorMail_Mailing is called after the response is sent.Iroquois
Right, this can happen if the mail is being sent asynchronously on a thread from the thread pool and perhaps after the request has eneded. That is the default behavior. You can configure mails to be sent synchronous to the request by setting the async attribute of the <errorMail> element in your config to false.Tamatave
H
4

first install nuget package : Newtonsoft.Json

install-package Newtonsoft.Json

then:

 public override void OnException(HttpActionExecutedContext filterContext)
        {
    var message = new StringBuilder();
            foreach (var param in filterContext.ActionContext.ActionArguments)
            {
                message.Append(string.Format("{0}:{1}\r\n", param.Key, Newtonsoft.Json.JsonConvert.SerializeObject(param.Value)));
            }
            var ex = new Exception(message.ToString(), filterContext.Exception);
            var context = HttpContext.Current;
            ErrorLog.GetDefault(context).Log(new Error(ex, context));
}
Hejira answered 8/12, 2013 at 18:37 Comment(0)
B
1

Further to Atif's answer here, there is a way to add additional details to ELMAH log by manually throwing a new Exception. It's not particularly elegant but it seems to do the job!

I'd be interested to hear any comments from the man himself...

Bothy answered 29/5, 2012 at 22:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.