Скомпилируйте независимую от версии DLL в .NET.
-
07-07-2019 - |
Вопрос
Сценарий
У меня есть две оболочки Microsoft Office: одна для 2003 года, другая для 2007 года.Поскольку одновременное использование двух версий Microsoft Office «официально невозможно» и не рекомендуется Microsoft, у нас есть две версии: одна с Office 2003, другая с Office 2007.Обертки компилируем отдельно.DLL включены в наше решение, каждая коробка имеет такой же checkout, но с «выгруженным» Office 2003 или 2007, поэтому он не пытается скомпилировать эту конкретную DLL.Если этого не сделать, при компиляции возникнут ошибки, поскольку библиотеки Office COM DLL недоступны.
Мы используем .NET 2.0 и Visual Studio 2008.
Факты
Поскольку в 2007 году Microsoft таинственным образом изменила API Office 2003, переименовав и изменив некоторые методы (вздох), что делает их несовместимыми обратно, мы нуждаться две обертки.У нас есть каждая машина сборки с этим решением и одной активированной библиотекой Office DLL.Например.:на машине с Office 2003 выгружена DLL «Office 2007», поэтому она не компилируется.Другая коробка — та же идея, но наоборот.Все это потому, что мы не можем иметь два разных Office в одном ящике для целей программирования.(технически вы можете объединить два Office вместе), но нет для программирования и не без некоторых проблем.
Проблема
Когда мы меняем версию приложения (например, с 1.5.0.1 на 1.5.0.2), нам необходимо перекомпилировать DLL, чтобы она соответствовала новой версии приложения, это делается автоматически, поскольку в решение включена оболочка Office.Поскольку оболочки содержатся в решении, они наследуют версию приложения, но нам придется сделать это дважды, а затем «скопировать» другую DLL на машину, которая создает установщик.(Боль…)
Вопрос
Можно ли скомпилировать DLL, которая будет работать с любой версия приложения, несмотря на то, что она «более старая»?Я читал кое-что о манифестах, но мне никогда не приходилось с ними взаимодействовать.Любые указатели будут оценены.
Секретная причина этого в том, что мы не меняли наши оболочки уже много лет, как и Microsoft с их древними API, однако мы перекомпилируем DLL, чтобы она соответствовала версии приложения на каждый релиз, который мы делаем.Я хотел бы автоматизировать этот процесс вместо того, чтобы полагаться на два машины.
Я не могу удалить DLL из проекта (ни одну из них), потому что есть зависимости.
Я мог бы создать третью «главную обертку», но пока об этом не думал.
Есть идеи?Кто-нибудь еще с таким же требованием?
ОБНОВЛЯТЬ
Уточнение:
У меня есть 1 решение с N проектами.
«Приложение» + Office11Wrapper.dll + Office12Wrapper.dll.
Обе «обертки» используют зависимости для приложения + других библиотек в решении (уровень данных, бизнес-уровень, фреймворк и т. д.).
Каждая оболочка содержит ссылки на соответствующий пакет Office (2003 и 2007).
Если я скомпилирую и у меня не установлен Office 12, я получаю ошибки из Office12Wrapper.dll, не находящего библиотеки Office 2007.Итак, у меня есть две строительные машины: одна с Office 2003, другая с Office 2007.После полного обновления SVN + компиляции на каждой машине мы просто используем office12.dll в «установщике», чтобы оболочка скомпилировалась с «тот же код, та же версия».
Примечание:На машине сборки Office 2007 оболочка для Office 2003 «выгружена», и наоборот.
Заранее спасибо.
Решение
Когда преобразователь сборок .NET не может найти указанную сборку во время выполнения (в этом случае он не может найти конкретную версию DLL-оболочки, с которой было связано приложение), его поведение по умолчанию заключается в сбое и существенном аварийном завершении приложения.Однако это поведение можно переопределить, подключив событие AppDomain.AssemblyResolve.Это событие вызывается всякий раз, когда не удается найти указанную сборку, и дает вам возможность заменить отсутствующую сборку другой (при условии, что они совместимы).Так, например, вы можете заменить более старую версию DLL-оболочки, которую загружаете самостоятельно.
Лучший способ, который я нашел для этого, — добавить статический конструктор в основной класс приложения, который перехватывает событие, например:
using System.Reflection;
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
{
AssemblyName requestedName = new AssemblyName(e.Name);
if (requestedName.Name == "Office11Wrapper")
{
// Put code here to load whatever version of the assembly you actually have
return Assembly.LoadFile("Office11Wrapper.DLL");
}
else
{
return null;
}
}
}
Поместив это в статический конструктор основного класса приложения, он гарантированно запустится до того, как какой-либо код попытается получить доступ к чему-либо в DLL-оболочке, гарантируя, что перехват будет установлен заранее.
Вы также можете использовать файлы политики для перенаправления версий, но это, как правило, более сложно.
Другие советы
Просто мысль: можете ли вы использовать TlbExp для создания двух сборок взаимодействия (с разными именами и сборками) и использовать интерфейс/фабрику для кодирования этих двух через свой собственный интерфейс?Если у вас есть библиотека взаимодействия, вам не нужна зависимость COM (за исключением, конечно, тестирования и т. д.).
У TlbImp есть версия /asmversion, поэтому это можно сделать как часть сценария сборки;но я уверен, что вам даже это нужно:просто убедитесь, что «конкретная версия» в ссылке (обозреватель решений) является ложной?
Кроме того, я знаю, что это не помогает, но С# 4.0 с dynamic
и/или «Нет PIA» может здесь помочь (в будущем;может быть).
Я не уверен, что полностью следую всему, что вы сказали, но позвольте мне попробовать:
Похоже, у вас есть одно решение с двумя (?) проектами.Один из них — это само приложение, а другой — оболочка API Office.Затем ваше приложение будет иметь ссылку на проект вашей оболочки API Office.Я никогда раньше не программировал для офиса, но похоже, что API-интерфейсы программирования — это общий компонент, у которого на компьютере может быть только одна версия (т.2003 или 2007, не оба).И, возможно, проблема именно в этом, но поскольку у вас есть ссылка на проект, оболочка будет скомпилирована первой, скопирована в каталог bin вашего приложения, где ваше приложение будет связано с этой сборкой оболочки.Это приведет к тому, что манифест приложения будет специально запрашивать эту версию оболочки во время выполнения.
Если бы у вас была оболочка в отдельном решении и вы добавляли ссылку на скомпилированную библиотеку, а не на проект, вы всегда связывали бы свое приложение с этой версией оболочки и могли бы избежать этой проблемы.
Другой возможный вариант — перенаправление привязки сборки.Это более сложный вариант, и у него есть свои проблемы, но вы можете прочитать об этом. здесь.
Или, аналогично идее Марка, вы можете извлечь интерфейс и поместить некоторые общие объекты в библиотеку Framework и закодировать свое приложение на основе интерфейса и общих объектов.Затем во время выполнения используйте отражение, чтобы загрузить сборку и создать экземпляр нужной оболочки.
Я думаю, что ключом является удаление зависимости проекта, если вы можете.Похоже, что оболочка довольно стабильна и не меняется, иначе вы бы не просили дать ссылку на ее предыдущую версию.
Параллельная установка Office 2003 и 2007 на одном компьютере определенно возможно - мы делаем это в нашей организации даже на производственных рабочих станциях конечных пользователей.
В этой связанной статье Microsoft рекомендует не делать этого при реальном использовании.Но в вашем случае это похоже только на одну сборочную машину, т.е.вы не собираетесь использовать ни одну из версий Office на этом компьютере.В этом контексте я хотел бы попытаться посмотреть, сможете ли вы выполнить параллельную установку.
Мое предположение может быть ошибочным, и вы пытаетесь сделать это для каждой машины разработчика.В этом случае вам следует игнорировать этот ответ :-)
Хорошая детективная работа!Я только что собрал реализацию, основанную на концепции, представленной выше, и она работает чудесно:
static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string partialName = args.Name.Substring(0, args.Name.IndexOf(','));
return Assembly.Load(new AssemblyName(partialName));
}
Конечно, есть куда расти, но для меня это важно!