【问题标题】:Using Assembly.GetCallingAssembly() does not return the calling assembly使用 Assembly.GetCallingAssembly() 不会返回调用程序集
【发布时间】:2012-02-11 17:05:31
【问题描述】:

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

我在这里做错了什么?

【问题讨论】:

    标签: c# asp.net-mvc reflection


    【解决方案1】:

    我在这里做错了什么?

    什么都没有。您可能错过了 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;
        }
    }
    

    【讨论】:

      【解决方案2】:

      来自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 所属的程序集。

      【讨论】:

      • 不,它不会是辅助程序集。辅助程序集是当前正在执行的程序集。调用程序集将是调用此辅助方法的程序集。这恰好是执行 Razor 视图的程序集。
      • 亲爱的 Darin,在调试时,生成的程序集是帮助程序程序集,而不是您认为的动态视图程序集......
      • Darin,收回我的话,我从 GetControllerNames 执行了 GetCallingAssembly,程序集是:App_Web_5u2v2fi4, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null 正如你所说。我会听从你的指示。我还不得不说 M.Babcock 帮助我解决了这个问题,这要归功于我确实从助手中的另一个方法调用了该方法。所以谢谢你们!
      • 这个问题是内联是不可预测的,所以不能肯定地使用这种方法:S,确定吗?
      • 迟到了一个时代,说 GetCallingAssembly 很可能会在异步代码中返回垃圾,原因很明显,我不得不花几分钟才意识到。
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-24
        • 2023-04-06
        • 1970-01-01
        • 2017-07-16
        • 1970-01-01
        • 1970-01-01
        • 2021-04-24
        • 2016-05-26
        相关资源
        最近更新 更多