C# .NET Exception : AppDomain.UnhandledException
When an unhandled exception is manifested in a Console application, the AppDomain .UnhandledException is raised. Subscribe to the event to clean up the resources of the application, such as closing files and relinquishing data connections. You might also record the unhandled exception in the event log or another location. It is important to note that the exception is not caught in the AppDomain.UnhandledException handler. After the handler finishes, the unhandled exception causes the application to be terminated. The AppDomain.UnhandledException event is triggered only in the initial application domain; it is ignored in other application domains.
Subscribe to the AppDomain.UnhandledException event with an UnhandledExceptionEventHandler delegate. The delegate has two parameters. The object parameter is the AppDomain object of the initial application domain. The UnhandledExceptionEventArgs parameter contains the specifics of the unhandled exception. This is the syntax of the UnhandledExceptionEventHandler:
UnhandledExceptionEventHandler syntax:
-
void UnhandledExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)
UnhandledExceptionEventArgs offers the IsTerminating and ExceptionObject properties. IsTerminating is a Boolean property indicating the status of the application. If true, the application is terminating because of the exception. If false, the application survives the exception. In .NET 2.0, this property is always true. Unhandled exceptions on both managed and unmanaged threads terminate an application. This is cleaner than the .NET 1.1 unhandled exception model, where exceptions raised on managed threads were nonfatal. The Exception property is an exception object for the unhandled exception. Inexplicably, this property is an object type, not an Exception type. Cast the property to the Exception type to access the details of the exception.
In the following Console application, the OnUnhandledException method is added to the AppDomain.UnhandledException event. When the subsequent divide by zero exception occurs, the OnUnhandledException method is called.
using System;
namespace Examples.Exceptions
{
public class Program
{
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(
OnUnhandledException);
int vara = 5, varb = 0;
vara /= varb;
Console.ReadKey();
}
public static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
string application_name = sender.ToString();
Exception except = (Exception)e.ExceptionObject;
string errormessage = "Application " + application_name + " [ Exception " + except.Message + " ]";
Console.WriteLine(errormessage);
}
}
}
Log4Net Cofiguration
I had to post this one long days ago as I promised in one of my earlier post about Log4Net. Sorry for this late. I am not a man of words. Thanks to Chris, for reminding me about this post. There are lots of things in the configuration of Log4Net. I will only about the commonly used sections.
<log4net> <appender name="LogFileAppender" type="log4net.Appender.FileAppender"> <param name="File" value="D:\Temp\ApplicationLog.log" /> <param name="AppendToFile" value="true" /> <layout type="log4net.Layout.PatternLayout"> <param name="Header" value="" /> <param name="Footer" value="" /> <param name="ConversionPattern" value="%d [%t] %-5p %m%n" /> </layout> </appender> <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" > <layout type="log4net.Layout.PatternLayout"> <param name="Header" value="[Header]\r\n" /> <param name="Footer" value="[Footer]\r\n" /> <param name="ConversionPattern" value="%d [%t] %-5p %m%n" /> </layout> </appender> <root> <level value="DEBUG" /> <appender-ref ref="LogFileAppender" /> <appender-ref ref="ConsoleAppender" /> </root> </log4net>
Log4Net is configured in the configuration section “log4net”, specified with the tag <log4net>. Under this tag, you can find two tags, <appender> and <root>. (There could be more actually. but I did not need them yet.)
<appender> section says where and how the log should be written. It could be in the console, in a file, or database. Logs can even be sent to an email address. So, depending on you needs, you have to configure the appender. Under <log4net> element one or more appenders can be defined. I am interested to describe some of the appenders. Please remind me if I forget to do so.
<root> section is to say, which appender will be used to log, and what types of log will be written.Only one root logger element may only be defined and it must be a child of <log4net> element. To define te log-level, you have to specify your desired log-level in the <level> element. You can set the ‘value’ attribute to any of the five log-levels. The levels are as follows hierarchically:
- FATAL
- ERROR
- WARN
- INFO
- DEBUG
Once you specify the level of the log in the ‘value’ attribute, logs for that level and the levels above will be written.
C# .NET Exceptions : Application.ThreadException
In a Windows Forms application, the windows procedure raises the Application.ThreadException event upon an unhandled exception. Subscribe to the ThreadException event to handle the unhandled exception. The subscriber is an exception handler, which prevents the application from being terminated. Do not propagate an exception caught in this manner in the unhandled exception handler. The new exception is unprotected and will likely terminate the application. After the unhandled exception handler completes, execution continues at the next message in the message pump.
Subscribe to the ThreadException event with a ThreadExceptionEventHandler delegate, which has two parameters. The object parameter is the thread object of the thread that raised the exception. The ThreadExceptionEventArg parameter of the System.Threading namespace contains the exception that was unhandled. This is the signature of the ThreadExceptionEventHandler:
ThreadExceptionEventHandler syntax:
void ThreadExceptionEventHandler(object sender, ThreadExceptionEventArgs e)
In the following code, the OnThreadException handler is added to the ThreadException event. The bthException_Click method raises an unhandled divide by zero exception. The unhandled exception is then handled in the OnThreadException method, which displays an informative message. Run the application in release mode for the expected results. Otherwise, the Visual Studio debugger intercedes the exception.
private void btnException_Click(object sender, EventArgs e)
{
int vara = 5, varb = 0;
vara /= varb;
}
private void Form1_Load(object sender, EventArgs e)
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(OnThreadException);
}
void OnThreadException(object sender, ThreadExceptionEventArgs e)
{
Thread t = (Thread)sender;
Exception threadexception = e.Exception;
string errormessage = "Thread ID: " + t.ManagedThreadId.ToString() + " [ " + threadexception.Message + " ]";
MessageBox.Show(errormessage);
}
Why Log4Net?
Microsoft has its own application block for logging. So, why should we use Log4Net instead of that?
Log4Net has some advantages over Enterprise Library Logging Application Block. These made Log4Net more preferable.
Works with .NET 1.0 & 1.1 - The much improved logging of EntLib 2.0 and above is only available if your application is running on .NET 2.0 or greater. log4net however works on all versions of .NET.
Simpler install - When using the Enterprise Library there are some services you really should install. This is as simple as running a bat file included with EntLib but it does complicate your deployment process.
Slightly faster - log4net was significantly quicker than EntLib 1.1 logging. EntLib 2.0 onwards has improved its performance but log4net remains slightly faster. A benchmark I found while researching my presentation had EntLib taking approximately 5-6 seconds to log 100,000 entries while log4net took about 3 seconds. Does the speed difference matter? Probably not. However log4net net does support…
Appender Buffering - Buffering support with some appenders lets log4net queue up log entries and write them in a single go. If you are writing entries to the database then buffering is a good way to improve performance.
More platforms - Enterprise Library does not support the .NET Compact Framework while log4net does.
Remote Exceptions in C# .NET
Exceptions sometime occur in remote code. An exception that is raised in a different application domain is a remote exception. Remote exceptions include exceptions thrown in a .NET Remoting application or a Web service application. Exceptions that cross application domains must be serialized to maintain the state. System exceptions are serializable. However, you need to make application exceptions serializable.
Follow these steps to serialize an application exception:
-
Adorn the application exception with the serializable attribute.
-
Implement a two-argument constructor with a SerializationInfo and StreamingContext parameter. Deserialize the exception with the SerializationInfo parameter, which is a state bag. Retrieve state information of the exception using the Get methods of the SerializationInfo object. The StreamingContext parameter provides additional data about the source or target of the serialization process. In addition, call the same constructor in the base class to allow the base class to deserialize its state.
-
Implement the GetObjectData method to serialize the exception. The method also has two parameters: Serialization and StreamingContext. Use the Serialization.AddValue to serialize the state of the exception. Invoke GetObjectData on the base class to allow it to serialize itself.
-
For the exception to be available in the client assembly, share the assembly through a global assembly cache or an application configuration file. If the assembly is not shared, the assembly must be copied into the private directory of the client application.
CustomException is an application exception that supports remoting. There is one property, prop_Time, which is serialized in GetObjectData and deserialized in the two-argument constructor:
using System;
using System.Reflection;
using System.Runtime.Serialization;
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyCultureAttribute("")]
namespace Examples.Exceptions
{
[Serializable]
public class CustomException : Exception
{
public CustomException() : base("custom exception", null)
{
prop_Time = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString();
}
protected CustomException(SerializationInfo info, StreamingContext context) : base(info, context)
{
prop_Time = info.GetString("Time");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Time", prop_Time, typeof(string));
base.GetObjectData(info, context);
}
protected string prop_Time = null;
public string Time
{
get
{
return prop_Time;
}
}
}
}
In Microsoft Visual Studio, the assembly attributes, such as AssemblyVersion, are found in the AssemblyInfo.cs file.
Application Exceptions in C# .NET
Application exceptions are custom exceptions and are thrown by the application, not by the CLR. Application exceptions are derived from System.ApplicationException or System.Exception. System.ApplicationException adds nothing to System.Exception. While System.SystemException is a marker for system exceptions, System.ApplicationException brands application exceptions. A custom exception derived from System.Exception accomplishes the same feat. When several custom exceptions are planned, create a custom base exception class to categorize the exceptions. For convenience and maintainability, deploy application exceptions together in a separate assembly.
Do not create an application exception for an existing exception. Research the available system exceptions to avoid replicating an existing exception.
These are the steps for creating an application exception:
-
Name the application exception. As a best practice, the class name should have the Exception suffix, as in ApplicationException.
-
Derive the application exception from System.Exception.
-
Define constructors that initialize the state of the application exception. This includes initializing members inherited from the base class.
-
Within the application exception, refine System.Exception as desired, such as by adding attributes that further delineate this specific exception.
To raise an application exception, use the throw statement. You can also throw system exceptions. Thrown exceptions are considered software exceptions. The CLR treats software exceptions as standard exceptions.
throw syntax:
throw exceptioninstance1;
throw2;
The second syntax is specialized: It is available in the catch block, but nowhere else. This version of the throw statement rethrows as an exception caught in the catch block. However, the best policy is to add additional context to an exception before propagating the exception object. Propagating exceptions is reviewed later in this chapter.
Application exceptions are typically prompted by an exceptional event. What is an exceptional event? A strict definition does not exist. You define the basis of the event using whatever criteria are appropriate. Remember, raising an exception simply for transfer of control or a nonexceptional event is bad policy. In an application, the following could be considered exceptional events where throwing an application exception is warranted:
-
Constructor fails to initialize the state of an object.
-
A property does not pass validation.
-
Null parameters.
-
An exceptional value is returned from a function.
ConstructorException is an application exception. Throw this exception when a constructor fails. It refines the System.Exception base class with name of the type and time of exception. In addition, the Message property is assigned a congruous message. This is the code for the ConstructorException class:
using System;
namespace Examples.Exceptions
{
public class ConstructorException : Exception
{
public ConstructorException(object origin) : this(origin, null)
{
}
public ConstructorException(object origin, Exception innerException) : base("Exception in constructor", innerException)
{
prop_Typename = origin.GetType().Name;
prop_Time = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString();
}
protected string prop_Typename = null;
public string Typename
{
get
{
return prop_Typename;
}
}
protected string prop_Time = null;
public string Time
{
get
{
return prop_Time;
}
}
}
}
This code uses the ConstructorException class:
using System;
namespace Examples.Exceptions
{
public class Program
{
public static void Main()
{
try
{
ZClass obj = new ZClass();
}
catch (ConstructorException except)
{
Console.WriteLine(except.Message);
Console.WriteLine("Typename: " + except.Typename);
Console.WriteLine("Occured: " + except.Time);
}
Console.ReadKey();
}
}
class ZClass
{
public ZClass()
{
// initialization fails
throw new ConstructorException(this);
}
}
}
-
Archives
- February 2009 (1)
- November 2008 (6)
- October 2008 (4)
- September 2008 (13)
- August 2008 (11)
- July 2008 (29)
- June 2008 (19)
- May 2008 (8)
-
Categories
-
RSS
Entries RSS
Comments RSS

