A situation where a method tries to log a custom exception (custom exception class as code sample) causes a problem:
[Serializable]
public class CustomException : Exception
{
public CustomException() { }
public CustomException(string message) : base(message) { }
public CustomException(string message, Exception inner) : base(message, inner) { }
protected CustomException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
Creating the exception:
CustomException ex = new CustomException("Here is a new custom exception! ");
LogError(ex);
Method logging the exceptions (custom and others!):
public static void LogError(Exception ex)
{
//Saving exception messages, inner exceptions etc
//...
}
In this case the ex.Stacktrace of the custom exception is null when logging it!
I believe the reason is that the logging method (which tries to be a general purpose method) takes a Exception object as parameter rather than CustomException (?). What is the correct way to create a logging method, as overloading it with different exception types does seem a bit counterintuitive?
I believe the reason is that the logging method (which tries to be a general purpose method) takes a Exception object as parameter rather than CustomException (?)
Incorrect. It's null since you have not actually thrown the exception, just created it.
The stacktrace is generated as the exception travels up the callstack. Throwing the exception in the same method as you catch it will only create one stack trace item.
You can use:
public static void LogError<T>(T exception)
{
// Serialize the exception here and write to log
}
Note that you can simply use any object here in compbination with a human readable serialization format (i.e. formatted Json). Then you can simply log the serialized representation of the object, where all public fields/properties will be preserved.
Note that you'll also need throw/catch for stacktrace to be constructed for you.
Throw the CustomException instance before logging it. The runtime will fill in the stacktrace info
Log exceptions in catch block
Check logging level and log only message or full exception information.
For example, we use extension methods for TraceSource to log exceptions:
public static void TraceException(this TraceSource traceSource, Exception ex)
{
traceSource.TraceException(string.Empty, ex);
}
public static void TraceException(this TraceSource traceSource, string comment, Exception ex)
{
if (!string.IsNullOrWhiteSpace(comment))
comment += "\r\n";
traceSource.TraceEvent(TraceEventType.Error, (int)TraceEventType.Error,
comment + "ExceptionType: {0} \r\n ExceptionMessage: {1}", ex.GetType(), ex.Message);
if (traceSource.Switch.Level == SourceLevels.Verbose ||
traceSource.Switch.Level == SourceLevels.All)
{
traceSource.TraceEvent(TraceEventType.Verbose, 0, ex.ToString());
}
}
Usage:
catch(Exception ex)
{
_log.TraceException(ex);
}
Related
I have a separate project in my solution, a library (seclib.dll), for handling custom error messages.
This is the whole contents
using System;
using System.IO;
namespace seclib
{
public class Exception : System.Exception
{
[Serializable]
public class FileNotFound : IOException
{
public FileNotFound() { }
public FileNotFound(string message)
: base(message) { }
public FileNotFound(string message, Exception inner)
: base(message, inner) { }
}
public class ProcessException : ApplicationException
{
public ProcessException() { }
public ProcessException(string message)
: base(message) { }
public ProcessException(string message, Exception inner)
: base(message, inner) { }
}
}
}
When I try to use it from my main project in the solution (reference exists), like
try
{
//some code here:
//1. try open a non existing file -> File not found
//2. I read the file but is empty, or I dont recognise contents -> Process exception manually
}
catch (System.IO.FileNotFoundException e)
{
throw seclib.Exception.FileNotFound("file error message", e);
}
catch (System.ApplicationException e)
{
throw seclib.Exception.ProcessException("some other error message", e);
}
I have the error (before compile) "class seclib.Exception.FileNotFound" (or, ProcessException in the second catch) and "Non-invocable member 'Exception.FileNotFound cannot be used as a method' (same for next catch, i.e. Exception.ProcessException.. etc).
If I delete the parenthesis i.e. used it as throw seclib.Exception.FileNotFound; etc., I receive 'Exception.FileNotFound' is a type, which is not valid in the given context.
Could someone please help me? Thank you very much
You need to create a new instance of the exception you want to throw:
// notice the "new" keyword
throw new seclib.Exception.FileNotFound("file error message", e);
Is Exception right?
The constuctors defined for FileNotFound and ProcessException currently take an inner Exception as an argument, but Exception in that scope refers to the enclosing seclib.Exception class - change the constructor signatures to:
public FileNotFound(string message, System.Exception inner) // System.Exception will resolve to the type you expect
: base(message, inner) { }
Are your catch expressions right?
Since FileNotFound and ProcessException inherit from the base types you're currently catching, you might end up nesting either multiple times - maybe you'll want to test for that:
try {
}
catch (System.IO.FileNotFoundException e)
{
if(e is seclib.Exception.FileNotFound)
// Already wrapped in our custom exception type, re-throw as is
throw;
throw new seclib.Exception.FileNotFound("file error message", e);
}
or
try {
}
catch (seclib.Exception)
{
// already wrapped, move along
throw;
}
catch (System.IO.FileNotFoundException e)
{
throw new seclib.Exception.FileNotFound("file error message", e);
}
catch (System.ApplicationException e)
...
I want to overload the throw keyword to catch a class which inherits from Exception and to have it do some logging and other stuff before the actual throw. Is this possible? Or do I have to use a regular function?
I've tried:
public class cSilException : Exception
{
private string m_strMsg;
public override void throw(cSilException ex)
{
}
...
...
}
Register the event AppDomain.FirstChanceException. There you get all exceptions before the are actually thrown. In the event handler you can check for your exception and do the required logging.
No magic and no bad design.
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
DoBadThings();
}
private static void DoBadThings()
{
DoOneLevelBelow();
}
private static void DoOneLevelBelow()
{
for(int i=0;i<10;i++)
{
try
{
if (i == 5)
{
var invalidCast = (string)((object)i);
}
else
{
throw new InvalidTimeZoneException();
}
}
catch
{
}
}
}
static void CurrentDomain_FirstChanceException(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
{
if( e.Exception is InvalidCastException)
{
LogInvalidCast((InvalidCastException)e.Exception);
}
}
private static void LogInvalidCast(InvalidCastException invalidCastException)
{
Console.WriteLine("Got Invalid cast: {0}", invalidCastException);
}
This will lead to:
Got invalid cast: System.InvalidCastException: The object of the type
"System.Int32" cannot be converted to "System.String". at
ThrowTest.Program.DoOneLevelBelow() in
d:\Media\Blog\ThrowTest\Program.cs:line 31.
Please note since you are getting the exception before the stack is unwound you will see only the method where it did happen but not the calling methods since the stack was not unwound yet.
If you want the complete call stack you can use Environment.StackTrace to get all stack frames.
What you want to do is add a constructor to your exception and do whatever you need to do within that constructor.
public class cSilException : Exception
{
//constructor
public cSilException()
{
// do stuff here
}
}
Your notion of "overloading the throw keyword" was quite, er, how to put it, psychedelic.
Of course, as many have pointed out, it is best to avoid doing this if your intention is to do things such as logging. Alois Kraus has posted another answer with a very good suggestion.
I wouldn't recommend logging anything inside the exception's constructor since it violates the single responsibility principle and is considered a bad design. Also, the fact that an exception was created doesn't necessarily mean it has been thrown, and besides, exceptions can be caught and rethrown - these things may lead to incorrect logging messages.
Instead, you can use an application-wide exception handler which will handle exceptions according to your predefined policy. For example, you can have a look at the Enterprise Library Exception Handling Block and specifically this section.
You can't overload throw it is an integral part of the language (not a member of a class)
If you want to handle a specific Exception you should catch that exception:
try
{
// your code, which throws some exceptions
}
catch(cSilException csEx)
{
// handle csEx
throw; // rethrow this exception
}
catch(Exception ex)
{
// handle all other exceptions
}
This code catches the special exception cSilExceptionin a different code block than all other exceptions.
Look for methods and members of Exception class. You can define constructor for cSilException like this
public cSilException(string message)
{
Message = message;
}
and than in catch (cSilException ex) do Console.WriteLine(ex.Message);
Here's is my program
class Program
{
static void Main(string[] args)
{
throw new UserAlreadyLoggedInException("Hello");
}
}
public class UserAlreadyLoggedInException : Exception
{
public UserAlreadyLoggedInException(string message) : base(message)
{
Console.WriteLine("Here");
}
}
Now, I know that base class constructor runs before derived class constructor. But when I run the above code the output comes out to be
Here
Unhandled Exception:Testing.UserAlreadyLoggedInException:Hello.
How come "Here" is printed before Unhandled.....?
You first have to create the exception, before you can be thrown.
Creation of the exception instance initiated by new UserAlreadyLoggedInException;
UserAlreadyLoggedInException constructor called;
Call to Console.WriteLine inside constructor;
Constructor done;
Throwing of the newly created exception instance;
The exception isn't handled, thus the application error handler writes the error to the console.
Why don't you try this:
static class Program
{
static void Main()
{
throw new UserAlreadyLoggedInException("Hello");
}
}
class LoginException : Exception
{
public LoginException(string message) : base(message)
{
Console.WriteLine("least derived class");
}
}
class UserAlreadyLoggedInException : LoginException
{
public UserAlreadyLoggedInException(string message) : base(message)
{
Console.WriteLine("most derived class");
}
}
You can also try writing your Main method like this:
static void Main()
{
var ualie = new UserAlreadyLoggedInException("Hello");
Console.WriteLine("nothing bad has happened yet; nothing thrown yet");
throw ualie;
}
So constructing an Exception instance with the new keyword does not "raise" or "throw" an exception. You need throw for that. The throw statement works by first evaluating the expression that comes after the throw keyword. The result of that evaluation will be a reference to an exception instance. After evaluating the expression, throw "throws" the exception referred by the value of the expression.
Your misunderstanding is that the Exception "explodes" as soon as the instance constructor to System.Exception runs. That is not the case.
If you add a try/catch of your own the program flow becomes more apparent. Note that Exception's constructor does not write anything it just stores the message string for later use.
class Program
{
static void Main(string[] args)
{
try
{
throw new UserAlreadyLoggedInException("Hello");
}
catch (Exception e)
{
Console.WriteLine("My handled exception: {0}", e.Message);
}
}
}
public class UserAlreadyLoggedInException : Exception
{
public UserAlreadyLoggedInException(string message) : base(message)
{
Console.WriteLine("Here");
}
}
The exception is printed to the console after it has been instantiated and thrown.
The instantiation prints "Here", then the runtime catches it and prints the "Unhandled Exception:" ToString() representation.
I have a series of classes in my application set up like follows:
abstract class Foo<TYPE> where TYPE : new()
{
public void Error()
{
List<TYPE> foo = null;
foo.Add(new TYPE());
}
}
class Bar : Foo<int>
{
}
When the call to Bar.Error() throws an exception, the stack trace simply reports it as being in Foo'1.Error(). I know exactly why it does that, but I need to know that it was a Bar object actually throwing the error. How can I derive that from the Exception object that gets thrown?
You can't, just from an exception you don't control. There's no indication in the exception what instance happened to have a method executing when the exception was generated.
I would suggest using a debugger (so that you can break if the exception is thrown) and/or using more diagnostic logging. (For example, log the type of this at the start of the method.)
Original answer, when the method itself directly threw the exception
(Keeping this for posterity - it might be useful to others.)
You could use the Source property, or perhaps the Data property to record the name of the type or the instance. For example:
abstract class Foo<TYPE>
{
public void Error()
{
throw new Exception("Whoops") { Data = {{ "Instance", this }} };
}
}
... then use:
catch (Exception e)
{
var instance = e.Data["instance"];
// Use the instance
}
This is a pretty odd use, however. It may well be more appropriate to throw your own custom exception type which explicitly knows about the instance that generated it.
You could try writing a custom Exception type that has a Type property, something like
public class CustomException : Exception {
public Type ExceptionSourceType{get;set;}
}
abstract class Foo<TYPE>
{
public void Error()
{
var exception = new CustomException ("Whoops");
exception.ExceptionSourceType = this.GetType();
throw exception;
}
}
Then if you specifically catch those types of errors you can easily access the property
catch(CustomException ex){
var sourceType = ex.ExceptionSourceType;
}
Why does the high part of the stack (in Exception.StackTrace) gets truncated?
Let's see a simple example:
public void ExternalMethod()
{
InternalMethod();
}
public void InternalMethod()
{
try
{
throw new Exception();
}
catch(Exception ex)
{
// ex.StackTrace here doesn't contain ExternalMethod()!
}
}
It seems like this is "by design". But what are the reasons for such a strange design? It only makes debugging more complex, because in log messages I can't understand who called InternalMethod() and often this information is very necessary.
As for solutions (for those who don't know), there are 2 general solutions as I understand:
1) We can log static Environment.StackTrace property, which contains the whole stack (for example, starting at the hiest level (message queue) and ending at the deepest method in which exception occurs).
2) We have to catch and log exceptions on highest levels. When we need to catch exceptions on lower levels to do something, we need to rethrow (with "throw" statement in C#) it further up.
But the question is about reasons of such design.
Ok, now I see what your getting at... Sorry for my confusion on the inlining thing.
The 'stack' in a caught exception is only a delta from the currently executing catch block to where the exception was thrown. Conceptually this behavior is correct in that the Exception.StackTrack tells you where the exception occurred within the context of this try/catch block. This allows exception stacks to be forwarded across 'virtual' calls and still maintain accuracy. One classic example of this being done is .Net Remoting exceptions.
Thus if you want a complete stack report in the catch block you would add the current stack to the exception's stack as in the example below. The only problem is this can be more expensive.
private void InternalMethod()
{
try
{
ThrowSomething();
}
catch (Exception ex)
{
StackTrace currentStack = new StackTrace(1, true);
StackTrace exceptionStack = new StackTrace(ex, true);
string fullStackMessage = exceptionStack.ToString() + currentStack.ToString();
}
}
As csharptest said this is by design. The StackTrace stops at the try block. Further more there is no hook in the framework that is called when an exception is thrown.
So the best you can do is something along these lines, it its an absolute requirement to get full stack traces (store a full trace on exceptions creation):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
using System.Diagnostics;
namespace ConsoleApplication15 {
[global::System.Serializable]
public class SuperException : Exception {
private void SaveStack() {
fullTrace = Environment.StackTrace;
}
public SuperException() { SaveStack(); }
public SuperException(string message) : base(message) { SaveStack(); }
public SuperException(string message, Exception inner) : base(message, inner) { SaveStack(); }
protected SuperException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
private string fullTrace;
public override string StackTrace {
get {
return fullTrace;
}
}
}
class Program {
public void ExternalMethod() {
InternalMethod();
}
public void InternalMethod() {
try {
ThrowIt();
} catch (Exception ex) {
Console.WriteLine(ex.StackTrace);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThrowIt() {
throw new SuperException();
}
static void Main(string[] args) {
new Program().ExternalMethod();
Console.ReadKey();
}
}
}
Outputs:
at System.Environment.get_StackTrace()
at ConsoleApplication15.SuperException..ctor() in C:\Users\sam\Desktop\Source
\ConsoleApplication15\ConsoleApplication15\Program.cs:line 17
at ConsoleApplication15.Program.ThrowIt() in C:\Users\sam\Desktop\Source\Cons
oleApplication15\ConsoleApplication15\Program.cs:line 49
at ConsoleApplication15.Program.InternalMethod() in C:\Users\sam\Desktop\Sour
ce\ConsoleApplication15\ConsoleApplication15\Program.cs:line 41
at ConsoleApplication15.Program.Main(String[] args) in C:\Users\sam\Desktop\S
ource\ConsoleApplication15\ConsoleApplication15\Program.cs:line 55
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C
ontextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
It is not possible to inject this behaviour into the existing System defined exceptions, but .Net has a rich infrastructure for wrapping exceptions and rethrowing so it should not be a huge deal.
I know that in a catch block if you do throw ex; it truncates the stack trace at that point. It's possible that it's "by design" for throw since just throw; doesn't truncate the stack in a catch. Same may be going on here since you're throwing a new exception.
What happens if you cause an actual exception (i.e. int i = 100/0;)? Is the stack trace still truncated?
This is often caused by the compiler optimizations.
You can decorate methods you do not want to inline by using the following attribute:
[MethodImpl(MethodImplOptions.NoInlining)]
public void ExternalMethod()
{
InternalMethod();
}