Один и тот же источник, несколько целей с разными ресурсами (Visual Studio .Net 2008) - PullRequest
13 голосов
/ 01 марта 2010

Набор программных продуктов отличается только своими строками ресурсов, двоичными ресурсами и строками / графиками / ключами продуктов, используемыми в их проектах установки Visual Studio. Каков наилучший способ их создания, организации и обслуживания?

т.е. Все продукты по существу состоят из одной и той же базовой функциональности, настраиваемой с помощью графики, строк и других данных ресурсов для формирования каждого продукта. Представьте, что вы создаете набор продуктов, таких как "Excel for Bankers", Excel for Gardeners "," Excel for CEOs "и т. Д. Каждый продукт имеет одинаковую функциональность, но отличается по названию, графике, файлам справки, включая шаблоны и т. д.

Среда, в которой они создаются, выглядит следующим образом: ванильные Windows.Forms / Visual Studio 2008 / C # / .Net.

Идеальное решение будет легко поддерживать. например Если я представлю новую строку / новые ресурсы проектов, я не добавил ресурс, к которому должен произойти сбой во время компиляции, а не во время выполнения. (И последующая локализация продуктов также должна быть осуществимой).

Надеюсь, я упустил ослепительно очевидный и простой способ сделать все это. Что это?

============ Разъяснение (я) ================

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

В настоящее время у меня есть одно решение, состоящее из нескольких проектов (включая проект установки), которое создает набор сборок и создает один установщик.

Мне нужно создать несколько продуктов / инсталляторов со схожей функциональностью, которые построены из одного и того же набора сборок, но отличаются набором ресурсов, используемых одной из сборок. Какой лучший способ сделать это?

------------ 95% раствор -----------------

На основании ответа Daminen_the_unbeliever файл ресурса для каждой конфигурации может быть получен следующим образом:

  1. Создать проект библиотеки классов («Спутник»).
  2. Удалить файл .cs по умолчанию и добавить папку («По умолчанию»)
  3. Создать файл ресурсов в папке «MyResources»
  4. Свойства - установите CustomToolNamespace в нечто соответствующий (например, "XXX")
  5. Убедитесь, что модификатор доступа к ресурсам "Public". добавлять ресурсы. Отредактируйте исходный код. Обратитесь к ресурсам в вашем коде как XXX.MyResources.ResourceName)
  6. Создание конфигураций для каждого варианта продукта («ConfigN»)
  7. Для каждого варианта продукта создайте папку («VariantN»)
  8. Скопируйте и вставьте файл MyResources в каждую папку VariantN
  9. Выгрузите проект "Satellite" и отредактируйте файл .csproj
  10. Для каждого тега "VariantN / MyResources" <Compile> или <EmbeddedResource>, добавить атрибут Condition="'$(Configuration)' == 'ConfigN'".
  11. Сохраните, перезагрузите .csproj, и все готово ...

Это создает файл ресурсов для каждой конфигурации, который (предположительно) может быть дополнительно локализован. Сообщения об ошибках компиляции создаются для любой конфигурации, в которой отсутствует ресурс. Файлы ресурсов можно локализовать стандартным способом (создайте второй файл ресурсов (MyResources.fr.resx) и отредактируйте .csproj, как и раньше).

Причина того, что это решение на 95%, заключается в том, что ресурсы, используемые для инициализации форм (например, заголовки форм, тексты кнопок), не могут быть легко обработаны таким же образом - кажется, что самый простой подход - переписать их значениями спутниковая сборка.

Ответы [ 4 ]

11 голосов
/ 02 марта 2010

Вы можете добавить условные выражения к элементам в файле MSBuild. Например, если у вас есть ресурсы «Debug» и «Release», вы можете поместить их в две отдельные папки (например, «Debug» и «Release»). Тогда в вашем файле MSBuild вы можете иметь:

  <ItemGroup>
    <Compile Include="Debug\Resource1.Designer.cs" Condition=" '$(Configuration)' == 'Debug' ">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>Resource1.resx</DependentUpon>
    </Compile>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="Queue.cs" />
    <Compile Include="Release\Resource1.Designer.cs" Condition=" '$(Configuration)' == 'Release' ">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>Resource1.resx</DependentUpon>
    </Compile>
    <Compile Include="Stack.cs" />
  </ItemGroup>
  <ItemGroup>
    <Content Include="XMLFile1.xml" />
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Include="Debug\Resource1.resx" Condition=" '$(Configuration)' == 'Debug' ">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resource1.Designer.cs</LastGenOutput>
      <CustomToolNamespace>Resources</CustomToolNamespace>
    </EmbeddedResource>
    <EmbeddedResource Include="Release\Resource1.resx" Condition=" '$(Configuration)' == 'Release' ">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resource1.Designer.cs</LastGenOutput>
      <CustomToolNamespace>Resources</CustomToolNamespace>
    </EmbeddedResource>
  </ItemGroup>

Если весь ваш доступ к ресурсам осуществляется через класс Resources.Resource1, то вы получаете два разных набора ресурсов для отладочной и выпускной сборок. Очевидно, что это может быть расширено для дальнейших конфигураций.

К сожалению, я не думаю, что вы можете заставить ресурсы использовать одно и то же baseName (как предоставлено конструктору ResourceManager), поскольку оно основано на пути внутри проекта, и я не могу найти способ переопределить это. Если вам нужно, чтобы они использовали одно и то же имя (например, если вы создаете ResourceManager вручную), то я бы предложил использовать Resources1.resx (плюс связанный cs-файл) на верхнем уровне проекта, а не под управления источником. В качестве события перед сборкой скопируйте требуемый файл .resx из каталога Debug или Release соответствующим образом. (В этой ситуации вы, вероятно, захотите заставить его не компилировать файлы .Designer.cs в подкаталогах.

Редактировать

Забыл упомянуть (хотя это видно из приведенной выше выдержки из файла MSBuild), что для пространства имен настраиваемого инструмента в каждом файле .resx должно быть установлено одинаковое значение (например, ресурсы), в противном случае по умолчанию также включается папка. имя.

Редактировать 2

В ответ на запрос о проверке того, что каждый файл ресурсов содержит одинаковые ресурсы - если вы используете класс Resource (например, Resources.Resource1.MyFirstStringResource) для доступа к вашим ресурсам, то переключение конфигураций приведет к ошибкам сборки, если потребуется ресурс не существует, так что вы найдете его довольно быстро.

Для по-настоящему параноика (то есть, если ваш процесс сборки занимает 3 дня на сборку всех конфигураций, или что-то такое же безумное), в конце концов, файлы .resx - это просто файлы XML - вам просто нужно что-то проверить, чтобы каждый Файл .resx с тем же именем файла содержит одинаковое количество элементов с такими же атрибутами имени.

3 голосов
/ 03 октября 2012

Вот мое решение. Первоначальной проблемой было то, что Autodesk выпускает все библиотеки AutoCAD с чем-то другим и нарушает совместимость каждые 3 года. Но наш код на самом деле такой же. Это был болезненный момент на пути Develop-TFS-TFSbuild-DomainControllerInstallationOfApps.

Решение выглядит следующим образом:

  1. Создайте свой проект MOTHER со всей структурой и, скажем, ссылками на AutoCAD 2012.
  2. Затем создайте второй проект для AutoCAD 2013 в том же решении и создайте ссылку на свою собственную DLLS.
  3. Теперь вам нужно установить один символ компиляции для каждого проекта - acad2012 в первом проекте и acad2013 для второго.
  4. Затем в проекте 2013 года перейдите к «Добавить существующий элемент» и укажите источники проекта 2012, НО ПОСЛЕ ЭТОГО НАЖМИТЕ справа от кнопки «Добавить» и укажите «Добавить как ссылку»
  5. Если между 2012 и 2013 годами имеются какие-либо расхождения в библиотеках, их можно окружить #if acad2012 #endif or #if acad2013 #endif

Таким образом, у вас будет только один исходный код для поддержки и вам придется отдельно скомпилировать модули :)

UPDATE

Мне нужно создать несколько продуктов / установщиков со схожими функциональными возможностями, которые построены из одного и того же набора сборок, но отличаются набором ресурсов, используемых одной из сборок. Какой лучший способ сделать это?

  1. Настройка проектов Installers : Это именно то, что мы делаем, и именно то, что вам нужно. После шага 5 вы должны сделать два проекта установщика. Я имею в виду Проекты Windows Installer Xml или проекты WiX Допустим, первый - на 2012 год, а другой - на 2013 год. Следующая проблема - создание файлов XML, которые содержат все компоненты для сборки. Я использую инструментарий WiX со следующим скриптом:

    heat.exe dir "$ (TargetDir)" -cg MyAppComponents -dr INSTALLFOLDER -sfrag -srd -var "var.FilesPath" -out ". \ MyAppComponents.wxs"

Этот сценарий создает файл MyAppComponents.wxs со всеми необходимыми файлами. Если вы хотите познакомиться с Wix, перейдите к этой книге: «WiX 3.6: Руководство разработчика по XML для установщика Windows». Я сделал все необходимое после прочтения.

  1. Добавьте MyAppComponents.wxs непосредственно в ваш основной проект установщика (пусть это будет на 2012 год) и в любой другой проект «Добавить как ссылку» (пусть это будет для библиотек 2013 года). Если вы следовали инструкциям в шаге 5, то ваш скрипт сборки уже создан для компиляции с различными версиями сборок зависимостей. Вы хотите, чтобы один исходный код был скомпилирован с двумя разными зависимостями? Таким образом, у вас есть это - один .wxs, который содержит все, и внутри .cs файлов у вас есть прагмы, которые направляют компиляцию.

Теперь, когда вы добавляете новый файл в ваше решение, вам нужно будет добавить его в свой проект Mother, затем «добавить как ссылку» в другие ваши проекты и добавить регистрацию компонента в .wxs только в одном месте, чтобы его можно было распространять во всех установщиках.

С помощью скрипта из шага 6 у вас будут все ваши версионные библиотеки в одном .wxs, что означает, что они будут скомпилированы в одном инсталляторе. Конечно, вы можете создать несколько разных инсталляторов для всех ваших версий, но в долгосрочной перспективе проще создать один инсталлятор и решить во время установки, какую версию .dll скопировать на диск или определить во время выполнения, в какую .dll загружать. объем памяти. Я решил выбрать время выполнения, и оно отлично работает для меня.

  1. После того, как вы готовы к установке двух проектов, вы можете использовать TFS Build для интеграции. Вы можете пойти еще дальше и добавить в процесс сборки обфускатор, такой как Smart Assembly, чтобы в конце у вас было два или более отдельных установщика с раздельными сборками dll для различных зависимых библиотек, которые содержат запутанные сборки.

Все описанное выше - прямо из окопов, и это работает. Если я не четко изложил все шаги, просто отправьте мне сообщение, чтобы уточнить их и уточнить.

Я отказался от конфигураций сборки из-за слишком большого количества IF и условий в них, которые будут накапливаться со временем, когда «появляется еще одна dll Autodesk». Я не очень уверен в этом. Возможно, это решение, но вы должны быть очень уверены, что делаете, чтобы не затормозить сборку TFS, если это является требованием.

1 голос
/ 04 марта 2010

Ваш подход - использовать несколько отдельных проектов только для ресурсов (и сборок) - обоснован и типичен для локализованных приложений и в других сценариях. Есть некоторые проблемы с пространством имен и областями видимости, о которых вам нужно знать - VS2005 всегда генерирует типы ресурсов как внутренние (или Friend в VB), а VS2008 позволяет вам изменять это. Вам нужно будет сделать правильную вещь, чтобы иметь возможность доступа к нескольким сателлитным сборкам из вашей основной сборки - общедоступные типы ресурсов.

Как только у вас есть основная DLL и различные библиотеки ресурсов, у вас есть варианты для развертывания. Один из них заключается в том, чтобы развертывать отдельные библиотеки DLL отдельно и загружать соответствующие библиотеки во время выполнения. Предположим, ваш основной EXE-файл называется app.exe; тогда у вас также будет Sat1.dll, sat2.dll, sat3.dll и т. д. для всех спутниковых сборок. Ваш проект (ы) установки будет включать в себя все необходимые библиотеки DLL.

Другой вариант - объединить библиотеки DLL с ILMerge. В этом случае вы должны объединить app.exe с sat1.dll, получив app1.exe. Аналогично app.exe + sat2.exe => app2.exe.

Чтобы обойти это, используйте "локализация" и "Спутниковые сборки".

0 голосов
/ 01 марта 2010

Это то, что вы ищете для нескольких конфигураций? Взгляните на: Конфигурации сборки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...