1

A ConfigurationErrorsException was being thrown from within a class library linked to an ASP.NET site. The site logs all errors using the Global.ASAX error event and by overridding the ASP.NET page OnError() protected method. Neither of which handled the ConfigurationErrorsException when it was thrown.

When the type of exception in the class library was changed from ConfigurationErrorsException to ApplicationException, the page OnError method handles the exception.

Why does the type of the Exception thrown change the way ASP.NET handles the exception? If you want all errors to be handled in the ASP.NET OnError and/or Global.asax page Error event which Exceptions are safe to throw?

The following code demonstrates what I've described. A breakpoint in the OnError will get hit when you click the App Exception button but not when you click the Configurations Exception button...

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="OnErrorTest.WebForm1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Button ID="btnInvalidOpEx" runat="server" Text="Invalid OP Exception" OnClick="btnInvalidOpEx_OnClick" />
    <asp:Button ID="btnAppEx" runat="server" Text="Application Exception" OnClick="bthnAppEx_OnClick" />
    <asp:Button ID="btnConfigEx" runat="server" Text="Configurations Exception" OnClick="btnConfigEx_OnClick" />    
    </div>
    </form>
</body>
</html>

Code behind

using System;
using System.Configuration;
using System.Web;

namespace OnErrorTest
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected override void OnError(EventArgs e)
        {
            HttpContext ctx = HttpContext.Current;

            System.Exception exception = ctx.Server.GetLastError();
        }

        protected void bthnAppEx_OnClick(object sender, EventArgs e)
        {
            throw new ApplicationException("Application Error");
        }

        protected void btnConfigEx_OnClick(object sender, EventArgs e)
        {
            throw new ConfigurationErrorsException("Configurations Error");
        }

        protected void btnInvalidOpEx_OnClick(object sender, EventArgs e)
        {
            throw new InvalidOperationException("Configurations Error");
        }
    }
}

EDIT: It was suggested that ConfigurationErrorsException is a system exception and it's meant to be thrown by the .NET Framework and not an application. It does indeed derive from SystemException, however so does InvalidOperationException. OnError catches InvalidOperationException

CONCLUSION: Don't throw anything derived from ConfigurationException unless your intent is that it's not to be processed in either the OnError method of an ASP.NET Page or global exception handlers. I've tested MVC and no Controller.OnException has no such discrimination against ConfigurationException.

Mick
  • 6,527
  • 4
  • 52
  • 67

2 Answers2

1

I peeked into the source code for ProcessRequestMain. There is a try...catch block in this method which catches any ConfigurationException and throws it again (look into line 4680). All other Exceptions are handed over to HandleError method which will call OnError. (Also ThreadAbortException is handled separately which is not your concern here.)

This is why you can't capture ConfigurationException (and ConfigurationErrorsException which is inherited from ConfigurationException) using either OnError method or Error event in an ASP.NET page.

Alireza
  • 4,976
  • 1
  • 23
  • 36
  • Thanks. I can see it! So the answer is the only two exceptions not passed to OnError are ConfigurationException and ThreadAbortException. I can understand not passing ThreadAbortException. I can't say I understand the logic for not passing ConfigurationException, probably a good reason, but seems arbitrary and bizarre behavior to me. – Mick Aug 14 '14 at 08:28
  • I think it is because the configuration exceptions are usually not bound to the Page, but a more general problem in the application – Alireza Aug 14 '14 at 08:33
  • MVC has no such discrimination Controller.OnException receives exceptions derived from ConfigurationException – Mick Aug 14 '14 at 08:35
  • It seems that either they've learned their lesson or simply the MVC team thinks in different ways than the Web Forms team ;) – Alireza Aug 14 '14 at 08:36
  • But I'm still wondering why such an important thing is not documented. – Alireza Aug 14 '14 at 08:37
  • Yes I've had a good scour through MS docs on setting up error handling in classic ASP.NET I've yet to see a mention of OnError and ConfigurationException – Mick Aug 14 '14 at 23:55
0

I think it's because a configurationerror essentially blocks the app from running properly and the configurationerrorsexception also, according to the docs, is not meant to be thrown by us but by the framework itself. Since most configurations lead to the app not functioning it wouldn't be able to catch the configuration error anyways with a logging tool since it can't configure the environment to run the logging tool when it gets to that error.

Mark Fitzpatrick
  • 1,624
  • 1
  • 11
  • 8
  • Got a link to this documentation that suggests that this exception is only meant to be thrown by the .NET Framework? – Mick Aug 14 '14 at 04:03
  • Here's a whole thread of people discussing which exception should be thrown. The consensus seems to be use ConfigurationErrorsException ...http://stackoverflow.com/questions/417187/net-which-exception-to-throw-when-a-required-configuration-setting-is-missing – Mick Aug 14 '14 at 06:12