.ASP.MVC HandleError 属性不起作用
本文关键字:不起作用 属性 HandleError MVC ASP | 更新日期: 2023-09-27 18:26:36
我知道这是一个常见问题,但我爬了很多讨论都没有结果。
我正在尝试使用处理错误ASP的错误。MVC attrbiute.我正在使用 MVC 4。
我的错误页面位于Views/Shared/Error.cshtml中,看起来像这样:
Test error page
<hgroup class="title">
<h1 class="error">Error.</h1>
<h2 class="error">An error occurred while processing your request.</h2>
</hgroup>
我的 FilterConfig.cs 在 App-Start 文件夹中是:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
我的控制器:
public class TestController : Controller
{
[HandleError(View = "Error")]
public ActionResult Index()
{
throw new Exception("oops");
}
}
最后,我的 Web.config 具有以下节点:
<customErrors mode="On" defaultRedirect="Error">
</customErrors>
当我调用控制器操作时,我得到一个白屏,其中包含以下文本:
"/"应用程序中的服务器错误。
运行时错误说明:处理时发生异常 您的要求。此外,执行时发生另一个异常 第一个异常的自定义错误页。请求已 终止。
如果未在 Web.config 中设置 defaultRedirect="Error",则我会看到带有以下文本的黄屏:
"/"应用程序中的服务器错误。
运行时错误说明:应用程序错误发生在 服务器。此应用程序的当前自定义错误设置阻止 查看应用程序错误的详细信息。
详细信息:启用此特定错误消息的详细信息 在本地服务器计算机上可查看,请创建一个 标记位于根目录的"web.config"配置文件中 当前 Web 应用程序的目录。此标签 然后,应将其"模式"属性设置为"仅远程"。要启用 要在远程计算机上查看的详细信息,请将"模式"设置为 "关"。
注意:您看到的当前错误页面可以替换为 通过修改 指向自定义的应用程序配置标记 错误页面网址。
有谁知道可能出了什么问题?
编辑:
错误是由使用强类型布局引起的。当抛出错误时,MVC 的错误处理机制是创建传递给错误视图的 HandleErrorInfo 对象。但是,如果我们使用强类型布局,则类型不匹配。
就我而言,解决方案是在Global.asax中使用Application_Error方法,下面的SBirthare对此进行了完美描述。
我一直在努力在MVC中顺利实现"处理自定义错误 ASP.NET。
我以前曾成功使用过Elmah,但是由于需要以不同方式处理和测试的众多情况(即本地与IIS(而不知所措。
最近在我的一个现已上线的项目中,我使用了以下方法(似乎在本地和生产环境中工作正常(。
我根本没有在 web.config 中指定customErrors
或任何设置。
我覆盖Application_Error
并在那里处理所有情况,在ErrorController
中调用特定操作。
如果它有帮助并获得反馈,我正在分享这个(尽管事情正在工作,但你永远不知道它什么时候开始中断;)(
全球.asax.cs
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));
}
}
错误控制器.cs
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
注册。
我发现这种方法不那么令人困惑且易于扩展。希望这对某人有所帮助。
customErrors
设置为on
应该足以在本地查看结果。
<customErrors mode="On" />
当您全局注册HandleErrorAttribute
时,您无需使用它来装饰您的操作方法,因为它将在默认情况下应用。
public class TestController : Controller
{
public ActionResult Index()
{
throw new Exception("oops");
return View();
}
}
只要您已在filterConfig
注册了HandleErrorAttribute
并且
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
在Global.asax.cs
Application_Start()
,那么它应该可以工作。
如果您要创建自定义错误页面,我建议您阅读此博客文章
MVC 自定义错误页面
我几乎所有的应用程序都使用 DI。 即使您不使用依赖注入 - 它对于 MVC (Web API( 应用程序的全局异常处理程序也非常有用。
我喜欢@SBirthare的方法 - 但我会把它放在任何 IoC 都可以解决的类中。
我更喜欢 Autofac - 但将 @SBirthare 的技术与一些 DI 相结合应该为您提供一个集中的位置来配置异常处理 - 而且还能够注册不同类型的异常处理(如果需要(。
这是我传统上的做法:
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)
}
}
现在你需要注册这个
builder.RegisterType<ExceptionHandlerService>().As<IExceptionHandlerService();
在 MVC 应用程序中 - 您需要实现一个实现 IExceptionFilter 的类
public class CustomHandleError : IExceptionFilter
{
private readonly IExceptionHandlerService _exceptionHandlerService;
public CustomHandleError(IExceptionHandlerService exceptionHandlerService)
{
_exceptionHandlerService = exceptionHandlerService;
}
public void OnException(ExceptionContext filterContext)
{
_exceptionHandlerService.HandleException(filterContext.Exception);
}
}
在自动 FAC 中注册筛选器
builder.Register(ctx => new CustomHandleError(ctx.Resolve<IExceptionHandlerService>())).AsExceptionFilterFor<BaseController>();
我总是定义一个 BaseController 来派生我的所有其他控制器。您可以使用相同的技术定义授权过滤器。 现在,所有控制器都已得到保护并已处理异常。
现在你不需要任何类的属性 - 代码在一个地方。
我在任何地方都没有任何 try catch,因此我们可以在异常处理程序捕获异常时保留堆栈跟踪。
如果你将这种技术与@SBirthare的——
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));
}
}
这实现了同样的事情 - 但现在您使用依赖关系注入,并且能够注册多个异常处理程序并根据异常类型解析服务。
我无法弄清楚HandleErrorAttribute实际上做了什么。 它似乎什么也没做。
无论如何,只需要 OnException(( 中的 4 行代码即可使其表现为我的预期:
// Copyright(c) 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
using System.Web.Mvc;
namespace GoogleCloudSamples
{
internal class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
// Why oh Why doesn't base.OnException(filterContext) do this?
ViewDataDictionary viewData = new ViewDataDictionary(filterContext);
filterContext.Result = new ViewResult() { ViewName = "Error", ViewData = viewData };
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.ExceptionHandled = true;
}
}
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
}
}
}
解决方案:
首先,删除 web.config 文件中的"默认重定向"属性。
其次,在你的 FilterConfig.cs 文件中,我发现有些人引用了一些 MVC 模板中"HandleErrorAttribute"的"自定义类"版本,一些开发人员已经为其他人在线创建了该模板。这些将断开原始 MVC HandlerErrorAttribute 类与默认错误视图页面的连接。
您可以通过确保在 FilterConfig 文件中引用 ORIGINAL Microsoft MVC HandleErrorAttribute 并使用"using"语句来解决此问题,如下所示,向其添加全局"错误"视图以确保现在再次调用该页面。见下文....
using System.Web.Mvc;//add this to make sure you are referencing the MVC version
public class FilterConfig
{
public static void Configure(System.Web.Mvc.GlobalFilterCollection filters)
{
// Note I added {View = "Error"}. This applies the Error View Page to all Actions in all Controller classes
filters.Add(new HandleErrorAttribute { View = "Error" });
}
}
这会将共享视图文件夹中的"Error.cshtml"视图全局分配给引发的每个异常,当然 404 和其他服务器错误除外。您可以通过上述开发人员概述的其他方式处理这些内容。但这应该将 .NET 异常路由到自定义错误页。- 斯托克利