6

I have an MVC3 application that has a custom HandleErrorAttribute so that I can email the error. I often get the "A potentially dangerous Request.Form value was detected from the client", but it only shows the first few characters of the form value that caused the exception. I'd like to see the entire form value that was entered to try to get a better idea if the input was malicious or accidental by a user. However, when I try to pull the form values in the HandleErrorAttribute, it throws the same error! Any idea how to get the form values from the Request.Form without causing validation in my exception handler?

public class HandleErrorLogAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        base.OnException(context);

        //Record Error
        string errorDetails = HttpUtility.HtmlEncode(context.Exception.ToString());

        // Throws "otentially dangerous..." error here
        foreach (var key in context.RequestContext.HttpContext.Request.Form.AllKeys)
        {
            errorDetails += key + "=" + HttpUtility.HtmlEncode(context.RequestContext.HttpContext.Request.Form[key]);
        }

        // Send Email with errorDetails
    }
}
Austin
  • 4,638
  • 7
  • 41
  • 60
  • 1
    You could use `[ValidateInput(false)]` and validate it yourself. – M.Babcock Feb 02 '12 at 14:39
  • It is fine that it generates an error, I just want to know what input caused it. I tried adding [ValidateInput(false)] to my OnException method, but it still re-threw the error. – Austin Feb 02 '12 at 14:53
  • Well, `ValidateInput` doesn't actually "work" for this, at least not by itself. [Here's why.](http://stackoverflow.com/questions/807662/why-is-validateinputfalse-not-working/2530823#2530823) The real issue here is that there's no safe way to do this which will just affect one action. It's a global setting which affects the entire app. – Craig Stuntz Feb 02 '12 at 15:01

1 Answers1

15

In ASP.NET 4.5, you will be able to use the new HttpRequest.Unvalidated.Form property.

Until then, you can use reflection to read the private HttpRequest._form field:

HttpRequest request = context.RequestContext.HttpContext.Request;
NameValueCollection form = (NameValueCollection)request.GetType().InvokeMember(
    "_form",
    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
    null, request, null);

Note that _form is lazily initialized by the HttpRequest.Form property, so make sure HttpRequest.Form has been accessed at least once beforehand.

Michael Liu
  • 52,147
  • 13
  • 117
  • 150