Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# Lectures - Lecture 8: Disaster recovery. Exceptions and error handling by C# example

0.00/5 (No votes)
29 Aug 2016 1  
My lecture #8 about exceptions handling and organization of error handling in the project

Full Lectures Set


Introduction

In this article I'm going to review one of the fundamental aspects of development applications using .NET and C# language in particular. We are going to talk about exceptions and exceptions handling. Please be aware that here I'm reviewing sensitive topic and all below is my personal thoughts and opinion. If you have any questions I'll be happy to answer them, but I'm not ready to debate on rhetorical questions and just shared my opinion. If you disagree with me, try to find other sources about this topic.

Exceptions handling what is it?

Good programming design suppose that your functionality besides doing useful and required stuff will also report you about wrong and unexpected things that happened during runtime. Error handling and recovery form unexpected situations is fundamental and required for any application. There are many ways to handle errors and exceptional flows and one of these approaches is exceptions handling that I'm going to review in this article.

Let's review small example: your function tried to send data to server and in the middle network connection was down. Worst case your function ends or even crashes without any update. Better case it will return false. Very good case function will return error code with information from network layer plus write this error to logs, so finally you will be able to understand what was your flow and what was wrong.

Almost all good designed software writes detailed logs and returns meaningful error codes with textual explanations for user\technical stuff about the nature of error. This information is useful for troubleshooting and improving your application and all modern applications have good error handling and logging inside. Also all modern software designs suppose proper recovery from problematic situations. From initial example when our function failed to send data to server and received, let's call it NO_NETWORK error it may wait for a while and doing retry or ping for a network aliveness with another function and then when connection established doing retry again. All these things are designed and implemented by developers and they are controlled by program code as well. This is actually the idea of software development to develop system that wraps some functionality and works not only in "good" conditions but that is robust to faulty scenarios and able to recovery from them.

All described above is good for things that you design and create yourself, but in software development there are a lot of things that developer doesn't control and use a black box or error happen not in a straightforward way as I described in my sample. When you use  .NET functions, Windows API, 3rd party API you can't impact them and change their flow or behavior. You can't also change something when they fail or crash, but you need to be able to recovery from this. You rely on other developers product and operation systems to execute your own software. Also there are your own functions that you can't control, for example constructor doesn't return any error codes and result of its execution, but problems may happen there. Same with 3rd party, their functionality may crash with some circumstances and you even not receive any notification about it. There are many things like this that you can't control but you need to be able to catch this situation and recovery from it. In object oriented world and .NET framework in particular there is mechanism to notify about such types of error and handling them. This mechanism is called exceptions handling.

What is exceptions handling? I like citation from Wikipedia: "Exception handling is the process of responding to the occurrence, during computation, of exceptions – anomalous or exceptional conditions requiring special processing – often changing the normal flow of program execution. It is provided by specialized programming language constructs or computer hardware mechanisms". When exception happened and your application is prepared it has specific exception handler that receives notification about exception. There are some exceptions that you can ignore or recover from them, but there are exceptions such as Memory Overflow or Stack Overflow that you almost unable to handle properly and in good case you can only catch them and notify user by message or log line about such kind of exception. At least you will be able to do some clean up and user will be notified about a reason of your end of execution.

Almost all modern programming languages has built in support for exceptions. You can use language constructions that give you ability to be notified about exception - catch it and run a handler that will do specific actions basing on exception type. C# is one of languages that has well developed support for exceptions handling. Later in this article I'll review constructions and methodologies of exceptions handling in C#.

Structured Exceptions Handling (SEH)

Exception is usually some event that happened outside the flow of normal execution. There are two types of exceptions:

  • Hardware exceptions - initiated by CPU. An example is division to zero
  • Software exceptions - initiated by software or operation system

Structured exceptions handling is the common way to handle both hardware and software exceptions identically.  SEH is the Microsoft native way for exception handling it futures finally mechanism that is not present for example in standard C++ exceptions. SEH is set up and handled for each execution thread.

I'll try to explain how structured exceptions handling works. Each thread of execution has a link to  _EXCEPTION_REGISTRATION_RECORD at its information block. When try operator is executed it adds record to  _EXCEPTION_REGISTRATION_RECORD  at the head of it. When try block finishes revers operation is done. The record has pointer to __except_handler3 function from msvcrt.dll. All catch and finally blocks are called by this __except_handler3 routine, if they are present, of course. When exception happened in user mode operation system parses _EXCEPTION_REGISTRATION_RECORD in sequence until some handler signals it handled exception by return value or the list of handlers is finished. The last one in the list is always the kernel32 UnhandledExceptionFilter which displays the General protection fault error message. Once OS done with handlers it goes thru list of handlers again to find those that can do resource cleaners to clean up things that can be cleaned up. After all this done execution returns to kernel mode where process is resumed or terminated.

Exceptions handling in C#

As I mentioned above C# has built in mechanism for exceptions handling. C# uses .NET exceptions handling base and .NET uses Structured Exceptions Handling  (SEH). C# has three keywords for exceptions handling:

  • try - try is an operator to identify area of code where you're waiting for exception and where is located code that requires recovery or cleaning of resources after exception happened and was catch
  • catch - operator for the code that will be implemented after exception of specific or any type was catch. Code after catch is used for recovery from exception and changing execution flow after exception was raised. If you use specific exception type in catch statement it will look for this type of exception only, other case any exception will be catch. Code after catch will be executed only if exception happened.
  • finally - has a code that usually doing resources clean up after code in try block. Code in finally block is executing ever and not depends on the fact if exception happened or not.

Code below demonstrates simple C# code that shows usage of all operators described above:

void SampleFunction()
{
    try
    {
        //code that may raise exception and need to be revovered\cleaned up
    }
    catch (AccessViolationException av)
    {
        //code to recovery from AccessViolationException
    }
    catch (UnauthorizedAccessException ua)
    {
        //code to recovery from UnauthorizedAccessException
    }
    catch
    {
        //code to recovery from all other exception types
    }
    finally
    {
        //code that will be executed forever and that will do cleaning up
    }
}

Operators usage rules:

  • As developer it is up to you to decide how to combine operators for exceptions handling. It might be one try and one finally, one try and one catch, or one try and several catches. It might be try, catch and finally.
  • There can be nested try operators.
  • try block has to be connected with at least one catch or finally. You should decide about it basing on your needs.
  • If you have several catches and exception happened than runtime looks for handler from top to bottom and if you have specific exceptions handlers they should go first.
  • Once exception is catch runtime executes first code in block catch and then in block finally that is connected to same try. Before executing catch block all nested finally blocks are executed

Once you catch exception and are in catch block you have 3 options:

  • Throw same exception for code upper in stack code below demonstrate an example how to do this:
catch(FileNotFoundException e)
     {
        Console.WriteLine("[Data File Missing] {0}", e);
        throw new FileNotFoundException(@"[data.txt not in c:\temp directory]",e);
     }
  • Throw new exception with additional data for code upper in stack

  • Give ability for code to leave from catch block naturally and continue from next operator

System.Exception

In C# in catch block you have ability to use variable name to point for exception class that is derived from System.Exception. Using this variable name you can get detailed information about exception. Actually System.Exception or types derived from it are the way how .NET treats exceptions and all exceptions handling here is based on this class. Most compilers of .NET languages give you ability to generate only exceptions derived from System.Exception.

See code below:

try
{
    int i = 0;
    Console.WriteLine(1/i);//division by 0 causes exception
}
catch(Exception e)
{
    Console.WriteLine("Exception help link is: " + e.HelpLink);
    Console.WriteLine("Exception HReult is: " + e.HResult);
    Console.WriteLine("Exception message is: " + e.Message);
    Console.WriteLine("Exception source is: " + e.Source);
    Console.WriteLine("Exception stack trace is: " + e.StackTrace);
    Console.WriteLine("Exception target site i: " + e.TargetSite);
    Console.WriteLine();
}

The result of the code is following:

<img alt="" src="1097369/1.png" />

From my perspective most interesting things that you can get from exception class are:

  • StackTrace - that shows representation of the stack trace from the method where exception was throw to the method where it was catch.
  • TargetSite - provides a name of the method that throws an exception
  • Message - gets a message that describes current exception
  • HResult - gets an HRESULT numerical value assigned to specific exception

Using these fields you can print them to logs and then in case if some exceptions happened while your program runtime you will be able easily to find where they happened and understand them.

Generating your own exceptions

When your function do something wrong or can't solve its task you can (someone say should) generate exception. Mostly runtime generates exception object when it occurs. Exception is the way to say to caller that you reached abnormal situation and this situation should be handled there or at upper layers. If you decided to create and throw your own exception you should do following:

  • Make sure that caller of your function knows that you will throw it
  • Make sure that caller of your function knows why and when you throw it
  • Make sure that caller of your function knows what to do if your exception is thrown
  • Decide which type will used for your exception
  • If there is not standard type that satisfy your needs you may decide to create your own exception type

CLS Compatible exceptions

In C# every generated exception is derived from Sytem.Exception this is limitation of the C# language. This is also required by CLS (common language specification), but there are other languages that create exceptions of type String, Int or any other type that is not CLS compatible. Earlier versions of .NET runtime supported only CLS compatible exceptions and didn't catch any other types. It means that if your code used some component written on another language and that component raised non CLS compatible exception you wouldn't catch it. From CLR 2.0 .NET has class RuntimeWrappedException that is used for such cases. Now when there is CLS incompatible exception this class wraps it and your code will receive exception that is derived from System.Exception. By using such approach Microsoft increased robustness of C# applications and now they are catching all the exceptions types.

If you want to treat CLS and non-CLS exceptions differently, you can catch them in the right order:

try {
    // some code
catch(RuntimeWrappedException ex) {
    // non-CLS exceptions
catch(Exception ex) {
    // CLS exceptions
}

Exceptions hierarchy in .NET

There are two types of exceptions: those that are generated by CLR runtime and those that are generated by application. For this purpose Microsoft developers created two types derived from System.Exception: ApplicationException and SystemException. It is planned to use ApplicationException as parent for exceptions that are generated by applications and SystemException to be parent for exceptions from CLR. Reality is different and system exceptions sometime derive ApplicationException and some application exceptions derive SystemException, some derive directly System.Exception. Finally there is some mess and Microsoft event wanted to eliminate ApplicationException and SystemException but it will corrupt existing software and they are keeping for backward compatibility.

Mostly SystemException is thrown when runtime has some issue. When you design your application and own exceptions there you should derive them from Exception class not SystemException. It is also not recommended to catch SystemException and throw it. Most critical exceptions from runtime are:

  • ExcecutionEngineException
  • StackOwerflowException
  • OutOfMemoryException

Also interop exceptions are derived from SystemException and following exceptions are system also:

  • COMException
  • Win32Exception
  • SEHException

Typical exceptions samples

Not every exception it is easy to emulate and reproduce. Sometimes only specific conditions only required, but some of them you can easily generate in your code. See few examples from me below:

try
{
    //out of range
    char[] arr = new char[5];
    char c = arr[6];
}
catch(IndexOutOfRangeException e)
{
    Console.WriteLine("Out of range catch with message: " + e.Message);
}
try
{
    //null reference
    object o = null;
    o.ToString();
}
catch (NullReferenceException e)
{
    Console.WriteLine("Null reference catch with message: " + e.Message);
}
try
{
    //argument null exception
    string s = null;
    "somestring".Contains(s);
}
catch (ArgumentNullException e)
{
    Console.WriteLine("Argument null catch with message: " + e.Message);
}

To play with this code you may download attached to article sample code.

Exceptions best practices

Below is the list of advices that I feel important for exceptions handling and want to share with you. There are much more in different sources and you can search for them. I didn't include some as I think they are not so relevant or disagree with some advices. It is only recommendation and not rules and it is up to you to decide which approach to use for your work.

  • Don't catch all exceptions - you should catch only exceptions that you expect and know how to handle inside your code. Don't make decisions for other and hide problems from callers. You should give ability to make decisions in code that calls your methods and don't catch exceptions that you are not able to handle.
  • Don't forget to use finally - most developers use only try and catch in their code. This is good that they use at list this, but finally is very powerful operator and approach in exceptions handling. You should not forget about it and use for code block that should be executed in any case. You should put all your resource cleaning and closing code to finally block and this will guarantee you free your resources properly and don't have leaks
  • You can catch all exceptions in your code and do some actions after exception catch, but then you should throw it again from your catch block. This is good style and approach.
  • If you have an option to check some condition or doing validation without catching exception and by simple check operator. Do this. Exceptions are for exceptional situations and not for checking if you're calling something on null pointer or not.
  • Order your catch blocks from very specific exception at the beginning to most common at the end
  • Prefer to use framework exceptions instead of your own. Try to avoid generating new exception types if this possible
  • When you raise an exception try to fill its fields with maximum information and make this information properly formatted and meaningful
  • Do not throw general exception types as System.Exception or System.SystemException
  • Catch specific exception only if you know why it was thrown and how to handle situation. Catching just for fun is not correct way of work that may impact important application flows

Error codes practice

If you will take a look at Windows API you'll see that quite a lot of them return HRESULT which is error code that is used in Windows API. Open file Winerror.h and there you'll find full list of HRESULT error codes that Microsoft defines for results of its functions. Besides this in case of some Windows API failed to run you can know why by calling GetLastError API that will return you DWORD value which you can convert to error message using some tools or looking in web. Basing on it you can see that for Windows API Microsoft decided to use error codes and not raising exceptions. Of course there can be exception raised while you run some API, but with the big probability this will be system runtime exception and not the one that is raised by code of API implementation.

Wrapping result of execution to error codes has benefits:

  • You can create a specific type for result of your operation that can contain any data you want
  • You don't need to derive from any type like Exception to implement your result
  • You have full control over the returned data from your functions
  • Callers of your function shouldn't take care about any exceptions types besides system as you're not throwing anything

The biggest problem to implement software that is based on exception that, I ever meet in my career, was different understanding of developers for a purpose, role and idea of exceptions. Let’s review 3 development teams that work to implement 3 layered software that consists from low level functionality, middle layer logic and high level UI. When you work with error codes it is more easy to interpret something. You write specification, create one global file with codes and everyone works with them. Functions, even when they failed, simply return some wrong code and that's all. With the exceptions life is much more complicated. You need to catch exceptions, once it is not catch your application may be unexpectedly closed\crashed or user will receive annoying messages from runtime. Now let's return back to our sample. In this sample low layer team implemented everything good and they throw exceptions all time they can't do something or things go wrong. This is good in case if exception is thrown all the time. You can imagine that some developer didn't throw exception when function works not well. It means that upper layer treat that it worked as should and you may have a bug that is really hard to catch. This is not only one problem bad things happen on layers above. Some developer may catch exception at middle layer and throw it to level of UI, some might decide to handle it at middle layer, some don't catch it at all. This create such a big mess in the project that you can't control it at all.

I participated in dozens of projects that tried to build their error handling basing on exceptions. Only one was successful. If team decides to use exceptions over error codes they should work very closely and each engineer should understand idea or error handling in project the same way. Otherwise you will fail. This is the main reason why big companies and big projects decide to go with error codes as primary way of result notification and use exceptions for exceptional cases and really abnormal situations. Another problem with exception is that after exception is thrown execution doesn't go linear operator by operator it jumps to catch and finally blocks and not all developers are capable to design and implement software in such a way. Deciding to go with exceptions only, this is important decision and you should think about pros and cons of it. If you ask me I prefer to use combined way and create my own type for return value of the project and use exceptions in parallel for some common exceptional situations. I'll review it below.

Exceptions vs Errors

After diving into exceptions and exceptions handling in C# I want to join to, probably, millions of publications and discussions named as "exceptions vs errors" or something similar. Since antic times of exceptions people discussing what is better exceptions or errors and what you should decide to use. I'm not going to continue disputes about what is better or not and want to share how me and my team work on this.

When we develop some module or part of application that exposes some kind of API for other, we return error codes from there. We define some ENUM with error codes then wrap it to structure with string that is text message for this error and this is our Error structure that we return from all APIs. Inside this API implementation we try to handle possible exceptions if we're aware of them. NOTE we handle only those exceptions we know how to deal. Quite often when we catch exception and know how to recovery from it we wrap it to our Error structure where Error.Code is something like ERR_XCEPTION (one of our enum values) and Error.Text is exception text message. When we have such approach used users of our API can rely on our Error structure as result of operation and integrate it in their UI and Logging system. From my perspective this is the most efficient work to work and it is very convenient, extendible and flexible. Those exceptions we don't know how to handle sometimes we catch, log them and re-throw; sometimes we ignore them; sometimes we do another solution depending on situation.

Basing on it if you ask me error code vs exception? My answer is both, you should use both and integrate them according to your needs.

Sources:

Jeffrey Richter - CLR via C#

Andrew Troelsen - Pro C# 5.0 and the .NET 4.5 Framework

https://msdn.microsoft.com

https://www.wikipedia.org

 

 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here