Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read action method's attributes in ASP.NET Core MVC?

Based on this article I'm trying to create an IActionFilter implementation for ASP.NET Core that can process attributes that are marked on the controller and the controller's action. Although reading the controller's attributes is easy, I'm unable to find a way to read the attributes defined on the action method.

Here's the code I have right now:

public sealed class ActionFilterDispatcher : IActionFilter {     private readonly Func<Type, IEnumerable> container;      public ActionFilterDispatcher(Func<Type, IEnumerable> container)     {         this.container = container;     }      public void OnActionExecuting(ActionExecutingContext context)     {         var attributes = context.Controller.GetType().GetCustomAttributes(true);          attributes = attributes.Append(/* how to read attributes from action method? */);          foreach (var attribute in attributes)         {             Type filterType = typeof(IActionFilter<>).MakeGenericType(attribute.GetType());             IEnumerable filters = this.container.Invoke(filterType);              foreach (dynamic actionFilter in filters)             {                 actionFilter.OnActionExecuting((dynamic)attribute, context);             }         }     }      public void OnActionExecuted(ActionExecutedContext context)     {         throw new NotImplementedException();     } } 

My question is: how do I read the action method's attributes in ASP.NET Core MVC?

like image 277
Steven Avatar asked Aug 07 '15 09:08

Steven


People also ask

What is action attribute in MVC?

Action Name attribute allows and helps us to specify the different Action Names rather than method names. It means that you can hit URL in the Browser by your Action Name rather than the method name given above on your Action Result method. The example is given below.

How do I get an action filter model?

In case your controller action has multiple arguments and in your filter you want to select the one that is bound via [FromBody] , then you can use reflection to do the following: public void OnActionExecuting(ActionExecutingContext context) { foreach (ControllerParameterDescriptor param in context. ActionDescriptor.

What is action result in ASP.NET Core MVC?

What is Action Method in ASP.NET Core MVC? Actions are the methods in controller class which are responsible for returning the view or Json data. Action will mainly have return type “ActionResult” and it will be invoked from method InvokeAction called by controller.


Video Answer


2 Answers

You can access the MethodInfo of the action through the ControllerActionDescriptor class:

public void OnActionExecuting(ActionExecutingContext context) {     if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)     {         var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);     } } 

The MVC 5 ActionDescriptor class used to implement the ICustomAttributeProvider interface which gave access to the attributes. For some reason this was removed in the ASP.NET Core MVC ActionDescriptor class.

like image 154
Henk Mollema Avatar answered Sep 20 '22 13:09

Henk Mollema


Invoking GetCustomAttributes on a method and/or class is slow(er). You should not invoke GetCustomAttributes every request since .net core 2.2, which @Henk Mollema is suggesting. (There is one exception which I will explain later)

Instead, on application startup time, the asp.net core framework will invoke GetCustomAttributes on the action method and controller for you and store the result in the EndPoint metadata.

You can then access this metadata in your asp.net core filters via the EndpointMetadata property of the ActionDescriptor class.

public class CustomFilter : IActionFilter {     public void OnActionExecuting(ActionExecutingContext context)     {         // Get attributes on the executing action method and it's defining controller class         var attributes = context.ActionDescriptor.EndpointMetadata.OfType<MyCustomAttribute>();     }      public void OnActionExecuted(ActionExecutedContext context)     {     } } 

If you do not have access to the ActionDescriptor (for example: because you are operating from a Middleware instead of an filter) from asp.net core 3.0 you can use the GetEndpoint extension method to access it's Metadata. For more info see this github issue.

public class CustomMiddleware {     private readonly RequestDelegate next;      public CustomMiddleware(RequestDelegate next)     {         this.next = next;     }      public async Task Invoke(HttpContext context)     {         // Get the enpoint which is executing (asp.net core 3.0 only)         var executingEnpoint = context.GetEndpoint();          // Get attributes on the executing action method and it's defining controller class         var attributes = executingEnpoint.Metadata.OfType<MyCustomAttribute>();          await next(context);          // Get the enpoint which was executed (asp.net core 2.2 possible after call to await next(context))         var executingEnpoint2 = context.GetEndpoint();          // Get attributes on the executing action method and it's defining controller class         var attributes2 = executingEnpoint.Metadata.OfType<MyCustomAttribute>();     } } 

Like stated above, Endpoint Metadata contains the attributes for the action method and its defining controller class. This means that if you would want to explicitly IGNORE the attributes applied on either the controller class or the action method, you have to use GetCustomAttributes. This is almost never the case in asp.net core.

like image 29
Joas Avatar answered Sep 21 '22 13:09

Joas