基于this article我试图为ASP.NET Core创建一个IActionFilter
实现,它可以处理控制器上标记的属性和控制器的操作。虽然读取控制器的属性很容易,但我无法找到一种方法来读取操作方法中定义的属性。
这是我现在的代码:
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();
}
}
我的问题是:如何阅读ASP.NET Core MVC中的操作方法属性?
答案 0 :(得分:55)
您可以通过ControllerActionDescriptor
课程
MethodInfo
public void OnActionExecuting(ActionExecutingContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
}
}
MVC 5 ActionDescriptor
类用于实现允许访问属性的ICustomAttributeProvider
接口。出于某种原因,这已在ASP.NET Core MVC ActionDescriptor
类中删除。
答案 1 :(得分:11)
在方法和/或类上调用GetCustomAttributes
的操作慢。自.net core 2.2(@Henk Mollema建议)以来,您不应不调用每个GetCustomAttributes
请求。 (有一个例外情况,我将在后面解释)
相反,在应用程序启动时,asp.net核心框架将为您在操作方法和控制器上调用GetCustomAttributes
并将结果存储在EndPoint
metadata中。
然后您可以通过EndpointMetadata
property中的ActionDescriptor
class在asp.net核心过滤器中访问此元数据。
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)
{
}
}
如果您无权访问ActionDescriptor
(例如:因为您是通过中间件而不是过滤器操作的),则来自asp.net core 3.0 ,您可以使用{ {3}}来访问它的GetEndpoint
extension method。
有关更多信息,请参见Metadata
github问题。
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>();
}
}
类似于上面所述,端点元数据包含操作方法及其定义的控制器类的属性。这意味着,如果您想显式忽略应用于控制器类或操作方法的属性,则必须使用GetCustomAttributes
。在asp.net核心中几乎从来没有这种情况。
答案 2 :(得分:6)
我根据Henk Mollema的解决方案创建了一个模仿原始GetCustomAttributes
的扩展方法。
public static IEnumerable<T> GetCustomAttributes<T>(this Microsoft.AspNet.Mvc.Abstractions.ActionDescriptor actionDescriptor) where T : Attribute
{
var controllerActionDescriptor = actionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
return controllerActionDescriptor.MethodInfo.GetCustomAttributes<T>();
}
return Enumerable.Empty<T>();
}
希望它有所帮助。
答案 3 :(得分:5)
我的自定义属性是从ActionFilterAttribute继承的。我把它放在我的控制器上,但有一个动作不需要它。我想使用AllowAnonymous
属性忽略它,但它不起作用。因此,我在自定义属性中添加此代码段以查找AllowAnonymous
并跳过它。你可以在for循环中获得其他内容。
public class PermissionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
foreach (var filterDescriptors in context.ActionDescriptor.FilterDescriptors)
{
if (filterDescriptors.Filter.GetType() == typeof(AllowAnonymousFilter))
{
return;
}
}
}
}
答案 4 :(得分:0)
由Henk Mollena回答
public void OnActionExecuting(ActionExecutingContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var controllerAttributes = controllerActionDescriptor
.MethodInfo
.GetCustomAttributes(inherit: true);
}
}
是正确的方法。
如果您想检查是否存在应用于控制器的属性
,我只是想添加到他的答案中public void OnActionExecuting(ActionExecutingContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var actionAttributes = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(inherit: true);
}
}
您还可以使用GetCustomAttributes函数的重载函数来获取您的特定属性
var specificAttribute = GetCustomAttributes(typeof(YourSpecificAttribute), true).FirstOrDefault()