asp.net-mvc ASP.NET MVC 中的错误处理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/812235/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 23:33:26  来源:igfitidea点击:

Error Handling in ASP.NET MVC

asp.net-mvcexception

提问by Adrian Anttila

How can I correctly handle exceptions thrown from controllers in ASP.NET MVC? The HandleErrorattribute seems to only process exceptions thrown by the MVC infrastructure and not exceptions thrown by my own code.

如何正确处理从 ASP.NET MVC 中的控制器抛出的异常?该HandleError属性似乎只处理 MVC 基础设施抛出的异常,而不是我自己的代码抛出的异常。

Using this web.config

使用这个 web.config

<customErrors mode="On">
    <error statusCode="401" redirect="/Errors/Http401" />
</customErrors>

with the following code

使用以下代码

namespace MvcApplication1.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            // Force a 401 exception for testing
            throw new HttpException(401, "Unauthorized");
        }
    }
}

doesn't result in what I was hoping for. Instead I get the generic ASP.NET error page telling me to modify my web.config to see the actual error information. However, if instead of throwing an exception I return an invalid View, I get the /Shared/Views/Error.aspx page:

不会导致我所希望的。相反,我得到了通用 ASP.NET 错误页面,告诉我修改 web.config 以查看实际错误信息。但是,如果不是抛出异常而是返回无效视图,则会得到 /Shared/Views/Error.aspx 页面:

return View("DoesNotExist");

Throwing exceptions within a controller like I've done above seems to bypass all of the HandleErrorfunctionality, so what's the right way to create error pages and how do I play nice with the MVC infrastructure?

像我上面所做的那样在控制器中抛出异常似乎绕过了所有HandleError功能,那么创建错误页面的正确方法是什么,我如何与 MVC 基础设施配合得很好?

采纳答案by Adrian Anttila

Thanks to kazimanzurrashaid, here is what I wound up doing in Global.asax.cs:

感谢 kazimanzurrashaid,这是我在 Global.asax.cs 中所做的事情:

protected void Application_Error()
{
    Exception unhandledException = Server.GetLastError();
    HttpException httpException = unhandledException as HttpException;
    if (httpException == null)
    {
        Exception innerException = unhandledException.InnerException;
        httpException = innerException as HttpException;
    }

    if (httpException != null)
    {
        int httpCode = httpException.GetHttpCode();
        switch (httpCode)
        {
            case (int) HttpStatusCode.Unauthorized:
                Response.Redirect("/Http/Error401");
                break;
        }
    }
}

I'll be able to add more pages to the HttpContoller based on any additional HTTP error codes I need to support.

我将能够根据我需要支持的任何其他 HTTP 错误代码向 HttpContoller 添加更多页面。

回答by Adrian Anttila

Controller.OnException(ExceptionContext context). Override it.

Controller.OnException(ExceptionContext context). 覆盖它。

protected override void OnException(ExceptionContext filterContext)
{
    // Bail if we can't do anything; app will crash.
    if (filterContext == null)
        return;
        // since we're handling this, log to elmah

    var ex = filterContext.Exception ?? new Exception("No further information exists.");
    LogException(ex);

    filterContext.ExceptionHandled = true;
    var data = new ErrorPresentation
        {
            ErrorMessage = HttpUtility.HtmlEncode(ex.Message),
            TheException = ex,
            ShowMessage = !(filterContext.Exception == null),
            ShowLink = false
        };
    filterContext.Result = View("ErrorPage", data);
}

回答by Craig Stuntz

The HandleError attribute seems to only process exceptions thrown by the MVC infrastructure and not exceptions thrown by my own code.

HandleError 属性似乎只处理 MVC 基础设施抛出的异常,而不是我自己的代码抛出的异常。

That is just wrong. Indeed, HandleError will only "process" exceptions either thrown in your own code or in code called by your own code. In other words, only exceptions where your action is in the call stack.

那是错误的。实际上, HandleError 只会“处理”在您自己的代码中或在您自己的代码调用的代码中抛出的异常。换句话说,只有您的操作在调用堆栈中的异常。

The real explanation for the behavior you're seeing is the specific exception you're throwing. HandleError behaves differently with an HttpException. From the source code:

您所看到的行为的真正解释是您抛出的特定异常。HandleError 的行为与 HttpException 不同。从源代码:

        // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
        // ignore it.
        if (new HttpException(null, exception).GetHttpCode() != 500) {
            return;
        }

回答by kazimanzurrashid

I dont think you will be able to show specific ErrorPage based upon the HttpCode with the HandleError Attribute and I would prefer to use an HttpModule for this purpose. Assuming that I have folder "ErrorPages" where diffferent page exists for each specific error and the mapping is specifed in the web.config same as the regular web form application. And the following is the code which is used to show the error page:

我认为您无法根据带有 HandleError 属性的 HttpCode 显示特定的 ErrorPage,我更愿意为此目的使用 HttpModule。假设我有文件夹“ErrorPages”,其中每个特定错误都存在不同的页面,并且映射在 web.config 中指定为与常规 Web 表单应用程序相同。以下是用于显示错误页面的代码:

public class ErrorHandler : BaseHttpModule{

public override void OnError(HttpContextBase context)
{
    Exception e = context.Server.GetLastError().GetBaseException();
    HttpException httpException = e as HttpException;
    int statusCode = (int) HttpStatusCode.InternalServerError;

    // Skip Page Not Found and Service not unavailable from logging
    if (httpException != null)
    {
        statusCode = httpException.GetHttpCode();

        if ((statusCode != (int) HttpStatusCode.NotFound) && (statusCode != (int) HttpStatusCode.ServiceUnavailable))
        {
            Log.Exception(e);
        }
    }

    string redirectUrl = null;

    if (context.IsCustomErrorEnabled)
    {
        CustomErrorsSection section = IoC.Resolve<IConfigurationManager>().GetSection<CustomErrorsSection>("system.web/customErrors");

        if (section != null)
        {
            redirectUrl = section.DefaultRedirect;

            if (httpException != null)
            {
                if (section.Errors.Count > 0)
                {
                    CustomError item = section.Errors[statusCode.ToString(Constants.CurrentCulture)];

                    if (item != null)
                    {
                        redirectUrl = item.Redirect;
                    }
                }
            }
        }
    }

    context.Response.Clear();
    context.Response.StatusCode = statusCode;
    context.Response.TrySkipIisCustomErrors = true;

    context.ClearError();

    if (!string.IsNullOrEmpty(redirectUrl))
    {
        context.Server.Transfer(redirectUrl);
    }
}

}

}

回答by Simon_Weaver

One other possibility (not true in your case) that others reading this may be experiencing is that your error page is throwing an error itself, or is not implementing :

其他阅读本文的人可能遇到的另一种可能性(在您的情况下并非如此)是您的错误页面本身正在引发错误,或者没有执行:

 System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>

If this is the case then you will get the default error page (otherwise you'd get an infinite loop because it would keep trying to send itself to your custom error page). This wasn't immediately obvious to me.

如果是这种情况,那么您将获得默认错误页面(否则您将获得无限循环,因为它会不断尝试将自身发送到您的自定义错误页面)。这对我来说并不是很明显。

This model is the model sent to the error page. If your error page uses the same master page as the rest of your site and requires any other model information then you will need to either create your own [HandleError]type of attribute or override OnExceptionor something.

此模型是发送到错误页面的模型。如果您的错误页面使用与网站其余部分相同的母版页,并且需要任何其他模型信息,那么您将需要创建自己[HandleError]的属性类型或覆盖OnException或其他内容。

回答by mindplay.dk

I chose the Controller.OnException() approach, which to me is the logical choice - since I've chosen ASP.NET MVC, I prefer to stay at the framework-level, and avoid messing with the underlying mechanics, if possible.

我选择了 Controller.OnException() 方法,这对我来说是合乎逻辑的选择 - 因为我选择了 ASP.NET MVC,所以我更喜欢停留在框架级别,并尽可能避免与底层机制混淆。

I ran into the following problem:

我遇到了以下问题:

If the exception occurs within the view, the partial output from that view will appear on screen, together with the error-message.

如果视图中发生异常,则该视图的部分输出将与错误消息一起出现在屏幕上。

I fixed this by clearing the response, before setting filterContext.Result - like this:

在设置 filterContext.Result 之前,我通过清除响应来解决这个问题 - 像这样:

        filterContext.HttpContext.Response.Clear(); // gets rid of any garbage
        filterContext.Result = View("ErrorPage", data);

Hope this saves somebody else some time :-)

希望这可以为其他人节省一些时间:-)

回答by bharat

     protected override void OnException (ExceptionContext filterContext )
    {
        if (filterContext != null && filterContext.Exception != null)
        {
            filterContext.ExceptionHandled = true;
            this.View("Error").ViewData["Exception"] = filterContext.Exception.Message;
            this.View("Error").ExecuteResult(this.ControllerContext);
        }
    }

回答by Martin_W

Jeff Atwood's User Friendly Exception Handling moduleworks great for MVC. You can configure it entirely in your web.config, with no MVC project source code changes at all. However, it needs a small modification to return the original HTTP status rather than a 200status. See this related forum post.

Jeff Atwood 的User Friendly Exception Handling 模块非常适合 MVC。您可以在您的 web.config 中完全配置它,根本不需要更改 MVC 项目源代码。但是,它需要稍作修改才能返回原始 HTTP 状态而不是200状态。请参阅此相关论坛帖子

Basically, in Handler.vb, you can add something like:

基本上,在 Handler.vb 中,您可以添加如下内容:

' In the header...
Private _exHttpEx As HttpException = Nothing

' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
    _exHttpEx = CType(ex, HttpException)
    HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If