如何在 ASP.NET 核心 MVC 中读取操作方法的属性?
How to read action method's attributes in ASP.NET Core MVC?
基于 this article 我正在尝试为 ASP.NET 核心创建一个 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 中读取操作方法的属性?
您可以通过 ControllerActionDescriptor
class:
访问操作的 MethodInfo
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
}
}
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.
我根据 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>();
}
希望对您有所帮助。
我的自定义属性继承自 ActionFilterAttribute。我把它放在我的控制器上,但有一个动作不需要它。我想使用 AllowAnonymous
属性来忽略它,但它不起作用。所以我在我的自定义属性中添加了这个片段以找到 AllowAnonymous
并跳过它。你可以在for循环中获取other。
public class PermissionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
foreach (var filterDescriptors in context.ActionDescriptor.FilterDescriptors)
{
if (filterDescriptors.Filter.GetType() == typeof(AllowAnonymousFilter))
{
return;
}
}
}
}
的回答
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()
在方法 and/or class 上调用 GetCustomAttributes
是 slow(er)。自 .net core 2.2 以来,您应该 而不是 调用 GetCustomAttributes
每个请求,@Henk Mollema 建议这样做。 (有一个例外,我稍后会解释)
相反,在应用程序启动时,asp.net 核心框架将为您调用 GetCustomAttributes
操作方法和控制器,并将结果存储在 EndPoint
metadata.
然后您可以通过 EndpointMetadata
property of the 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 核心 3.0你可以使用GetEndpoint
extension method to access it's Metadata
。
有关详细信息,请参阅 this 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>();
}
}
如上所述,端点元数据包含操作方法及其定义控制器的属性 class。这意味着如果您想要显式地忽略应用在控制器 class 或操作方法上的属性,您必须使用 GetCustomAttributes
。在 asp.net core.
中几乎从来没有这种情况
基于 this article 我正在尝试为 ASP.NET 核心创建一个 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 中读取操作方法的属性?
您可以通过 ControllerActionDescriptor
class:
MethodInfo
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
}
}
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.
我根据 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>();
}
希望对您有所帮助。
我的自定义属性继承自 ActionFilterAttribute。我把它放在我的控制器上,但有一个动作不需要它。我想使用 AllowAnonymous
属性来忽略它,但它不起作用。所以我在我的自定义属性中添加了这个片段以找到 AllowAnonymous
并跳过它。你可以在for循环中获取other。
public class PermissionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
foreach (var filterDescriptors in context.ActionDescriptor.FilterDescriptors)
{
if (filterDescriptors.Filter.GetType() == typeof(AllowAnonymousFilter))
{
return;
}
}
}
}
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()
在方法 and/or class 上调用 GetCustomAttributes
是 slow(er)。自 .net core 2.2 以来,您应该 而不是 调用 GetCustomAttributes
每个请求,@Henk Mollema 建议这样做。 (有一个例外,我稍后会解释)
相反,在应用程序启动时,asp.net 核心框架将为您调用 GetCustomAttributes
操作方法和控制器,并将结果存储在 EndPoint
metadata.
然后您可以通过 EndpointMetadata
property of the 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 核心 3.0你可以使用GetEndpoint
extension method to access it's Metadata
。
有关详细信息,请参阅 this 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>();
}
}
如上所述,端点元数据包含操作方法及其定义控制器的属性 class。这意味着如果您想要显式地忽略应用在控制器 class 或操作方法上的属性,您必须使用 GetCustomAttributes
。在 asp.net core.