Скомпилируйте независимую от версии DLL в .NET

Сценарий

У меня есть две оболочки для Microsoft Office, одна для 2003 и одна для 2007. Поскольку две версии Microsoft Office, работающие бок о бок, «официально не возможны» и не рекомендуются Microsoft, у нас есть две коробки, одна с Office 2003, а другая с Office 2007. Мы компилируем обертки отдельно. Библиотеки DLL включены в наше решение, каждая ячейка имеет одинаковую проверку, но с "выгруженным" Office 2003 или 2007, поэтому он не пытается скомпилировать эту конкретную DLL. Невыполнение этого требования приведет к ошибкам компиляции из-за недоступности библиотек 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 включена в решение. Поскольку оболочки содержатся в решении, они наследуют версию приложения, но мы должны сделать это дважды, а затем «скопировать» другую 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 и наоборот.

Заранее спасибо.


person Martin Marconcini    schedule 10.11.2008    source источник
comment
Я исправил ссылку в своем ответе, которая указывает на статью MS о том, как установить их рядом.   -  person HTTP 410    schedule 11.11.2008


Ответы (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-оболочке, гарантируя, что ловушка будет на месте раньше времени.

Вы также можете использовать файлы политики для перенаправления версий, но это, как правило, более сложно.

person Eric Rosenberger    schedule 12.11.2008
comment
Не могли бы вы вкратце объяснить или дать мне направление, как реализовать это с помощью файлов политик? В настоящее время я пытаюсь решить проблемы при обновлении до более новой версии dll (см. stackoverflow.com/questions/30165393/) - person Vortex852456; 11.05.2015
comment
У меня проблема с использованием этого решения. Статический код не запускается до разрешения dll. Откуда я это знаю? Я попытался вызвать исключение в статическом инициализаторе, но все же разрешение dll - единственное появляющееся исключение. Однако, если есть библиотеки DLL, я вижу свое исключение. - person Jarekczek; 09.07.2016
comment
Решено путем создания основного метода оболочки, который вызывает исходный метод Main. См. Также: Перенаправление загрузок сборок во время выполнения - person Jarekczek; 09.07.2016

Просто подумайте - можете ли вы использовать TlbExp для создания двух сборок взаимодействия (с разными именами и сборками) и использовать интерфейс / фабрику для кодирования двух через свой собственный интерфейс? Когда у вас есть interop dll, вам не нужна COM-зависимость (за исключением, конечно, тестирования и т. Д.).

TlbImp имеет / asmversion для версии, поэтому это можно сделать как часть сценария сборки; но я уверен, что вам это даже нужно: просто убедитесь, что "конкретная версия" неверна в ссылке (обозреватель решений)?

Также - я знаю, что это не помогает, но C # 4.0 с dynamic и / или «Без PIA» может здесь помочь (в будущем; возможно).

person Marc Gravell    schedule 10.11.2008
comment
Спасибо, Марк, я тоже попробую. Я устал от двух строительных коробок. ;) - person Martin Marconcini; 10.11.2008

Я не уверен, что полностью следую всему, что вы сказали, но позвольте мне попробовать:

Похоже, у вас есть одно решение с 2 (?) Проектами. Одно - это собственное приложение, а другое - оболочка для Office API. Тогда ваше приложение будет иметь ссылку на проект вашей оболочки Office API. Я никогда раньше не занимался программированием для офиса, но похоже, что программные API-интерфейсы являются обычным компонентом, у вас может быть только одна версия на машине (например, 2003 или 2007, но не обе). И, возможно, здесь проблема, но поскольку у вас есть ссылка на проект, оболочка будет сначала скомпилирована, скопирована в каталог bin вашего приложения, где ваше приложение будет связано с этой сборкой оболочки. Это приведет к тому, что манифест приложения будет специально запрашивать эту версию оболочки во время выполнения.

Если бы у вас была оболочка в отдельном решении и вы добавили ссылку на скомпилированную библиотеку, а не на проект, вы всегда связали бы свое приложение с этой версией оболочки, и вы могли бы избежать проблемы.

Другой возможный выбор - перенаправление привязки сборки. Это более сложный вариант и имеет собственный набор проблем, но вы можете прочитать об этом здесь.

Или аналогично идее Марка, вы могли бы извлечь интерфейс и вытащить некоторые общие объекты в библиотеку Framework, а также закодировать свое приложение в соответствии с интерфейсом и общими объектами. Затем во время выполнения используйте отражение, чтобы загрузить сборку и создать экземпляр нужной оболочки.

Я думаю, что главное в том, чтобы по возможности удалить зависимость проекта. Похоже, оболочка довольно стабильна и не меняется, иначе вы бы не просили ссылку на ее предыдущую версию.

person NerdFury    schedule 10.11.2008
comment
Это близко, но неверно. ;) У меня есть одно решение с тремя проектами (ну больше, но актуально ...). Фактическое приложение и OfficeWrapper11.dll и OfficeWrapper12.dll. Я изучу твои идеи. ты. - person Martin Marconcini; 10.11.2008

Параллельная установка Office 2003 и 2007 на одном компьютере определенно возможна - мы делаем это в нашей организации даже на рабочих станциях конечных пользователей.

В этой связанной статье Microsoft рекомендует не делать этого на практике. Но в вашем случае это, похоже, только для одной машины сборки, т.е. вы не собираетесь использовать на этом компьютере ни одну из версий Office. В этом контексте я бы попытался посмотреть, сможете ли вы заставить работать параллельную установку.

Мое предположение может быть неверным, и вы пытаетесь сделать это для каждой машины разработчика. В таком случае игнорируйте этот ответ :-)

person HTTP 410    schedule 10.11.2008
comment
Я действительно не пробовал, но только предположил, что немного погуглил. Я думаю, что один из способов избежать прикосновения к рабочему коду - это попробовать установить оба офисных пакета, от более старых к более новым. (Первое 2003 г., второе 2007 г.). Спасибо, я тоже попробую. - person Martin Marconcini; 10.11.2008

Хорошая розыск! Я просто собрал реализацию, основанную на концепции, представленной выше, и она прекрасно работает:

static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
     string partialName = args.Name.Substring(0, args.Name.IndexOf(','));
     return Assembly.Load(new AssemblyName(partialName));
}

Конечно, есть возможности для улучшения, но это помогает мне!

person Sean Aitken    schedule 16.06.2009