【问题标题】:How to catch an error in a controller when thrown from an Attribute?从属性抛出时如何捕获控制器中的错误?
【发布时间】:2012-03-10 21:46:12
【问题描述】:

如果请求无效,我有一个 ActionFilterAttribute 会引发错误。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if((!filterContext.HttpContext.Request.IsAjaxRequest() ||
            !filterContext.HttpContext.Request.IsXMLHttpRequest()) &&
           (!filterContext.HttpContext.Request.IsLocal))
        {
            throw new InvalidOperationException("This operation can only be accessed via Ajax requests.");
        }
    }
}

现在在我的控制器中,我想捕捉错误并将其传递给视图

[AjaxOnly]
public JsonpResult List()
{
    try
    {
    var vimeoService = new VimeoService();
    var videos = vimeoService.GetVideosFromChannel(this._vimeoChannelId);

    return this.Jsonp(videos);
    }
    catch (Exception ex)
    {
        var err = new ErrorsModel() { ErrorMessage = ex.Message };
        return this.Jsonp(err, false);
    }
}

现在因为属性在控制器动作触发之前运行,我永远无法“捕捉”控制器中的错误,因此我无法将错误传递给视图。

我怎样才能做到这一点?

【问题讨论】:

    标签: asp.net-mvc-3 error-handling custom-attributes


    【解决方案1】:

    好的,所以简短的回答 (tl;dr) 是您需要以干净有序的方式处理所有异常。这并不是像我(作为一个假人)最初计划的那样在每个控制器操作中单独执行。

    相反,我已经连接了我的全局 Application_Error 方法来处理所有错误,并通过单个 index 操作将它们发送到错误控制器。

        private void Application_Error()
        {
            // setup the route to Send the error to
            var routeData = new RouteData();
            routeData.Values.Add("action", "Index");
    
            // Execute the ErrorController instead of the intended controller
            IController errorController = new Controllers.ErrorController();
            errorController.Execute(new RequestContext(new HttpContextWrapper(this.Context), routeData));
    
            // After the controller executes, clear the error.
            this.Server.ClearError();
        }
    

    我的错误控制器非常基础。基本上它会抛出最后一个错误并将相关数据推送到客户端(在我的例子中,将其序列化为 JsonP)。

    public class ErrorController : Controller
    {
        public JsonpResult Index()
        {
            var lastError = Server.GetLastError();
            var message = lastError.Message;
            int statusCode;
    
            // If the lastError is a System.Exception, then we
            // need to manually set the Http StatusCode.
            if (lastError.GetType() == typeof(System.Exception))
            {
                statusCode = 500;
            }
            else
            {
                var httpException = (HttpException)this.Server.GetLastError();
                statusCode = httpException.GetHttpCode();
            }
    
            // Set the status code header.
            this.Response.StatusCode = statusCode;
    
            // create a new ErrorsModel that can be past to the client
            var err = new ErrorsModel()
                {
                    ErrorMessage = message, 
                    StatusCode = statusCode
                };
            return this.Jsonp(err, false);
        }
    }
    

    现在,为了给我的应用增加一点稳健性,我创建了与 Http StatusCodes 对应的自定义 Exceptions

    public sealed class UnauthorizedException : HttpException
    {
        /// <summary>
        /// Similar to 403 Forbidden, but specifically for use when authentication is possible but has failed or not yet been provided
        /// </summary>
        public UnauthorizedException(string message) : base((int)StatusCode.Unauthorized, message) { }
    }
    

    现在我可以在适用的情况下在整个应用程序中抛出异常,它们都将被拾取并以易于管理的方式发送给客户端。

    这是一个抛出上述错误的示例。

    if (!User.Identity.IsAuthenticated)
        throw new UnauthorizedException("You are not authorized");
    

    【讨论】:

    • 这是我遇到的第一个 MVC 错误处理示例,我可以直接复制 + 粘贴并实际工作。向你致敬。
    猜你喜欢
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 2020-08-31
    • 2020-08-24
    • 1970-01-01
    • 2011-01-25
    相关资源
    最近更新 更多