C# Получение имени родительской сборки вызывающей сборки

У меня есть модульное тестовое приложение С#, над которым я работаю. Здесь задействованы три сборки: сборка самого приложения C#, вторая сборка, используемая приложением, и третья сборка, используемая второй.

Итак, звонки идут так:

First Assembly ------> Second Assembly---------> Third Assembly.

Что мне нужно сделать в третьей сборке, так это получить имя сборки Fist, которая вызвала вторую сборку.

Assembly.GetExecutingAssembly().ManifestModule.Name
Assembly.GetCallingAssembly().ManifestModule.Name

возвращает имя второй сборки. а также

Assembly.GetEntryAssembly().ManifestModule.Name

вернуть NULL

Кто-нибудь знает, есть ли способ получить имя сборки первой сборки?

По требованию других пользователей здесь я помещаю код. Это не 100% код, но следуйте такому коду.

namespace FirstAssembly{
public static xcass A
{
        public static Stream OpenResource(string name)
        {
            return Reader.OpenResource(Assembly.GetCallingAssembly(), ".Resources." + name);
        }
}
}

using FirstAssembly;
namespace SecondAssembly{
public static class B 

{
public static Stream FileNameFromType(string Name)

{
return = A.OpenResource(string name);
}
}
}

и метод тестового проекта

using SecondAssembly;
namespace ThirdAssembly{
public class TestC
{

 [TestMethod()]
        public void StremSizTest()
        {
            // ARRANGE
            var Stream = B.FileNameFromType("ValidMetaData.xml");
            // ASSERT
            Assert.IsNotNull(Stream , "The Stream  object should not be null.");
        }
}
}

person Saroop Trivedi    schedule 13.06.2012    source источник
comment
Были ли какие-либо из этих ответов полезными?   -  person Chris Gessler    schedule 14.06.2012
comment
@ChrisGessler: Ни один из ответов не полезен, потому что все предлагают использовать Assembly.GetEntryAssembly(), и здесь он возвращает NULL.   -  person Saroop Trivedi    schedule 15.06.2012
comment
Все, кроме моего, в котором используется StackFrames.   -  person Chris Gessler    schedule 15.06.2012
comment
@ChrisGessler: я еще не пробовал ваш код.   -  person Saroop Trivedi    schedule 20.06.2012
comment
Вам нужно предоставить больше информации, возможно, код, который загружает вторую сборку, чтобы люди могли воспроизвести ваше поведение. GetEntryAssembly должен работать, если исходный процесс не является неуправляемым. Возможно, вы загружаете вторую сборку как COM-объект?   -  person Panagiotis Kanavos    schedule 21.06.2012
comment
@PanagiotisKanavos: Хорошо, я обновлю здесь.   -  person Saroop Trivedi    schedule 21.06.2012
comment
Код, который вы разместили, на самом деле не показывает, что нам нужно. Я проверил и подтвердил, что GetEntryAssembly действительно возвращает правильную сборку в ситуации, которую вы описываете. Похоже, у вас должен быть где-то задействован собственный код, и сборка B вызывается из этого собственного кода.   -  person Tim Copenhaver    schedule 22.06.2012


Ответы (9)


Я думаю, вы должны быть в состоянии сделать это следующим образом:

using System.Diagnostics;
using System.Linq;

...

StackFrame[] frames = new StackTrace().GetFrames();
string initialAssembly = (from f in frames 
                          select f.GetMethod().ReflectedType.AssemblyQualifiedName
                         ).Distinct().Last();

Это даст вам сборку, содержащую первый метод, который был запущен первым в текущем потоке. Поэтому, если вы не в основном потоке, это может отличаться от EntryAssembly, если я правильно понимаю вашу ситуацию, это должна быть сборка, которую вы ищете.

Вы также можете получить фактическую сборку вместо имени следующим образом:

Assembly initialAssembly = (from f in frames 
                          select f.GetMethod().ReflectedType.Assembly
                         ).Distinct().Last();

Редактировать - по состоянию на 23 сентября 2015 г.

Пожалуйста, обратите внимание, что

GetMethod().ReflectedType

может быть нулевым, поэтому получение его AssemblyQualifiedName может вызвать исключение. Например, это интересно, если кто-то хочет проверить ванильный c.tor, предназначенный только для класса POCO ORM (например, linq2db и т. д.).

person AVee    schedule 21.06.2012
comment
Это отличный ответ! Действительно помог мне получить то, что мне нужно - person Piotr Kula; 15.10.2015
comment
Зачем вам .Distinct(), если вы следуете .Last()? - person Dorus; 16.04.2018
comment
@Dorus, потому что в противном случае вы могли бы (будете?) получить неправильный результат, например. У меня mscorlib без .Distinct(). - person Jack Miller; 02.11.2018
comment
@JackMiller Мне это кажется очень странным, на самом деле, как если бы последний кадр был mscorlib, а ваш стек - что-то вроде aba, где второй a отфильтровывается с помощью отдельного, а last затем берет b. - person Dorus; 12.11.2018
comment
Я полностью согласен с тобой. Это очень странно. С другой стороны, я не пытался выяснить, как на самом деле работает .Distinct(). - person Jack Miller; 12.11.2018
comment
Хорошо работал с синхронными вызовами. С асинхронным кодом стек, видимый в GetFrames(), не совпадает с местом возобновления асинхронного выполнения, поэтому я не вижу, кто на самом деле звонил. Отладчик VS может сказать, откуда возобновилось асинхронное выполнение, поэтому есть способ выяснить, кто начал асинхронное выполнение. Кто-нибудь знает, как настроить решение для работы с асинхронными абонентами? - person David Burg; 06.05.2021

Это вернет исходную сборку, которая ссылается на вашу текущую сборку.

var currentAssembly = Assembly.GetExecutingAssembly();
var callerAssemblies = new StackTrace().GetFrames()
            .Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
            .Where(x => x.GetReferencedAssemblies().Any(y => y.FullName == currentAssembly.FullName));
var initialAssembly = callerAssemblies.Last();
person realstrategos    schedule 28.01.2014

Это сработало для меня, используя это:

System.Reflection.Assembly.GetEntryAssembly().GetName()
person Marcello    schedule 19.12.2016

Assembly.GetEntryAssembly() имеет значение null, если вы также запускаете тесты из nunit-console.

Если вам просто нужно имя исполняемого приложения, используйте:

 System.Diagnostics.Process.GetCurrentProcess().ProcessName 

or

 Environment.GetCommandLineArgs()[0];

Для nunit-console вы получите «nunit-console» и «C:\Program Files\NUnit 2.5.10\bin\net-2.0\nunit-console.exe» соответственно.

person tymtam    schedule 22.06.2012

Пытаться:

Assembly.GetEntryAssembly().ManifestModule.Name

Это должна быть сборка, которая фактически была выполнена для запуска вашего процесса.

person Jon Egerton    schedule 13.06.2012

Не совсем уверен, что вы ищете, тем более что при запуске в контексте модульного теста вы получите:

mscorlib.dll
Microsoft.VisualStudio.TestPlatform.Extensions.VSTestIntegration.dll

(или что-то подобное, в зависимости от вашего исполнителя тестов) в наборе сборок, которые приводят к вызову любого метода.

Приведенный ниже код выводит имена каждой из сборок, участвующих в вызове.

var trace = new StackTrace();
var assemblies = new List<Assembly>();
var frames = trace.GetFrames();

if(frames == null)
{
    throw new Exception("Couldn't get the stack trace");
}

foreach(var frame in frames)
{
    var method = frame.GetMethod();
    var declaringType = method.DeclaringType;

    if(declaringType == null)
    {
        continue;
    }

    var assembly = declaringType.Assembly;
    var lastAssembly = assemblies.LastOrDefault();

    if(assembly != lastAssembly)
    {
        assemblies.Add(assembly);
    }
}

foreach(var assembly in assemblies)
{
    Debug.WriteLine(assembly.ManifestModule.Name);
}
person mlorbetske    schedule 21.06.2012
comment
Я знаю все правила модульного тестирования. Теперь я хочу сказать, что я не хочу читать всю сборку. Просто мне нужна ссылка на C. Это усложняет мой код. - person Saroop Trivedi; 21.06.2012

Если вы знаете номер кадра в стеке, вы можете использовать объект StackFrame и пропустить номер предыдущего кадра.

// You skip 2 frames
System.Diagnostics.StackFrame stack = new System.Diagnostics.StackFrame(2, false);
string assemblyName = stack.GetMethod().DeclaringType.AssemblyQualifiedName;

Но, если вы хотите получить первый вызов, вам нужно получить все кадры и взять первый. (см. решение AVee)

person Hyralex    schedule 22.06.2012

Как насчет Assembly.GetEntryAssembly()? Он возвращает основной исполняемый файл процесса.

Process.GetCurrentProcess().MainModule.ModuleName также должен возвращать примерно то же самое, что и имя ManifestModule ("yourapp.exe").

person Botz3000    schedule 13.06.2012
comment
Ах, имя модуля манифеста возвращает null, как насчет: Assembly.GetEntryAssembly().FullName (или GetName() в зависимости от ваших потребностей) - person Me.Name; 13.06.2012
comment
@sarooptrivedi Я добавил еще один вариант. - person Botz3000; 13.06.2012
comment
@Botz3000: я использовал этот вызов сборки в проекте unittest. - person Saroop Trivedi; 13.06.2012
comment
@sarooptrivedi Какой модульный тест? Если сборки загружены собственным кодом (не знаете, как настроена ваша среда модульного тестирования), GetEntryAssembly() вернет значение null. Вы уже пробовали второй вариант? - person Botz3000; 13.06.2012
comment
@Botz3000: у меня есть несколько файлов ресурсов в тестовом проекте. Я не хочу развертывать все файлы через DeploymentItem. Поэтому я создаю один проект, в котором я использую все файлы в своем модульном тесте с помощью создания одного тестового вспомогательного проекта B. Но проект, вызывающий сборку, находится в каком-то другом вспомогательном проекте C , Итак, когда я получаю ссылку на сборку проекта модульного тестирования в Project C, то для GetEntryAssembly() он возвращает NULL. - person Saroop Trivedi; 15.06.2012
comment
@sarooptrivedi Если вы используете MStest, вы можете добавить элементы, которые должны быть развернуты для всех тестов, в файл настроек теста. - person habakuk; 26.06.2012

Это работает для получения исходной сборки при использовании двух сборок в тесте NUnit без возврата NULL. Надеюсь это поможет.

var currentAssembly = Assembly.GetExecutingAssembly();
var callerAssemblies = new StackTrace().GetFrames()
        .Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
        .Where(x => x.GetReferencedAssemblies().Any(y => y.FullName ==     currentAssembly.FullName));
var initialAssembly = callerAssemblies.Last();
person user4793658    schedule 15.04.2015
comment
Публикация ответов только для кода не одобряется, поскольку это ничего не помогает ОП понять их проблему или ваше решение. - person leigero; 15.04.2015
comment
18 месяцев спустя вы публикуете ответ, такой же, как и ваш? - person dinotom; 12.08.2016