2012-02-11 1 views
4

В моем приложении ASP.NET MVC я использую небольшой помощник для итерации через все контроллеры. Этот помощник расположен на другой сборке, чем мое приложение MVC, и я ссылаюсь на него.Использование Assembly.GetCallingAssembly() не возвращает вызывающую сборку

Проблема заключается в том, что при вызове метода Assembly.GetCallingAssembly() в помощнике он не возвращает сборку приложения MVC, но вместо этого возвращает вспомогательную сборку, и это не то, что я ожидаю получить, потому что все мои контроллеры живут в сборке приложений MVC, и мне нужно их отразить.

Мой код:

**The view code(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> 

**The Helper code(independent assembly):** 

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

Что я здесь делаю неправильно?

ответ

14

Что я здесь делаю неправильно?

Ничего. Вероятно, вам не хватает того, что представления 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; 
    } 
} 
+0

+1 за предложение хорошей альтернативы. –

0

От GetCallingAssembly MSDN docs:

Возвращает ассамблею метода, который вызывается метод исполняемую в данный момент.

В вашем случае, GetSubClasses вызывается GetControllerNames в том же самом объекте, так что он должен возвращаться на вспомогательный узел.

Edit:

Из выступления на документы MSDN:

Если метод, который вызывает метод GetCallingAssembly расширяется встроенный в точно в срок (JIT) компилятор, или если его вызывающим абонентом является расширенный встроенный, сборка, возвращаемая GetCallingAssembly может неожиданно отличаться. Например, рассмотрим следующие методы: и узлы:

Метод M1 в сборке A1 вызывает GetCallingAssembly.

Способ M2 в сборке A2 вызывает M1.

Способ M3 в сборке A3 вызывает M2.

Когда M1 не встроен, GetCallingAssembly возвращает A2. Когда M1 имеет значение , GetCallingAssembly возвращает A3. Точно так же, когда M2 не является inlined, GetCallingAssembly возвращает A2. Когда M2 встроен, GetCallingAssembly возвращает A3.

Так если предположить, что GetSubClasses не встраивается, он должен возвращаться Ассамблеей, которая GetControllerNames принадлежит.

+0

Нет, это не будет помощником в сборе. Вспомогательная сборка является текущей исполняющей сборкой. Вызывающая сборка будет той, которая вызвала этот вспомогательный метод. Который является сборкой, выполняющей представление Razor. –

+0

@DarinDimitrov - Итак, документы MSDN ошибочны? –

+0

Уважаемый Дарин, при отладке результирующая сборка была вспомогательной сборкой, а не сборкой динамического представления, как вы думаете ... –

0

Я считаю, что GetCallingAssembly работает - метод, который вызывает GetSubClasses находится в пределах модуля MvcHelper (и сборки), а не само приложение MVC. Если вы вызываете Assembly.GetCallingAssembly непосредственно в пределах GetControllerNames, вы можете найти другой результат.

отметить также, что поведение GetCallingAssembly может варьироваться в зависимости от того, встраиваемой, или нет методов - см http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getcallingassembly.aspx

Смежные вопросы