views:

443

answers:

2

Hey

I want to use Application_Error with my MVC project, but i can't get it to work. I add the following to my Global.asax file:

    protected void Application_Error(object sender, EventArgs e)
    {
        Exception objErr = Server.GetLastError().GetBaseException();
        Session["Test"] = "Message:" + objErr.Message.ToString();
    }

(The Session is only for tests. Im gonna use a database to log error, if i get this to work.) Then i try to throw an exception from my HomeController and my Home/Index View, but it only triggers Debug.

    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to ASP.NET MVC!";
        throw (new Exception());
        return View();
    }

In my Webconfig file i set a defaulterror page but it doesn't redirect to the view:

    <customErrors defaultRedirect="Home/Error">
        <error statusCode="403" redirect="NoAccess.htm" />
        <error statusCode="404" redirect="FileNotFound.htm" />
    </customErrors>
A: 
  • Do you have a Session set up in the first place? If the error is triggered from an IHttpHandler not marked with IRequiresSessionState, then accessing Session will fail.
  • What are you doing with Session["Test"]? Are you sure your code is actually not working? You could try a File.Open and simply output some text (say, the current time) to C:\my-log.txt, which is slightly more likely to succeed than using Session.
  • GetBaseException isn't useful in this case (nor generally for logging) as far as I can tell.
  • Message is of type string - calling .ToString() isn't necessary. In general, I'd strongly recommend avoiding ToString() where possible - if you're using it because you're unsure of the type of the object, that should be a red flag; doing an end-run around the type system can hide subtle bugs (for instance, DBNull.Value.ToString() == ""). For GUI's the builtin types provide a .ToString(IFormatProvider) overload which is culture-sensitive and avoid portability issues. Since that overload is also not present on object it's also a safeguard to avoid the very weakly typed .ToString calls.
Eamon Nerbonne
+1  A: 

So firstly remember that global error handling should be a last resort, and controller classes have a specific error method for errors;

protected virtual bool OnError(string actionName, 
    System.Reflection.MethodInfo methodInfo, Exception exception)

Within this you can redirect to the standard shared error view;

protected override bool OnError(string actionName, 
    System.Reflection.MethodInfo methodInfo, Exception exception)
{
   RenderView("Error", exception);
   return false;
}

The problem you have in the global application error is that it has no concept of views or controllers, so if you want to redirect in there then you must use a known URL

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    System.Diagnostics.Debug.WriteLine(exception);
    Response.Redirect("/Home/Error");
}

but you don't need to do this. If you set the default error page in web.config then you don't need that redirect

<customErrors defaultRedirect="Home/Error" />

However, unless you've added an error view to your Home controller that doesn't exist, so add the following to the home controller

public ActionResult Error()
{
    return View();
}

Then (if you're sensible) you'd put the error handling code in the Error() method, as that's where all unhandled errors will end up.

public ActionResult Error()
{
    Exception exception = Server.GetLastError();
    System.Diagnostics.Debug.WriteLine(exception);
    return View();
}

And finally remember that by default you don't see custom errors if you are connecting to localhost! So you need to change that behaviour

<customErrors mode="On" defaultRedirect="/Home/Error" />
blowdart
I have a problem with your solution. The CustomErrors redirects directly to the Home/Errors view without triggering the Controller. I didn't know what this was possible, but when i put a debug point at the Error Action method the debug is never call. The Error View is just displayed at screen, but the url is still the same as the URL which triggered the error. For example if i trigger a error at /Home/Job i will get the error view but the URL is still /Home/Job
Poku