I have the following code:
[Serializable]
class ExceptionAspectHandler:OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
Console.WriteLine("{0}", args.Exception);
args.FlowBehavior = FlowBehavior.Continue;
}
}
[OnExceptionAspect]
public static void divide()
{
int n = Convert.ToInt32(Console.ReadLine());
var a = 100 / n; //the exception happens here
Console.WriteLine("it should get here");
}
Using FlowBehavior.Continue ends divide() and returns to the main() method.
Remember, the OnException aspect wraps your code in a try/catch so the code will continue from the catch (instead of rethrowing) and it's behavior will default to return. Are you wanting it to continue from where it threw the exception? If so, you need to explicitly wrap that line in a try/catch yourself.
Please read http://www.sharpcrafters.com/blog/post/Day-6-Your-code-after-PostSharp.aspx for more details.
The attribute used in divide() method should be ExceptionAspectHandler (you've created), not OnExceptionAspect.
Related
I would like to list down the method call sequence from top to bottom in my .net project.
using System;
public class Program
{
public static void Main()
{
One();
}
public static void One(){
Two();
}
public static void Two(){
Three();
}
public static void Three(){
Four();
}
public static void Four(){
Console.WriteLine("Hello World!");
}
}
In the above sample class I required to get the log like
"Main()->One()->Two()->Three()->Four()"
you can use System.Diagnostics.StackTrace to get the current stackTrace and use it to log the required:
Demo as per your code:
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
One();
}
public static void One(){
Two();
}
public static void Two(){
Three();
}
public static void Three(){
Four();
}
public static void Four(){
Console.WriteLine("Hello World!");
var stackTrace = new System.Diagnostics.StackTrace();
List<string> methods = new List<string>();
for (int i = stackTrace.FrameCount - 1; i >= 0; i--)
{
methods.Add($"{stackTrace.GetFrame(i).GetMethod().Name}()");
}
Console.WriteLine(string.Join("->", methods));
}
}
The above code prints the output as
Main()->One()->Two()->Three()->Four()
Check the fiddle - https://dotnetfiddle.net/Ee8ni8
There is one non-ideal solution:
Prepare a set of test cases that will run your program methods in as many combinations as possible, and so provide good code coverage.
Manually add a stack trace logging functionality at the beginning of each method's body and adjust stack trace logging format to your needs (Main()->One()...). This could be done with System.Diagnostics.StackTrace, as user1672994 pointed out.
Filter your stack trace log so that it contains only stack traces which are not prefix of any other stack traces, thus leaving off incomplete paths.
You could also discover the call flow from Call Hiearchy window in Visual Studio, but it doesn't give you the data in requested format. It will however find call flows independently of your possibly imperfect test cases.
See also: Visual Studio Call Hierarchy View: call it programmatically
This question already has answers here:
What is the best way to catch exception in Task?
(2 answers)
Catching Error when using Task.Factory
(5 answers)
Closed 5 years ago.
I'm trying to catch a "nested" or "encapsulated" custom error (I504Error) in my code. I know this normally isn't best practice, but it should work for my use case as the error is very specific. I'm trying to get the try/catch block to catch the I504Error in my Main method but it doesn't catch it, even though it's getting called from inside the try/catch block. My program just stops where I'm throwing the error. What am I doing wrong here?
// Custom Error Handler
public class I504Error : Exception
{
public I504Error()
{
}
}
// Classes
public abstract class AbstractIternetThing
{
public abstract void DoSomething();
}
public class IternetThing : AbstractIternetThing
{
public override void DoSomething()
{
// bunch of other stuff
if (iternetThingWorkedProperly == false)
{
// Program stops here, doesn't get caught by the try/catch block in Program.Main()
throw new I504Error();
}
}
}
// Main script
class Pogram
{
static void Main(string[] args)
{
List<Task<AbstractIternetThing>> programThreads = new List<Task<AbstractIternetThing>>();
IternetThing iThing = new IternetThing();
try
{
for (int wantedThread = 0; wantedThread < 5; wantedThread++)
{
Task<AbstractIternetThing> iThingTask = new Task<AbstractIternetThing>(() => iThing.DoSomething());
iThingTask.Start();
}
}
// The Error should get caught here, but it doesnt?
catch (I504Error)
{
// Do something else
}
}
}
It is because you have it in a Task which is on a separate asynchronous execution path. Consider using async-await. Then the compiler will rewrite your code to make it work as you expect.
I have a multicast OnExceptionAspect from Postsharp which is applied on the assembly level. This naturally means that all methods, upon throwing an exception, will invoke the Aspect.
Within the Aspect I'm logging the exception details including the values of the parameters passed when the exception occured, this is working properly.
However because this is applied to all methods in the assembly a log entry is created for each method in the stack as the exception bubbles up through each.
I'm out of ideas on how to prevent this, initially I was going to compare the exception (to see if it's the same one) but this just seems messy. Someone must have had this problem before, any ideas?
There are two solutions to this problem.
A. Use a thread-static field to store any exception that has already been logged.
[Serializable]
public class MyAspect : OnExceptionAspect
{
[ThreadStatic]
private static Exception lastException;
public override void OnException(MethodExecutionArgs args)
{
if(args.Exception != lastException)
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
lastException = args.Exception;
}
}
}
B. Add a tag to the Exception object.
[Serializable]
public class MyAspect : OnExceptionAspect
{
private static object marker = new object();
public override void OnException(MethodExecutionArgs args)
{
if(!args.Exception.Data.Contains(marker))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
args.Exception.Data.Add(marker, marker);
}
}
}
FYI--Gael is a PostSharp guru because he is employed there...just so you are aware.
For what it is worth you can always tell where the exception originated by examining the StackTrace. The StackTrace is made available via args.Exception.StackTrace. You may try what Dustin Davis (another PostSharp employee) recommends here: PostSharp - OnExceptionAspect - Get line number of exception
Parse the StackTrace (via the method outlined here: How to split a stacktrace line into namespace, class, method file and line number?) then compare the args.Method.Name with the parsed results. If your args.Method.Name is the same as the originating method (found via parsing the StackTrace) then you know you should log it otherwise ignore.
Here is some code to make my solution more concrete (building on the prior two solutions cited):
[Serializable]
public class ExceptionWrapper : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
var st = new StackTrace(args.Exception, true);
var frame = st.GetFrame(0);
var lineNumber = frame.GetFileLineNumber();
var methodName = frame.GetMethod().Name;
if(methodName.Equals(args.Method.Name))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
}
}
}
(Or, honestly, you could just use one of Gael's recommended solutions.)
One way i could see this being done would be to define a custom exception and just throw that one in your aspect. then also in your aspect check the exception before loggin, if it's not your custom exception log it, otherwise don't log it and (re-throw?).
That's what the example code would look like:
[Serializable]
public class DatabaseExceptionWrapper : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
if(!(args.Exception is CustomException))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
}
throw new CustomException("There was a problem");
}
}
Of course you'd still have to define that exception and everything. :)
So this is a follow-up to a previous question that I asked: Trying to figure out if this code creates any benefit by using a Singleton
In a nutshell, I have inherited a poorly architected program that uses a pseudo-facade class and places it into a Singelton. Every method call goes through the Singleton which then calls different methods.
The Singelton looks like this:
public class FooFacade
{
private static FooFacade m_facade = null;
private static DataAccessManager m_dataAccessMgr = null;
public StringBuilder Status {get; set; }
private FooFacade()
{
this.Status = new StringBuilder();
}
public static FooFacade getInstance()
{
if (m_facade == null)
{
m_dataAccessMgr = DataAccessManager.getInstance();
m_facade = new FooFacade();
}
return m_facade;
}
public void clearStatus()
{
this.Status.Remove(0, Status.Length);
}
public void Method1(string value1, int value2)
{
// do something
}
public int Method2(int value1, int value2)
{
return externalMethod(value1, value2)
}
}
So in this example above, would there be a security concern if the externalMethod that is being called in Method2 threw an error?
For example:
public int externalMethod(value1, value2)
{
try
{
return value1/value2;
}
catch
{
throw;
}
}
In this method, should I be concerned that a Singleton could display a thrown error to the wrong user?
When I have the chance to refactor, I'm getting rid of the Singleton, but in the meantime, I just don't want to accidentally add a huge security hole by adding better exception handling.
-Chad
There is no way that the exception thrown is displayed to another "user". The exception is thrown in the call stack of the current call, so if two different threads were to call Method2 and in thread A the external method throws an exception and in thread B it doesn't, than only thread A would receive the exception.
I am trying to get the list of calls made from the beginning of a try block to the exception. In the code below, when I fall into the Catch block, the StackTrace in the Exception object is the following :
at ConsoleApplication.Program.MethodC() / at
ConsoleApplication.Program.Main(String[] args).
This is totally expected, but doesn't help me to get the history of calls. Does anybody have an idea on how I could do this?
static void MethodA() { }
static void MethodB() { }
static void MethodC() { throw new Exception(); }
static void Main(string[] args)
{
try
{
MethodA();
MethodB();
MethodC();
}
catch (Exception e)
{
// Get list of calls
throw;
}
}
I was surprised to see that the StackTrace property of the Exception object isn't StackTrace object. Is there any reason for this?
In the end, the purpose of all this is simple. If an exception is thrown during the execution of the code, I want to look at the meta data (attribute) of each of the methods called.
As I understand your question, you want to be able to know which methods was called before MethodC in your try block. I don't think you can do that without adding code to your methods.
When MethodA finishes executing, it is no longer on the stack, so there is nowhere you can get the information from. Same goes for MethodB, and only MethodC is on the stack when the Exception occurs.
It seems you're not going to be able to get a stack trace for each method called with the try block unless you add custom logging code to each method. However, you can create a System.Diagnostics.StackTrace option easily from an exception simply by passing the Exception object to the constructor. This will make available all the information about the stack trace including whether the exception was thrown from MethodA/MethodB/MethodC, which might be at least somewhat helpful to you.
Example code:
static void MethodA() { }
static void MethodB() { }
static void MethodC() { throw new Exception(); }
static void Main(string[] args)
{
try
{
MethodA();
MethodB();
MethodC();
}
catch (Exception e)
{
System.Diagnostics.StackTrace callStack = new System.Diagnostics.StackTrace(e);
System.Diagnostics.StackFrame frame = null;
System.Reflection.MethodBase calledMethod = null;
System.Reflection.ParameterInfo[] passedParams = null;
for (int x = 0; x < callStack.FrameCount; x++)
{
callStack.GetFrame(x);
calledMethod = frame.GetMethod();
passedParams = calledMethod.GetParameters();
foreach (System.Reflection.ParameterInfo param in passedParams)
System.Console.WriteLine(param.ToString());
}
}
}
(You can see this SO thread for the original answer containing the code. I've just slightly modified it.)
Hope that's at least a partial solution to your question.
You can easily get a StackTrace object from anywhere in your code but as has already been pointed out you can not get the full history of method calls.