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?
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.
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.
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;
}
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.
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.
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With