Web Application exception handling

Topics: Web Client Software Factory
Feb 19, 2007 at 7:08 AM
I successfully followed the hands on lab to see how I could add a global exeption handler to an application.
I tried doing the same in a web application and the build failed because it was looking for a messagebox class.
I believe messagebox class is in windows apps not web apps.
Did I do something wrong or is there a version of the library that supports web applications or has someone modified the source to replace messagebox with a web form?
Please help if you can.
Regards, Major (thats my Christian name ;-)
Feb 19, 2007 at 7:39 AM
Which hands-on-lab did you follow? Could you post a link? I'm guessing this is not a lab explicitly for the Web Client Factory...?

Simon
http://www.dotnetblogs.co.uk/
Feb 19, 2007 at 9:03 AM
The lab was from the enterprise library 2.0 page
http://msdn2.microsoft.com/en-us/library/aa480453.aspx
Regards, Major.
Feb 19, 2007 at 9:57 AM
Ah - is it a lab that targets Windows applications? Error handling is usually handled in very different ways in ASP.NET to how it is in a Windows application. Generally you put code in Global.asax to deal with errors...

Check out this url;

http://msdn2.microsoft.com/en-us/library/aa480453.aspx

Does that help?

Simon
http://www.dotnetblogs.co.uk/
Feb 19, 2007 at 11:44 AM
Simon, thanks but that is the same URL.
I have since discovered that I may, in theory, achieve what I want by using the Global.asax page and coding the event handling/logging in the Application_error section.
Having looked back at the Enterprise Library it is only for Windows Applications.
I will progress with trying to get Global.asax to work.
Regards, Major.
Feb 19, 2007 at 5:18 PM
Oops - serious copy/paste error there - sorry!

I meant http://msdn2.microsoft.com/en-us/w16865z6.aspx - in case you're still interested.

Simon
http://www.dotnetblogs.co.uk/
Coordinator
Feb 19, 2007 at 10:49 PM
Edited Feb 19, 2007 at 10:49 PM
Did you create a brand new "Web Client Solution"?

If you did, you have a built in global exception handler, using the Microsoft.Practices.CompositeWeb.EnterpriseLibrary.ExceptionLogger. This is a very simple Enterprise Library-based exception handler that logs everything to the event log with an event id of 100. If you want to change the logging rules, youy can edit the "exceptionHandling" section in the config. If you want to have the handler do more, you should be able to easily extend the ExceptionLogger.

Check out the web.config to see how it does setup for logging and exception handling, and creates an http module to intercept exceptions.
Feb 20, 2007 at 7:11 AM
Simon, thanks for the corrrected link.
I am still interested in establishing a global exception handler with the minimum of coding.
The article confirmed my understanding but the code example files were missing.
Regards, Major.
Feb 20, 2007 at 7:15 AM
Michael, I created a new Web site. Is that the same thing as web client solution?
There was nothing in the web.config for exceptions.
I used EntLibConfig.exe to edit the web.config and added an exception block.
The problem is still that the exception handler in global.asax does not get triggered on a server under IIS. It only works under Visual Studio 2005.
Regards, Major.
Feb 20, 2007 at 1:01 PM
Hi Major,

Have you installed the Web Client Software Factory? It sounds like you are manually creating a Web site in Visual Studio. With the Web Client Software Factory, you can create a starting "Web client application" that includes a Web site. For instructions on how to do this, see the topic "How to: Create a Web Client Solution" in the documentation. I think you'll find that the software factory can be a big help to you.

Cheers,
Tim

Feb 20, 2007 at 1:46 PM
Major,

You need to create a new Web Client Solution which is not the same as creating a New Website.

First, you need to make sure you to download and install the Web Client Software Factory and all its prerequisites. Note it does not tell you the Guidance Automation Extensions is a prerequisite ( but it is ), someone needs to add that :)

When you do successfully install it, you create a new Web Client Solution by

1) Choosing File > New > Project...
2) Selecting a Project Type of Guidance Packages
3) Selecting Web Client Development under Guidance Packages
3) Choosing Web Client Solution on the right under Visual Studio Installed templates

This creates a Web Client Solution for you with a Web.config file that has a considerable amount of information to support the Composite Web Application Block and Enterprise Library Security, Logging, and Exception Handling Blocks.

The Exception Handling Block is configured to use the Logging Application Block to log exceptions to the EventLog. You can of course change this using the GUI Configuration Tool to log to a flat file, etc.

That being said, I don't see where unhandled exceptions are being logged by handling the Application's Error Event. If I am wrong, someone please tell me :) They are being suppressed by enabling CustomErrors, but that is not the same as logging them. ASP.NET 2.0 will do its own logging, but typically you want your own.

You have a couple things you will want to do.

1) Log Unhandled Exceptions by configuring Application_Error in your custom HttpApplication Class like:

public class MyApplication : WebClientApplication
{
    // ...
 
    void Application_Error(object sender, EventArgs e) 
    {
        Exception ex = Server.GetLastError().GetBaseException();
        
        string message = ex.Message + 
                        "\nSOURCE: " + ex.Source +
                        "\nFORM: " + Request.Form.ToString() + 
                        "\nQUERYSTRING: " + Request.QueryString.ToString() +
                        "\nTARGETSITE: " + ex.TargetSite +
                        "\nSTACKTRACE: " + ex.StackTrace;
 
        Logger.Write(message);
    }
}

Here I am just logging messages to the default category using the Logging Application Block in Enterprise Library. You may want to create a separate category and TraceListener to log unhandled exceptions.

2) Turn on Custom Errors in the Web.config so nobody sees the confidential information exposed by your errors:

<customErrors defaultRedirect="put your user friendly error url here" mode="On">
</customErrors

Some resources on this stuff:

HOW TO: Create Custom Error Reporting Pages in ASP.NET by Using Visual C# .NET

Logging Application Block - Simple ASP.NET 2.0 Website Example - Logging Unhandled Exceptions

Hope this helps,

Dave

____________________

David Hayden
Microsoft MVP C#
Feb 20, 2007 at 2:52 PM
Dave, thanks for that information.
Unfortunately the download is for .NET 3.0 and we are still on 2.0.

I had alread read through the information in the links you provided.
I did have a go at using Enterprise Library Logging but seem to recall getting a build error as it was looking for a MessageBox class.
I will have another go at that as I have no other path to follow at this point.
Regards, Major.
Feb 20, 2007 at 3:25 PM
Dave, further results.
I tried the logging but although the exception was handled in VS2005 (no debug) I could not find the trace.log file. Where would it be located. I did do a file search.

I also tried the same on the IIS server.
In that case global.asax is not running.
I have evidence of that as I have added a line
File.WriteAllText(@"c:\temp\log.txt", message_text);
to the ApplicationStart, SessionStart and BeginRequest functions in global.asax
and there was not data written to the file.

How do I get global.asax to work on IIS?

Regards, Major.
Feb 20, 2007 at 4:49 PM
Major,

If you are running the app in VS2005 you will always get a break at the exception with debugging turned on. Just click continue and your custom error page will be activated as well as any logging via the Application_Error Event Handler. However, once you deploy the application outside of the IDE, IIS will automatically activate the items.

Just use the EventLog to make sure all is working and forget about a log file right now. The WCSF already has the EventLog as a TraceListener for you.

As far as why you think IIS is not looking at your Global.asax file, I don't know what to tell you. It is too difficult to debug the problem via this forum. I recommend checking out the ASP.NET 2.0 QuickStarts for more information on how various features work and code snippets.

http://quickstarts.asp.net/QuickStartv20/aspnet/Default.aspx

I also recommend the ASP.NET Forums for general questions about ASP.NET 2.0 which is what I think your questions are more about:

http://forums.asp.net/

Regards,

Dave

______________________

David Hayden
Microsoft MVP C#
Coordinator
Feb 20, 2007 at 7:41 PM
DavidHayden, to answer one of your questions:


...
That being said, I don't see where unhandled exceptions are being logged by handling the Application's Error Event. If I am wrong, someone please tell me :)
...


There is a little bit of magic happening behind the scenes here. First, in the Web.Config we have this:
    <httpModules>
      <add name="ExceptionLoggerHttpModule" type="Microsoft.Practices.CompositeWeb.EnterpriseLibrary.ExceptionLogger, Microsoft.Practices.CompositeWeb.EnterpriseLibrary" />
    </httpModules>

This hooks up a very simple little IHttpModule. The following does the magic in this Module
        public void Init(HttpApplication context)
        {
            if (!Debugger.IsAttached)
            {
                context.Error += new EventHandler(OnUnhandledException);
            }
        }
...
	protected virtual void OnUnhandledException(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            Exception ex = application.Server.GetLastError().GetBaseException();
            ExceptionPolicy.HandleException(ex, "GlobalExceptionLogger");
        }

So, unhandled exceptions should get logged to the "GlobalExceptionLogger", however it is configured.

Does that make sense?

Michael Puleio - patterns & practices
Web – http://msdn.microsoft.com/practices/
Blog – http://blogs.msdn.com/mpuleio/
Feb 20, 2007 at 9:40 PM
Fantastic! I knew it had to be hooked up, but I just didn't see it. The HttpModule was staring at me the whole time in Web.config :)

It wasn't logging while I was running the application in the IDE and now I know why-

        public void Init(HttpApplication context)
        {
            if (!Debugger.IsAttached)
            {
                context.Error += new EventHandler(OnUnhandledException);
            }
        }

You silenced it by checking if the Debugger is attached.

Thanks for the awesome clarification!

Regards,

Dave

_______________________

David Hayden
Microsoft MVP C#
Feb 21, 2007 at 7:58 AM
Dave, I read through the articles in the link (have some still to go but thought I would get back to you anyway).
I tried enabling the application trace facility to see if that would work.
I got back a message telling me the trace option was not enabled but you can see from the web.config at the bottom of this post it is.
I have included the global.asax as well as I thought I would try proving that it is not running.
I removed the test error so the application would work normally.
The expected overflowexception coded in the global.asax did not happen. The text write to the file did not happen either.
I have tried this on two different servers.
Regards, Major.
Web.Config
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings>
<add name="histrxConnectionString" connectionString="User ID=helen;Password=123456;Initial Catalog=Histrx;Data Source=PHT-SQLSVR\DW"/>
<add name="EForms21ConnectionString" connectionString="server=qahbtsdev1; User ID=EForms21; Password=eFormsUser5; DataBase=EForms21"/>
</connectionStrings>
<system.web>
<customErrors mode="Off"/>
<trace enabled="true"/>
<compilation debug="false" strict="false" explicit="true"/>
<pages enableSessionState="true" masterPageFile="~/EForms21/EForms21.master">
<namespaces>
<clear/>
<add namespace="System"/>
<add namespace="System.Collections"/>
<add namespace="System.Collections.Specialized"/>
<add namespace="System.Configuration"/>
<add namespace="System.Text"/>
<add namespace="System.Text.RegularExpressions"/>
<add namespace="System.Web"/>
<add namespace="System.Web.Caching"/>
<add namespace="System.Web.SessionState"/>
<add namespace="System.Web.Security"/>
<add namespace="System.Web.Profile"/>
<add namespace="System.Web.UI"/>
<add namespace="System.Web.UI.WebControls"/>
<add namespace="System.Web.UI.WebControls.WebParts"/>
<add namespace="System.Web.UI.HtmlControls"/>
</namespaces>
</pages>
</system.web>
</configuration>

Global.asax
<%@ Application Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>

<script runat="server">

void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
File.WriteAllText(@"c:\temp\log.txt", "Start App");
throw new OverflowException();
}

void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown

}

void Application_Error(object sender, EventArgs e)
{
//get reference to the source of the exception chain
Exception ex = Server.GetLastError().GetBaseException();

//log the details of the exception and page state to the
//Windows Event Log
EventLog.WriteEntry("EForms21 Demonstration",
"MESSAGE: " + ex.Message +
"\nSOURCE: " + ex.Source +
"\nFORM: " + Request.Form.ToString() +
"\nQUERYSTRING: " + Request.QueryString.ToString() +
"\nTARGETSITE: " + ex.TargetSite +
"\nSTACKTRACE: " + ex.StackTrace,
EventLogEntryType.Error);


//Insert optional email notification here...

Server.ClearError();
Server.Execute("EFORMS21error.aspx");

}

void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
File.WriteAllText(@"c:\temp\log.txt", "Start Session");

}

void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.

}

</script>
Coordinator
Feb 23, 2007 at 12:23 AM
I turned the interesting WCSF-centric parts of this thread into a blog post so more folks can read about it.

Thanks for the feedback and insight.