Установить пользовательский путь к ссылочным DLL?
У меня есть проект С# (назовите его MainProj
), который ссылается на несколько других DLL-проектов. Добавив эти проекты в MainProj
ссылки, он их построит и скопирует их в DLL в рабочий каталог MainProj.
Что бы я хотел сделать, так это то, что эти DLL с указанными ссылками будут расположены в подкаталоге рабочего каталога MainProj
, то есть MainProj/bin/DLL, а не в самом рабочем каталоге.
Я не очень опытный программист на С#, но, исходя из мира С++, я предполагаю, что одним из подходов будет удаление ссылок на проект и явная загрузка необходимой DLL по пути и имени файла (т.е. в С++, LoadLibrary
). Однако то, что я предпочел бы сделать, если бы это было так, было бы установить какой-то "ссылочный двоичный путь", поэтому все они были бы автоматически скопированы в этот субдир, когда я построю (а затем буду ссылаться туда без мне нужно явно загружать каждый). Возможно ли это?
Если нет, то какой предпочтительный метод в С# выполнить то, что мне нужно (т.е. что-то с Assembly.Load
/Assembly.LoadFile
/Assembly.LoadFrom
? Возможно, что-то в AppDomain
или System.Environment
?)
Ответы
Ответ 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>
Ответ 2
От Tomek ответьте на: Загрузка DLL из пути, указанного в SetdllDirectory, в С#
var dllDirectory = @"C:/some/path";
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + dllDirectory)
Он отлично работает для меня!
Ответ 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
, это слишком трудоемко.