Разрешить ссылки на сборки из другой папки - PullRequest
7 голосов
/ 10 марта 2011

Я разрабатываю приложение, которое ссылается и использует некоторые сторонние сборки от определенного Продавца;В окне разработки у меня есть эти 3 сборки в справочной папке в моем исходном дереве, и я могу ссылаться на них и создавать приложение, приложение собирается, но не запускается, потому что не установлено целое серверное приложение, но это нормально.

На сервере, на котором я хочу скопировать это пользовательское приложение и запустить все сборки, на которые я ссылаюсь, находятся в папке что-то вроде:

D:\ProgramFiles\VendorName\ProductName\Support\API\Bin64

, и если я скопирую свой небольшой исполняемый файл в эту папку и запусту его, онработает отлично, но если я помещаю свой .exe в более подходящую папку, как я хочу:

D:\ProgramFiles\MyCompanyName\MyProduct\bin\...

, он не работает, потому что не может разрешить эти сборки.

Я знаю, что могу использоватьпрощупывание в app.config, чтобы указать, в каких папках мой exe должен искать ссылки, но в этом случае сборки находятся не во вложенной папке, а в совершенно другом месте.

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

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

Спасибо.

Редактировать: здесь окончательный рабочий код

static System.Reflection.Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    Logger logger = new Logger();

    try
    {
        string RMSAssemblyFolder = ConfigurationManager.AppSettings["RMSAssemblyFolder"];

        Assembly MyAssembly = null;
        string strTempAssmbPath = string.Empty;

        Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly();
        AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();

        AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name);

        if (myAssemblyName != null)
        {
            MyAssembly = Assembly.LoadFrom(myAssemblyName.CodeBase);
        }
        else
        {
            strTempAssmbPath = Path.Combine(RMSAssemblyFolder, args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll");

            if (!string.IsNullOrEmpty(strTempAssmbPath))
            {
                if (File.Exists(strTempAssmbPath))
                {
                    logger.Information("Assembly to load: {0} - File was found in: {1}", args.Name, strTempAssmbPath);

                    // Loads the assembly from the specified path.                  
                    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);
                }
            }
        }

        // Returns the loaded assembly.
        return MyAssembly;
    }
    catch (Exception exc)
    {
        logger.Error(exc);
        return null;
    }
}

Ответы [ 2 ]

12 голосов
/ 10 марта 2011

Сначала вы должны найти папку, в которой установлены эти библиотеки DLL, затем использовать AppDomain.AssemblyResolve, чтобы перехватить разрешение сборки и попытаться загрузить требуемые сборки из этой папки.

Это будет выглядеть как-товот так (не тестировалось, и вам нужно проверить, что именно args.Name содержит, может содержать версию и строгое имя вместе с именем типа):

var otherCompanyDlls = new DirectoryInfo(companyFolder).GetFiles("*.dll");

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var dll = otherCompanyDlls.FirstOrDefault(fi => fi.Name == args.Name);
    if (dll == null)
    {
        return null;
    }

    return Assembly.Load(dll.FullName);
};
0 голосов
/ 10 марта 2011

Используйте SN.exe : SN -T VendorAssembly.dll, при этом возвращается шестнадцатеричное число, являющееся токеном открытого ключа, а затем ссылка на сборку из app.config. Чтобы получить версию, щелкните правой кнопкой мыши сборку вашего поставщика и используйте ее для значения версии codeBase по указанному вами пути href =.

  <configuration>
       <runtime>
          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
             <dependentAssembly>
                <assemblyIdentity name="VendorAssembly"  culture="neutral" publicKeyToken="307041694a995978"/>
                <codeBase version="1.1.1.1" href="FILE://D:/ProgramFiles/VendorName/ProductName/Support/API/Bin64/VendorAssembly.dll"/>
             </dependentAssembly>
          </assemblyBinding>
       </runtime>
    </configuration>
...