Op basis van dit artikelprobeer ik om een IActionFilter
-implementatie voor ASP.NET Core te maken die attributen kan verwerken die zijn gemarkeerd op de controller en de actie van de controller. Hoewel het gemakkelijk is om de attributen van de controller te lezen, kan ik geen manier vinden om de attributen te lezen die zijn gedefinieerd in de actiemethode.
Dit is de code die ik nu heb:
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();
}
}
Mijn vraag is: hoe lees ik de attributen van de actiemethode in ASP.NET Core MVC?
Antwoord 1, autoriteit 100%
Je hebt toegang tot de MethodInfo
van de actie via de ControllerActionDescriptor
klasse:
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
}
}
De MVC 5 ActionDescriptor
klasse gebruikt om de ICustomAttributeProvider
interface te implementeren die toegang gaf tot de attributen. Om de een of andere reden is dit verwijderd in de ASP.NET Core MVC ActionDescriptor
klasse.
Antwoord 2, autoriteit 32%
Het aanroepen van GetCustomAttributes
op een methode en/of klasse is traag(er). Je moet nietelk verzoek GetCustomAttributes
aanroepen sinds .net core 2.2, wat @Henk Mollema suggereert. (Er is één uitzondering die ik later zal uitleggen)
In plaats daarvan zal het asp.net core-framework tijdens het opstarten van de applicatie GetCustomAttributes
aanroepen voor de actiemethode en controller voor u en het resultaat opslaan in de EndPoint
metagegevens.
Je hebt dan toegang tot deze metadata in je asp.net-kernfilters via de EndpointMetadata
-eigenschapvan de ActionDescriptor
klasse.
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)
{
}
}
Als u geen toegang heeft tot de ActionDescriptor
(bijvoorbeeld: omdat u werkt vanuit een middleware in plaats van een filter) van asp.net core 3.0kunt u gebruik de GetEndpoint
-extensiemethodeom toegang te krijgen tot zijn Metadata
.
Zie ditgithub-probleem voor meer informatie.
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>();
}
}
Zoals hierboven vermeld, bevatten Endpoint Metadata de attributen voor de actiemethode en de bepalende controllerklasse. Dit betekent dat als je expliciet de attributen wilt NEGEREN die zijn toegepast op de controllerklasse of de actiemethode, je GetCustomAttributes
moet gebruiken. Dit is bijna nooit het geval in asp.net core.
Antwoord 3, autoriteit 9%
Mijn aangepaste kenmerk is overgenomen van ActionFilterAttribute. Ik heb het op mijn controller gezet, maar er is een actie die het niet nodig heeft. Ik wil het kenmerk AllowAnonymous
gebruiken om dat te negeren, maar het werkt niet. Dus ik voeg dit fragment toe aan mijn aangepaste kenmerk om de AllowAnonymous
te vinden en sla het over. Je kunt anderen in de for-lus krijgen.
public class PermissionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
foreach (var filterDescriptors in context.ActionDescriptor.FilterDescriptors)
{
if (filterDescriptors.Filter.GetType() == typeof(AllowAnonymousFilter))
{
return;
}
}
}
}
Antwoord 4, autoriteit 8%
Ik heb een extensiemethode gemaakt die de originele GetCustomAttributes
nabootst op basis van de oplossing van Henk Mollema.
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>();
}
Hopelijk helpt het.
Antwoord 5
Als beantwoord door Henk Mollena
public void OnActionExecuting(ActionExecutingContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var controllerAttributes = controllerActionDescriptor
.MethodInfo
.GetCustomAttributes(inherit: true);
}
}
is de juiste manier als u de aanwezigheid wilt controleren van een kenmerk toegepast op een actie.
Ik wil alleen iets toevoegen aan zijn antwoord voor het geval je de aanwezigheid wilt controleren van een attribuut toegepast op de controller
public void OnActionExecuting(ActionExecutingContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var actionAttributes = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(inherit: true);
}
}
U kunt ook de overbelaste functie van de GetCustomAttributes-functies gebruiken om uw specifieke kenmerk(en) te krijgen
var specificAttribute = GetCustomAttributes(typeof(YourSpecificAttribute), true).FirstOrDefault()