ASP.NET MVC: Obtenez tous les contrôleurs
-
18-09-2019 - |
Question
Est-il possible d'obtenir tous les contrôleurs disponibles à un ControllerFactory
Ce que je veux faire est d'obtenir une liste de tous les types de contrôleur dans l'application, mais d'une manière cohérente.
Alors que tous les contrôleurs que je reçois sont les mêmes que ceux de la résolution demande par défaut utilise.
(La tâche réelle est de trouver toutes les méthodes d'action qui ont un attribut donné).
La solution
Vous pouvez utiliser la réflexion pour énumérer toutes les classes dans un ensemble, et filtrer uniquement les classes héritent de la classe Controller.
La meilleure référence est asp.net code source mvc. Jetez un oeil des implémentations de ControllerTypeCache et ActionMethodSelector classe . ControllerTypeCache montre comment obtenir toutes les classes de contrôleur disponibles.
internal static bool IsControllerType(Type t) {
return
t != null &&
t.IsPublic &&
t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
!t.IsAbstract &&
typeof(IController).IsAssignableFrom(t);
}
public void EnsureInitialized(IBuildManager buildManager) {
if (_cache == null) {
lock (_lockObj) {
if (_cache == null) {
List<Type> controllerTypes = GetAllControllerTypes(buildManager);
var groupedByName = controllerTypes.GroupBy(
t => t.Name.Substring(0, t.Name.Length - "Controller".Length),
StringComparer.OrdinalIgnoreCase);
_cache = groupedByName.ToDictionary(
g => g.Key,
g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
}
}
}
}
Et ActionMethodSelector montre comment vérifier si une méthode a attribut souhaité.
private static List<MethodInfo> RunSelectionFilters(ControllerContext controllerContext, List<MethodInfo> methodInfos) {
// remove all methods which are opting out of this request
// to opt out, at least one attribute defined on the method must return false
List<MethodInfo> matchesWithSelectionAttributes = new List<MethodInfo>();
List<MethodInfo> matchesWithoutSelectionAttributes = new List<MethodInfo>();
foreach (MethodInfo methodInfo in methodInfos) {
ActionMethodSelectorAttribute[] attrs = (ActionMethodSelectorAttribute[])methodInfo.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), true /* inherit */);
if (attrs.Length == 0) {
matchesWithoutSelectionAttributes.Add(methodInfo);
}
else if (attrs.All(attr => attr.IsValidForRequest(controllerContext, methodInfo))) {
matchesWithSelectionAttributes.Add(methodInfo);
}
}
// if a matching action method had a selection attribute, consider it more specific than a matching action method
// without a selection attribute
return (matchesWithSelectionAttributes.Count > 0) ? matchesWithSelectionAttributes : matchesWithoutSelectionAttributes;
}
Autres conseils
Je ne pense pas qu'il soit possible de donner une réponse simple à cette question, parce que cela dépend de beaucoup de choses différentes, y compris la mise en œuvre de IControllerFactory.
Par exemple, si vous avez une implémentation IControllerFactory complètement sur mesure, tous les paris sont ouverts, car il peut utiliser une sorte de mécanisme pour créer des instances de contrôleur.
Cependant, le DefaultControllerFactory regarde après le type de contrôleur approprié dans tous les ensembles définis dans le RouteCollection (configuré dans Global.asax).
Dans ce cas, vous en boucle pourrait par tous les ensembles associés à la RouteCollection et rechercher les contrôleurs dans chaque.
Trouver des contrôleurs dans un assemblage donné est relativement facile:
var controllerTypes = from t in asm.GetExportedTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
où asm
est une instance de l'Assemblée.