使用Assembly.GetCallingAssembly()不返回调用程序集

时间:2012-02-11 17:05:32

标签: c# asp.net-mvc reflection

在我的ASP.NET MVC应用程序中,我正在使用一个小助手来遍历所有控制器。 这个帮助器位于与我的MVC应用程序不同的程序集中,我正在引用它。

问题是,当在helper中调用Assembly.GetCallingAssembly()方法时,它不会返回MVC app程序集,而是返回帮助程序集。 这不是我期望得到的,因为我的所有控制器都存在于MVC app程序集中,我需要反映它。

视图代码(MVC app assembly):

<nav>
   <ul id="menu">
      @foreach(var item in new MvcHelper().GetControllerNames())
      {
         @Html.ActionMenuItem(
              (string)HttpContext.GetGlobalResourceObject("StringsResourse", item), "Index",
              item)
      }
   </ul>
</nav>

帮助程序代码(独立程序集):

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

我在这里做错了什么?

3 个答案:

答案 0 :(得分:15)

  

我在这里做错了什么?

无。您可能错过了Razor视图由ASP.NET运行时编译为单独的程序集的事实。那些集会是动态的。它们与ASP.NET MVC应用程序程序集无关。由于您在视图中调用帮助器,Assembly.GetCallingAssembly()方法将返回如下内容:

App_Web_fqxdopd5, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

如果您想获取所有控制器,为什么不只是遍历所有引用的程序集并查找从Controller派生的类型?您可以使用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;
    }
}

答案 1 :(得分:1)

来自GetCallingAssembly MSDN docs

  

返回调用当前正在执行的方法的方法的程序集。

在您的情况下,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所属的程序集。

答案 2 :(得分:0)

我相信GetCallingAssembly正在运行 - 调用GetSubClasses的方法在你的MvcHelper模块(和程序集)中,而不是MVC应用程序本身。如果您直接在Assembly.GetCallingAssembly内调用GetControllerNames,则可能会发现您获得了不同的结果。

另请注意,GetCallingAssembly的行为可能会有所不同,具体取决于方法是否内联 - 请参阅http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getcallingassembly.aspx