Подтвердить что ты не робот

Установить пользовательский путь к ссылочным DLL?

У меня есть проект С# (назовите его MainProj), который ссылается на несколько других DLL-проектов. Добавив эти проекты в MainProj ссылки, он их построит и скопирует их в DLL в рабочий каталог MainProj.

Что бы я хотел сделать, так это то, что эти DLL с указанными ссылками будут расположены в подкаталоге рабочего каталога MainProj, то есть MainProj/bin/DLL, а не в самом рабочем каталоге.

Я не очень опытный программист на С#, но, исходя из мира С++, я предполагаю, что одним из подходов будет удаление ссылок на проект и явная загрузка необходимой DLL по пути и имени файла (т.е. в С++, LoadLibrary). Однако то, что я предпочел бы сделать, если бы это было так, было бы установить какой-то "ссылочный двоичный путь", поэтому все они были бы автоматически скопированы в этот субдир, когда я построю (а затем буду ссылаться туда без мне нужно явно загружать каждый). Возможно ли это?

Если нет, то какой предпочтительный метод в С# выполнить то, что мне нужно (т.е. что-то с Assembly.Load/Assembly.LoadFile/Assembly.LoadFrom? Возможно, что-то в AppDomain или System.Environment?)

4b9b3361

Ответ 1

От эта страница (непроверенная мной):

Где-то в вашей инициализации вашей программы (до того, как вы получите доступ к любым классам из ссылочной сборки) сделайте следующее:

AppDomain.CurrentDomain.AppendPrivatePath(@"bin\DLLs");

Изменить: В этой статье сказано, что AppendPrivatePath считается устаревшим, но также дает обходное решение.

Изменить 2: Похоже, что самый простой и самый кошерный способ сделать это в файле app.config(см. здесь):

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="bin\DLLs" />
    </assemblyBinding>
  </runtime>
</configuration>

Ответ 3

Вот еще один способ продолжить без использования устаревшего AppendPrivatePath. Он ловит какое-то событие "ассоциированная dll not found" (поэтому он будет вызываться только в том случае, если dll не найден в каталоге по умолчанию).

Работает для меня (.NET 3.5, не проверены другие версии)

/// <summary>
/// Here is the list of authorized assemblies (DLL files)
/// You HAVE TO specify each of them and call InitializeAssembly()
/// </summary>
private static string[] LOAD_ASSEMBLIES = { "FooBar.dll", "BarFooFoz.dll" };

/// <summary>
/// Call this method at the beginning of the program
/// </summary>
public static void initializeAssembly()
{
    AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args)
    {
        string assemblyFile = (args.Name.Contains(','))
            ? args.Name.Substring(0, args.Name.IndexOf(','))
            : args.Name;

        assemblyFile += ".dll";

        // Forbid non handled dll's
        if (!LOAD_ASSEMBLIES.Contains(assemblyFile))
        {
            return null;
        }

        string absoluteFolder = new FileInfo((new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).LocalPath).Directory.FullName;
        string targetPath = Path.Combine(absoluteFolder, assemblyFile);

        try
        {
            return Assembly.LoadFile(targetPath);
        }
        catch (Exception)
        {
            return null;
        }
    };
}

PS: Мне не удалось использовать AppDomainSetup.PrivateBinPath, это слишком трудоемко.