Скомпилируйте независимую от версии DLL в.NET
сценарий
У меня есть две оболочки вокруг Microsoft Office, одна для 2003 и одна для 2007. Поскольку две версии Microsoft Office работают бок о бок, это "официально невозможно" и не рекомендуется Microsoft, у нас есть две коробки, одна с Office 2003, а другая с Office 2007. Мы компилируем обертки отдельно. Библиотеки DLL включены в наше решение, каждый блок имеет одинаковую проверку, но Office 2003 или 2007 "выгружен", поэтому он не пытается компилировать эту конкретную DLL. Невыполнение этого условия приведет к ошибкам компиляции из-за недоступности библиотек Office COM.
Мы используем.NET 2.0 и Visual Studio 2008.
факты
Так как Microsoft загадочным образом изменила API Office 2003 в 2007 году, переименовав и изменив некоторые методы (вздох), сделав их несовместимыми, нам нужны две оболочки. У нас есть каждая сборочная машина с активированным решением и одна Office DLL. Например: на компьютере с Office 2003 выгружена DLL-библиотека "Office 2007", поэтому она не компилируется. Другая коробка - та же самая идея, но наоборот. Все это потому, что у нас не может быть двух разных Office в одной коробке для целей программирования. (технически вы могли бы иметь два Office вместе с Microsoft), но не для программирования и не без проблем.
проблема
Когда мы меняем версию приложения (например, с 1.5.0.1 на 1.5.0.2), нам нужно перекомпилировать DLL, чтобы она соответствовала новой версии приложения, это выполняется автоматически, поскольку в решение включена оболочка Office. Поскольку в решении содержатся обертки, они наследуют версию APP, но мы должны сделать это дважды, а затем "скопировать" другую 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 и наоборот.
Заранее спасибо.
5 ответов
Когда распознаватель сборок.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-оболочке, гарантируя, что зацепка будет установлена заранее.
Вы также можете использовать файлы политик для перенаправления версий, но это может быть более сложным.
Я не уверен, что полностью следую всему, что вы заявили, но позвольте мне попробовать:
Похоже, у вас есть одно решение с 2(?) Проектами. Одним из них является собственно приложение, а другим - оболочка для Office API. Тогда ваше приложение имеет ссылку на проект на оболочку Office API. Я никогда не программировал для офиса раньше, но похоже, что API-интерфейсы программирования являются общим компонентом, на котором можно иметь только одну версию на компьютере (т. Е. 2003 или 2007, но не обе). И, возможно, именно в этом проблема, но, поскольку у вас есть ссылка на проект, оболочка будет сначала скомпилирована, скопирована в каталог bin вашего приложения, где ваше приложение будет связано с этой сборкой оболочки. Это заставит манифест приложения специально запрашивать эту версию оболочки во время выполнения.
Если бы у вас была оболочка в отдельном решении и вы добавили ссылку на скомпилированную библиотеку, а не на проект, вы всегда связывали бы свое приложение с этой версией оболочки, и вы могли бы избежать этой проблемы.
Другой возможный выбор - перенаправление привязки сборки. Это более продвинутый вариант, и у него есть свои проблемы, но вы можете прочитать об этом здесь.
Или, аналогично идее Марка, вы можете извлечь интерфейс и вставить некоторые общие объекты в библиотеку Framework, а также закодировать свое приложение в соответствии с интерфейсом и общими объектами. Затем во время выполнения используйте отражение, чтобы загрузить сборку и создать экземпляр нужной оболочки.
Я думаю, что ключ должен удалить зависимость проекта, если вы можете. Похоже, что обертка довольно стабильна и не меняется, в противном случае вы бы не просили ссылку на предыдущую версию.
Просто мысль - не могли бы вы использовать TlbExp для создания двух сборок взаимодействия (с разными именами и сборками) и использовать интерфейс / фабрику для кодирования этих двух через ваш собственный интерфейс? Если у вас есть dll взаимодействия, вам не нужна зависимость от COM (за исключением, конечно, тестирования и т. Д.).
TlbImp имеет /asmversion для версии, так что это можно сделать как часть сценария сборки; но я уверен, что вам даже нужно это: просто убедитесь, что "конкретная версия" является ложной в ссылке (обозреватель решений)?
Кроме того - я знаю, что это не помогает, но C# 4.0 с dynamic
и / или "Нет PIA" может помочь здесь (в будущем; возможно).
Установка 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));
}
Конечно, есть место для совершенствования, но это делает мой трюк!