I have caught an exception and after catching it I have to append the method name so that I should know which method the error came from, and then throw it to another function and save it in database.
try
{
}
catch (Exception ex)
{
string strError = ex.Message.ToString() + "methodname:getNoOfRecordsForBatchProcess";
throw strError.ToString();
}
but it gives me error that you can't use string variable to throw exception.the throw exception only use with system exception. is there any way to handle this error.
The method name is visible in Exception.StackTrace property too.
By the way you may rely on some other way to recover its name using StackFrame Class, like for example:
private static string GetCallingMethodName()
{
const int iCallDeepness = 2; //DEEPNESS VALUE, MAY CHANGE IT BASED ON YOUR NEEDS
System.Diagnostics.StackTrace stack = new System.Diagnostics.StackTrace(false);
System.Diagnostics.StackFrame sframe = stack.GetFrame(iCallDeepness);
return sframe.GetMethod().Name;
}
An answer to your question:
throw new Exception(strError);
(However, as others have said, this might not be the best way to handle this.)
Possible duplicate of How to get the name of the method that caused the exception.
catch (Exception ex)
{
MethodBase site = ex.TargetSite;
string methodName = site == null ? null : site.Name;
...
}
When catching and rethrowing an exception it's 'recommended' to create a new Exception, with a meaningful error message, and pass the original exception in as the inner exception.
For example:
catch(Exception ex)
{
const string message = "Some error message.";
throw new MeaningfulException(message, ex);
}
I would also go for the StackFrame. I'm posting an extension to #Tigran's answer (because you asked for a bit more clarified usage inside the try{...}catch{...} block), so if this is helping you to understand the usage, please accept his answer, not mine:
try
{
int a = 0;
var r = 1 / a;
}
catch (Exception ex)
{
throw new Exception(
String.Format("{0} Method name: {1}",
ex.Message,
GetCallingMethodName()),
ex);
}
The GetCallingMethodName:
private static string GetCallingMethodName()
{
const int iCallDeepness = 1; //DEEPNESS VALUE, MAY CHANGE IT BASED ON YOUR NEEDS
System.Diagnostics.StackTrace stack = new System.Diagnostics.StackTrace(false);
System.Diagnostics.StackFrame sframe = stack.GetFrame(iCallDeepness);
return sframe.GetMethod().Name;
}
P.S. #Tigran, I will remove this answer if you consider that it's not needed.
Related
I have read about why we need to throw an exception and Rethrow it. But I have confused about when Rethrow an exception? I added an example when I put throw in CalculationOperationNotSupportedException catch, and after that, I compared Stack Trace with Rethrowing and without Rethrowing. It's the same 99%, but when you rethrow an exception, it just adds location.
Of course, if you accurately two stack trace. Line 35 is "throw" location number, and line 28 is int result = calculator.Calculate(number1, number2, operation);
I think Stack Trace without rethrowing in here is better. What do you think about that?
Stack Trace without rethrowing(throw) I commented it.
at ConsoleCalculator.Calculator.Calculate(Int32 number1, Int32
number2, String operation) in
C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Calculator.cs:line
25 at ConsoleCalculator.Program.Main(String[] args) in
C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Program.cs:line
28
Stack Trace with rethrow in catch (CalculationOperationNotSupportedException ex)
at ConsoleCalculator.Calculator.Calculate(Int32 number1, Int32 number2, String operation) in C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Calculator.cs:line 25
at ConsoleCalculator.Program.Main(String[] args) in C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Program.cs:line 35
public int Calculate(int number1, int number2, string operation)
{
string nonNullOperation =
operation ?? throw new ArgumentNullException(nameof(operation));
if (nonNullOperation == "/")
{
try
{
return Divide(number1, number2);
}
catch (ArithmeticException ex)
{
throw new CalculationException("An error occurred during division", ex);
}
}
else
{
throw new CalculationOperationNotSupportedException(operation);
}
}
static void Main(string[] args)
{
var calculator = new Calculator();
int number1=1;
int number2=1;
string operation = "+";
try
{
int result = calculator.Calculate(number1, number2, operation);
DisplayResult(result);
}
catch (CalculationOperationNotSupportedException ex)
{
// Log.Error(ex);
WriteLine(ex);
throw;
}
}
There are two articles on the thematic I link often. I consider them required reading.
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/
https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
At the basic, you should not catch an exception if you can not handle it. But sometimes, you have to make exceptions (no pun intended) to any rule about Exception. You might have to catch wider and then apply "catch and release" to the extra Exceptions you got. For example, here is my atempt at repilicating TryParse:
//Parse throws ArgumentNull, Format and Overflow Exceptions.
//And they only have Exception as base class in common, but identical handling code (output = 0 and return false).
bool TryParse(string input, out int output){
try{
output = int.Parse(input);
}
catch (Exception ex){
if(ex is ArgumentNullException ||
ex is FormatException ||
ex is OverflowException){
//these are the exceptions I am looking for. I will do my thing.
output = 0;
return false;
}
else{
//Not the exceptions I expect. Best to just let them go on their way.
throw;
}
}
//I am pretty sure the Exception replaces the return value in exception case.
//So this one will only be returned without any Exceptions, expected or unexpected
return true;
}
No, your understanding of how throwing and rethrowing works is incorrect.
When you throw an exception you loose all stack trace information of what happened prior to the newly thrown exception. The problem is that you have all your code in the same files and you are having trouble reading and correctly comparing the information in each stacktrace.
Build the following code, making sure that each class is in a diferent .cs file. Run it and compare both printed stack traces and you will see that throwing loses information:
//Foo.cs
public class Foo
{
public void Crash() => throw new Exception();
}
//Blah.cs
public class Blah
{
public void CrashAndThrow()
{
var foo = new Foo();
try
{
foo.Crash();
}
catch (Exception ex)
{
throw ex;
}
}
public void CrashAndReThrow()
{
var foo = new Foo();
try
{
foo.Crash();
}
catch
{
throw;
}
}
}
//Program.cs
class Program
{
static void Main(string[] args)
{
var bla = new Blah();
try
{
bla.CrashAndThrow();
}
catch (Exception ex)
{
Console.WriteLine("Throw:");
Console.WriteLine(ex.StackTrace);
Console.WriteLine();
}
try
{
bla.CrashAndReThrow();
}
catch (Exception ex)
{
Console.WriteLine("Rethrow:");
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
}
}
The output of this program is, in my computer:
Throw:
at SOStuff.Alpha.Blah.CrashAndThrow() in ...\SOStuff\Blah.cs:line 16
at SOStuff.Program.Main(String[] args) in ...\SOStuff\Program.cs:line 13
Rethrow:
at SOStuff.Alpha.Foo.Crash() in ...\SOStuff\Foo.cs:line 7
at SOStuff.Alpha.Blah.CrashAndReThrow() in ...\SOStuff\Blah.cs:line 24
at SOStuff.Program.Main(String[] args) in ...\SOStuff\Program.cs:line 24
As you can see, when you throw, all information of the orignal exception thrown in Foo is lost.
The general rules I apply are:
If you can't handle it, don't catch it
If you can't handle it, but you need to catch it in order to clean up, log information, or whatever, rethrow it.
If you can't handle it but you can't allow sensistive or non appropiate information in the exception reach the consumer, then throw a new one with enough information that allows correct debugging later on.
If you can handle it, then handle it.
99% of the time, I apply rule #1.
The Best practices for exceptions document on MSDN says that you can have an exception builder method inside your class if the same exception is to be used in many parts of the class. But also, it says that in some cases, it's better to use the exception's constructor.
Let's say I have the following code in an UserData class:
private MailAddress _addr;
public UserData(string emailAddress)
{
// Tries to validate the e-mail address
try
{
_addr = new MailAddress(emailAddress);
}
catch
{
throw new ArgumentException(nameof(emailAddress), "Invalid email address.");
}
if (_addr.Address != emailAddress)
{
throw new ArgumentException(nameof(emailAddress), "Invalid email address.");
}
}
You can see that in both throw statements, I'm throwing the exact same exception.
The question is: Is it correct to add an exception builder method to get my exception and throw that? Will I get the correct stacktrace and such if I do so? And if not, how do I determine between exception builders and constructors?
Is it correct to add an exception builder method to get my exception and throw that
That depends. As suggested in the article you linked: If it's the same exception (with the same information), it makes sense to create such a helper method to keep your code clean.
Will I get the correct stacktrace and such if I do so
Yes, you will.
Take a look at this example. (DotNetFiddle).
public static void Main()
{
try{
throw CreateEx("Hi");
} catch(Exception ex) {
Console.WriteLine(ex.ToString());
}
try {
CreateEx2("Hi");
} catch(Exception ex) {
Console.WriteLine(ex.ToString());
}
}
public static Exception CreateEx(string text){
text += " Additional text";
return new ArgumentOutOfRangeException(text);
}
public static void CreateEx2(string text){
text += " Additional text";
throw new ArgumentOutOfRangeException(text);
}
The stacktrace depends on where the exception is thrown, not where it is built.
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: Hi Additional text
at Program.Main() in d:\Windows\Temp\b4ln3dbq.0.cs:line 13
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: Hi Additional text
at Program.CreateEx2(String text) in d:\Windows\Temp\b4ln3dbq.0.cs:line 34
at Program.Main() in d:\Windows\Temp\b4ln3dbq.0.cs:line 19
Regarding the duplicated. I can access the Message property but not the Detail property even when I can see is part of the Exception object during debuging. So the question is Why cant access Detail property.
I catch an exception.
catch (Exception ex)
{
string msg = ex.InnerException.InnerException.Message;
// say Exception doesnt have Detail property
// string detail = ex.InnerException.InnerException.Detail;
return Json(new { status = "Fail", message = msg, detail: detail });
}
ex doesnt say anthing
ex.InnerException show same message
ex.InnerException.InnerException. finally some real message, "db table duplicated key"
ex.InnerException.InnerException.Message I can get the message.
But cant get the Detail "the guilty key" even when there is one property Detail
So how can I get the Detail?.
Bonus: Why have to go deep InnerException twice to get some meaningfull message?
I think the most elegant way to do this now is using C# 6 when keyword in a catch statement and C# 7 is operator.
try
{
//your code
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException pex)
{
string msg = pex.Message;
string detail = pex.Detail;
return Json(new { status = "Fail", message = msg, detail: detail });
}
The trick is to recognize the type of exception being thrown and cast the General Exception to the correct Type where you will then have access to extended properties for that Exception type.
for example:
if (processingExcption is System.Data.Entity.Validation.DbEntityValidationException)
{
exceptionIsHandled = true;
var entityEx = (System.Data.Entity.Validation.DbEntityValidationException)processingExcption;
foreach (var item in entityEx.EntityValidationErrors)
{
foreach (var err in item.ValidationErrors)
returnVal.Invalidate(SystemMessageCategory.Error, err.ErrorMessage);
}
}
else if (processingExcption is System.Data.SqlClient.SqlException && ((System.Data.SqlClient.SqlException)processingExcption).Number == -2)//-2 = Timeout Exception
{
exceptionIsHandled = true;
returnVal.Invalidate(SystemMessageCategory.Error, "Database failed to respond in the allotted time. Please retry your action or contact your system administrator for assistance.",
messageCode: Architecture.SystemMessage.SystemMessageCode.DBTimeout);
}
The fact that the detail you are looking for is 2 inner exceptions deep is incidental. Depending on how many times the exception is caught and wrapped will determine how deep the exception you care about is - your best bet is to iterate through the exception stack looking for exception types you wish to handle.
Referring to your own answer I commented, you definitely should be much more defensive, otherwise you risk of a null reference exception from within your catch clause.
catch (Exception ex)
{
string Detail = string.Empty;
while ( ex != null )
{
if ( ex is Npgsql.NpgsqlException )
{
// safe check
Npgsql.NpgsqlException ex_npg = (Npgsql.NpgsqlException)ex;
Details = ex_npg.Detail;
}
// loop
ex = ex.InnerException;
}
// warning, Detail could possibly still be empty!
return Json(new { status = "Fail", detail = Detail });
}
You cannot get details more than found in this exception
To show real exception loop over innerexceptions until it is null. Then you reached the first one
The exception was thrown from a source class or function then readed by upper level class that throw it with more global details because there is no error handling on the source
Well, it's very sad, but the inner exception is not a magic stick. Usually it's just an object that author of the code that you call puts as the second parameter of the Exception constructor. So, the general answer: "no way". But debugger sometimes could help :). I would say - call stack of the exception usually more descriptive the InnerException.
A quick solution would be to click on the "Detail" property in the "Quick Watch" window. Your answer will be in "Expression" texbox at the top of the quick watch window. Example, the expression for Postgres duplicate detail is:
((Npgsql.PostgresException)ex.InnerException.InnerException).Detail
Here is my function to get some more info from Postgres exception
catch (Exception ex) {
// Get PGSQL exception info
var msg = ExceptionMessage (ex);
}
public static string ExceptionMessage (Exception ex) {
string msg = ex.Message;
var pgEx = ex as PostgresException;
if (pgEx != null) {
msg = pgEx.Message;
msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
msg += pgEx.Where != null ? "\n"+ pgEx.Where : "";
}
return msg;
}
Thanks Maciej
this solution is great to intercept PostgreSQL Errors
Only correction I did on this
msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
instead
msg += pgEx.Detail != null ? "\n" + pgEx.Detail.ToString() : "";
msg += pgEx.InternalQuery != null ? "\n" + pgEx.InternalQuery.ToString() : "";
try
{
object result = processClass.InvokeMethod("Create", methodArgs);
}
catch (Exception e)
{
// Here I was hoping to get an error code.
}
When I invoke the above WMI method I am expected to get Access Denied. In my catch block I want to make sure that the exception raised was indeed for Access Denied. Is there a way I can get the error code for it ? Win32 error code for Acceess Denied is 5.
I dont want to search the error message for denied string or anything like that.
Thanks
You can use this to check the exception and the inner exception for a Win32Exception derived exception.
catch (Exception e) {
var w32ex = e as Win32Exception;
if(w32ex == null) {
w32ex = e.InnerException as Win32Exception;
}
if(w32ex != null) {
int code = w32ex.ErrorCode;
// do stuff
}
// do other stuff
}
Starting with C# 6, when can be used in a catch statement to specify a condition that must be true for the handler for a specific exception to execute.
catch (Win32Exception ex) when (ex.InnerException is Win32Exception) {
var w32ex = (Win32Exception)ex.InnerException;
var code = w32ex.ErrorCode;
}
As in the comments, you really need to see what exception is actually being thrown to understand what you can do, and in which case a specific catch is preferred over just catching Exception. Something like:
catch (BlahBlahException ex) {
// do stuff
}
Also System.Exception has a HRESULT
catch (Exception ex) {
var code = ex.HResult;
}
However, it's only available from .NET 4.5 upwards.
Building on Preet Sangha's solution, the following should safely cover the scenario where you're working with a large solution with the potential for several Inner Exceptions.
try
{
object result = processClass.InvokeMethod("Create", methodArgs);
}
catch (Exception e)
{
// Here I was hoping to get an error code.
if (ExceptionContainsErrorCode(e, 10004))
{
// Execute desired actions
}
}
...
private bool ExceptionContainsErrorCode(Exception e, int ErrorCode)
{
Win32Exception winEx = e as Win32Exception;
if (winEx != null && ErrorCode == winEx.ErrorCode)
return true;
if (e.InnerException != null)
return ExceptionContainsErrorCode(e.InnerException, ErrorCode);
return false;
}
This code has been unit tested.
I won't harp too much on the need for coming to appreciate and implement good practice when it comes to Exception Handling by managing each expected Exception Type within their own blocks.
You should look at the members of the thrown exception, particularly .Message and .InnerException.
I would also see whether or not the documentation for InvokeMethod tells you whether it throws some more specialized Exception class than Exception - such as the Win32Exception suggested by #Preet. Catching and just looking at the Exception base class may not be particularly useful.
I suggest you to use Message Properte from The Exception Object Like below code
try
{
object result = processClass.InvokeMethod("Create", methodArgs);
}
catch (Exception e)
{
//use Console.Write(e.Message); from Console Application
//and use MessageBox.Show(e.Message); from WindowsForm and WPF Application
}
catch (Exception e)
{
if (e is MyCustomExeption myEx)
{
var errorCode = myEx.ErrorCode;
}
}
Another method would be to get the error code from the exception class directly. For example:
catch (Exception ex)
{
if (ex.InnerException is ServiceResponseException)
{
ServiceResponseException srex = ex.InnerException as ServiceResponseException;
string ErrorCode = srex.ErrorCode.ToString();
}
}
When C# throws an exception, it can have an inner exception. What I want to do is get the inner-most exception, or in other words, the leaf exception that doesn't have an inner exception. I can do this in a while loop:
while (e.InnerException != null)
{
e = e.InnerException;
}
But I was wondering if there was some one-liner I could use to do this instead.
Oneliner :)
while (e.InnerException != null) e = e.InnerException;
Obviously, you can't make it any simpler.
As said in this answer by Glenn McElhoe, it's the only reliable way.
I believe Exception.GetBaseException() does the same thing as these solutions.
Caveat: From various comments we've figured out it doesn't always literally do the same thing, and in some cases the recursive/iterating solution will get you further. It is usually the innermost exception, which is disappointingly inconsistent, thanks to certain types of Exceptions that override the default. However if you catch specific types of exceptions and make reasonably sure they're not oddballs (like AggregateException) then I would expect it gets the legitimate innermost/earliest exception.
Looping through InnerExceptions is the only reliable way.
If the caught exception is an AggregateException, then GetBaseException() returns only the innermost AggregateException.
http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx
If you don't know how deep the inner exceptions are nested, there is no way around a loop or recursion.
Of course, you can define an extension method that abstracts this away:
public static class ExceptionExtensions
{
public static Exception GetInnermostException(this Exception e)
{
if (e == null)
{
throw new ArgumentNullException("e");
}
while (e.InnerException != null)
{
e = e.InnerException;
}
return e;
}
}
I know this is an old post, but I'm surprised nobody suggested GetBaseException() which is a method on the Exception class:
catch (Exception x)
{
var baseException = x.GetBaseException();
}
This has been around since .NET 1.1. Documentation here:
http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx
Sometimes you might have many inner exceptions (many bubbled exceptions).
In which case you might want to do:
List<Exception> es = new List<Exception>();
while(e.InnerException != null)
{
es.add(e.InnerException);
e = e.InnerException
}
You could use recursion to create a method in a utility class somewhere.
public Exception GetFirstException(Exception ex)
{
if(ex.InnerException == null) { return ex; } // end case
else { return GetFirstException(ex.InnerException); } // recurse
}
Use:
try
{
// some code here
}
catch (Exception ex)
{
Exception baseException = GetFirstException(ex);
}
The extension method suggested (good idea #dtb)
public static Exception GetFirstException(this Exception ex)
{
if(ex.InnerException == null) { return ex; } // end case
else { return GetFirstException(ex.InnerException); } // recurse
}
Use:
try
{
// some code here
}
catch (Exception ex)
{
Exception baseException = ex.GetFirstException();
}
Not quite one line but close:
Func<Exception, Exception> last = null;
last = e => e.InnerException == null ? e : last(e.InnerException);
In fact is so simple, you could use Exception.GetBaseException()
Try
//Your code
Catch ex As Exception
MessageBox.Show(ex.GetBaseException().Message, My.Settings.MsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
End Try
You have to loop, and having to loop, it's cleaner to move the loop into a separate function.
I created an extension method to deal with this. It returns a list of all of the inner exceptions of the specified type, chasing down Exception.InnerException and AggregateException.InnerExceptions.
In my particular problem, chasing down the inner exceptions was more complicated than usual, because the exceptions were being thrown by the constructors of classes that were being invoked through reflection. The exception we were catching had an InnerException of type TargetInvocationException, and the exceptions we actually needed to look at were buried deep in the tree.
public static class ExceptionExtensions
{
public static IEnumerable<T> innerExceptions<T>(this Exception ex)
where T : Exception
{
var rVal = new List<T>();
Action<Exception> lambda = null;
lambda = (x) =>
{
var xt = x as T;
if (xt != null)
rVal.Add(xt);
if (x.InnerException != null)
lambda(x.InnerException);
var ax = x as AggregateException;
if (ax != null)
{
foreach (var aix in ax.InnerExceptions)
lambda(aix);
}
};
lambda(ex);
return rVal;
}
}
Usage is pretty simple. If, for example, you want to know if we encountered a
catch (Exception ex)
{
var myExes = ex.innerExceptions<MyException>();
if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error")))
{
// ...
}
}
I ran into this and wanted to be able to list all of the exception messages from the exception "stack". So, I came up with this.
public static string GetExceptionMessages(Exception ex)
{
if (ex.InnerException is null)
return ex.Message;
else return $"{ex.Message}\n{GetExceptionMessages(ex.InnerException)}";
}
Another way you could do it is by calling GetBaseException() twice:
Exception innermostException = e.GetBaseException().GetBaseException();
This works because if it is an AggregateException, the first call gets you to the innermost non-AggregateException then the second call gets you to the innermost exception of that exception. If the first exception is not an AggregateException, then the second call just returns the same exception.