【问题标题】:How to report error to $.ajax without throwing exception in MVC controller?如何向 $.ajax 报告错误而不在 MVC 控制器中引发异常?
【发布时间】:2012-01-02 14:41:50
【问题描述】:

我有一个控制器和一个定义的方法...

[HttpPost]
public ActionResult UpdateUser(UserInformation model){

   // Instead of throwing exception
   throw new InvalidOperationException("Something went wrong");


   // I need something like 
   return ExecutionError("Error Message");

   // which should be received as an error to my 
   // $.ajax at client side...

}

异常问题

  1. 我们必须记录异常以防设备或网络错误,例如 SQL 连接错误。
  2. 这些消息类似于用户验证消息,我们不想记录。
  3. 抛出异常也会淹没事件查看器。

我需要一些简单的方法来向我的 $.ajax 调用报告一些自定义 http 状态,以便它应该在客户端导致错误,但我不想抛出错误。

更新

我无法更改客户端脚本,因为它与其他数据源不一致。

到目前为止,HttpStatusCodeResult 应该可以工作,但这里是 IIS 导致的问题。无论我设置什么错误消息,尝试了所有答案,我仍然只收到默认消息。

【问题讨论】:

    标签: c# ajax asp.net-mvc controller


    【解决方案1】:

    这就是 HTTP 状态代码发挥作用的地方。使用 Ajax,您将能够相应地处理它们。

    [HttpPost]
    public ActionResult UpdateUser(UserInformation model){
        if (!UserIsAuthorized())
            return new HttpStatusCodeResult(401, "Custom Error Message 1"); // Unauthorized
        if (!model.IsValid)
            return new HttpStatusCodeResult(400, "Custom Error Message 2"); // Bad Request
        // etc.
    }
    

    这是defined status codes 的列表。

    【讨论】:

    • 我本来打算接受这个答案,但不幸的是,看起来 MVC 正在重写这个状态并放回它自己的消息而不是我要发送的错误消息。
    • 即使在构造函数中设置了描述? (相应地编辑答案)
    • 很奇怪的是,当我设置错误 500 时,我得到内部服务器错误(不是我设置的描述),否则对于 401、400,对于所有请求,我在 $.ajax 错误对象中得到 404 .
    • 您的回答是正确的,这是 asp.net 中的错误,它没有发送正确的描述,或者我们缺少一些配置。如果微软会接受这个错误,我会接受你的回答。
    • IIS 正确,错误在 ASP.NET 开发服务器中。
    【解决方案2】:

    说明

    如何将一个对象返回到您的页面并在您的 ajax 回调中进行分析。

    样本

    [HttpPost]
    public ActionResult UpdateUser(UserInformation model)
    {
        if (SomethingWentWrong)
            return this.Json(new { success = false, message = "Uuups, something went wrong!" });
    
        return this.Json(new { success=true, message=string.Empty});
    }
    

    jQuery

    $.ajax({
      url: "...",
      success: function(data){
        if (!data.success) 
        {
           // do something to show the user something went wrong using data.message
        } else {
           // YES! 
        }
      }
    });
    

    【讨论】:

    • 我就是这么用的,但它让我改变了现有的脚本,也迫使其他开发者写更多的东西,而我只想在服务器端做任何事情。
    • 简单的一个。感谢分享 dknaack
    【解决方案3】:

    您可以在基本控制器中创建一个辅助方法,该方法将返回服务器错误,但带有您的自定义状态代码。示例:

    public abstract class MyBaseController : Controller
    {
        public EmptyResult ExecutionError(string message)
        {
            Response.StatusCode = 550;
            Response.Write(message);
            return new EmptyResult();
        }
    }
    

    您将在需要时在您的操作中调用此方法。 在您的示例中:

    [HttpPost]
    public ActionResult UpdateUser(UserInformation model){
    
       // Instead of throwing exception
       // throw new InvalidOperationException("Something went wrong");
    
    
       // The thing you need is 
       return ExecutionError("Error Message");
    
       // which should be received as an error to my 
       // $.ajax at client side...
    
    }
    

    错误(包括自定义代码“550”)可以在客户端全局处理,如下所示:

    $(document).ready(function () {
        $.ajaxSetup({
            error: function (x, e) {
                if (x.status == 0) {
                    alert('You are offline!!\n Please Check Your Network.');
                } else if (x.status == 404) {
                    alert('Requested URL not found.');
    /*------>*/ } else if (x.status == 550) { // <----- THIS IS MY CUSTOM ERROR CODE
                    alert(x.responseText);
                } else if (x.status == 500) {
                    alert('Internel Server Error.');
                } else if (e == 'parsererror') {
                    alert('Error.\nParsing JSON Request failed.');
                } else if (e == 'timeout') {
                    alert('Request Time out.');
                } else {
                    alert('Unknow Error.\n' + x.responseText);
                }
            }
        });
    });
    

    【讨论】:

    • 当我无法访问客户端脚本时出现问题。目前我正在使用相同的方法,但是当我使用第三方客户端库时它会失败。
    • 您的意思是 $.ajaxSetup 无法捕获异常吗?
    • 不,它捕捉到了,但是错误信息是在 IIS 中默认设置的,而不是我设置的。
    【解决方案4】:

    这是一个类,我将发送异常作为 JSON 写回 ajax 请求

    public class FormatExceptionAttribute : HandleErrorAttribute
        {
            public override void OnException(ExceptionContext filterContext)
            {
                if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
                {
                    filterContext.Result = new JsonResult()
                                            {
                                                ContentType = "application/json",
                                                Data = new
                                                        {
                                                            name = filterContext.Exception.GetType().Name,
                                                            message = filterContext.Exception.Message,
                                                            callstack = filterContext.Exception.StackTrace
                                                        },
                                                JsonRequestBehavior = JsonRequestBehavior.AllowGet
                                            };
    
                    filterContext.ExceptionHandled = true;
                    filterContext.HttpContext.Response.StatusCode = 500;
                    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
                }
                else
                {
                    base.OnException(filterContext);
                }
            }
        }
    

    它在应用程序的 Global.asax.cs 文件中向 MVC 注册,如下所示:

    GlobalFilters.Filters.Add(new FormatExceptionAttribute());
    

    【讨论】:

    • 我喜欢过滤器,但是这样它会吃掉所有的异常,我不想抛出和捕获,而是我想要通用的执行逻辑,如果错误只是由我设置,我想举报。
    • 然后定义你自己的 CustomException 并通过 if (filterContext.Exception is MyCustomException) 捕获那些
    • 好吧,我仍然不喜欢将异常用作逻辑的一部分,我让服务器每秒处理 100 次请求,抛出异常会减慢执行速度,而不是正确完成调用。而且它不利于可重用性,因为将来一些其他第三方过滤器或任何试图捕获异常的人都可能破坏我的逻辑。
    【解决方案5】:

    我使用这个特殊的类来处理 Ajax 错误

    public class HttpStatusCodeResultWithJson : JsonResult
    {
        private int _statusCode;
        private string _description;
        public HttpStatusCodeResultWithJson(int statusCode, string description = null)
        {
            _statusCode = statusCode;
            _description = description;
        }
        public override void ExecuteResult(ControllerContext context)
        {
            var httpContext = context.HttpContext;
            var response = httpContext.Response;
            response.StatusCode = _statusCode;
            response.StatusDescription = _description;
            base.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
            base.ExecuteResult(context);
        }
    }
    

    状态码是自定义 HTTP 状态码,在全局 Ajax 错误函数中我测试它如下:

    MyNsp.ErrorAjax = function (xhr, st, str) {
            if (xhr.status == '418') {
                MyNsp.UI.Message("Warning: session expired!");
                return;
            }
            if (xhr.status == "419") {
                MyNsp.UI.Message("Security Token Missing");
                return;
            }
            var msg = 'Error: ' + (str ? str : xhr.statusText);
            MyNsp.UI.Message('Error. - status:' + st + "(" + msg + ")");
            return;
        };
    

    【讨论】:

      【解决方案6】:

      我找到的最佳方法如下:

      // Return error status and custom message as 'errorThrown' parameter of ajax request
      return new HttpStatusCodeResult(400, "Ajax error test");
      

      【讨论】:

      • 这是我在整个互联网上看到的最简单的方法。谢谢!
      【解决方案7】:

      根据 BigMike 发布的内容,这是我在我的 NON MVC/WEBAPI 网络项目中所做的。

      Response.ContentType = "application/json";
      Response.StatusCode = 400;
      Response.Write (ex.Message);
      

      物有所值(感谢 BigMike!)它运行良好。

      【讨论】:

      • 啊,这对我有用!谢谢。我刚刚做了一个 ControllerExtension,它返回一个新的 ContentResult。但在里面我应用了上面的代码。我只需要传递两个参数:状态码和消息。现在我可以轻松地在 $.ajax().error() 中捕捉到这一点:)
      猜你喜欢
      • 1970-01-01
      • 2012-12-30
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      • 2018-04-11
      相关资源
      最近更新 更多