После нескольких часов, потраченных на эту тему (а также десятки посещенных страниц), я вынужден обратиться за помощью. Я видел много сообщений на эту тему, но я не мог исправить проблему, которую я получаю.Загрузка сборок во время выполнения, пример плагина Autocad
В принципе, я хочу сделать очень простую вещь: загрузить сборку из папки в приложение.
Вот вопрос короче (все остальные детали объясняются в остальной части текста) Я хочу использовать метод Assembly.LoadFrom, чтобы загрузить мои сборки (тот же файл сборки с привязкой проектом, но с CopyLocal лжи), но хотя сборка загружается при вызове метода, использующего его, программа пытается загрузить сборку из местоположений по умолчанию. Если он найден, то загружаются две одинаковые сборки, а программа использует последнюю, если она не найдена, тогда возникает событие FileNotFoundException. Но, когда я использую ту же идею в плагине Autocad, все работает, и исключение не возникает, хотя файлы не найдены.
У меня есть тестовое решение с двумя простыми проектами: TestExe (консольное приложение) и TestDll (библиотека DLL). Я хочу использовать типы из TestDll в TestExe, поэтому я добавил ссылку на TestDll (я не ссылаюсь на проект TestDll, но файл в указанном месте), но я хочу загрузить TestDll вручную во время выполнения. Почему это необходимо, объясняется в конце текста, с примером Autocad.
Насколько я понимаю, для этой цели может быть использован метод Assembly.LoadFrom. Итак, основная идея заключается в следующем: Load TestDll перед тем, как метод в TestExe использует его, поэтому, когда метод вызывается, мы уже загрузили сборку. Таким образом, независимо от того, существует ли ссылка dll в каталогах по умолчанию или нет, у нас уже есть сборка, и она будет использоваться.
Из MSDN:
Если сборка с той же идентичностью уже загружена, LoadFrom возвращает загруженную сборку, даже если другой путь был указан.
Так что я понимаю, что если я загружу dll один раз, каждый следующий груз такой же сборки (также из другого места) будет знать, что он уже добавлен, поэтому первый будет использоваться.
Проект: TestExe
//File: Program.cs
using System;
namespace TestExe
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new ClassExe().ExeMethod());
}
}
}
//File: ClassExe.cs
namespace TestExe
{
class ClassExe
{
public string ExeMethod()
{
return new TestDll.ClassDll().DllMethod();
}
}
}
Проект TestDll
using System.Reflection;
namespace TestDll
{
public class ClassDll
{
public string DllMethod()
{
return Assembly.GetExecutingAssembly().Location;
}
}
}
Как вы можете видеть, задача проста: показать местоположение вызываемого узла.
Скажем, TestDll.dll скопирован в папку приложения Extern \ TestDll.dll.
Если я установил свойство CopyLocal: false для ссылки на TestDll в проекте TestExe, программа завершится неудачно с FileNotFoundException. (1) Это потому, что сборка выполняется только в каталогах по умолчанию (application dir и TestDll \ TestDll.dll)?
Затем я попытался загрузить сборку вручную, прежде чем использовать его:
static void Main(string[] args)
{
Assembly.LoadFrom(@"Extern\TestDll.dll");
Console.WriteLine(new ClassExe().ExeMethod());
}
Но я получаю же FileNotFoundException, хотя TestDll был загружен
Когда я установить атрибут CopyLocal: верно, то программа работает. Но он снова загружает TestDll.dll из местоположения по умолчанию и игнорирует сборку, которая уже загружена.
Единственный способ, которым я сумел программу для работы, как я хотел (чтобы использовать сборки Экстерн \ TestDll.dll) является с помощью AppDomain.AssemblyResolve событие.
У меня есть плагин Autocad, который использует 10 различных dll, из разных решений. Поэтому у меня есть plugin.dll, который ссылается на 10 файлов DLL в папке Documents и устанавливает CopyLocal: true. Но при развертывании для клиента я держу только файл plugin.dll в папке приложения, а все остальные DLL находятся в подкаталоге Libraries. В статическом конструкторе класса plugin я помещаю Assembly.LoadFrom для загрузки из подкаталога Libraries, и все работает нормально.
Извините за длинный пост, но я хотел объяснить его подробностями.
И спасибо за любую обратную связь :)
Не уверен, что в плагине AutoCAD в конце вы разрабатываете встроенный или внешний (вне процесса) EXE? –
@AugustoGoncalves In-process exe. Все делается на поток exe, скажем, простейшее консольное приложение. – miki
Когда я говорю «in-process», я имею в виду DLL, которая является NETLOADed внутри AutoCAD и может использовать как .NET, так и COM API. Теперь EXE (вне процесса) будет запускаться в отдельном потоке и вызывать AutoCAD через COM API (Interop). Тем не менее, когда вы говорите «in-process» EXE, это не имеет смысла. –