简体   繁体   English

捕获HttpRequestValidationException并将其添加到ModelState的最佳方法是什么?

[英]What's the best way to trap a HttpRequestValidationException and add it to the ModelState?

Regarding the decorator [AllowHtml] on a property or even the [ValidateInput(false)] on a method, what is the best way to catch the HttpRequestValidationException and append it to the ModelState to show as a friendly error on the user side and not show an error page (either throwing a new page under Application_Error or make the use of custom error pages. 关于属性上的装饰器[AllowHtml]甚至方法上的[ValidateInput(false)] ,捕获HttpRequestValidationException并将其附加到ModelState以在用户端显示为友好错误而不显示的最佳方法是什么错误页面(在Application_Error下抛出新页面或使用自定义错误页面。

Inside the global.asax I have a trap: global.asax里面我有一个陷阱:

protected void Application_Error()
{
    // http://romsteady.blogspot.dk/2007/06/how-to-catch-httprequestvalidationexcep.html
    // Code that runs when an unhandled error occurs

    System.Exception ex = Server.GetLastError();

    if (ex is System.Web.HttpRequestValidationException)
    { 
        // I got the exception here, I can do plenty now!

        Server.ClearError(); // no need to continue, I know the error
    }
}

how do I get from here to the model state , without using any Session/Application variables (thinking about cloud here and all those different server hosting the user request)? 如何从这里进入模型状态 ,而不使用任何会话/应用程序变量(在这里思考云以及托管用户请求的所有不同服务器)?

I was thinking add to the route, or TempData but such is not available here... maybe a Cookie but seams to hacky... 我正在考虑添加到路线,或TempData但这里没有这样的...也许是一个Cookie但接缝到hacky ......

Any ideas? 有任何想法吗?

Error handling in ASP.NET MVC is a controversial subject. ASP.NET MVC中的错误处理是一个有争议的主题。 You have different choices to handle errors. 您有不同的选择来处理错误。 Read: 读:

I once handled this situation via a custom ModelBinder and throwing a try/catch around the base.BindModel call. 我曾经通过自定义的ModelBinder处理这种情况,并在base.BindModel调用周围抛出try / catch。 It's ugly, but it gets the job done. 这很丑陋,但它完成了工作。

I repeat, it's ugly. 我再说一遍,这很难看。

Here's an example: 这是一个例子:

public class FooModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        Foo model;
        try
        {
            model = (Foo)base.BindModel(controllerContext, bindingContext);
        }
        catch (HttpRequestValidationException)
        {
            // handle here
        }
    }
}

Now, in a valiant effort to populate the ModelState with errors, I have a helper class that does its best to maintain state. 现在,在努力用错误填充ModelState时,我有一个帮助类,它尽力维护状态。 Its use (and implementation) leave a lot to be desired (a lot of plumbing, use of magic strings, type-specific, regex of exception message text, etc), so any suggestions are welcome. 它的使用(和实现)留下了很多不足之处(很多管道,使用魔术字符串,特定类型,异常消息文本的正则表达式等),所以欢迎任何建议。 This is the ugliest part, imo. 这是最丑陋的部分,imo。

Usage: 用法:

// from above code snippet
catch (HttpRequestValidationException)
{
    // handle any potentially dangerous form values here.  Don't want an exception bubbling up to the user
    // so handle the HttpRequestValidationException by hand here
    // manually populate the model here so that the original values are presented back to the user
    model = new Foo()
    {
        Bar = HandleHttpRequestValidationExceptionHelper.TryAssignment(bindingContext.ModelState, () => bindingContext.ValueProvider.GetValue("Bar").AttemptedValue),
        Baz = HandleHttpRequestValidationExceptionHelper.TryAssignment(bindingContext.ModelState, () => bindingContext.ValueProvider.GetValue("Baz").AttemptedValue)
    };
}

return model;

The helper does its best to mine out pertinent error information for the user, but it's really crappy. 帮助程序尽力为用户挖掘相关的错误信息,但它真的很糟糕。 (Notice a theme?) (注意一个主题?)

Implementation: 执行:

public static class HandleHttpRequestValidationExceptionHelper
{
    /// <summary>
    /// Use TryAssignment in anticipation of a HttpRequestValidationException; it's used to help return error information to the user
    /// </summary>
    /// <param name="modelStateDictionary">The ModelStateDictionary to add the errors to</param>
    /// <param name="action">The attempted value to assign</param>
    /// <returns>Either the proper value or the errored value read from the HttpRequestValidationException Message property</returns>
    public static string TryAssignment(ModelStateDictionary modelStateDictionary, Func<string> action)
    {
        try
        {
            return action();
        }
        catch (HttpRequestValidationException ex)
        {
            // in effort to better inform the user, try to fish out the offending form field
            var parenthesesMatch = Regex.Match(ex.Message, @"\(([^)]*)\)");
            if (parenthesesMatch.Success)
            {
                var badFormInput = parenthesesMatch.Groups[1].Value.Split('=');
                modelStateDictionary.AddModelError(badFormInput[0], badFormInput[1] + " is not valid.");
                return badFormInput[1].TrimStart('"').TrimEnd('"');
            }
            else
            {
                // if attempt to find the offending field fails, just give a general error
                modelStateDictionary.AddModelError("", "Please enter valid information.");
                return string.Empty;
            }
        }
    }

    /// <summary>
    /// Use TryAssignment in anticipation of a HttpRequestValidationException; it's used to help return error information to the user
    /// </summary>
    /// <typeparam name="T">Type of the value</typeparam>
    /// <param name="modelStateDictionary">The ModelStateDictionary to add the errors to</param>
    /// <param name="action">The attempted value to assign</param>
    /// <returns>Either the proper value or default(T)</returns>
    public static T TryAssignment<T>(ModelStateDictionary modelState, Func<T> action)
    {
        try
        {
            return action();
        }
        catch (HttpRequestValidationException ex)
        {
            // in effort to better inform the user, try to fish out the offending form field
            var parenthesesMatch = Regex.Match(ex.Message, @"\(([^)]*)\)");
            if (parenthesesMatch.Success)
            {
                var badFormInput = parenthesesMatch.Groups[1].Value.Split('=');
                modelState.AddModelError(badFormInput[0], badFormInput[1] + " is not valid.");
                // can't really cast a string to an unknown type T.  safer to just return default(T)
            }
            else
            {
                // if attempt to find the offending field fails, just give a general error
                modelState.AddModelError("", "Please enter valid information.");
            }
            return default(T);
        }
    }
}

Basically, upon catching an exception, try rebinding the model manually, ready to catch a potential HttpRequestValidationException error for each property. 基本上,在捕获异常时,尝试手动重新绑定模型,准备捕获每个属性的潜在HttpRequestValidationException错误。 If one is caught, populate the ModelStateDictionary accordingly with as specific of a message as I can get. 如果有一个被捕获,请相应地使用我可以获得的消息特定填充ModelStateDictionary。

I really wish the framework made it easier to 1) catch this exception and 2) gracefully handle it instead of crapping the entire bed. 我真的希望框架更容易1)抓住这个例外,2)优雅地处理它而不是整个床。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 以所有者形式捕获按键组合的最佳方法是什么? - What is the best way to trap key press combinations in owner form? 将列添加到现有数据集中的最佳方法是什么? - What's the best way to add a column to an existing dataset? 将可互换行为添加到ruby类的最佳方法是什么? - What's the best way to add interchangeable behavior to a ruby class? 在运行时在网格中添加ui控件的最佳方法是什么? - What's the best way to add an ui control in the grid at runtime? 在另一个列表中添加列表副本的最佳方法是什么? - What's the best way to add a copy of a list in another list? 将项目添加到C#数组的最佳方法是什么? - What's the best way to add an item to a C# array? 将一项添加到 IEnumerable 的最佳方法是什么<T> ? - What's the Best Way to Add One Item to an IEnumerable<T>? 什么是多线程的最佳方式? - What's the best way to multithread? 有没有办法将控制器的ModelState传递(或访问)到ActionFilterAttribute? - Is there a way to pass (or access) a controller's ModelState to an ActionFilterAttribute? 有什么方法可以将错误代码添加到 ModelState 错误 - Is there any way to add error code to ModelState error
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM