web-dev-qa-db-fra.com

Obtention de tous les noms de contrôleurs et d'actions en C #

Est-il possible de lister les noms de tous les contrôleurs et leurs actions par programme?

Je souhaite implémenter une sécurité basée sur la base de données pour chaque contrôleur et action. En tant que développeur, je connais tous les contrôleurs et toutes les actions et je peux les ajouter à une table de base de données, mais existe-t-il un moyen de les ajouter automatiquement?

55
sagheer

Vous pouvez utiliser la réflexion pour rechercher tous les contrôleurs de l'assembly actuel, puis trouver leurs méthodes publiques qui ne sont pas décorées avec l'attribut NonAction.

Assembly asm = Assembly.GetExecutingAssembly();

asm.GetTypes()
    .Where(type=> typeof(Controller).IsAssignableFrom(type)) //filter controllers
    .SelectMany(type => type.GetMethods())
    .Where(method => method.IsPublic && ! method.IsDefined(typeof(NonActionAttribute)));
71
dcastro

Les éléments suivants extrairont des contrôleurs, des actions, des attributs et des types de retour:

Assembly asm = Assembly.GetAssembly(typeof(MyWebDll.MvcApplication));

var controlleractionlist = asm.GetTypes()
        .Where(type=> typeof(System.Web.Mvc.Controller).IsAssignableFrom(type))
        .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
        .Where(m => !m.GetCustomAttributes(typeof( System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
        .Select(x => new {Controller = x.DeclaringType.Name, Action = x.Name, ReturnType = x.ReturnType.Name, Attributes = String.Join(",", x.GetCustomAttributes().Select(a => a.GetType().Name.Replace("Attribute",""))) })
        .OrderBy(x=>x.Controller).ThenBy(x => x.Action).ToList();

Si vous exécutez ce code dans linqpad par exemple et appelez

controlleractionlist.Dump();

vous obtenez la sortie suivante:

enter image description here

80
AVH

Je cherchais un moyen d’obtenir Zone, Contrôleur et Action et j’arrivais à modifier un peu les méthodes que vous publiez ici, donc si quelqu'un cherche un moyen de obtenir le AREA voici ma méthode laide (que je sauvegarde dans un xml):

 public static void GetMenuXml()
        {
       var projectName = Assembly.GetExecutingAssembly().FullName.Split(',')[0];

        Assembly asm = Assembly.GetAssembly(typeof(MvcApplication));

        var model = asm.GetTypes().
            SelectMany(t => t.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
            .Where(d => d.ReturnType.Name == "ActionResult").Select(n => new MyMenuModel()
            {
                Controller = n.DeclaringType?.Name.Replace("Controller", ""),
                Action = n.Name,
                ReturnType = n.ReturnType.Name,
                Attributes = string.Join(",", n.GetCustomAttributes().Select(a => a.GetType().Name.Replace("Attribute", ""))),
                Area = n.DeclaringType.Namespace.ToString().Replace(projectName + ".", "").Replace("Areas.", "").Replace(".Controllers", "").Replace("Controllers", "")
            });

        SaveData(model.ToList());
    }

Edit:

//assuming that the namespace is ProjectName.Areas.Admin.Controllers

 Area=n.DeclaringType.Namespace.Split('.').Reverse().Skip(1).First()
8
Lucian Bumb
Assembly assembly = Assembly.LoadFrom(sAssemblyFileName)
IEnumerable<Type> types = Assembly.GetTypes().Where(type => typeof(Controller).IsAssignableFrom(type)).OrderBy(x => x.Name);
foreach (Type cls in types)
{
      list.Add(cls.Name.Replace("Controller", ""));
      IEnumerable<MemberInfo> memberInfo = cls.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any()).OrderBy(x => x.Name);
      foreach (MemberInfo method in memberInfo)
      {
           if (method.ReflectedType.IsPublic && !method.IsDefined(typeof(NonActionAttribute)))
           {
                  list.Add("\t" + method.Name.ToString());
           }
      }
}
3
Gyan
var result = Assembly.GetExecutingAssembly()
            .GetTypes()
            .Where(type => typeof(ApiController).IsAssignableFrom(type))
            .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
            .Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
            .GroupBy(x => x.DeclaringType.Name)
            .Select(x => new { Controller = x.Key, Actions = x.Select(s => s.Name).ToList() })
            .ToList();
2
FazelMan

Utilisez Reflection , énumérez tous les types dans les classes Assembly et filter héritées de System.Web.MVC.Controller, que la liste des méthodes publiques de ce type sous forme d'actions

1
Arsen Mkrtchyan

@decastro répond que c'est bien. J'ajoute ce filtre pour ne renvoyer que les actions publiques déclarées par le développeur.

        var asm = Assembly.GetExecutingAssembly();
        var methods = asm.GetTypes()
            .Where(type => typeof(Controller)
                .IsAssignableFrom(type))
            .SelectMany(type => type.GetMethods())
            .Where(method => method.IsPublic 
                && !method.IsDefined(typeof(NonActionAttribute))
                && (
                    method.ReturnType==typeof(ActionResult) ||
                    method.ReturnType == typeof(Task<ActionResult>) ||
                    method.ReturnType == typeof(String) ||
                    //method.ReturnType == typeof(IHttpResult) ||
                    )
                )
            .Select(m=>m.Name);
1
Bellash

Ou, pour minimiser l’idée de @dcastro et obtenir les contrôleurs:

Assembly.GetExecutingAssembly()
.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
0
Don Rolling