Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET error handling

I have been writing .NET applications and have been impressed with the error handling included in the framework.

When catching an error that has been throw by the processes or somewhere in the code I like to include the message (ex.Message, which is usually pretty general) but also the stacktrace (ex.stacktrace) which helps to trace the problem back to a specific spot.

For a simple example let's say for instance that we are recording numbers to a log in a method:

public void ExampleMethod(int number){
    try{
        int num = number
        ...open connection to file
        ...write number to file
    }
    catch(Exception ex){
        .... deal with exception (ex.message,ex.stacktrace etc...)
    }
    finally{
    ...close file connection
    }
}

Is there any way to see the method called (in this case ExampleMethod) with the specific number that was passed that potentially crashed the method call? I believe you could log this perhaps in the catch block but I am interested essentially in catching the method call and parameters that caused the system to throw the exception.

Any ideas?

like image 700
JBone Avatar asked Aug 18 '11 15:08

JBone


People also ask

Which is the best way to handle errors in net?

You can handle default errors at the application level either by modifying your application's configuration or by adding an Application_Error handler in the Global. asax file of your application. You can handle default errors and HTTP errors by adding a customErrors section to the Web. config file.

What are the error handling methods?

Error-handling techniques for logic errors or bugs is usually by meticulous application debugging or troubleshooting. Error-handling applications can resolve runtime errors or have their impact minimized by adopting reasonable countermeasures depending on the environment.


4 Answers

I suggest stuffing the parameter values into the exception's Data dictionary, e.g.

public void ExampleMethod(int number) {
try {
    int num = number
    ...open connection to file
    ...write number to file
}
catch(Exception ex) {
    ex.Data["number"] = number;
    //.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally {
    //...close file connection
}

Another advantage of this method is that you can stuff the parameters in the catch block, then re-throw the exception and log it somewhere else without losing the stack trace, e.g.

catch(Exception ex) {
    ex.Data["number"] = number;
    throw;
}
like image 84
Christian Hayter Avatar answered Oct 20 '22 13:10

Christian Hayter


If you want to know the value of the parameters in your method, then there is only one way, IMO, to do it - you need to repackage the exception with data.

For example:

 int param1 = 10;
 string param2 = "Hello World";

 try
 {
     SomeMethod(param1, param2)
 }
 catch(SomeExpectedException e)
 {
      throw new MyParameterSensitiveException(e, param1, param2);
 }

You basically repackage the original exception as the inner exception of another exception, and additionally supply the parameters you used to call the method. Then you could inspect that in some way to figure out what went wrong.

like image 7
Tejs Avatar answered Oct 20 '22 14:10

Tejs


The accepted answer and many of the solutions described will work fine but what you're doing is littering your source with a slightly different blob of code depending on what parameters are in your method signature.

When it comes time to add a new parameter you need to remember to update your handler to add that new parameter. Or if you remove a parameter then you need to remember to remove the parameter from your exception handler.

What if you have a two or more try..catch blocks? Then you now have two blocks of code to keep up to date. Definitely not refactor friendly.

Another approach is to remove the logging code use a technique called Aspect Oriented Programming.

One such tool to facilitate this is a product called PostSharp.

With PostSharp you can write a logger than is invoked whenever an exception is thrown without the need for messy method and parameter specific code. For example (using version 1.5 of PostSharp):

LoggerAttribute.cs -

[Serializable]
public class LoggerAttribute : OnExceptionAspect
{
  public override void OnException(MethodExecutionEventArgs eventArgs)
  {
    Console.WriteLine(eventArgs.Method.DeclaringType.Name);
    Console.WriteLine(eventArgs.Method.Name);
    Console.WriteLine(eventArgs.Exception.StackTrace);

    ParameterInfo[] parameterInfos = eventArgs.Method.GetParameters();
    object[] paramValues = eventArgs.GetReadOnlyArgumentArray();

    for (int i = 0; i < parameterInfos.Length; i++)
    {
      Console.WriteLine(parameterInfos[i].Name + "=" + paramValues[i]);
    }

    eventArgs.FlowBehavior = FlowBehavior.Default;
  }
}

You then decorate your classes with the LoggerAttribute:

[Logger]
public class MyClass
{
  public void MyMethod(int x, string name)
  {
      // Something that throws an exception
  }
}

Anything that throws an exception in MyMethod will cause the OnException method to be executed.

There are two versions of PostSharp. Version 1.5 is free and open sourced under the GPL and is targeted at .NET 2.0. PostSharp 2.0 is not entirely free but its community edition will support the basic functionality described above.

like image 1
Kev Avatar answered Oct 20 '22 15:10

Kev


In order to do this:

public void MyProblematicMethod(int id, string name)
{
    try
    {
        object o = null;
        int hash = o.GetHashCode(); // throws NullReferenceException
    }
    catch (Exception ex)
    {
        string errorMessage = SummarizeMethodCall(MethodBase.GetCurrentMethod(), id, name);
        // TODO: do something with errorMessage
    }
}

...and get this:

"MyProblematicMethod invoked: id = 1, name = Charlie"

...you could do something like this:

public static string SummarizeMethodCall(MethodBase method, params object[] values)
{
    var output = new StringBuilder(method.Name + " invoked: ");
    ParameterInfo[] parameters = method.GetParameters();
    for (int i = 0; i < parameters.Length; i++)
    {
        output.AppendFormat("{0} = {1}",
            parameters[i].Name,
            i >= values.Length ? "<empty>" : values[i]
        );
        if (i < parameters.Length - 1)
            output.Append(", ");
    }
    return output.ToString();
}
like image 1
D. A. Terre Avatar answered Oct 20 '22 14:10

D. A. Terre