Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the function/action name that custom attribute is attached to while it is executing?

Ideally, I want to create a filter that inherits from ActionFilterAttribute that I can apply in Global.asax that will create performance counters for all the actions in my application. That problem is easy, but the issue is that I want the performance counters to have the method signature of the action that they are attached to in their name. However, I can't find a way to extract the method name of the method that an attribute is attached to during construction. This is causing me to have to apply the attributes to each action individually and pass in their signature as a parameter. However, this poses obvious problems (i.e. updates to method signature not automatically synchronized with perf counter naming).

To simplify the problem, if I attach an attribute to a method of any kind, can I access the name/signature of the method that it is attached to? I'm looking for a generic solution that works for attributes that don't derive from ActionFilterAttribute also.

public class SomeAttribute : ActionFilterAttribute
{
    public string FunctionSignature { get; set; }

    public SomeAttribute() 
    {
        this.FunctionName = { HOW DO I GET THE NAME OF THE METHOD I'M ON WITHOUT PASSING IT IN AS AN INPUT ARGUMENT? }
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // Some code to update perf counter(s) with recorded time that will use string.Format("{0}: Avg. Time or Something", this.FunctionSignature).
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    {
        // Some code to record time.
    }
}

[SomeAttribute]
public void SomeMethod()
{
    // Some code.
}
like image 445
Brandon P. Avatar asked Sep 11 '15 19:09

Brandon P.


People also ask

How would you define a custom attribute that can only be applied to class code elements?

The following code fragment specifies that a custom attribute can be applied to any class or method: C# Copy. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] End Class.

Which attribute is attached to the Web Service class declaration?

it lets you turn any public method of a WebService subclass into a method that you can expose as part of the Web Service merely by attaching the [WebMethod] attribute to the method definition.

What is custom attribute in C#?

Attributes are used to impose conditions or to increase the efficiency of a piece of code. There are built-in attributes present in C# but programmers may create their own attributes, such attributes are called Custom attributes. To create custom attributes we must construct classes that derive from the System.


2 Answers

Find the name of executing action:

var actionName = filterContext.ActionDescriptor.ActionName;

or alternatively

var actionName = filterContext.RouteData.Values["action"] as string

Find parameters (Name, Type, DefaultValue):

var parameters = filterContext.ActionDescriptor.GetParameters();

Find parameters values:

 var value= filterContext.ActionParameters["parameterName"]; 
like image 108
Reza Aghaei Avatar answered Sep 18 '22 12:09

Reza Aghaei


As I understand, you want generic solution for that, not related to ActionFilterAttribute or asp.net at all. Then you can use Aspect Oriented Programming, and best implementation of that for .NET is PostSharp. Free version of that library is enough to achieve your goal. For example:

class Program
{
    static void Main(string[] args)
    {
        Test();
        Console.ReadKey();
    }

    [Measure]
    public static void Test() {
        Thread.Sleep(1000);
    }
}

[Serializable]
public sealed class MeasureAttribute : OnMethodBoundaryAspect
{        
    private string _methodName;
    [NonSerialized]
    private Stopwatch _watch;
    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo) {
        base.CompileTimeInitialize(method, aspectInfo);
        // save method name at _compile_ time
        _methodName = method.Name;
    }


    public override void OnEntry(MethodExecutionArgs args) {
        base.OnEntry(args);
        // here you have access to everything about method
        _watch = Stopwatch.StartNew();
    }

    public override void OnExit(MethodExecutionArgs args) {
        base.OnExit(args);
        if (_watch != null) {
            _watch.Stop();
            Console.WriteLine("Method {0} took {1}ms", _methodName, _watch.ElapsedMilliseconds);
        }
    }

    public override void OnException(MethodExecutionArgs args) {
        base.OnException(args);
        // do what you want on exception
    }
}

Here we create MeasureAttribute which you can apply on any method and intercept method invocation in many points. Even more, you can even apply it dynamically to all methods based on some condition (i.e. all methods in given class or whole assembly, or whatever). It also allows you to save some information in compile time, to increase perfomance. In example above we save method name once during compilation.

PostSharp (and AOP in general) can do much more than that.

like image 28
Evk Avatar answered Sep 21 '22 12:09

Evk