[ACCEPTED]-Application_Error not firing when customerrors = "On-application-error
UPDATE
Since this answer does provide a solution, I 49 will not edit it, but I have found a much 48 cleaner way of solving this problem. See 47 my other answer for details...
Original Answer:
I figured out why the Application_Error()
method 46 is not being invoked...
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()); // this line is the culprit
}
...
}
By default (when 45 a new project is generated), an MVC application 44 has some logic in the Global.asax.cs
file. This logic 43 is used for mapping routes and registering 42 filters. By default, it only registers one 41 filter: a HandleErrorAttribute
filter. When customErrors are 40 on (or through remote requests when it is 39 set to RemoteOnly), the HandleErrorAttribute 38 tells MVC to look for an Error view and 37 it never calls the Application_Error()
method. I couldn't find 36 documentation of this but it is explained 35 in this answer on programmers.stackexchange.com.
To get the ApplicationError() method 34 called for every unhandled exception, simple 33 remove the line which registers the HandleErrorAttribute 32 filter.
Now the problem is: How to configure 31 the customErrors to get what you want...
The 30 customErrors section defaults to redirectMode="ResponseRedirect"
. You can 29 specify the defaultRedirect attribute to 28 be a MVC route too. I created an ErrorController 27 which was very simple and changed my web.config 26 to look like this...
web.config
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
The problem with this 25 solution is that it does a 302 redirect 24 to your error URLs and then those pages 23 respond with a 200 status code. This leads 22 to Google indexing the error pages which 21 is bad. It also isn't very conformant to 20 the HTTP spec. What I wanted to do was not 19 redirect, and overrite the original response 18 with my custom error views.
I tried to change 17 redirectMode="ResponseRewrite"
. Unfortunately, this option does not support MVC routes, only static HTML pages 16 or ASPX. I tried to use an static HTML page 15 at first but the response code was still 14 200 but, at least it didn't redirect. I 13 then got an idea from this answer...
I decided to give 12 up on MVC for error handling. I created 11 an Error.aspx
and a PageNotFound.aspx
. These pages were very simple 10 but they had one piece of magic...
<script type="text/C#" runat="server">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
}
</script>
This block 9 tells the page to be served with the correct 8 status code. Of course, on the PageNotFound.aspx 7 page, I used HttpStatusCode.NotFound
instead. I changed my web.config 6 to look like this...
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>
It all worked perfectly!
Summary:
- Remove the line:
filters.Add(new HandleErrorAttribute());
- Use
Application_Error()
method to log exceptions - Use customErrors with a ResponseRewrite, pointing at ASPX pages
- Make the ASPX pages responsible for their own response status codes
There 5 are a couple downsides I have noticed with 4 this solution.
- The ASPX pages can't share any markup with Razor templates, I had to rewrite our website's standard header and footer markup for a consistent look and feel.
- The *.aspx pages can be accessed directly by hitting their URLs
There are work-arounds for 3 these problems but I wasn't concerned enough 2 by them to do any extra work.
I hope this 1 helps everyone!
I solved this by creating an ExceptionFilter 2 and logging the error there instead of Application_Error. All 1 you need to do is add a call to in in RegisterGlobalFilters
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());
}
I found an article which describes a much cleaner 21 way of making custom error pages in an MVC3 20 web app which does not prevent the ability 19 to log the exceptions.
The solution is to 18 use the <httpErrors>
element of the <system.webServer>
section.
I configured 17 my Web.config like so...
<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>
I also configured customErrors
to have 16 mode="Off"
(as suggested by the article).
That makes 15 the responses overriden by an ErrorController's 14 actions. Here is that controller:
public class ErrorController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult NotFound()
{
return View();
}
}
The views 13 are very straightforward, I just used standard 12 Razor syntax to create the pages.
That alone 11 should be enough for you to use custom error 10 pages with MVC.
I also needed logging of 9 Exceptions so I stole the Mark's solution of using a custom 8 ExceptionFilter...
public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext exceptionContext)
{
var exception = exceptionContext.Exception;
var request = exceptionContext.HttpContext.Request;
// log stuff
}
}
The last thing you need 7 to so is register the Exception Filter in 6 your Global.asax.cs file:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ExceptionPublisherExceptionFilter());
filters.Add(new HandleErrorAttribute());
}
This feels like a much cleaner 5 solution than my previous answer and works 4 just as well as far as I can tell. I like 3 it especially because it didn't feel like 2 I was fighting against the MVC framework; this 1 solution actually leverages it!
In case of ASP.NET MVC5 use
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);
}
}
You can find it in FilterConfig.cs
of App_Start
folder.
0
To get around this I ended up leaving customerrors 7 disabled and handling all errors from the 6 Application_Error event in global.asax. It's 5 slightly tricky with MVC as I didn't want 4 to return a 301 redirect, I wanted to return 3 suitable error codes. More details can be 2 viewed on my blog at http://www.wduffy.co.uk/blog/using-application_error-in-asp-net-mvcs-global-asax-to-handle-errors/ but the final code 1 is listed below...
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);
}
And here is the controller
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();
}
}
I like Mark's answer with the ExceptionFilter, but 11 another option, if you have all your controllers 10 derive from the same base controller, is 9 to simply override OnException in your base 8 controller. You can do your logging and 7 emailing there. This has the advantage 6 of being able to use whatever dependencies 5 you've already got injected into your base 4 controller with your IoC container.
You can 3 still use your IoC with an IExceptionFilter, but 2 it's a bit more tricky to configure your 1 bindings.
As far as I know, you are passing control 4 over to the Page specified in the url parameter 3 and your event notification would sit in 2 here, rather than Application_Error
<customErrors defaultRedirect="myErrorPage.aspx"
mode="On">
</customErrors>
A lot 1 of information can be found here: http://support.microsoft.com/kb/306355
This blog entry helped me:
http://asp-net.vexedlogic.com/2011/04/23/asp-net-maximum-request-length-exceeded/
If you're using 20 IIS 7.0 or higher, you can alter your Web.config 19 file to handle requests that are too large. There 18 are some caveats, but here is an example:
<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>
There 17 are additional details about these config 16 file elements here:
http://www.iis.net/ConfigReference/system.webServer/security/requestFiltering/requestLimits
Status code 404.13 is 15 defined as "Content Length Too Large". One 14 important thing to note is that the maxAllowedContentLength
is 13 specified in bytes. This is different from 12 the maxRequestLength
setting you find in the <system.web>
section, which 11 is specified in kilobytes.
<system.web>
<httpRuntime maxRequestLength="10240" />
</system.web>
Also note that 10 the path
attribute must be an absolute path 9 when the responseMode
is Redirect
, so prepend the virtual directory 8 name, if relevant. Jesse Webb's informative 7 answers show how to do this with responseMode="ExecuteURL"
, and I 6 would think that approach would work well, too.
This 5 approach does not work if you're developing 4 using the Visual Studio Development Server 3 (Cassini, the Web server integrated into 2 Visual Studio). I'm assuming it would work 1 in IIS Express, but I haven't tested that.
I was having the same problem where Application_Error()
wasn't 7 getting hit. I tried everything, until finally 6 I stepped through what was happening. I 5 had some custom code in an ELMAH event that 4 was adding JSON to the email it sends, and 3 there was a null error in there!
Fixing the 2 internal error allowed the code to continue 1 on to the Application_Error()
event as expected.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.