Обнаружение сборки из кода библиотеки - PullRequest
3 голосов
/ 25 января 2012

У меня есть код в общей библиотеке для поддержки интернационализации. Основная идея заключается в том, что, учитывая полное имя местоположения файла RESX, вы можете искать значения, используя расширение разметки:

    resx:ResxProperty.Name="SampleApp.Common.Resources.MainWindow"
    Title="{Resx Key=Window.Title}" 
    Icon="{Resx Key=Window.Icon}"

Чтобы найти файл RESX, существует процедура для поиска во всех сборках, как показано ниже, и она прекрасно работает, когда файл RESX находится в той же сборке, что и xaml. НО он ломается, когда это не так.

Рассмотрим структуру решения ниже, где SampleApp.Wpf имеет вызывающий XAML и зависит как от LocalizationLib, так и от SampleApp.Common.

enter image description here

AppDomain.CurrentDomain.GetAssemblies () не имеет SampleApp.Common во время выполнения (хотя это происходит во время разработки).

Как я могу изменить этот код, чтобы он знал о SampleApp.Common во время выполнения?

Приветствия
Berryl

Библиотечный код

/// <summary>
/// Find the assembly that contains the type
/// </summary>
/// <returns>The assembly if loaded (otherwise null)</returns>
public static Assembly FindResourceAssembly(string resxName)
{
    // check the entry assembly first - this will short circuit a lot of searching
    //
    var assembly = Assembly.GetEntryAssembly();
    if (assembly != null && HasSpecifiedResx(assembly, resxName))
        return assembly;

    var assemblies = AppDomain.CurrentDomain.GetAssemblies();
    foreach (var searchAssembly in assemblies)
    {
        // skip system assemblies
        var name = searchAssembly.FullName;
        if (_isSystemAssembly(name)) continue;

        if (HasSpecifiedResx(searchAssembly, resxName))
            return searchAssembly;
    }
    return null;
}

UPDATE

Подробнее.

SampleApp.Wpf нацелено на .net 4.0. Ниже приведены ссылки на него, отображаемые в Visual Studio.

enter image description here

Единственными ссылками на проекты являются Infralution.Localization.Wpf и SampleApp.Common, которые также нацелены на .Net 4.0.

Основываясь на входных данных Metro Smurf, я попытался использовать assembly.GetReferencedAssemblies (). Когда я использую этот метод, конструктор VS НЕ находит SampleApp.Common, и следующие имена AssemblyNames известны в отладчике во время выполнения:

{System.Reflection.AssemblyName[6]}
    [0]: {PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [1]: {mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [2]: {System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [3]: {Infralution.Localization.Wpf, Version=2.1.2.0, Culture=neutral, PublicKeyToken=547ccae517a004b5}
    [4]: {System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [5]: {PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}

И когда я использую origional AppDomain.CurrentDomain.GetAssemblies (), конструктор знает SampleApp.Common, и эти сборки известны во время выполнения:

?AppDomain.CurrentDomain.GetAssemblies()
{System.Reflection.RuntimeAssembly[21]}
    [0]: {mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [1]: {Microsoft.VisualStudio.HostingProcess.Utilities, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [2]: {System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [3]: {System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [4]: {System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [5]: {Microsoft.VisualStudio.HostingProcess.Utilities.Sync, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [6]: {Microsoft.VisualStudio.Debugger.Runtime, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [7]: {vshost32, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [8]: {System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [9]: {System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [10]: {System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [11]: {Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [12]: {System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [13]: {System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [14]: {System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [15]: {WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [16]: {PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [17]: {PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [18]: {SampleApp.Wpf, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [19]: {System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [20]: {Infralution.Localization.Wpf, Version=2.1.2.0, Culture=neutral, PublicKeyToken=547ccae517a004b5}

В обоих случаях SampleApp.Common не известен во время выполнения. Для удовольствия я загрузил эту сборку в отладчик и получил:

?Assembly.Load("SampleApp.Common")
{SampleApp.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [System.Reflection.RuntimeAssembly]: {SampleApp.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    CodeBase: "file:///C:/.../SampleApp.Wpf/bin/Release/SampleApp.Common.DLL"
    EntryPoint: null
    EscapedCodeBase: "file:///C:.../SampleApp.Wpf/bin/Release/SampleApp.Common.DLL"
    Evidence: {System.Security.Policy.Evidence}
    FullName: "SampleApp.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    GlobalAssemblyCache: false
    HostContext: 0
    ImageRuntimeVersion: "v4.0.30319"
    IsDynamic: false
    IsFullyTrusted: true
    Location: "C:\\...\\SampleApp.Wpf\\bin\\Release\\SampleApp.Common.dll"
    ManifestModule: {SampleApp.Common.dll}
    PermissionSet: {<PermissionSet class="System.Security.PermissionSet"
version="1"
Unrestricted="true"/>
}
    ReflectionOnly: false
    SecurityRuleSet: Level2

Я также попробовал предложение Метро Смурфа сослаться на статическую строку из SampleApp.Common в SampleApp.Wpf. Без изменений, хотя, думаю, это еще раз доказывает, что SampleApp.Common имеет правильную ссылку.

Другие вещи, которые можно попробовать в SampleApp.Common, могут включать добавление EntryPoint, SNK или HashAlgorithm.

ИСПРАВЛЕНИЕ

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

Оказывается, что AppDomain.CurrentDomain.GetAssemblies () работает так же.

Metro Smurf был на правильном пути, но, очевидно, статическая ссылка не загрузит сборку, а создаст экземпляр типа из сборки. Итак:

Console.WriteLine(Class1.MyDummyString)  // this won't do it
Console.WriteLine(new Class1())  // finally, the assembly is loaded

Как бы мне не нравилось создавать фиктивный класс, в этом случае это легко исправить; Я могу оставить исходный код библиотеки как есть.

1 Ответ

1 голос
/ 25 января 2012

Возможно, вы захотите воспользоваться методом Assembly.GetReferencedAssemblies .Однако, если я не ошибаюсь, вам также нужно исключить сборки фреймворка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...