Get exception method name [duplicate] - c#

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.

Related

Create c# exception and not throw it

Is there a way better than what I'll have written below to get an exception properly set like when thrown?
try {
throw new Exception("Blah");
}
catch (Exception exe) {
Assert.NotNull(exe.StackTrace);
DoSomeWork(exe);
// throw;
}
The short answer is : NO.
The System.Exception properties are filled in when it is thrown:
By default, the stack trace is captured immediately before an exception object is thrown. Use Environment.StackTrace to get stack trace information when no exception is being thrown.
So if you really need an exception object in the state it is after being thrown you have no other good way but to throw and catch it.
Still do not drop off the main question: do you really need the exception object?
If you've got a method that has System.Exception as an input parameter and you need a StackTrace inside, think of these possible solutions:
Method overload with an optional StackTrace input parameter.
A successor of System.Exception with a hiding StackTrace property which memorizes the StackTrace when the object is created not thrown.
As the last resort you could make an extension method for the System.Exception class which "populates" an instance of the System.Exception:
private void MyCode()
{
Exception exe = new Exception("Blah");
exe.Populate();
DoSomeWork(exe);
}
public static void Populate(this System.Exception source)
{
try
{
throw source;
}
catch
{
}
}

Using reflection, setter throws exception which can't be caught

I am using reflection to set properties on an object. If any of the setters throw an exception, the exception is not caught by the code that makes the SetValue call. Visual Studio tells me that the exception is uncaught by user code.
For example, imagine in the example below that the Title property setter on the object referenced by the "target" variable throws an ArgumentException.
Looking at the call stack, it seems that there is unmanaged code between the snippet below and the setter.
Can somebody please (& thank you!) explain:
Why is this happening in the first place?
Is there a simple way to fix it without re-thinking the program logic?
Here is my code:
try
{
prop.SetValue(target, attr.Value); // target does have a "Title" property
// attr.Value == "Title"
// the setter throws an ArgumentException
}
catch (Exception ex) // No exception is ever caught.
{
errors.Add(ex.Message);
}
Here is the code for one of many properties that I want to set like this:
public string Title
{
get
{
return this.title;
}
set
{
if (string.IsNullOrEmpty(value) || value.Length < 1 || value.Length > 128)
{
throw new ArgumentException("Title must be at least 1 character and cannot be longer than 128 characters.");
}
this.title = value;
}
}
EDIT as stated by #Default, Framework 4.5 does have an overload with only two parameters, so if the user is working with FW 4.5 this answer does not have relevance (at least the last part about PropertyInfo),
You are wrong, it is trapped and here is an example to demonstrate it:
public class ExceptionGenerator
{
public static void Do()
{
ClassToSet clas = new ClassToSet();
Type t = clas.GetType();
PropertyInfo pInfo = t.GetProperty("Title");
try
{
pInfo.SetValue(clas, "test", null);
}
catch (Exception Ex)
{
Debug.Print("Trapped");
}
}
}
class ClassToSet
{
public string Title {
set {
throw new ArgumentException();
}
}
}
What you are doing wrong is obtaining the PropertyInfo, the PropertiInfo's SetValue method expects a third parameter, the index at the property (null in your case), so your "prop" is not a PropertyInfo, I assume it's a FieldInfo, and because that it throws an unhandled exception.
Any exception there should be caught.
See fiddle: https://dotnetfiddle.net/koUv4j
This includes errors in the reflection call itself (setting the property to the wrong Type), or having an exception within the property's setter itself (set throws).
This leads to something else being wrong. Possibilities:
You've got your IDE set to halt on all exceptions
The exception isn't happening where you think it is (like, in the catch, which will rethrow)
If it's not one of those 2 then please provide more information.

Is there a way of getting the compiler to initialize a string with the enclosing method name?

Our C# codebase have several methods that create error messages that include the method's name. Can I get the compiler to statically insert the method name for me? I know I could do something with reflection, but I'd rather not.
Amongst other things, I'm seeing quite a few copy-paste errors where the exception handling from one method is copied to another, without the method name changing.
public void Method1()
{
try
{
DoStuff();
}
catch (Exception e)
{
HandleError("Method1", details);
}
}
Rather than include the string "Method1" (and "Method2" up to "Methodn") is there a way of telling the compiler to insert the current method name there?
In NET 4.5 you can use the CallerMemberName attribute. Your HandleError method would then look like so:
void HandleError(YourDetailsClass details,
[CallerMemberName] callingMethod = null)
and you'd simply use
HandleError(details);
you can use MethodBase.GetCurrentMethod which returns MethodInfo
using System.Reflection;
and then
catch (Exception e)
{
HandleError(MethodBase.GetCurrentMethod().Name, details);
}
Yes, you can try with this:
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
string methodName = st.GetFrame(0).GetMethod().Name;
And you will have the name of your running method.
One way is to use the StackTrace and StackFrame classes in System.Diagnostics to retrieve the method name:
private void HandleError(Exception ex) {
var st = new StackTrace ();
var sf = st.GetFrame (1); // get the previous method that called this
// (not this method)
var previousMethod = sf.GetMethod ();
var errorMessage = string.Format("Error in method {0} with Exception {1}",
previousMethod.Name,
ex.Message);
}
Example:
void MyMethod() {
HandleError(new Exception("Error here"));
}
errorMessage would contain: Error in method MyMethod with Exception Error here.

Get name of last called method

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.

.NET error handling

I have been writing .NET applications and have been impressed with the error handling included in the framework.
When catching an error that has been throw by the processes or somewhere in the code I like to include the message (ex.Message, which is usually pretty general) but also the stacktrace (ex.stacktrace) which helps to trace the problem back to a specific spot.
For a simple example let's say for instance that we are recording numbers to a log in a method:
public void ExampleMethod(int number){
try{
int num = number
...open connection to file
...write number to file
}
catch(Exception ex){
.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally{
...close file connection
}
}
Is there any way to see the method called (in this case ExampleMethod) with the specific number that was passed that potentially crashed the method call? I believe you could log this perhaps in the catch block but I am interested essentially in catching the method call and parameters that caused the system to throw the exception.
Any ideas?
I suggest stuffing the parameter values into the exception's Data dictionary, e.g.
public void ExampleMethod(int number) {
try {
int num = number
...open connection to file
...write number to file
}
catch(Exception ex) {
ex.Data["number"] = number;
//.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally {
//...close file connection
}
Another advantage of this method is that you can stuff the parameters in the catch block, then re-throw the exception and log it somewhere else without losing the stack trace, e.g.
catch(Exception ex) {
ex.Data["number"] = number;
throw;
}
If you want to know the value of the parameters in your method, then there is only one way, IMO, to do it - you need to repackage the exception with data.
For example:
int param1 = 10;
string param2 = "Hello World";
try
{
SomeMethod(param1, param2)
}
catch(SomeExpectedException e)
{
throw new MyParameterSensitiveException(e, param1, param2);
}
You basically repackage the original exception as the inner exception of another exception, and additionally supply the parameters you used to call the method. Then you could inspect that in some way to figure out what went wrong.
The accepted answer and many of the solutions described will work fine but what you're doing is littering your source with a slightly different blob of code depending on what parameters are in your method signature.
When it comes time to add a new parameter you need to remember to update your handler to add that new parameter. Or if you remove a parameter then you need to remember to remove the parameter from your exception handler.
What if you have a two or more try..catch blocks? Then you now have two blocks of code to keep up to date. Definitely not refactor friendly.
Another approach is to remove the logging code use a technique called Aspect Oriented Programming.
One such tool to facilitate this is a product called PostSharp.
With PostSharp you can write a logger than is invoked whenever an exception is thrown without the need for messy method and parameter specific code. For example (using version 1.5 of PostSharp):
LoggerAttribute.cs -
[Serializable]
public class LoggerAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionEventArgs eventArgs)
{
Console.WriteLine(eventArgs.Method.DeclaringType.Name);
Console.WriteLine(eventArgs.Method.Name);
Console.WriteLine(eventArgs.Exception.StackTrace);
ParameterInfo[] parameterInfos = eventArgs.Method.GetParameters();
object[] paramValues = eventArgs.GetReadOnlyArgumentArray();
for (int i = 0; i < parameterInfos.Length; i++)
{
Console.WriteLine(parameterInfos[i].Name + "=" + paramValues[i]);
}
eventArgs.FlowBehavior = FlowBehavior.Default;
}
}
You then decorate your classes with the LoggerAttribute:
[Logger]
public class MyClass
{
public void MyMethod(int x, string name)
{
// Something that throws an exception
}
}
Anything that throws an exception in MyMethod will cause the OnException method to be executed.
There are two versions of PostSharp. Version 1.5 is free and open sourced under the GPL and is targeted at .NET 2.0. PostSharp 2.0 is not entirely free but its community edition will support the basic functionality described above.
In order to do this:
public void MyProblematicMethod(int id, string name)
{
try
{
object o = null;
int hash = o.GetHashCode(); // throws NullReferenceException
}
catch (Exception ex)
{
string errorMessage = SummarizeMethodCall(MethodBase.GetCurrentMethod(), id, name);
// TODO: do something with errorMessage
}
}
...and get this:
"MyProblematicMethod invoked: id = 1, name = Charlie"
...you could do something like this:
public static string SummarizeMethodCall(MethodBase method, params object[] values)
{
var output = new StringBuilder(method.Name + " invoked: ");
ParameterInfo[] parameters = method.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
output.AppendFormat("{0} = {1}",
parameters[i].Name,
i >= values.Length ? "<empty>" : values[i]
);
if (i < parameters.Length - 1)
output.Append(", ");
}
return output.ToString();
}
You could make a class that inherits Exception and add some arguments to it so you could pass the number to it.
You can get the method name and the parameters like this,
try
{
int a = 0;
int i = 1 / a;
}
catch (Exception exception)
{
StackTrace s = new StackTrace(exception);
StackFrame stackFrame = s.GetFrame(s.FrameCount - 1);
if (stackFrame != null)
{
StringBuilder stackBuilder = new StringBuilder();
MethodBase method = stackFrame.GetMethod();
stackBuilder.AppendFormat("Method Name = {0}{1}Parameters:{1}", method.Name, Environment.NewLine);
foreach (ParameterInfo parameter in method.GetParameters())
{
stackBuilder.AppendFormat("{0} {1}", parameter.ParameterType.FullName, parameter.Name);
stackBuilder.AppendLine();
}
// or use this to get the value
//stackBuilder.AppendLine("param1 = " + param1);
//stackBuilder.AppendLine("param2 = " + param2);
}
}
I am not sure whether you can get the parameter values directly off the stack like a debugger.
The Automatic Exception Handling from Crypto Obfuscator can do what you need.
The exception reports include all pertinent information including full stack trace info along with the values of all method arguments and local variables, plus the system information, the time of the exception, the build number, and optional developer defined custom data like log files, screenshots, etc.
DISCLAIMER: I work for LogicNP Software, the developer of Crypto Obfuscator.

Categories