我在global.asax
文件的Application_Error
事件中有代码,该事件在发生错误时执行,并将错误的详细信息通过电子邮件发送给我自己。
void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
if (error.Message != "Not Found")
{
// Send email here...
}
}
当我在Visual Studio中运行它时,这很好用,但是当我发布到我们的实时服务器时,Application_Error
事件不会触发。
经过一些测试后,我可以在设置Application_Error
时触发customErrors="Off"
,但是将其设置回customErrors="On"
可以阻止事件再次触发。
在Application_Error
启用customErrors
后,有人可以建议为什么web.config
不会被解雇?
答案 0 :(得分:130)
<强>更新强>
由于这个答案确实提供了解决方案,我不会编辑它,但我找到了一种更清晰的方法来解决这个问题。有关详细信息,请参阅my other answer
原文答案:
我弄清楚为什么没有调用Application_Error()
方法......
<强>的Global.asax.cs 强>
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()); // this line is the culprit
}
...
}
默认情况下(生成新项目时),MVC应用程序在Global.asax.cs
文件中有一些逻辑。该逻辑用于映射路由和注册过滤器。默认情况下,它只注册一个过滤器:HandleErrorAttribute
过滤器。当customErrors打开时(或当设置为RemoteOnly时通过远程请求),HandleErrorAttribute告诉MVC查找错误视图,它从不调用Application_Error()
方法。我找不到这方面的文档,但在this answer on programmers.stackexchange.com中解释了它。
要获取为每个未处理的异常调用的ApplicationError()方法,只需删除注册HandleErrorAttribute过滤器的行。
现在的问题是:如何配置customErrors以获得你想要的东西......
customErrors部分默认为redirectMode="ResponseRedirect"
。您也可以将defaultRedirect属性指定为MVC路由。我创建了一个非常简单的ErrorController,并将我的web.config更改为这样......
<强>的web.config 强>
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
此解决方案的问题在于它会对您的错误网址进行302重定向,然后这些网页会以200状态代码进行响应。这导致谷歌索引错误页面,这是不好的。它也不符合HTTP规范。我想做的不是重定向,而是使用我的自定义错误视图覆盖原始响应。
我尝试更改redirectMode="ResponseRewrite"
。不幸的是,this option does not support MVC routes,只有静态HTML页面或ASPX。我最初尝试使用静态HTML页面,但响应代码仍然是200但是,至少它没有重定向。然后我从this answer ...
我决定放弃使用MVC进行错误处理。我创建了Error.aspx
和PageNotFound.aspx
。这些页面非常简单,但它们有一块魔法......
<script type="text/C#" runat="server">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
}
</script>
此块告诉页面使用正确的状态代码。粗略的,在PageNotFound.aspx页面上,我使用HttpStatusCode.NotFound
代替。我改变了我的web.config看起来像这样......
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>
这一切都很完美!
<强>要点:强>
filters.Add(new HandleErrorAttribute());
Application_Error()
方法记录例外我已经注意到这个解决方案有几个缺点。
这些问题有解决办法,但我并不担心他们做任何额外的工作。
我希望这对每个人都有帮助!
答案 1 :(得分:67)
我通过创建ExceptionFilter并在那里记录错误而不是Application_Error来解决这个问题。您需要做的就是在RegisterGlobalFilters中添加对in的调用
log4netExceptionFilter.cs
using System
using System.Web.Mvc;
public class log4netExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
Exception ex = context.Exception;
if (!(ex is HttpException)) //ignore "file not found"
{
//Log error here
}
}
}
的Global.asax.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new log4netExceptionFilter()); //must be before HandleErrorAttribute
filters.Add(new HandleErrorAttribute());
}
答案 2 :(得分:35)
我找到了一个article,它描述了一种在MVC3网络应用程序中制作自定义错误页面的更简洁的方法,它不会阻止记录异常的能力。
解决方案是使用<system.webServer>
部分的<httpErrors>
元素。
我将 Web.config 配置为......
<httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL" />
<error statusCode="500" path="/Error" responseMode="ExecuteURL" />
</httpErrors>
我还将customErrors
配置为mode="Off"
(正如文章所建议的那样)。
这使得响应被ErrorController的操作覆盖。这是控制器:
public class ErrorController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult NotFound()
{
return View();
}
}
视图非常简单,我只是使用标准的Razor语法来创建页面。
仅此一项就足以让您将自定义错误页面与MVC一起使用。
我还需要记录异常,所以我偷了Mark's solution使用自定义的ExceptionFilter ......
public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext exceptionContext)
{
var exception = exceptionContext.Exception;
var request = exceptionContext.HttpContext.Request;
// log stuff
}
}
您需要做的最后一件事是在 Global.asax.cs 文件中注册异常过滤器:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ExceptionPublisherExceptionFilter());
filters.Add(new HandleErrorAttribute());
}
这比我以前的答案感觉更清晰,并且就我所知的情况而言也是如此。我喜欢它,特别是因为我觉得我不喜欢与MVC框架作斗争;这个解决方案实际上利用了它!
答案 3 :(得分:8)
如果 ASP.NET MVC5 使用
public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
public void OnException(ExceptionContext exceptionContext)
{
var exception = exceptionContext.Exception;
var request = exceptionContext.HttpContext.Request;
// HttpException httpException = exception as HttpException;
// Log this exception with your logger
_logger.Error(exception.Message);
}
}
您可以在FilterConfig.cs
文件夹App_Start
中找到它。
答案 4 :(得分:1)
我喜欢Mark对ExceptionFilter的回答,但是如果你的所有控制器都来自同一个基本控制器,那么另一个选择就是简单地覆盖你的基本控制器中的OnException。您可以在那里进行日志记录和电子邮件。这样做的好处是能够使用您已经使用IoC容器注入基本控制器的任何依赖项。
您仍然可以将IoC与IExceptionFilter一起使用,但配置绑定更加棘手。
答案 5 :(得分:0)
据我所知,您正在将控制权传递给url参数中指定的Page,而您的事件通知将位于此处,而不是Application_Error
<customErrors defaultRedirect="myErrorPage.aspx"
mode="On">
</customErrors>
可在此处找到大量信息:http://support.microsoft.com/kb/306355
答案 6 :(得分:0)
为了解决这个问题,我最终禁用了customerrors并处理了global.asax中Application_Error事件的所有错误。这对MVC来说有点棘手,因为我不想返回301重定向,我想返回合适的错误代码。更多细节可以在我的博客http://www.wduffy.co.uk/blog/using-application_error-in-asp-net-mvcs-global-asax-to-handle-errors/上查看,但最终的代码列在下面......
void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;
if (code != 404)
{
// Generate email with error details and send to administrator
}
Response.Clear();
Server.ClearError();
string path = Request.Path;
Context.RewritePath(string.Format("~/Errors/Http{0}", code), false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(Context);
Context.RewritePath(path, false);
}
这是控制器
public class ErrorsController : Controller
{
[HttpGet]
public ActionResult Http404(string source)
{
Response.StatusCode = 404;
return View();
}
[HttpGet]
public ActionResult Http500(string source)
{
Response.StatusCode = 500;
return View();
}
}
答案 7 :(得分:0)
此博客条目帮助了我:
http://asp-net.vexedlogic.com/2011/04/23/asp-net-maximum-request-length-exceeded/
如果您使用的是IIS 7.0或更高版本,则可以更改Web.config文件以处理过大的请求。有一些警告,但这是一个例子:
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1048576" />
</requestFiltering>
</security>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="13" />
<error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="/UploadTooLarge.htm" responseMode="Redirect" />
</httpErrors>
</system.webServer>
这里有关于这些配置文件元素的其他详细信息:
http://www.iis.net/ConfigReference/system.webServer/security/requestFiltering/requestLimits
状态代码404.13被定义为“内容长度太大”。需要注意的一件重要事情是maxAllowedContentLength
以字节为单位指定。这与您在maxRequestLength
部分中找到的<system.web>
设置不同,后者以千字节为单位。
<system.web>
<httpRuntime maxRequestLength="10240" />
</system.web>
另请注意,当path
为responseMode
时,Redirect
属性必须是绝对路径,因此,如果相关,则添加虚拟目录名称。 Jesse Webb的内容丰富的答案显示了如何使用responseMode="ExecuteURL"
来做到这一点,我认为这种方法也能很好地运作。
如果您使用Visual Studio开发服务器(Cassini,集成到Visual Studio中的Web服务器)进行开发,则此方法不起作用。我假设它可以在IIS Express中运行,但我没有测试过。
答案 8 :(得分:0)
我遇到同样的问题Application_Error()
没有被击中。我尝试了一切,直到最后我逐步完成了所发生的事情。我在ELMAH事件中有一些自定义代码,它将JSON添加到它发送的电子邮件中,并且那里有一个空错误!
修复内部错误允许代码按预期继续进行Application_Error()
事件。