I am trying to understand Exception handling in C#. I have a sample program.
class Program
{
static void Main(string[] args)
{
Program p = new Program();
try
{
p.Method2();
}
catch (Exception ex)
{
Console.WriteLine("Enter into Main()");
Console.WriteLine("The original Stack Trace Line No 47 is missing in current Stack Trace.");
Console.WriteLine("------------------------------------------------------------------------");
Console.Write(ex.StackTrace.ToString());
Console.ReadKey();
}
}
private void Method2()
{
try
{
Method1();
}
catch (Exception ex)
{
//throw ex resets the stack trace Coming from Method 1 and propogates it to the caller(Main)
throw;
}
}
private void Method1()
{
try
{
throw new Exception("Inside Method1");
}
catch (Exception ex)
{
Console.WriteLine("Exception " + ex);
throw;
}
}
}
I would like to see the original stack trace line number in the main method(which I can see in the catch block of the Method1). Is this possible?
I'm on .NET Core, but I think it works the same for .NET Framework. I copied your code, and just added line number as comments in the interesting lines:
private void Method1()
{
try
{
throw new Exception("Inside Method1"); // line 42
}
catch (Exception ex)
{
Console.WriteLine("Exception " + ex);
throw; // line 47
}
}
The code above print the following:
at Main.Program.Method1() in C:...\Main.cs:line 42
in both Console.WriteLine in Method1 and Main.
If I replace throw by throw ex in the catch block, then it prints:
at Main.Program.Method1() in C:...\Main.cs:line 42
in Console.WriteLine in Method1, and
at Main.Program.Method1() in C:...\Main.cs:line 47
in Console.WriteLine in Main, because the exception is rethrown, so the line number change.
All of that to say that your code works as you expect; so the code you are executing is maybe not the one you compile :-)
You can make use of the StackTrace class to get more information like ClassName , LineNumber etc. Eg below
catch (Exception ex)
{
// Get stack trace for the exception with source file information
var st = new StackTrace(ex, true);
// Get the top stack frame
var frame = st.GetFrame(0);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
}
Edit
An even better way to do is, create a concrete place like this where you can just pass the Exception to get all the information you need.
public static AdditionalInformation GetStackTrace(Exception exception)
{
var trace = new StackTrace(exception, true);
var reflectedType = trace.GetFrame(0).GetMethod().ReflectedType;
var additionalInformation = new AdditionalInformation();
if (reflectedType != null)
{
additionalInformation = new AdditionalInformation()
{
Column = trace.GetFrame(0).GetFileColumnNumber(),
Line = trace.GetFrame(0).GetFileLineNumber(),
MethodName = reflectedType.FullName,
File = trace.GetFrame(0).GetFileName()
};
}
return additionalInformation;
}
Related
Is there a way when catching an exception to determine if it were constructed with a non-default message.
try
{
throw new Exception(message); // case 1
//throw new Exception(); // case 2
}
catch(Exception exp)
{
/* what do I put here such that if the case 2 exception were
caught it would output exp.ToString() instead of exp.Message? */
textBox1.Text = exp.Message; // case 1 handeling
}
Just to clarify when Exception(message) is thrown I want it to ouptut exp.Message and when Exception() is thrown I want to output exp.ToString(). I would prefer to accomplish this without adding a custom exception. Thanks.
You need to check the message against a default exception
catch (Exception e)
{
bool isDefaultMessage = e.Message == new Exception().Message;
}
Update
Difference types of Exception
catch (Exception e)
{
bool isDefaultMessage = false;
try
{
var x = (Exception) Activator.CreateInstance(e.GetType());
isDefaultMessage = e.Message == x.Message;
}
catch (Exception) {} // cannot create default exception.
}
Hi all you clever guys,
I have a question regarding exception handling when dealing with .NET Reflection in C#.
Basically I call a constructor on a class through the use of ContructorInfo.Invoke(new object[] { ... }).
I wrap it all in a try/catch like this:
try
{
preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
Exception baseEx = e.GetBaseException();
Utilities.Log("GetBaseException", baseEx.StackTrace);
if (baseEx != null)
throw baseEx;
else
throw e;
}
My question is that why is baseEx.StackTrace not the stacktrace I see when the baseEx is thrown?
The stacktrace I see when throwing the exception does only contain a trace "outside of" constructor.Invoke() whilst Utilities.Log("GetBaseException", baseEx.StackTrace); shows me the full trace "inside of" constructor.Invoke().
EDIT:
By using the answer of #Knaģis, here is the actual solution to my problem:
Exception baseEx = e.GetBaseException();
if (baseEx != null)
{
throw new Exception("CreateExport Exception", baseEx);
}
When you do throw baseEx; the runtime will assign a new stack trace for the exception thrown. This has nothing to do with Reflection or your specific use case.
If you need to preserve the original stack trace, use a simple throw; (without an argument) - it rethrows the exact same exception you caught, preserving all details:
try
{
preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
Exception baseEx = e.GetBaseException();
Utilities.Log("GetBaseException", baseEx.StackTrace);
throw;
}
try this:
using System.Runtime.Serialization;
public static class ExceptionHelper
{
public static void PreserveStackTrace(this Exception e)
{
var streamingContext = new StreamingContext(StreamingContextStates.CrossAppDomain);
var objectManager = new ObjectManager(null, streamingContext);
var serializationInfo = new SerializationInfo(e.GetType(), new FormatterConverter());
e.GetObjectData(serializationInfo, streamingContext);
objectManager.RegisterObject(e, 1, serializationInfo);
objectManager.DoFixups();
}
}
and use before rethrow:
try
{
preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
Exception baseEx = e.GetBaseException();
Utilities.Log("GetBaseException", baseEx.StackTrace);
baseEx.PreserveStackTrace();
if (baseEx != null)
throw baseEx;
else
throw e;
}
Story: I've 3 functions from 3 different classes. Functions calling order is:
Form1_Load(...) -> Student.GetAllStudents(...) -> StudentDAL.GetStudentInformation(...) -> ConnectionManager.GetConnection(...)
What I want to do is to display StackTrace of the inner most function i.e. ConnectionManager.GetConnection(), in a MessageBox in Form1 class. In other words I don't want to use MessageBox in any inner classes, but only in outer most class that is Form1 class.
Problem: To get inner exceptions we can use InnerException or GetBaseException() etc. but when I try to get inner exception it throws an exception "Object reference not set to an instance", meaning that there is no inner exception and, when I check, the value is also null. All I want to know here why it's null? Shouldn't it be holding reference to the inner exception? Correct me if I'm wrong.
Function codes :
Form1_Load(...)
private void Form1_Load(object sender, EventArgs e)
{
try
{
DataTable dt = new DataTable();
dt.Load((**new Student().GetAllStudents()**));
if (dt.Rows.Count <= 0)
{
MessageBox.Show("Student table empty.");
}
else
{
this.dataGridView1.DataSource = dt;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message+Environment.NewLine+"Source(s) : "+ex.StackTrace.Substring(0, ex.StackTrace.LastIndexOf("at")));
}
GetAllStudents(...)
public SqlDataReader GetAllStudents()
{
try
{
return StudentInformationDataAccessLayer.GetStudentInformation();
}
catch (Exception ex)
{
throw ex;
}
}
GetStudentInformation(...)
public static SqlDataReader GetStudentInformation()
{
try
{
SqlConnection sqlCon = null;
sqlCon = ConnectionManager.GetConnection();
if (sqlCon == null)
{
return null;
}
String Query = null;
Query = "SELECT * FROM [dbo].[Student]";
SqlCommand cmd = new SqlCommand(Query, sqlCon);
SqlDataReader dr = null;
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return dr;
}
catch (Exception ex)
{
throw ex;
}
}
GetConnection(...)
public static SqlConnection GetConnection()
{
String _connectionString = null;
_connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
if (_connectionString == null)
{
return null;
}
try
{
SqlConnection connection = new SqlConnection(_connectionString);
connection.Open();
return connection;
}
catch (Exception ex)
{
throw ex;
}
}
If you want stack trace and exception information to be preserved, you should change the code that re-throws caught exceptions like this:
}
catch(Exception ex)
{
// do what you need to do with ex
// ..
// rethrow..
throw; // notice this is not "throw ex";
}
Re-throwing the exception using just throw; preserves the original stack trace. There won't necessarily be an inner exception but that's not what you should care about. What you need to know is the stack trace of where the exception originated.
If you want to re-throw with inner exception set, use below code, but remember that you will lose stack trace:
try
{
...
}
catch (Exception ex)
{
throw new Exception("message", ex);
}
To just re-throw an exception and preserve stack trace, use:
try
{
...
}
catch (Exception ex)
{
throw;
}
Not every exception do actually have an inner exception. First check if inner ex is a null and if it is not then process it.
Having said this, you can of course re-throw your exception like below:
catch(Exception ex)
{
// so smth
// ..
// rethrow..
throw;
}
But please remember two things:
Do not type throw ex, just throw.
Do it only if you really want to do something with this exception before rethrowing. If you don't have such a plan, just don't catch it on this level.
I would do something like:
try
{
...
}
catch (Exception ex)
{
if (ex.InnerException == null)
throw ex;
else
throw ex.InnerException;
}
then at some point where you want to do the stack trace, do something along the lines of:
StackTrace trace = new StackTrace(System.Threading.Thread.CurrentThread, true);
StackFrame[] frames = trace.GetFrames();
string result = string.Empty;
foreach (StackFrame sf in frames)
{
string += sf.GetMethod().Name;
}
MessageBox(result);
If a finally block throws an exception, what exactly happens?
Specifically, what happens if the exception is thrown midway through a finally block. Do the rest of statements (after) in this block get invoked?
I am aware that exceptions will propagate upwards.
If a finally block throws an exception what exactly happens ?
That exception propagates out and up, and will (can) be handled at a higher level.
Your finally block will not be completed beyond the point where the exception is thrown.
If the finally block was executing during the handling of an earlier exception then that first exception is lost.
C# 4 Language Specification § 8.9.5: If the finally block throws another exception, processing of the current exception is terminated.
For questions like these I usually open up an empty console application project in Visual Studio and write a small sample program:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
catch (Exception ex)
{
Console.WriteLine("Inner catch block handling {0}.", ex.Message);
throw;
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
When you run the program you will see the exact order in which catch and finally blocks are executed. Please note that code in the finally block after the exception is being thrown will not be executed (in fact, in this sample program Visual Studio will even warn you that it has detected unreachable code):
Inner catch block handling exception thrown from try block.
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block
Additional Remark
As Michael Damatov pointed out, an exception from the try block will be "eaten" if you don't handle it in an (inner) catch block. In fact, in the example above the re-thrown exception does not appear in the outer catch block. To make that even more clear look at the following slightly modified sample:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
As you can see from the output the inner exception is "lost" (i.e. ignored):
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block
If there is an exception pending (when the try block has a finally but no catch), the new exception replaces that one.
If there is no exception pending, it works just as throwing an exception outside the finally block.
Quick (and rather obvious) snippet to save "original exception" (thrown in try block) and sacrifice "finally exception" (thrown in finally block), in case original one is more important for you:
try
{
throw new Exception("Original Exception");
}
finally
{
try
{
throw new Exception("Finally Exception");
}
catch
{ }
}
When code above is executed, "Original Exception" propagates up the call stack, and "Finally Exception" is lost.
The exception is propagated.
Throwing an exception while another exception is active will result in the first exception getting replaced by the second (later) exception.
Here is some code that illustrates what happens:
public static void Main(string[] args)
{
try
{
try
{
throw new Exception("first exception");
}
finally
{
//try
{
throw new Exception("second exception");
}
//catch (Exception)
{
//throw;
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
Run the code and you will see "second exception"
Uncomment the try and catch statements and you will see "first exception"
Also uncomment the throw; statement and you will see "second exception" again.
Some months ago i also faced something like this,
private void RaiseException(String errorMessage)
{
throw new Exception(errorMessage);
}
private void DoTaskForFinally()
{
RaiseException("Error for finally");
}
private void DoTaskForCatch()
{
RaiseException("Error for catch");
}
private void DoTaskForTry()
{
RaiseException("Error for try");
}
try
{
/*lacks the exception*/
DoTaskForTry();
}
catch (Exception exception)
{
/*lacks the exception*/
DoTaskForCatch();
}
finally
{
/*the result exception*/
DoTaskForFinally();
}
To solve such problem i made a utility class like
class ProcessHandler : Exception
{
private enum ProcessType
{
Try,
Catch,
Finally,
}
private Boolean _hasException;
private Boolean _hasTryException;
private Boolean _hasCatchException;
private Boolean _hasFinnallyException;
public Boolean HasException { get { return _hasException; } }
public Boolean HasTryException { get { return _hasTryException; } }
public Boolean HasCatchException { get { return _hasCatchException; } }
public Boolean HasFinnallyException { get { return _hasFinnallyException; } }
public Dictionary<String, Exception> Exceptions { get; private set; }
public readonly Action TryAction;
public readonly Action CatchAction;
public readonly Action FinallyAction;
public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null)
{
TryAction = tryAction;
CatchAction = catchAction;
FinallyAction = finallyAction;
_hasException = false;
_hasTryException = false;
_hasCatchException = false;
_hasFinnallyException = false;
Exceptions = new Dictionary<string, Exception>();
}
private void Invoke(Action action, ref Boolean isError, ProcessType processType)
{
try
{
action.Invoke();
}
catch (Exception exception)
{
_hasException = true;
isError = true;
Exceptions.Add(processType.ToString(), exception);
}
}
private void InvokeTryAction()
{
if (TryAction == null)
{
return;
}
Invoke(TryAction, ref _hasTryException, ProcessType.Try);
}
private void InvokeCatchAction()
{
if (CatchAction == null)
{
return;
}
Invoke(TryAction, ref _hasCatchException, ProcessType.Catch);
}
private void InvokeFinallyAction()
{
if (FinallyAction == null)
{
return;
}
Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally);
}
public void InvokeActions()
{
InvokeTryAction();
if (HasTryException)
{
InvokeCatchAction();
}
InvokeFinallyAction();
if (HasException)
{
throw this;
}
}
}
And used like this
try
{
ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally);
handler.InvokeActions();
}
catch (Exception exception)
{
var processError = exception as ProcessHandler;
/*this exception contains all exceptions*/
throw new Exception("Error to Process Actions", exception);
}
but if you want to use paramaters and return types that's an other story
The exception propagates up, and should be handled at a higher level. If the exception is not handled at the higher level, the application crashes. The "finally" block execution stops at the point where the exception is thrown.
Irrespective of whether there is an exception or not "finally" block is guaranteed to execute.
If the "finally" block is being executed after an exception has occurred in the try block,
and if that exception is not handled
and if the finally block throws an exception
Then the original exception that occurred in the try block is lost.
public class Exception
{
public static void Main()
{
try
{
SomeMethod();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void SomeMethod()
{
try
{
// This exception will be lost
throw new Exception("Exception in try block");
}
finally
{
throw new Exception("Exception in finally block");
}
}
}
Great article for Details
I had to do this for catching an error trying to close a stream that was never opened because of an exception.
errorMessage = string.Empty;
try
{
byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent);
webRequest = WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "text/xml;charset=utf-8";
webRequest.ContentLength = requestBytes.Length;
//send the request
using (var sw = webRequest.GetRequestStream())
{
sw.Write(requestBytes, 0, requestBytes.Length);
}
//get the response
webResponse = webRequest.GetResponse();
using (var sr = new StreamReader(webResponse.GetResponseStream()))
{
returnVal = sr.ReadToEnd();
sr.Close();
}
}
catch (Exception ex)
{
errorMessage = ex.ToString();
}
finally
{
try
{
if (webRequest.GetRequestStream() != null)
webRequest.GetRequestStream().Close();
if (webResponse.GetResponseStream() != null)
webResponse.GetResponseStream().Close();
}
catch (Exception exw)
{
errorMessage = exw.ToString();
}
}
if the webRequest was created but a connection error happened during the
using (var sw = webRequest.GetRequestStream())
then the finally would catch an exception trying to close up connections it thought was open because the webRequest had been created.
If the finally didnt have a try-catch inside, this code would cause an unhandled exception while cleaning up the webRequest
if (webRequest.GetRequestStream() != null)
from there the code would exit without properly handling the error that happened and therefore causing issues for the calling method.
Hope this helps as an example
public void MyMethod()
{
try
{
}
catch{}
finally
{
CodeA
}
CodeB
}
The way the exceptions thrown by CodeA and CodeB are handled is the same.
An exception thrown in a finally block has nothing special, treat it as the exception throw by code B.
It throws an exception ;) You can catch that exception in some other catch clause.
Basically, what I want to do is pass a specific Exception to a more general Exception within the same try block. I've tried the following and it doesn't work:
static bool example(int count = 0)
{
try
{
work();
}
catch (TimeoutException e)
{
if (count < 3)
{
Console.WriteLine("Caught TimeoutException: {0}", e.Message);
return example(count + 1);
}
else
{
throw new Exception(e.Message);
}
}
catch (Exception e)
{
Console.WriteLine("Caught Exception: {0}", e.Message + " rethrown");
return false;
}
return true;
}
static void work()
{
throw new TimeoutException("test");
}
I want the TimeoutException to be only handled a certain amount of times before going to a more generic Exception. This is because the TimeoutException has additional information about the exception on a case by case basis. I do not want to duplicate the code for Exception under the else clause of TimeoutException. The reason I want all exceptions to be handled is that there may be other unknown exceptions that are thrown. The nature of the program requires it to not crash so I must account for any other exceptions and log them. How can I implement this?
You would need to nest this as 2 tries if you want to handle this this way:
static bool example(int count = 0)
{
try
{
try
{
work();
}
catch (TimeoutException e)
{
if (count < 3)
{
Console.WriteLine("Caught TimeoutException: {0}", e.Message);
return example(count + 1);
}
else
{
// Just throw, don't make a new exception
throw; // new Exception(e.Message);
}
}
}
catch (Exception e)
{
Console.WriteLine("Caught Exception: {0}", e.Message + " rethrown");
return false;
}
return true;
}
The "inner try/catch" will only catch TimeoutException, so any other exception will always go to the outer scope. When you rethrow, it'll automatically get caught by the outer scope, as well, which eliminates the need for killing the exception information. (If you throw new Exception, you lose your stack trace data, and other very valuable debugging information.)
Here's my take:
bool example()
{
// Attempt the operation a maximum of three times.
for (int i = 0; i < 3; i++)
{
try
{
work();
return true;
}
catch (Exception e)
{
Console.WriteLine("Caught exception {0}", e.Message);
// Fail immediately if this isn't a TimeoutException.
if (!(e is TimeoutException))
return false;
}
}
return false;
}
EDIT
If you want to actually do something with the TimeoutException, you could change the catch block like so:
catch (Exception e)
{
// As Reed pointed out, you can move this into the if block if you want
// different messages for the two cases.
Console.WriteLine("Caught exception {0}", e.Message);
TimeoutException timeoutException = e as TimeoutException;
if (timeoutException != null)
{
// Do stuff with timeout info...
}
else
{
// Not a timeout error, fail immediately
return false;
}
}