Is there anyway to get the current method name from inside an async function?
I\'ve tried:
System.Reflection.MethodInfo.GetCurrentMethod();
C# 5 added caller info attributes which may give you more what you are looking for. Note that these insert the appropriate information into the call site at compile-time rather than using run-time information. The functionality is more limited (you can't get a complete call stack, obviously), but it is much faster.
An example using CallerMemberNameAttribute:
using System.Runtime.CompilerServices;
public static void Main(string[] args)
{
Test().Wait();
}
private static async Task Test()
{
await Task.Yield();
Log();
await Task.Yield();
}
private static void Log([CallerMemberName]string name = "")
{
Console.WriteLine("Log: {0}", name);
}
There are also CallerFilePath and CallerLineNumber attributes which can get other pieces of info about the call site.
This method works from async method call as well as from normal method. (C#5)
/// <summary>
/// Returns Current method name
/// </summary>
/// <returns>callers method name</returns>
public string GetCurrentMethod([CallerMemberName] string callerName = "")
{
return callerName;
}
You need to capture the method name early in the async method, somewhere before the first async call. The most convenient way I've found to skip past the compiler generated state machine is to look at the declaring type of each method in the stack trace.
var method = new StackTrace()
.GetFrames()
.Select(frame => frame.GetMethod())
.FirstOrDefault(item => item.DeclaringType == GetType());
await Task.Yield();
if (method != null)
{
Console.WriteLine(method.Name);
}
You can send the strackTrace.GetFrame(i).GetMethod() which is a System.Reflection.MethodBase object to a function that checks if the System.Reflection.MethodBase.DeclaringType.FullName has the <> chars and if so will get the requested method name that lays between the <...> chars.
static private string getMethodName(System.Reflection.MethodBase method)
{
string _methodName = method.DeclaringType.FullName;
if (_methodName.Contains(">") || _methodName.Contains("<"))
{
_methodName = _methodName.Split('<', '>')[1];
}
else
{
_methodName = method.Name;
}
return _methodName;
}
And the how to use example is:
var _stackTrace = new System.Diagnostics.StackTrace(exception, true);
string _methodName = getMethodName(_stackTrace.GetFrame(0).GetMethod());
I came across the same issue recently for my log message and the answers here helped. I am sharing my code in case it can help others with their questions.
using System.Runtime.CompilerServices;
namespace Foo.Services
{
public interface ILogFormatter
{
public string FormatMessage(LogType logType, string details, [CallerMemberName] string caller = "");
}
public enum LogType
{
Debug,
Information,
Warning,
Error
}
public class LogFormatterOptions
{
public string Subject { get; set; }
}
public class LogFormatter : ILogFormatter
{
public LogFormatter(LogFormatterOptions options)
{
Subject = options.Subject;
}
public string Subject { get; set; }
public string FormatMessage(LogType logType, string details, [CallerMemberName] string caller = "")
{
return $"{Subject} - {logType}: caller: {caller} - {details}";
}
}
}
This is how this method is called and it works for both async and synchronized methods. Note that I am not passing value for the caller input & it picks up the caller method name.
logger.LogInformation(logFormatter.FormatMessage(LogType.Information, ""));
I used a mix of Nathan's and Mike's answers.
Using GetType()
to query the method from stack trace did not work for me. Not guaranteed. But using CallerMemberNameAttrinute
lets me get the exact method by its name.
So my code would be:
using System.Runtime.CompilerServices;
public static void Main(string[] args)
{
Test().Wait();
}
private static async Task Test()
{
await Task.Yield();
Log();
await Task.Yield();
}
private static void Log([CallerMemberName]string methodName = "")
{
var method = new StackTrace()
.GetFrames()
.Select(frame => frame.GetMethod())
.FirstOrDefault(item => item.Name == methodName);
Console.WriteLine("Log: {0}", method.DeclaringType + "." + method.Name);
}
This way I get method name with its full namespace path.