This documentation has been updated for Themelia Framework 2.0 Beta 3.
Regardless of what type of web site you are building, you absolutely must have some way to have the web site tell you that it's having problems. If the web site isn't important enough to keep up, I can't see how it's important enough to put up in the first place. Thus, ASP.NET developers tap into the beauty of the HttpApplication object's Error event. By handling this event, we get immediate notification whenever an unhandled exception is thrown anywhere on the web site. For personal web sites, this is awesome, but corporate web sites, it could keep you from being fired.
When I mention the Error event to junior developers (this is one of the things which, to me, defines a junior developer), they immediately think I'm talking about Global.asax. Yes, it's related to Global.asax , but that's not where we're going to do this. This isn't ASP. This is ASP.NET. Just because the letters of the file name contain "Global.asa", that doesn't mean it's the same thing This is the powerful and professional beast known as ASP.NET and as such we should apply the best tried and true elegant design pattern and best practices wherever possible. In this case, this means not putting all kinds of stuff into your Global.asax file.
Aside from the magical Application_Start method and its buddies, which must be in Global.asax, this file is really just a connection to the web site's HttpApplication instance. Furthermore, since we are in an object-oriented world, we can inherit from that and keep our implementation away from the file entirely. Thus the average Global.asax file should look like this:
<%@ Application Language="C#" Inherits="MySite.Web.HttpApplication" %>
That's it. Well, unless you need the Application_Start method (or its buddies), but for the most part that's it. Don't go handling events in there. You will have your own HttpApplication class with error handling in another place. Here's an example:
namespace MySite.Web
{
public class HttpApplication : System.Web.HttpApplication
{
//- @Init -//
public override void Init()
{
this.Error += new EventHandler(OnError);
//+
base.Init();
}
//- $OnError -//
private void OnError(Object sender, EventArgs e)
{
HttpApplication ha = sender as HttpApplication;
if (ha != null)
{
System.Web.HttpContext context = ha.Context;
Themelia.Tracing.ReportFacade.Send(context.Error);
}
}
}
}
This example traps each unhandled exception and sends it to the default exception notification contact in Themelia. All exception details including all inner exceptions will be included in the e-mail.
This is primarily the ASP.NET world before Themelia 2.0 (well, the ReportFacade is Themelia 2.0!): you trap an error and send it, save it, or whatever.
Themelia 2.0 Error Processors
In the real world, sometimes you don't need to be notified of every error on every part of your web site. Sometimes you only need to know about a certain sensitive portion. The rest, perhaps, can be saved into a database or queued up for sending once a day. On the other hand, some parts of a web site should not just notify you of an exception, it should also be logged... in triplicate. Thus Themelia 2.0 provides error processors which handle error within the boundaries of a web domain.
If you recall, a web domain is a Themelia 2.0 concept that bring the idea of an AppDomain to the web. What happens in a web domain, stays in the web domain. Thus, if you register an error processor in a web domain, you will only see error about that particular web domain.
Configuration of error processors is incredibly simply: just register one in a web domain. Period!
Here's the actual configuration, which replaces everything we did with Global.asax and the custom HttpApplication file:
<themelia.web>
<webDomains>
<errorProcessors>
<add type="EmailSendingErrorProcessor" />
</errorProcessors>
</webDomains>
</themelia.web>
In this sample, EmailSendingErrorProcessor is an error processor provided by Themelia and is, obviously, registered in Themelia's processor factory to allow it's usage outside of declaring it's full type (Themelia.Web.Routing.EmailSendingErrorProcessor, Themelia.Web).
If you would like to create your own custom error processor, just create a class which inherits from Themelia.Web.Routing.ErrorProcessorBase. This abstract class requires that you implement one method:
void OnErrorProcessorExecute(System.Web.HttpContext context, params Object[] parameterArray)
In this method you can do whatever you want. Here's a sample custom error processor:
namespace Sample.Web.Routing
{
public class SavingErrorProcessor : Themelia.Web.Routing.ErrorProcessorBase
{
public override void OnErrorProcessorExecute(System.Web.HttpContext context, params Object[] parameterArray)
{
Exception ex = context.Error;
if (ex != null && !Themelia.Web.Http.UrlPartArray.Contains("problem"))
{
String problemGuid = Web.ExceptionSaver.Save(ex);
Themelia.Web.Http.Redirect("/problem/" + problemGuid);
}
else
{
try
{
Themelia.Tracing.ReportFacade.Send("Unknown exception occurred");
}
catch
{
//+ just in case the sample web.config isn't configured for mail
}
}
}
}
}
In this sample (as seen in the Themelia "Basic" sample), when an exception is thrown that is not caught by anyone, this error processor will catch it and check if we are already on the problem page. If we aren't, then save the exception in the database and send the reference to the appropriate page to allow the user to enter in a description of what he or she was doing when the exception was raised. If the exception was thrown on that page... oops, then just send us an alert so we know to get on it right away.
Error Processors in WebDomain Inheritance
In the following example, we have three web domains each with its own configuration:
<themelia.web>
<webDomains>
<add>
<errorProcessors>
<add type="Sample.Web.Routing.SavingErrorProcessor, Sample.Web" />
</errorProcessors>
</add>
<add name="sales" path="sales">
<errorProcessors>
<add type="EmailSendingErrorProcessor" />
</errorProcessors>
</add>
<add name="finance" path="finance" basedOn="sales">
<errorProcessors>
<add type="Sample.Web.Routing.DatabaseSavingErrorProcessor, Sample.Web" />
</errorProcessors>
</add>
</webDomains>
</themelia.web>
When the root webdomain has an error, the exception is handled as we previously explained. If the sales web domain has a problem, send an alert immediately. Finally, notice that the finance web domain is based on the sales web domain. Thus, when an error is raised in the finance web domain, an email is sent immediately and the error is saved to the database (assuming thats what the DatabaseSavingErrorProcessor does!) To be clear, this does NOT mean that sales errors will go to the finance web domain. Web domain inheritance just copies configuration and maintains the protective boundaries. Thus each web domain will see only its' own exceptions.
Thus, using Themelia 2.0 you have fine grained control over how your exceptions are handled in various parts of your web site. Not only that, your error processors are always packages in nice little envelopes (called classes!) which can be easily reused on various other sites.
Links
Math Problem: (type the answer in the box)
Notice: all comments are subject to moderation.
Comment saved. All comments are moderated and may not show up for some time.