Get name of last called method - c#

I have the following code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
try
{
this.CheckValue(true); // call method
}
catch(Exception ex)
{
// how to get here name of last called method
}
}
public int CheckValue(bool sender)
{
var qwe = int.Parse("qwe"); // invoke an exception
return 0;
}
}
I need to get in "catch block" name of last called method (in this case "CheckValue"), but it return that called method is "StringToNumber".
I try to get it using StackTrace:
stackTrace.GetFrame(1).GetMethod().Name; -> "Main"
MethodBase.GetCurrentMethod(); -> "Void .ctor()"
ex.TargetSite.Name; -> "StringToNumber"
It's possible to do this?

Short Answer:
Yes, You can!!!
I'd just play around with Extension Methods and the trick here, is to get the last frame of the desired class, otherwise it would get methods of mscorlib assembly. So here it go:
public static string GetLastCalledMethod<T>(this Exception ex)
{
var stackTrace = new System.Diagnostics.StackTrace(ex);
var lastFrame = stackTrace.GetFrames().FirstOrDefault(frame => frame.GetMethod().DeclaringType.FullName == typeof(T).FullName);
string methodName = string.Empty;
if (lastFrame != null)
methodName = lastFrame.GetMethod().Name;
return methodName;
}

Short Answer:
You can't.
Long Answer:
If you really need to do that, you will need to perform logging code in all the methods you want to track.
You can create a global variable (ugh) to store a MethodInfo with the last called method, and inside every method, set it to MethodBase.GetCurrentMethod(). Then whenever you want, you can examine that variable to see which method set it last.
In your case, you probably are trying to determine which method the exception was thrown in. You are looking at TargetSite, which returns the lowest method in the hierarchy, whereas you seem to want the one immediately below the current method. If simply examining Exception.StackTrace doesn't provide enough information, you might be able to parse out information from StackTrace and use reflection to get a MethodInfo. Usually, the StackTrace is good enough.
You may also be able to throw a new exception in the top-level method, so you can get the TargetSite from the new one.
Summary:
If Exception.StackTrace doesn't provide enough information, then you will either have to:
Perform logging code in each method you want to check for.
Parse out what information you can get from the Exception.
Change the exception throwing scheme to throw a new exception with InnerException set to the original exception.

I don't know why you want to do this.. because this is expected behaviour. The site of the exception is what you're being shown.. within the int.Parse() calls.
That being said.. if you really want to do this, you need to wrap a try.. catch in CheckValue, and re-throw the exception from there, but in a way that breaks the call stack.. like so:
public int CheckValue(bool sender) {
try {
var qwe = int.Parse("qwe"); // invoke an exception
return 0;
}
catch (Exception ex) {
throw ex; // this breaks the call stack and re-throws the exception from here..
}
}
Then, ex.TargetSite.Name == "CheckValue". I'm still not sure why you'd want to do this.. as a stack trace will actually show you where it all unwinds from after failure.

Related

Is there a way to block or assert on accidental recursion in c#

I am working with a large and complex event driven body of code and there are piles of opportunity to accidentally create a recursive condition.
Sometimes the recursive condition is temporary and the application catches up with itself but even that usually creates unnecessary lag. Other times it creates a stackoverflow which is often very difficult to debug when it happens at a client site.
I would like to have a way to either blacklist or whitelist sections of code that are permitted to recurse. If the recursive condition happens during DEV then I want it to assert so that I can correct the code.
What I am considering is having the application examine its own stack to ensure that the method it just entered is not already on the stack.
Any pointers would be appreciated.
Note: This is for a Web Application but I have run into this challenge in multiple environments.
You can inspect stack like this:
[MethodImpl(MethodImplOptions.NoInlining)]
// optionally decorate with Conditional to only be used in Debug configuration
[Conditional("DEBUG")]
public static void FailIfCallerIsRecursive() {
var trace = new StackTrace();
// previous frame is the caller
var caller = trace.GetFrame(1).GetMethod();
// inspect the rest
for (int i = 2; i < trace.FrameCount; i++) {
// if found caller somewhere up the stack - throw
if (trace.GetFrame(i).GetMethod() == caller)
throw new Exception("Recursion detected");
}
}
Then just call it a the beginning:
void MyPotentiallyRecursiveMethod() {
FailIfCallerIsRecursive()
}
But note that it's quite expensive. However since you are going to use that only in dev (debug) configuration - why not. You can also modify it a bit to throw only when certain level of recursion is detected (so caller appears X time up the stack).
You could call the RuntimeHelpers.EnsureSufficientExecutionStack method and then catch the InsufficientExecutionStackException that is thrown if the next method call would cause a (not catchable) StackOverflowException.
You could create an extension method for it:
public static T EnsureSafeRecursiveCall<T>(this Func<T> method)
{
try
{
RuntimeHelpers.EnsureSufficientExecutionStack();
return method();
}
catch (InsufficientExecutionStackException ex)
{
string msg = $"{method.Method.Name} would cause a {nameof(StackOverflowException)} on the next call";
Debug.Fail(msg);
// logging here is essential here because Debug.Fail works only with debug
throw new StackOverflowException(msg, ex); // wrap in new exception to avoid that we get into this catch again and again(note we are in a recursive call)
}
}
Now your original method remains almost unchanged:
public static IEnumerable<T> YourRecursiveMethod<T>(IEnumerable<T> seq)
{
var method = new Func<IEnumerable<T>>(() => YourRecursiveMethod(seq));
return method.EnsureSafeRecursiveCall();
}

Get exception method name [duplicate]

My code looks as below.
try
{
_productRepo.GetAllProductCategories();
}
catch (Exception ex)
{
//Do Something
}
I need a way to show the method name, suppose in the above case if any exception is thrown in the GetAllProductCategories() method, I need to get this method name i.e. "GetAllProductCategories()" as my result. Can any one suggest me how to do this?
There's a TargetSite property on System.Exception that should come in handy.
Gets the method that throws the
current exception.
In your case, you probably want something like:
catch (Exception ex)
{
MethodBase site = ex.TargetSite;
string methodName = site == null ? null : site.Name;
...
}
It's worth pointing out some of the issues listed:
If the method that throws this
exception is not available and the
stack trace is not a null reference
(Nothing in Visual Basic), TargetSite
obtains the method from the stack
trace. If the stack trace is a null
reference, TargetSite also returns a
null reference.
Note: The TargetSite property may not
accurately report the name of the
method in which an exception was
thrown if the exception handler
handles an exception across
application domain boundaries.
You could use the StackTrace property as #leppie suggests too, but do note that this is a string representation of the frames on the stack; so you'll have to manipulate if you only want the name of the method that threw the execption.
It's in the StackFrame...
private string GetExecutingMethodName()
{
string result = "Unknown";
StackTrace trace = new StackTrace(false);
Type type = this.GetType();
for (int index = 0; index < trace.FrameCount; ++index)
{
StackFrame frame = trace.GetFrame(index);
MethodBase method = frame.GetMethod();
if (method.DeclaringType != type && !type.IsAssignableFrom(method.DeclaringType))
{
result = string.Concat(method.DeclaringType.FullName, ".", method.Name);
break;
}
}
return result;
}
This method was written for an Logging handler class and the use of GetType() simply eliminates the methods within the Logging handler class from being returned as the last executing method. Since the Logging handler class was written for more than just logging exceptions, a new StackTrace object was required. Obviously, for finding "the method that threw the exception" GetType() might not be necessary.
If you just want the top of the stack, take the first frame, call GetMethod() and return that, or simply use TargetSite. GetType() could then be removed. Also note, that the Exception would need to be passed in to create the StackTrace object. For example:
class Program
{
static void Main(string[] args)
{
try
{
Test();
}
catch (Exception ex)
{
// does not work properly - writes "Main"
Console.WriteLine(MethodBase.GetCurrentMethod());
// properly writes "TestConsole.Program.Test"
Console.WriteLine(GetExecutingMethodName(ex));
// properly writes "Test"
Console.WriteLine(ex.TargetSite.Name);
}
Console.ReadKey();
}
static void Test()
{
throw new Exception("test");
}
private static string GetExecutingMethodName(Exception exception)
{
var trace = new StackTrace(exception);
var frame = trace.GetFrame(0);
var method = frame.GetMethod();
return string.Concat(method.DeclaringType.FullName, ".", method.Name);
}
}
Basically, if TargetSite() does what you want, then go no further. But, often times in Logging handlers, an exception object is not available (i.e. tracing and auditing) so a new StackTrace() object is necessary for retrieving the last executed method, the one BEFORE the Logging method.
Look at the stacktrace.
It's a property on the exception.

why my exception shown like this?

I created my own class library and I have create() method like this:
public int create()
{
try
{
if(path!=null){
//do somethings
}
else{
throw new ArgumentNullException("path cannot be null ro empty", "path");
}
catch{
throw;
}
return 0;
}
}
In another project, I add my class library DLL and when I use my library method and because of something for example path=null my method thrown an exception and I get that in line that I wrote throw inside the catch...
I don't want that,how can I get error in line that I call create() method in my project
Thank you
SORRY I DONT KNOW ENGLISH VERY WELL so i try again to say my mean
I try to create class library and I want to get it to some one else to use, I want when exception in my create() method thrown visual studio highlight the line that create method was called, but it open my dll and go to create method and highlight the line that I wrote throw;... how can I solve it?
....................................................................................
finally I found the answer,see this link:
Hiding code from a DLL while debugging
To stop the debugger at the correct line when you throw your exception, all you have to do is to remove your try catch block (which is completely unnecessary in your case either way):
public int create()
{
if(path==null)
throw new ArgumentNullException("path", "path cannot be null or empty");
// do something
return 0;
}
Also as Oscar pointed out, you should switch the arguments when throwing the exception, as the first parameter is for the parameter name, the second for the message.
You have swapped the arguments of ArgumentNullException constructor. First goes the param name, and later the message.
public ArgumentNullException(
string paramName,
string message
)
http://msdn.microsoft.com/es-es/library/k8a0dfcy(v=vs.110).aspx
Also, you can safely remove the catch clause, as you're doing nothing there. Only catch exception you suppose to handle somehow, otherwise, let it bubble up.
When you rethrow an exception, only one stack frame is saved inside each method, therefore, you can't find out which line threw the exception, only the line that rethrew it. You can either log the message when you catch it for the first time, or don't rethrow but instead throw a new exception, and supply the caught exception as an inner exception.
You can always do check before try :
public int create(){
if(path!=null){
try{
//do somethings
}
catch{
throw;
}
else{
throw new ArgumentNullException("path cannot be null ro empty", "path");
}
return 0;
}

Single method executer and error handler

I've written what I initially thought was a generic method executer and error handler for any method I add or might add in the future but after many hours of struggling and googling, I have resorted to going to forums.
Aim: To try and get away from individual error handling in a method and handle all errors in one single method. (hope this makes sense).
Code for Generic method executer and error handler:
internal static Tuple<SystemMessage, object> ExecuteAndHandleAnyErrors<T,TArg1>(this object callingMethod, params object[] args)
{
dynamic methodToExecute;
if (callingMethod.GetType() == typeof(Func<T, TArg1>))
{
methodToExecute = (callingMethod as Func<T,TArg1>);
}
else
{
methodToExecute = (callingMethod as Action<T, TArg1>);
}
try
{
var result = methodToExecute.DynamicInvoke(args);
return new Tuple<SystemMessage, object>(null,result);
}
catch (Exception ex)
{
return new Tuple<SystemMessage, object>(new SystemMessage
{
MessageText = ex.Message,
MessageType = SystemMessage.SystemMessageType.Error
}, null);
}
}
//This is the code for a sample method:
internal QuestionAnswerSet LoadQuestions(DataWrapper dataWrapper)
{
var taskExecuter = new Func<DataWrapper, QuestionAnswerSet> (InternalDeserializeObject<QuestionAnswerSet>);
var questionAnswerSet = taskExecuter.ExecuteAndHandleAnyErrors<DataWrapper, QuestionAnswerSet>(dataWrapper);
return questionAnswerSet.Item2 as QuestionAnswerSet;
}
my question is this: Is it possible that if the LoadQuestions method falls over, how do I catch the error and defer the error handling to the ExecuteAndHandleAnyErrors method without manually adding a try...catch statement to the LoadQuestions method?
Hope this makes sense.
thank u.
charles
You could wrap every call of LoadQuestions in its own call to ExecuteAndHandleAnyErrors.
However, this seems to be missing part of the point of exception handling. When using exceptions to communicate error, one usually doesn't "handle all errors in one single method". That one single method usually cannot deal with any possible exception sensibly. For example, could your method handle a ThreadAbortedException? What about an ArgumentException? Nor does one add a lot of try ... catch block all over the place.
In general, try to write try ... catch blocks that handle specific exceptions when your code can handle the failure sensibly (e.g., catching FileNotFoundException near where you open a file and triggering a dialog box or attempting to open a default file at a different path).
Often, an application will have one top-level try ... catch block in Main() to log any otherwise unhandled exceptions. Then it rethrows the exception/crashes the program/exits the program.
I solved it.
What I was doing was is seeing the first time the exception is thrown and not stepping further down by pressing F10.
THanks for all the help

if statement for throwing Exception?

Hi I wanted to ask because I'm not sure if is it propriete using of Exception:
public int Method(int a, int b) {
if(a<b) throw new ArgumentException("the first argument cannot be less than the second");
//do stuff...
}
can I throw Exception after if statement? or should I always use try - catch when it goes with the exceptions?
That is perfectly valid. That is exactly what exceptions are used for, to check for "Exceptions" in your logic, things that weren't suppose to be.
The idea behind catching an exception is that when you pass data somewhere and process it, you might not always know if the result will be valid, that is when you want to catch.
Regarding your method, you don't want to catch inside Method but infact when you call it, here's an example:
try
{
var a = 10;
var b = 100;
var result = Method(a, b);
}
catch(ArgumentException ex)
{
// Report this back to the user interface in a nice way
}
In the above case, a is less than b so you can except to get an exception here, and you can handle it accordingly.
In this case, you don't want to catch the exception. You're throwing it to alert the caller that they've made a mistake in the way they called your method. Catching it yourself would prevent that from happening. So yes, your code looks fine.
That's perfectly fine. You're throwing the exception, not catching/handling it, so you wouldn't need a try/catch block for it.
This is perfectly valid, you can use the same construct even with the constructors.
But What you should not do is
public int Method(int a, int b)
{
try
{
if (a < b)
throw new ArgumentException("the first argument cannot be less than the second");
}
catch (Exception)
{
}
return 0;
}
You've got the right idea. You could use your code like this:
void MyMainMethod()
{
// ... oh, let's call my Method with some arguments
// I'm not sure if it'll work, so best to wrap it in a try catch
try
{
Method(-100, 500);
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message);
}
}
public int Method(int a, int b)
{
if (a < b) throw new ArgumentException("the first argument cannot be less than the second");
//do stuff ... and return
}
It might help to look through MSDN's Handling and Throwing Exceptions and Best Practices for Handling Exceptions
What you've done here is perfectly Ok.
A common pattern for arg checks is to wrap the check/throw code in a static "Contract" class ensuring you have a consistent approach to exception management when validating input arguments.
Slightly off topic but if using .NET 4.0 you can also look at the new Code Contracts feature for validation of method input and output.
All above answers are correct but I like to mention one additional point here which I did not see mentioned in any of the answers. The reason why you should throw an exception and not return an integer e.g. 0 or -1 for signalling that an error occurred, is that the returned integer can be mistakenly treated/assumed as a valid result of your method. It is an integer anyway, and your method, after performing its internal logic returns an integer. So the caller of this method can mistakenly treat any returned integer as a valid result, which can lead to bugs down the line. In that case, throwing an exception makes perfect sense.

Categories