首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ASP.MVC HandleError属性不工作

ASP.MVC HandleError属性不工作
EN

Stack Overflow用户
提问于 2014-10-14 09:34:17
回答 5查看 17.2K关注 0票数 9

我知道这是一个常见的问题,但我已经爬了很多次的讨论,但没有结果。

我试图用HandleError ASP.MVC吸引器来处理错误。我正在使用MVC 4。

我的错误页面位于Views/Shared/Error.cshtml中,如下所示:

代码语言:javascript
复制
Test error page
<hgroup class="title">
    <h1 class="error">Error.</h1>
    <h2 class="error">An error occurred while processing your request.</h2>
</hgroup>

我在App文件夹中的FilterConfig.cs是:

代码语言:javascript
复制
public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
    }

我的控制器:

代码语言:javascript
复制
public class TestController : Controller
    {
        [HandleError(View = "Error")]
        public ActionResult Index()
        {
            throw new Exception("oops");
        }
    }

最后,我的Web.config中有以下节点:

代码语言:javascript
复制
<customErrors mode="On" defaultRedirect="Error">
</customErrors>

当我调用控制器操作时,将得到一个白色屏幕,其中包含以下文本:

'/‘应用程序中的服务器错误。 运行时错误描述:处理请求时出现异常。此外,在为第一个异常执行自定义错误页时发生了另一个异常。请求已被终止。

如果defaultRedirect="Error“未在Web.config中设置,那么我将得到黄色屏幕,其中包含以下文本:

'/‘应用程序中的服务器错误。 运行时错误描述:服务器上发生应用程序错误。此应用程序的当前自定义错误设置防止查看应用程序错误的详细信息。 详细信息:若要在本地服务器计算机上查看此特定错误消息的详细信息,请在当前web应用程序根目录中的"web.config“配置文件中创建一个标记。然后,该标记应该将其"mode“属性设置为"RemoteOnly”。若要使详细信息可在远程计算机上查看,请将“模式”设置为"Off“。注意:您看到的当前错误页可以通过修改应用程序配置标记的"defaultRedirect“属性来指向自定义错误页面URL来替换为自定义错误页。

有人知道什么是不对的吗?

编辑:

使用强类型布局会导致错误。当抛出错误时,MVC的错误处理机制是创建HandleErrorInfo对象,该对象被传递给error视图。但是,如果我们使用强类型的布局,那么类型就不匹配。

在我的例子中,解决方案是在Global.asax中使用Global.asax方法,下面的SBirthare很好地描述了这个方法。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2014-10-14 11:13:31

多年来,我一直努力在ASP.NET MVC中顺利地实现“处理自定义错误”。

我以前已经成功地使用了Elmah,但是很多需要以不同的方式处理和测试的案例(即本地的和IIS的)让我不知所措。

最近,在我的一个项目中,我使用了下面的方法(似乎在本地和生产环境中工作得很好)。

我根本不指定customErrors或web.config中的任何设置。

我覆盖Application_Error并处理那里的所有情况,调用ErrorController中的特定操作。

如果有帮助的话,我也会分享这一点,并得到反馈(尽管事情正在进行,但你永远不知道它何时开始破裂;)

Global.asax.cs

代码语言:javascript
复制
public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }

    protected void Application_Error(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("Enter - Application_Error");

        var httpContext = ((MvcApplication)sender).Context;

        var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
        var currentController = " ";
        var currentAction = " ";

        if (currentRouteData != null)
        {
            if (currentRouteData.Values["controller"] != null &&
                !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
            {
                currentController = currentRouteData.Values["controller"].ToString();
            }

            if (currentRouteData.Values["action"] != null &&
                !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
            {
                currentAction = currentRouteData.Values["action"].ToString();
            }
        }

        var ex = Server.GetLastError();

        if (ex != null)
        {
            System.Diagnostics.Trace.WriteLine(ex.Message);

            if (ex.InnerException != null)
            {
                System.Diagnostics.Trace.WriteLine(ex.InnerException);
                System.Diagnostics.Trace.WriteLine(ex.InnerException.Message);
            }
        }

        var controller = new ErrorController();
        var routeData = new RouteData();
        var action = "CustomError";
        var statusCode = 500;

        if (ex is HttpException)
        {
            var httpEx = ex as HttpException;
            statusCode = httpEx.GetHttpCode();

            switch (httpEx.GetHttpCode())
            {
                case 400:
                    action = "BadRequest";
                    break;

                case 401:
                    action = "Unauthorized";
                    break;

                case 403:
                    action = "Forbidden";
                    break;

                case 404:
                    action = "PageNotFound";
                    break;

                case 500:
                    action = "CustomError";
                    break;

                default:
                    action = "CustomError";
                    break;
            }
        }
        else if (ex is AuthenticationException)
        {
            action = "Forbidden";
            statusCode = 403;
        }

        httpContext.ClearError();
        httpContext.Response.Clear();
        httpContext.Response.StatusCode = statusCode;
        httpContext.Response.TrySkipIisCustomErrors = true;
        routeData.Values["controller"] = "Error";
        routeData.Values["action"] = action;

        controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
        ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }

}

ErrorController.cs

代码语言:javascript
复制
public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    public ActionResult CustomError()
    {
        Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        return View();
    }
}

这就是我的全部。无HandleErrorAttribute注册。

我发现这种方法不那么令人困惑,而且很容易扩展。希望这能帮上忙。

票数 18
EN

Stack Overflow用户

发布于 2014-10-14 09:56:46

customErrors设置为on就足以在本地看到结果。

代码语言:javascript
复制
<customErrors mode="On" />

当您在全局注册HandleErrorAttribute时,您不需要用它来修饰您的操作方法,因为它将在默认情况下应用。

代码语言:javascript
复制
public class TestController : Controller
{
    public ActionResult Index()
    {
        throw new Exception("oops");
        return View();
    }
}

只要你已经在HandleErrorAttribute上注册了filterConfig

代码语言:javascript
复制
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

是在Application_Start()中的Global.asax.cs中,那么它应该可以工作。

如果您要创建自定义错误页面,我建议您阅读这篇博客文章。

Mvc自定义错误页

票数 2
EN

Stack Overflow用户

发布于 2016-06-30 18:22:22

我几乎在我的所有应用程序中都使用DI。即使您不使用依赖注入,它对于MVC (Web )应用程序的全局异常处理程序也非常有用。

我喜欢@SBirthare的方法--但是我会把它放在任何IoC都能解决的类中。

我更喜欢Autofac --但是结合@SBirthare的技术和一些DI应该可以为您提供一个集中的位置来配置您的异常处理--还可以注册不同类型的异常处理(如果您需要的话)。

我传统上就是这样做的:

代码语言:javascript
复制
public abstract class ExceptionHandlerService : IExceptionHandlerService
{
    ILoggingService _loggingSerivce;

    protected ExceptionHandlerService(ILoggingService loggingService)
    {
        //Doing this allows my IoC component to resolve whatever I have
        //configured to log "stuff"
        _loggingService = loggingService;


    }
    public virtual void HandleException(Exception exception)
    {


        //I use elmah a alot - and this can handle WebAPI 
       //or Task.Factory ()=> things where the context is null
        if (Elmah.ErrorSignal.FromCurrentContext() != null)
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
        }
        else
        {
            ErrorLog.GetDefault(null).Log(new Error(exception));
        }

        _loggingService.Log("something happened", exception)
    }
}

现在你需要注册这个

代码语言:javascript
复制
builder.RegisterType<ExceptionHandlerService>().As<IExceptionHandlerService();

在MVC应用程序中,您需要实现一个实现IExceptionFilter的类。

代码语言:javascript
复制
public class CustomHandleError : IExceptionFilter
{
    private readonly IExceptionHandlerService _exceptionHandlerService;
    public CustomHandleError(IExceptionHandlerService exceptionHandlerService)
    {
        _exceptionHandlerService = exceptionHandlerService;
    }

    public void OnException(ExceptionContext filterContext)
    {
        _exceptionHandlerService.HandleException(filterContext.Exception);
    }
}

在Autofac中注册过滤器

代码语言:javascript
复制
builder.Register(ctx => new CustomHandleError(ctx.Resolve<IExceptionHandlerService>())).AsExceptionFilterFor<BaseController>();

我总是定义一个BaseController,所有其他控制器都是从它派生的。您可以使用相同的技术定义授权筛选器。现在,所有控制器都被保护并处理异常。

现在,您不需要任何类的属性-代码位于一个位置。

我在任何地方都没有trace,所以我们可以在异常处理程序捕获异常时保留堆栈跟踪。

如果你把这项技术和@SBirthare的结合起来-

代码语言:javascript
复制
public abstract class ExceptionHandlerService : IExceptionHandlerService
{
ILoggingService _loggingSerivce;

protected ExceptionHandlerService(ILoggingService loggingService)
{
    //Doing this allows my IoC component to resolve whatever I have
    //configured to log "stuff"
    _loggingService = loggingService;


}
public virtual void HandleException(Exception exception)
{


    //I use elmah a alot - and this can handle WebAPI 
   //or Task.Factory ()=> things where the context is null
    if (Elmah.ErrorSignal.FromCurrentContext() != null)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
    }
    else
    {
        ErrorLog.GetDefault(null).Log(new Error(exception));
    }

    _loggingService.Log("something happened", exception)

    //re-direct appropriately
    var controller = new ErrorController();
    var routeData = new RouteData();
    var action = "CustomError";
    var statusCode = 500;

        statusCode = exception.GetHttpCode();

        switch (exception.GetHttpCode())
        {
            case 400:
                action = "BadRequest";
                break;

            case 401:
                action = "Unauthorized";
                break;

            case 403:
                action = "Forbidden";
                break;

            case 404:
                action = "PageNotFound";
                break;

            case 500:
                action = "CustomError";
                break;

            default:
                action = "CustomError";
                break;
         }
    //I didn't add the Authentication Error because that should be a separate filter that Autofac resolves.

   var httpContext = ((MvcApplication)sender).Context;
    httpContext.ClearError();
    httpContext.Response.Clear();
    httpContext.Response.StatusCode = statusCode;
    httpContext.Response.TrySkipIisCustomErrors = true;
    routeData.Values["controller"] = "Error";
    routeData.Values["action"] = action;

    controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
    ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
}

}

这实现了同样的功能--但是现在您使用了依赖项注入,并且您能够注册多个ExceptionHandlers并根据异常类型解析服务。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26357340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档