在我的ASP.NET MVC应用程序中,我使用一个小助手来遍历所有控制器。这个助手位于与我的MVC应用程序不同的程序集,我正在引用它
问题是,在助手中调用Assembly.GetCallingAssembly()方法时,它不会返回MVC应用程序集,而是返回助手程序集。这不是我所期望的,因为我所有的控制器都生活在MVC应用程序集中,我需要反映它
视图代码(MVC应用程序集):
<nav>
<ul id="menu">
@foreach(var item in new MvcHelper().GetControllerNames())
{
@Html.ActionMenuItem(
(string)HttpContext.GetGlobalResourceObject("StringsResourse", item), "Index",
item)
}
</ul>
</nav>
Helper代码(独立程序集):
public class MvcHelper
{
public List<string> GetControllerNames()
{
var controllerNames = new List<string>();
GetSubClasses<Controller>().ForEach(
type => controllerNames.Add(type.Name));
return controllerNames;
}
private static List<Type> GetSubClasses<T>()
{
return Assembly.GetCallingAssembly().GetTypes().Where(
type => type.IsSubclassOf(typeof(T))).ToList();
}
}
我在这里做错了什么?
我在这里做错了什么?
什么都没有。您可能忽略了Razor视图由ASP.NET运行时编译为单独的程序集这一事实。这些程序集是动态的。它们与ASP.NET MVC应用程序集无关。由于您正在调用视图中的助手,Assembly.GetCallingAssembly()
方法将返回如下内容:
App_Web_fqxdopd5, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
如果您想获得所有控制器,为什么不遍历所有引用的程序集并查找从控制器派生的类型?对此,可以使用AppDomain.CurrentDomain.GetAssemblies()
方法。然后,对于每个组件,仅GetTypes()
和过滤:
public class MvcHelper
{
private static List<Type> GetSubClasses<T>()
{
return AppDomain
.CurrentDomain
.GetAssemblies()
.SelectMany(
a => a.GetTypes().Where(type => type.IsSubclassOf(typeof(T)))
).ToList();
}
public List<string> GetControllerNames()
{
var controllerNames = new List<string>();
GetSubClasses<Controller>().ForEach(
type => controllerNames.Add(type.Name));
return controllerNames;
}
}
来自GetCallingAssembly
MSDN文档:
返回调用当前正在执行的方法的方法的程序集。
在您的情况下,GetSubClasses
由同一对象中的GetControllerNames
调用,因此它应该返回辅助程序集。
编辑:
来自MSDN文档上的备注:
如果调用GetCallingAssembly方法的方法已展开由实时(JIT)编译器内联,或者如果其调用程序是展开内联,GetCallingAssembly返回的程序集可能会出乎意料地有所不同。例如,考虑以下方法和组件:
程序集A1中的方法M1调用GetCallingAssembly。
程序集A2中的方法M2调用M1。
程序集A3中的方法M3调用M2。
当M1没有内联时,GetCallingAssembly返回A2。当M1为内联,GetCallingAssembly返回A3。类似地,当M2不是内联,GetCallingAssembly返回A2。当M2被内联时,GetCallingAssembly返回A3。
因此,假设GetSubClasses
没有内联,它应该返回GetControllerNames
所属的Assembly。
我相信GetCallingAssembly
正在工作——调用GetSubClasses
的方法在MvcHelper模块(和程序集)中,而不是MVC应用程序本身。如果您直接在GetControllerNames
中调用Assembly.GetCallingAssembly
,您可能会发现得到不同的结果。
还要注意,GetCallingAssembly
的行为可能会因方法是否内联而有所不同——请参阅http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getcallingassembly.aspx