0

I was checking FilterAttribute class in .Net Core, and I found that it has multiple methods which are called at specific time. E.g.:

OnAuthorization(AuthorizationContext) Called when a process requests authorization.

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

I am wondering, if I am writing my custom attribute, how can I use the methods defined in it?

Mohammed Noureldin
  • 14,913
  • 17
  • 70
  • 99
  • If your custom attributes inherits the FilterAttribute then those methods will still be called and you can do whatever you want in those methods (you can even call the base methods from your method). Not sure what your question is. – CodingYoshi Oct 31 '17 at 02:36
  • your tags suggest .net-core. The link you have provided is actually of .net framework. Which version do you want to make your custom attribute in? – Neville Nazerane Oct 31 '17 at 02:46

4 Answers4

3

Simple call it.

We made an Test Attribute:

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

Using GetCustomAttribute we are retrieving the attribute, and call Greet on it:

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

Related:

Christian Gollhardt
  • 16,510
  • 17
  • 74
  • 111
  • If you are using `Attribute` class directly, also look into the `AttributeUsage` attribute that you can use when creating your custom attribute class for type safety – Neville Nazerane Oct 31 '17 at 03:14
1

The link you have shared is not .net core. In .net core, the ActionFilterAttribute class has all the functions you will need to make a custom filter. To create a custom filter, simple create a class extending ActionFilterAttribute and override the function of your choice. You can check the timeline of when which filter is called here: https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters

For using this filter, lets say the class you created was named MyCustomFilterAttribute, you will use it like this in your controller:

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

    }

}

If you want to implement the filter for every action in the controller, you can add the attribute to the controller:

[MyCustomFilter]
public class LoginController : Controller
DLeh
  • 23,806
  • 16
  • 84
  • 128
Neville Nazerane
  • 6,622
  • 3
  • 46
  • 79
1

Attributes are dumb

Attributes don't do anything by themselves, except hold data. The only reason attributes like FilterAttribute do anything is because the MVC framework looks for them and invokes them before or after calling the method they are applied to.

How MVC invokes them

Here is what it looks like in the 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();
}

Sort of hard to follow without context, and the loop is hard to spot (they use a bit of LINQ and the Aggregate method to invoke each filter in the collection) but suffice it to say that MVC will look at the method, look for attributes of a certain kind, and invoke them before and after the actual action method invocation. So it's not automatic.

How you can do it

You could do something similar, if you're willing to write code to invoke the attribute. Here's an example how to do it.

First, we define out custom attribute. This custom attribute will output a message to the console when its OnBeforeExecute method is invoked.

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

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

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

Now we write a class that applies the attribute to one of its methods:

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

Now by itself, the attribute does nothing at run-time:

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

Output:

MyClassMethod says 'Main call'

But if we write code to look for the attribute and invoke it, we can get the message to appear. This is a very simple example:

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");
    }
}

Output:

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

Full example on Fiddle.

John Wu
  • 50,556
  • 8
  • 44
  • 80
1

Not 100% sure what you are asking, but here's some super contrived demo code that accesses methods and attributed methods

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()));
    }
}
Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
  • Could explain this syntax when you defined Lambda expression? It is weird for me: `(method: m, attribute: m.GetCustomAttribute(typeof(Hook), true) as Hook)`, is it like this: `new {method = ...; attribute = ....}`? – Mohammed Noureldin Nov 01 '17 at 20:09
  • 1
    it's kind of similar to an annoynmous object but not quite, it's C#s new tuple syntax. In the past I'd of used an annoymous object. https://blogs.msdn.microsoft.com/mazhou/2017/05/26/c-7-series-part-1-value-tuples/ – Keith Nicholas Nov 01 '17 at 20:49