如何使用Attributes中定义的方法?

时间:2017-10-31 02:22:53

标签: c# .net asp.net-core

我正在检查FilterAttribute中的.Net Core类,我发现它有多个在特定时间调用的方法。 E.g:

  

OnAuthorization(AuthorizationContext)   在进程请求授权时调用。

https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.118).aspx

我想知道,如果我正在编写自定义属性,我该如何使用其中定义的方法?

4 个答案:

答案 0 :(得分:3)

简单地称呼它。

我们制作了一个测试属性:

class TestAttribute : Attribute
{
    public void Greet(string text)
    {
        Console.WriteLine(text);
    }
}

使用GetCustomAttribute我们正在检索该属性,并在其上调用Greet

[Test]
class Program
{
    static void Main(string[] args)
    {
        var attribute = typeof(Program).GetCustomAttribute<TestAttribute>();
        attribute.Greet("Hello World");
        Console.ReadKey();
    }
}

相关:

答案 1 :(得分:1)

您分享的链接不是.net core。在.net core中,ActionFilterAttribute类具有制作自定义过滤器所需的所有功能。要创建自定义过滤器,只需创建一个扩展ActionFilterAttribute的类并覆盖您选择的功能。您可以在此处查看调用过滤器的时间轴:https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters

要使用此过滤器,假设您创建的类名为MyCustomFilterAttribute,您将在控制器中使用它:

public class LoginController : Controller
{
    [MyCustomFilter]
    public void Index(){

    }

}

如果要为控制器中的每个操作实现过滤器,可以将属性添加到控制器:

[MyCustomFilter]
public class LoginController : Controller

答案 2 :(得分:1)

属性愚蠢

除了保留数据外,

属性不会自行执行任何操作。像FilterAttribute这样的属性做任何事情的唯一原因是因为MVC框架在调用它们应用的方法之前或之后查找它们并调用它们。

MVC如何调用它们

以下是MVC reference code base中的内容:

protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
    ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
    Func<ActionExecutedContext> continuation = () =>
        new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */)
        {
            Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
        };

    // need to reverse the filter list because the continuations are built up backward
    Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation, (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
    return thunk();
}

在没有上下文的情况下很难遵循,并且很难发现循环(他们使用一些LINQ和Aggregate方法来调用集合中的每个过滤器)但是足以说明MVC会看起来在该方法中,查找某种类型的属性,并在实际的操作方法调用之前和之后调用它们。所以它不是自动的。

你如何做到

如果你愿意编写代码来调用属性,你可以做类似的事情。这是一个如何做的例子。

首先,我们定义自定义属性。此自定义属性将在调用其OnBeforeExecute方法时向控制台输出消息。

public class HelloWorldAttribute : System.Attribute  
{  
    private string _someString;

    public HelloWorldAttribute(string text)  
    {  
        _someString = text;
    }  

    public void OnBeforeExecute()
    {
        Console.WriteLine("OnBeforeExecute says '{0}'.", _someString);
    }
}  

现在我们编写一个将该属性应用于其中一个方法的类:

public class MyClass
{
    [HelloWorld("This is a test!!")]
    public void MyClassMethod(string text)
    {
        Console.WriteLine("MyClassMethod says '{0}'", text);
    }
}

现在,该属性在运行时不执行任何操作:

public class Program
{
    public static void Main()
    {
        //By itself, the attribute does nothing
        var c = new MyClass();
        c.MyClassMethod("Main call");
    }
}

输出:

MyClassMethod says 'Main call'

但是如果我们编写代码来查找属性并调用它,我们就可以显示消息了。这是一个非常简单的例子:

public class Program
{
    public static void Main()
    {
        var c = new MyClass();
        typeof(MyClass)
            .GetMethod(nameof(c.MyClassMethod))
            .GetCustomAttributes(true)
            .OfType<HelloWorldAttribute>()
            .First()
            .OnBeforeExecute();
        c.MyClassMethod("Main call");
    }
}

输出:

OnBeforeExecute says 'This is a test!!'.
MyClassMethod says 'Main call'

Full example on Fiddle

答案 3 :(得分:1)

不是100%肯定你在问什么,但是这里有一些超人为的演示代码可以访问方法和归因方法

class Program
{
    public class Hook : Attribute
    {
        public string Action { get; set; }

        public void Talk(string s)
        {
            var prefix = string.IsNullOrEmpty(Action) ? "" : $"{Action} ";
            Console.WriteLine($"{prefix}{s}");
        }
    }

    public class A
    {
        [Hook] public string Option1()=> "A1";
        public string Option2() => "A2";
    }

    public class B
    {
        [Hook(Action = "Blah")] public string Option1() => "B1";
        [Hook] public string Option2() => "B2";
    }

    static void Main(string[] args)
    {
        var things = new List<object>() {new A(), new B()};
        things.SelectMany(t => t.GetType().GetMethods()
                .Select(m => (method: m, attribute: m.GetCustomAttribute(typeof(Hook), true) as Hook))
                .Where(h => h.attribute != null)
                .Select(h => (target: t, hook: h)))
            .ToList()
            .ForEach(v => v.hook.attribute.Talk(v.hook.method.Invoke(v.target, new object[] { }).ToString()));
    }
}