【问题标题】:What's the best way to trap a HttpRequestValidationException and add it to the ModelState?捕获 HttpRequestValidationException 并将其添加到 ModelState 的最佳方法是什么?
【发布时间】:2012-06-28 19:23:23
【问题描述】:

关于属性上的装饰器[AllowHtml] 甚至方法上的[ValidateInput(false)],捕获HttpRequestValidationException 并将其附加到ModelState 以在用户端显示为友好错误的最佳方法是什么?不显示错误页面(在Application_Error 下抛出新页面或使用自定义错误页面。

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
    }
}

如何在不使用任何会话/应用程序变量的情况下从此处获取模型状态(考虑此处的云以及托管用户请求的所有不同服务器)?

我正在考虑添加到路线,或者TempData,但这里不可用......也许是Cookie,但接缝很糟糕......

有什么想法吗?

【问题讨论】:

    标签: c# asp.net-mvc-3 exception-handling


    【解决方案1】:

    ASP.NET MVC 中的错误处理是一个有争议的话题。您有不同的选择来处理错误。阅读:

    【讨论】:

      【解决方案2】:

      我曾经通过自定义 ModelBinder 处理过这种情况,并在 base.BindModel 调用周围抛出 try/catch。它很丑,但它可以完成工作。

      我再说一遍,这很丑。

      这是一个例子:

      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
              }
          }
      }
      

      现在,为了用错误填充 ModelState,我有一个帮助类,它尽最大努力维护状态。它的使用(和实现)还有很多不足之处(很多管道、魔术字符串的使用、特定类型、异常消息文本的正则表达式等),因此欢迎提出任何建议。这是最丑的部分,imo。

      用法:

      // 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;
      

      helper 尽最大努力为用户挖掘出相关的错误信息,但它真的很糟糕。 (注意主题?)

      实施:

      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);
              }
          }
      }
      

      基本上,在捕获异常时,尝试手动重新绑定模型,准备捕获每个属性的潜在HttpRequestValidationException 错误。如果一个人被抓到,用我能得到的尽可能具体的消息相应地填充 ModelStateDictionary。

      我真的希望该框架能够更轻松地 1) 捕获此异常并 2) 优雅地处理它,而不是把整张床弄得一团糟。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-10
        • 1970-01-01
        • 2013-02-21
        • 1970-01-01
        • 1970-01-01
        • 2019-08-20
        • 2011-07-28
        • 2014-12-17
        相关资源
        最近更新 更多