Как прочитать атрибуты метода действия в ASP.NET Core MVC?
На основании этой статьи я пытаюсь создать IActionFilter
реализация для ASP.NET Core, которая может обрабатывать атрибуты, отмеченные на контроллере, и действия контроллера. Хотя чтение атрибутов контроллера легко, я не могу найти способ прочитать атрибуты, определенные в методе действия.
Вот код, который я сейчас имею:
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?
3 ответа
Вы можете получить доступ к MethodInfo
действия через ControllerActionDescriptor
учебный класс:
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
учебный класс.
Вызов GetCustomAttributes
в методе и / или классе работает медленно(эр). Вы не должны вызыватьGetCustomAttributes
каждый запрос, начиная с ядра.net 2.2, который предлагает @Henk Mollema. (Есть одно исключение, которое я объясню позже)
Вместо этого во время запуска приложения основная структура asp.net будет вызывать GetCustomAttributes
для метода действия и контроллера и сохраните результат в EndPoint
метаданные.
Затем вы можете получить доступ к этим метаданным в основных фильтрах asp.net через EndpointMetadata
Свойство из ActionDescriptor
класс.
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 вы можете использовать GetEndpoint
метод расширения для доступа к нему 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 этого почти никогда не бывает.
Мой пользовательский атрибут унаследован от 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;
}
}
}
}
Я создал метод расширения, который имитирует оригинал 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>();
}
Надеюсь, поможет.
Как ответил Henk Mollema
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()