2014-02-05 158 views
45

是否可以通過編程方式列出所有控制器的名稱及其操作?獲取C#中的所有控制器和操作名稱

我想爲每個控制器和操作實現數據庫驅動的安全性。作爲一名開發人員,我知道所有的控制器和操作,並且可以將它們添加到數據庫表中,但有什麼方法可以自動添加它們嗎?

+1

相關:http://stackoverflow.com/questions/11300327/how-can-i-get-the-list-of-all-actions-of-mvc-controller-by-傳遞 - controllernam – Nathan

回答

60

您可以使用反射來查找當前裝配的所有控制器,然後找到自己沒有用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))); 
+0

是否爲動作方法的動作強制屬性? –

+0

@ArsenMkrt好點,我認爲方法必須標記爲'Action'屬性。事實證明,除非使用'NonAction'屬性進行修飾,否則所有公共方法都是動作。我已經更新了我的答案。 – dcastro

+0

我們可以進一步瞭解,所有方法都有返回類型ActionResult的公共方法或從它繼承的 –

1

使用Reflection,枚舉所有類型從System.Web.MVC.Controller繼承了組件和過濾器類中,比榜單類型的公共方法作爲行動

-1

或者,以削減掉在@dcastro的想法和剛剛得到的控制器:

Assembly.GetExecutingAssembly().GetTypes().Where(type => typeof(Controller).IsAssignableFrom(type)) 
56

下面將提取控制器,動作,屬性和返回類型:

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(); 

如果您在linqpad中運行此代碼,請致電

controlleractionlist.Dump(); 

將得到以下的輸出:

enter image description here

+1

與這個答案,我可以立即得到結果接受的一個很難使用! – hakuna1811

+0

這是什麼:'MyWebDll.MvcApplication'是模型類? –

+0

如果存在區域值,是否有辦法獲取區域值? –

1
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()); 
      } 
     } 
} 
6

我一直在尋找一種方式來獲得區,控制器和行動,對此我設法改變一個小方法,你張貼在這裏,所以如果任何人都在尋找一種方式來得到AREA這裏是我的醜方法(我保存到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()); 
    } 

編輯:

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

Area=n.DeclaringType.Namespace.Split('.').Reverse().Skip(1).First() 
+1

我組合了你的代碼和這個字符串擴展名:http://stackoverflow.com/a/17253735/453142來獲取該區域。所以你可以得到這樣的區域:Area = n.DeclaringType.Namespace.ToString()。Substring(「Areas。」,「.Controllers」) 你需要更新擴展以返回string.empty而不是例外,它是。這是一個不太醜陋的=) –

相關問題