I can get StackTrace for Exception. But I don't know how to get StackTrace for Assert. How to find out in which method Assert was called?
My code:
namespace ConsoleApp1
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
class MyProgram
{
static void Main(string[] agrs)
{
AppDomain.CurrentDomain.FirstChanceException += FirstChanceException!;
var foo = new Foo();
try
{
foo.FuncException();
}
catch { }
try
{
foo.FuncAssert();
}
catch { }
AppDomain.CurrentDomain.FirstChanceException -= FirstChanceException!;
}
static private void FirstChanceException(object source, FirstChanceExceptionEventArgs firstChanceExceptionEventArgs)
{
var ex = firstChanceExceptionEventArgs.Exception;
if (ex != null)
Console.WriteLine($" * * * \n Message: {ex.Message} \n StackTrace: {GetStackTrace(ex)} \n");
}
static private string GetStackTrace(Exception ex)
{
var list = new List<string>();
var trace = new StackTrace(ex, true);
foreach (var frame in trace.GetFrames())
{
list.Add($"{frame.GetMethod()?.ReflectedType?.Name}.{frame.GetMethod()?.Name}");
}
return string.Join(" -> ", list);
}
public class Foo
{
public void FuncException()
{
throw new Exception("Exception - FuncException");
}
public void FuncAssert()
{
Assert.Fail("Assert - FuncAssert");
}
}
}
}
You register an event handler for AppDomain.CurrentDomain.FirstChanceException:
AppDomain.CurrentDomain.FirstChanceException += FirstChanceException;
You call Assert.Fail():
public class Foo
{
public void FuncAssert()
{
Assert.Fail("Assert - FuncAssert");
}
}
I assume that you expect to see the whole call stack in the exception. But call stack is only gathered when exception is bubbling through the stack.
And AppDomain.FirstChanceException catches the exception right in the place where it's thrown.
Occurs when an exception is thrown in managed code, before the runtime searches the call stack for an exception handler in the application domain.
https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.firstchanceexception
So, I would say that you are trying to do something wrong.
What is the problem that you are actually trying to solve?
This code will work well because I let exception to bubble along the call stack and be caught:
try
{
foo.FuncAssert();
}
catch (Exception ex)
{
Console.WriteLine($" * * * \n Message: {ex.Message} \n StackTrace: {GetStackTrace(ex)} \n");
}
Output:
Message: Assert - FuncAssert
StackTrace: Assert.ReportFailure -> Assert.Fail -> Assert.Fail -> Foo.FuncAssert -> MyProgram.Main
Related
Good afternoon. I cannot understand, why the block "catch" is not invoked, instead of it the programme stops working with NullReferenceException.
string? nullable_string_1 = null;
try
{
string non_nullable_string_1 = (string)nullable_string_1;
System.Console.WriteLine(non_nullable_string_1.Length);
}
catch (System.NullReferenceException nullReferenceException)
{
System.Console.WriteLine($"There is an invalid operation exception with message: \"{nullReferenceException.Message}\"");
}
using System;
public class Program
{
public static void Main()
{
string? nullableString = null;
try
{
string nonNullableString = (string)nullableString;
Console.WriteLine(nonNullableString.Length);
}
catch (NullReferenceException nullReferenceException)
{
Console.WriteLine($"There is an invalid operation exception with message: \"{nullReferenceException.Message}\"");
}
Console.WriteLine("After Exception Code Run");
}
}
Output - It's Working
[1]: https://i.stack.imgur.com/66Qum.png
We have a PostSharp's OnExceptionAspect applied to every method of our project which is corrupting the line numbers reported in the stack traces: the inner stack frame line number is no longer pointing to the line where the exception happened but to the closing brace of the method where the exception happened.
This seems to be a known limitation of Windows which, when rethrowing an exception, resets the stack trace origin (see Incorrect stacktrace by rethrow).
You can reproduce this issue with this code (you need PostSharp installed):
namespace ConsoleApplication1
{
using System;
using PostSharp.Aspects;
public static class Program
{
public static void Main()
{
try
{
Foo(2);
}
catch (Exception exception)
{
var type = exception.GetType();
Console.Write(type.FullName);
Console.Write(" - ");
Console.WriteLine(exception.Message);
Console.WriteLine(exception.StackTrace);
}
}
private static void Foo(int value)
{
if (value % 2 == 0)
{
throw new Exception("Invalid value.");
}
Console.WriteLine("Hello, world.");
}
}
[Serializable]
public class LogExceptionAspect : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs methodExecutionArgs)
{
}
}
}
Executing this code gives the following stack trace:
System.Exception - Invalid value.
at ConsoleApplication1.Program.Foo(Int32 value) in …\Program.cs:line 36
at ConsoleApplication1.Program.Main() in …\Program.cs:line 15
Line 36 is not throw new Exception("Invalid value."); but the closing brace of private static void Foo(int value).
A solution is to wrap the exception in a new one and rethrow it inside the OnException method of the OnExceptionAspect:
[assembly: ConsoleApplication1.LogExceptionAspect]
namespace ConsoleApplication1
{
using System;
using PostSharp.Aspects;
public static class Program
{
public static void Main()
{
try
{
Foo(2);
}
catch (Exception exception)
{
while (exception != null)
{
var type = exception.GetType();
Console.Write(type.FullName);
Console.Write(" - ");
Console.WriteLine(exception.Message);
Console.WriteLine(exception.StackTrace);
exception = exception.InnerException;
}
}
}
private static void Foo(int value)
{
if (value % 2 == 0)
{
throw new Exception("Invalid value.");
}
Console.WriteLine("Hello, world.");
}
}
[Serializable]
public class LogExceptionAspect : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs methodExecutionArgs)
{
throw new Exception("Foo", methodExecutionArgs.Exception);
}
}
}
This gives the correct line numbers (throw new Exception("Invalid value."); is on line 37 now):
System.Exception - Foo
at ConsoleApplication1.LogExceptionAspect.OnException(MethodExecutionArgs methodExecutionArgs) in …\Program.cs:line 49
at ConsoleApplication1.Program.Foo(Int32 value) in …\Program.cs:line 41
at ConsoleApplication1.Program.Main() in …\Program.cs:line 15
System.Exception - Invalid value.
at ConsoleApplication1.Program.Foo(Int32 value) in …\Program.cs:line 37
However this solution is adding garbage to the stack traces (the System.Exception - Foo entry should not really exist) and for us is making them nearly useless (remember that the aspect is applied to every method in our project: so if an exception bubbles up twenty methods we have twenty new nested exceptions added to the stack trace).
Given that we can't — cough PHB cough — get rid of the aspect, which alternatives do we have to have correct line numbers and readable stack traces?
I'm one of PostSharp's developers. This is a known issue (or rather a feature) of CLR's rethrow instruction. For brevity, it changes the stack trace based on the sequence point of that instruction. The same happens if you use throw; in a catch statement, but that's more apparent as you see the statement that causes it.
We are working on a major change that should provide a fix of this behavior and hopefully would be released in a future version (I cannot tell which one at this point). I'm afraid that until it is released the workaround that you are using (or a similar one) is the only possible solution.
As stated by Daniel Balas and Incorrect stacktrace by rethrow, due to a "feature" of the CLR there is no way to preserve the original stack trace when rethrowing an exception raised in the same method.
The following examples show how we implemented a work around by wrapping the original exception in the first stack frame (as mentioned in my comment).
The instruction causing the exception — throw new Exception("Invalid value."); — is on line 41 in both examples.
Before:
[assembly: Sandbox.TrapExceptionAspect]
namespace Sandbox
{
using System;
using System.Runtime.Serialization;
using PostSharp.Aspects;
public static class Program
{
public static void Main()
{
try
{
Foo(2);
}
catch (Exception exception)
{
while (exception != null)
{
Console.WriteLine(exception.Message);
Console.WriteLine(exception.StackTrace);
exception = exception.InnerException;
}
}
Console.ReadKey(true);
}
private static void Foo(int value)
{
Bar(value);
}
private static void Bar(int value)
{
if (value % 2 == 0)
{
throw new Exception("Invalid value.");
}
Console.WriteLine("Hello, world.");
}
}
[Serializable]
public class TrapExceptionAspect : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
}
}
}
Stack trace:
Invalid value.
at Sandbox.Program.Bar(Int32 value) in …\Sandbox\Sandbox\Program.cs:line 45
at Sandbox.Program.Foo(Int32 value) in …\Sandbox\Sandbox\Program.cs:line 35
at Sandbox.Program.Main() in …\Sandbox\Sandbox\Program.cs:line 16
After:
[assembly: Sandbox.TrapExceptionAspect]
namespace Sandbox
{
using System;
using System.Runtime.Serialization;
using PostSharp.Aspects;
public static class Program
{
public static void Main()
{
try
{
Foo(2);
}
catch (Exception exception)
{
while (exception != null)
{
Console.WriteLine(exception.Message);
Console.WriteLine(exception.StackTrace);
exception = exception.InnerException;
}
}
Console.ReadKey(true);
}
private static void Foo(int value)
{
Bar(value);
}
private static void Bar(int value)
{
if (value % 2 == 0)
{
throw new Exception("Invalid value.");
}
Console.WriteLine("Hello, world.");
}
}
[Serializable]
public class TrapExceptionAspect : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
if (args.Exception is CustomException)
{
return;
}
args.FlowBehavior = FlowBehavior.ThrowException;
args.Exception = new CustomException("Unhandled exception.", args.Exception);
}
}
[Serializable]
public class CustomException : Exception
{
public CustomException() : base()
{
}
public CustomException(string message) : base(message)
{
}
public CustomException(string message, Exception innerException) : base(message, innerException)
{
}
public CustomException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
Stack trace:
Unhandled exception.
at Sandbox.Program.Bar(Int32 value) in …\Sandbox\Sandbox\Program.cs:line 45
at Sandbox.Program.Foo(Int32 value) in …\Sandbox\Sandbox\Program.cs:line 35
at Sandbox.Program.Main() in …\Sandbox\Sandbox\Program.cs:line 16
Invalid value.
at Sandbox.Program.Bar(Int32 value) in …\Sandbox\Sandbox\Program.cs:line 41
Is it Syntax error or compiliing error?
using System;
namespace AAA
{
class MyException : Exception{
}
class My2Exception : MyException{
}
class MainClass
{
public static void Main (string[] args)
{
try{
throw new MyException();
}
catch(Exception e){ // compiler says that this catch all exception occur error? Is it syntax error?
}
catch(MyException m){ // Syntax error
}
}
}
}
Is it kind of syntax error?
Is this error syntax error?
thanks
Since a catch block for type Exception is the least specific exception handler possible, the need to provide a more specific catch block is not only redundant, but in C# it's a compile time error. Thus, in a multi-catch block, you should always specify the most generic catch block last:
using System;
namespace AAA
{
class MyException : Exception
{
}
class MainClass
{
public static void Main (string[] args)
{
try
{
throw new MyException();
}
catch (MyException m)
{
//TODO: something
}
catch (Exception e)
{
//TODO: something
}
}
}
}
Exception is a more general class than MyException that's why you should catch it last.
As mentioned by Shaharyar it a 'semantic error'
try{
throw new MyException();
}
catch(MyException m){
}
catch(Exception e){ // Syntax error
}
This question already has answers here:
Is there a way to catch all unhandled exceptions thrown by a given class?
(6 answers)
Closed 8 years ago.
I have a lot of classes (WCF services) that contain several function. Now I need to handle errors, but I don't want to create a block try ... catch within each function (for error handling).
How can I make try...catch in any class (or something else) so that we catch errors but did not write the same block within each method?
There will always be some duplication of code but you can reduce it to one line
public static class ExceptionHandler
{
public static void Run(Action action)
{
try
{
a();
}
catch(Exception e)
{
//Do Something with your exception here, like logging
}
}
}
and then just call
ExceptionHandler.Run(yourAction);
you can add overloads for functions and what not but this approach is not ideal. As you may want to catch specific exceptions in certain cases.
Since you did not provide code specifically, I will write some sample code to make it more obvious. If you have this:
public class MyClass
{
public void Method1ThatCanThrowException()
{
try
{
// the Method1 code that can throw exception
}
catch (MySpecificException ex)
{
// some specific error handling
}
}
public object Method2ThatCanThrowException()
{
try
{
// the Method2 code that can throw exception
}
catch (MySpecificException ex)
{
// the same specific error handling
}
}
}
So, if you intend to have single place error handling, you can use lambda, and the help of a private method:
private T CheckAndCall<T>(Func<T> funcToCheck)
{
try
{
return funcToCheck();
}
catch (MySpecificException ex)
{
// the old specific error handling
}
}
Notice the use of the Func<T> delegate. This is because you may need to wrap the try-catch logic around some code that can return a value.
Then you can rewrite the above methods like this:
public void Method1ThatCanThrowException()
{
CheckAndCall(
() =>
{
// the Method1 code that can throw exception
return null;
});
}
public object Method2ThatCanThrowException()
{
return CheckAndCall(
() =>
{
// the Method2 code that can throw exception
return someObject;
});
}
For example, rather than having to do this:
public class Program
{
public static string ReadFile(string filename)
{
//A BCL method that throws various exceptions
return System.IO.File.ReadAllText(filename);
}
public static void Main(string[] args)
{
try
{
Console.Write(ReadFile("name.txt"));
}
catch (Exception e)
{
Console.WriteLine("An error occured when retrieving the name! {0}", e.Message);
}
try
{
Console.Write(ReadFile("age.txt"));
}
catch (Exception e)
{
Console.WriteLine("An error occured when retrieving the age! {0}", e.Message);
}
}
}
You could implement a "Try..." method, using the ref or out keyword as appropriate:
public class Program
{
public static bool TryReadFile(string filename, out string val)
{
try
{
val = System.IO.File.ReadAllText(filename);
return true;
}
catch (Exception)
{
return false;
}
}
public static void Main(string[] args)
{
string name, age;
Console.WriteLine(TryReadFile("name.txt", out name) ? name : "An error occured when retrieving the name!");
Console.WriteLine(TryReadFile("age.txt", out age) ? age: "An error occured when retrieving the age!");
}
}
The downside to this approach is that you can't act upon a specific exception, but in the case of simply determining if an operation has or has not succeeded, I find this to be a syntactically clean approach.
I've made a method that logs an exception into a folder called Logs and save it in the text file. The format of the text output is like so:
Main thread has thrown an exception # ClassName::MethodName : Exception.ToString();
ClassName::MethodName is a text that should contain which class and which method throws it (while doing the task). How is it possible to pass those arguments? For example, if I have a class named "Test", and I have this method:
public void DoSomething() {
try {
this.Name = "Test";
} catch (Exception e) {
MainForm.Instance.LogException(e);
}
Then if an exception was thrown, the arguments Test::DoSomething will be passed and shown. How is it possible to do it in C#?
You could use Reflection..
public void DoSomething() {
try {
this.Name = "Test";
} catch (Exception e) {
var method = System.Reflection.MethodBase.GetCurrentMethod();
var methodName = method.Name;
var className = method.ReflectedType.Name;
MainForm.Instance.LogException(String.Format("{0} - {1}:{2}", className, methodName, e));
}
The exception has a StackTrace property which gives you as much information as possible as to where the exception was thrown.
You can use the code below:
public static void DoSomething()
{
try
{
throw new InvalidOperationException("Exception");
}
catch (Exception e)
{
StackTrace stackTrace = new StackTrace();
StackFrame stackFrame = stackTrace.GetFrame(0);
Console.WriteLine("Class Name: {0}, Method Name: {1}", stackFrame.GetMethod().Module, stackFrame.GetMethod().Name);
}
}
e.StackTrace.GetFrame(0) will give you the most recent StackFrame.
Given that, e.StackTrace.GetFrame(0).GetMethod() will give you an instance of MethodBase, from this instance, you can get the method name and class