【问题标题】:How can I get the function/action name that custom attribute is attached to while it is executing?如何获取自定义属性在执行时附加到的函数/操作名称?
【发布时间】:2015-09-11 19:13:35
【问题描述】:

理想情况下,我想创建一个从 ActionFilterAttribute 继承的过滤器,我可以在 Global.asax 中应用它,为我的应用程序中的所有操作创建性能计数器。这个问题很简单,但问题是我希望性能计数器具有以它们的名义附加到的操作的方法签名。但是,我找不到一种方法来提取在构造过程中附加属性的方法的方法名称。这导致我必须将属性单独应用于每个操作并将其签名作为参数传递。但是,这会带来明显的问题(即方法签名的更新不会自动与性能计数器命名同步)。

为了简化问题,如果我将属性附加到任何类型的方法,我可以访问它附加到的方法的名称/签名吗?我正在寻找一个通用的解决方案,它也适用于不是从 ActionFilterAttribute 派生的属性。

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.
}

【问题讨论】:

  • 你试过filterContext.ActionDescriptor.ActionName吗?
  • 还有filterContext.RouteData.Values["action"]?
  • ActionFilter 对动作有意义,而不是对任何类型的方法。
  • 我没有这样做,因为我明确地想要一个通用的解决方案,它甚至可以用于不是从 ActionFilter 派生的属性。理想情况下,我想在构造函数中获取它。
  • 我认为您应该使用外部方法,该方法将使用反射来查找具有此或其他属性的操作,并将信息写入日志。您无法找到将属性附加到其构造函数 (AFAIUI) 中的哪个方法。

标签: c# asp.net .net asp.net-mvc action-filter


【解决方案1】:

查找执行动作的名称:

var actionName = filterContext.ActionDescriptor.ActionName;

或者

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

查找参数(名称、类型、默认值):

var parameters = filterContext.ActionDescriptor.GetParameters();

查找参数值:

 var value= filterContext.ActionParameters["parameterName"]; 

【讨论】:

  • 是的。你正确理解了我的问题。但是,性能计数器是在应用程序启动时在 global.asax 中创建的。所以,那个时候,属性没有filterContext,这就是为什么我需要能够在构造过程中获取方法的名称/签名。我可以让它工作的唯一方法是如果 filterContext 中的值与构造期间从反射获得的值完全相同。我可以试试这个;但是,我正在寻找一种解决方案,它甚至适用于不是从 ActionFilterAttribute 派生的属性。感谢您的回复!
【解决方案2】:

据我了解,您需要通用解决方案,与 ActionFilterAttribute 或 asp.net 完全无关。然后您可以使用面向方面的编程,.NET 的最佳实现是 PostSharp。该库的免费版本足以实现您的目标。例如:

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
    }
}

在这里,我们创建 MeasureAttribute,您可以将其应用于 any 方法并在许多点拦截方法调用。更重要的是,您甚至可以根据某些条件将其动态应用于所有方法(即给定类或整个程序集中的所有方法,或其他)。它还允许您在编译时保存一些信息,以提高性能。在上面的示例中,我们在编译期间保存了一次方法名称。

PostSharp(以及一般的 AOP)可以做的远不止这些。

【讨论】:

  • 这看起来很有趣。我会仔细看看的!感谢您的建议!
  • 忘了提到要安装 PostSharp - 只需安装他们的 nuget 包,无需下载任何东西。
【解决方案3】:

我假设您的方法名称将与 filterContext.ActionDescriptor.ActionName 相同。

你可以从filterContext.Controller获取Controller实例。

所以有了类和方法名你可以得到签名,但不能在构造函数中。

【讨论】:

  • 感谢您的回复!我正在寻找一种解决方案,即使对于不是从 ActionFilterAttribute 派生的属性也适用,这些属性可能想要利用它们所附加的方法的签名。由于属性生命周期的管理方式,我还希望能够在构造函数中获取此值。
  • @BrandonPhillips 老实说,我不认为这是可能的,也不应该是可能的。我的理解是属性是对象,“附加”到不同的语言结构。因此,他们如何在实例化时知道他们将附加到什么方法?如果我错了,请纠正我
  • 这很有意义,但似乎如果使用属性的方式是附加到其他东西,那么它应该可以访问上下文(例如,至少身份) 无论它被附加到什么。这可能是不可能的,但我想在我放弃这个想法之前确定一下。但是,如果我使用属性,我认为访问我所附加的任何内容的身份是值得的。
【解决方案4】:

我可以想象两种选择。您可以在加载的程序集中反映类中的所有类型 - 不是很直接但有效。问题是 - 我不确定是否及时加载了有趣的程序集 - 您可能必须使用配置信息作为指导主动加载它们。

属性可以是对各种 MethodInfo/PropertyInfo 对象的查询,您可以反射式地询问这些对象。然后用MemberInfo.GetCustomeAttributes查询属性。

或者,您可以让感兴趣的类型在静态初始化期间注册自己以供​​检查,而不是 global.asax。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    • 2014-01-26
    相关资源
    最近更新 更多