Тот же источник, несколько целей с разными ресурсами (Visual Studio.Net 2008)
Набор программных продуктов отличается только их строками ресурсов, бинарными ресурсами и клавишами строк/графики/продуктов, используемыми их проектами установки Visual Studio. Каков наилучший способ их создания, организации и поддержки?
то есть. Все продукты по существу состоят из одной и той же функциональности ядра, настраиваемой графикой, строками и другими данными ресурсов для формирования каждого продукта. Представьте, что вы создаете набор продуктов, таких как "Excel для банкиров", Excel для садоводов "," Excel для руководителей "и т.д. Каждый продукт имеет одинаковую функциональность, но отличается именем, графикой, файлами справки, включенными шаблонами и т.д.
Среда, в которой они создаются, является: vanilla Windows.Forms/Visual Studio 2008/С#/.Net.
Идеальное решение было бы легко поддерживать. например Если я представлю новые проекты с новыми/новыми ресурсами, я не добавил, что ресурс должен завершиться неудачно во время компиляции, а не запускать время. (И последующая локализация продуктов также должна быть осуществимой).
Надеюсь, я пропустил ослепительно-очевидный и простой способ сделать все это. Что это?
============ Уточнение =================
Под "продуктом" я подразумеваю пакет программного обеспечения, который устанавливается установщиком и продается конечному пользователю.
В настоящее время у меня есть одно решение, состоящее из нескольких проектов (включая проект установки), который создает набор сборок и создает один установщик.
Мне нужно создать несколько продуктов/инсталляторов, все с похожими функциями, которые построены из одного и того же набора сборок, но отличаются набором ресурсов, используемых одной из сборок. Какой лучший способ сделать это?
------------ 95% -ное решение -----------------
На основе ответа Daminen_the_unbeliever файл ресурсов для каждой конфигурации может быть достигнут следующим образом:
- Создайте проект библиотеки классов ( "Спутник" ).
- Удалить файл .cs по умолчанию и добавить папку ( "По умолчанию" )
- Создайте файл ресурсов в папке "MyResources"
- Свойства. Задайте значение CustomToolNamespace.
(например, "XXX" )
- Убедитесь, что модификатор доступа для ресурсов "Public". Добавить
ресурсов. Отредактируйте исходный код.
Обратитесь к ресурсам вашего кода.
как XXX.MyResources.ResourceName)
- Создание конфигураций для каждого варианта продукта ( "ConfigN" )
- Для каждого варианта продукта создайте папку ( "ВариантN" )
- Скопируйте и вставьте файл MyResources в каждую папку VariantN
- Выгрузите проект "Спутник" и отредактируйте файл .csproj.
- Для каждого тега "VariantN/MyResources"
<Compile>
или <EmbeddedResource>
добавьте атрибут Condition="'$(Configuration)' == 'ConfigN'"
.
- Сохранить, перезагрузить .csproj, и все готово...
Это создает файл ресурсов для каждой конфигурации, который (предположительно) может быть локализован. Компилировать сообщения об ошибках создаются для любой конфигурации, где отсутствует ресурс. Файлы ресурсов могут быть локализованы с использованием стандартного метода (создайте второй файл ресурсов (MyResources.fr.resx) и отредактируйте .csproj, как и раньше).
Причина, по которой это решение составляет 95%, заключается в том, что ресурсы, используемые для инициализации форм (например, титры форм, тексты кнопок), не могут быть легко обработаны одинаково - самый простой подход заключается в том, чтобы переписать их значениями из спутниковая сборка.
Ответы
Ответ 1
Вы можете добавить условные обозначения к элементам в файле MSBuild. Например, если у вас есть ресурсы "Отладка" и ресурсы "Отпустить", вы можете разместить их в двух отдельных папках (например, 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), я бы предложил иметь файл Resource1.resx(плюс связанный файл cs) на верхнем уровне проекта, а не в управления источником. В качестве события предварительной сборки скопируйте требуемый файл .resx из каталога Debug или Release, если это необходимо. (В этой ситуации вы, вероятно, захотите заставить его не компилировать файлы .Designer.cs в подкаталогах.
Изменить
Забыл упомянуть (хотя он был замечен в вышеприведенной отрывке из файла MSBuild), что вы должны установить пространство имен пользовательских инструментов в каждом файле .resx на одно и то же значение (например, ресурсы), в противном случае оно также по умолчанию включает в себя папку имя.
Изменить 2
В ответ на запрос о проверке того, что каждый файл ресурсов содержит одни и те же ресурсы. Если вы используете класс Resource (например, Resource.Resource1.MyFirstStringResource) для доступа к вашим ресурсам, то при переключении конфигураций будут возникать ошибки сборки, если требуется ресурса не существует, поэтому вы найдете это довольно быстро.
Для действительно параноидального (т.е. если ваш процесс сборки занимает 3 дня, чтобы построить все конфигурации или что-то такое же безумное), в конце дня .resx файлы - это просто файлы XML - вам просто нужно что-то проверить, чтобы каждый .resx с тем же именем файла содержит такое же количество <data> элементы с одинаковыми атрибутами имени.
Ответ 2
Вот мое решение. Первоначальная проблема заключалась в том, что Autodesk выпускает все DLL файлы AutoCAD с чем-то другим и разрывает совместимость каждые 3 года. Но наш код на самом деле тот же. Это была болезненная точка в способе разработки TFS-TFSbuild-DomainControllerInstallationOfApps.
Решение выглядит следующим образом:
- Сделайте проект MOTHER со всей структурой и, скажем, ссылки для AutoCAD 2012.
- Затем создайте второй проект для AutoCAD 2013 в том же решении и обратитесь к его собственным DLLS.
- Теперь вам нужно установить один символ компиляции для каждого проекта - acad2012 в первом проекте и acad2013 для второго.
- Затем в проекте 2013 года перейдите к "Добавить существующий элемент" и укажите источники проекта 2012 года, но затем нажмите "Ключ" справа от кнопки "Добавить" и укажите "Добавить как ссылку"
- Если есть какие-либо расхождения в библиотеках между 2012 и 2013 годами, вы можете окружить их
#if acad2012 #endif or #if acad2013 #endif
Таким образом, вы будете иметь только один исходный код для поддержки и иметь отдельные компилируемые модули:)
UPDATE
Мне нужно создать несколько продуктов/инсталляторов, все с похожими функциями, которые построены из одного и того же набора сборок, но отличаются набором ресурсов, используемым одной из сборок. Какой лучший способ сделать это?
-
Настройка проектов установщиков. Это именно то, что мы делаем и именно то, что вам нужно. После шага 5 вы должны создать два проекта установки. Я имею в виду проекты Windows Installer Xml или проекты WiX Допустим, что первый - для 2012 года и один для 2013 года. Следующая проблема заключается в генерации XML файлов которые содержат все компоненты для сборки. Я использую набор инструментов WiX со следующим script:
heat.exe dir "$ (TargetDir)" -cg MyAppComponents -dr INSTALLFOLDER -sfrag -srd -var "var.FilesPath" -out ".\MyAppComponents.wxs"
Этот script создает файлы MyAppComponents.wxs со всеми необходимыми файлами. Если вы хотите познакомиться с Wix, возьмите эту книгу: "WiX 3.6: Руководство разработчика для Windows Installer XML". Я сделал все необходимое после прочтения.
- Добавьте MyAppComponents.wxs в свой основной проект установщика напрямую (пусть это будет в 2012 году) и в любом другом проекте "Добавить как ссылку" (пусть это будет для dll 2013 года). Если вы выполнили инструкции на шаге 5, то ваша сборка script уже сделана для компиляции с различными версиями сборок зависимостей. Вы хотите, чтобы один исходный код был скомпилирован с двумя разными зависимостями? Таким образом, у вас есть это - один .wxs, который содержит все и внутри файлов .cs, у вас есть прагмы, которые ведут компиляцию.
Теперь, когда вы добавляете новый файл в свое решение, вам нужно добавить его в свой проект "Мать", затем "добавить в качестве ссылки" в другие проекты и добавить регистрацию компонента в .wxs только в одном месте, чтобы распространить его во всех установщиках.
С помощью script с шага 6 у вас будут все ваши DLL-версии с версиями внутри одного .wxs, что означает, что они будут скомпилированы в один установщик. Конечно, вы можете сделать несколько разных инсталляторов для всех своих версий, но в конечном итоге проще сделать один единственный установщик и решить во время установки, какую версию .dll скопировать на диск или решить runtime.dll для загрузки в Память. Я решил решить время выполнения, и он отлично работает для меня.
- После того, как вы подготовили две готовые проекты, вы можете использовать TFS Build для интеграции. Вы можете сделать еще один шаг и добавить обфускатор, такой как Smart Assembly, в ваш процесс сборки, чтобы в конце у вас было два или более отдельных установщика с отдельно построенными dll на разных зависимых библиотеках, которые содержат обфусканные сборки.
Все, что описано выше, прямо из траншей, и оно работает. Если бы я не изложил все шаги, просто отправьте мне сообщение, чтобы прояснить их и подробнее продолжить.
Я перешел от конфигураций сборки из-за слишком большого количества IFs и условий в них, которые будут накапливаться со временем, когда появится еще одна DLL Autodesk. Я не очень уверен в этом. Возможно, это решение, но вы должны быть уверены, что делаете, чтобы не тормозить сборку TFS, если это требуется.
Ответ 3
Ваш подход - использование нескольких отдельных проектов только для ресурсов (и сборок) - является звуковым и типично для локализованных приложений, и в других сценариях. Вам нужно знать некоторые проблемы с пространством имен и областью видимости - VS2005 всегда генерирует типы ресурсов как внутренние (или Friend in 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.
Для этого в Google используйте "локализацию" и "Спутниковые сборки".
Ответ 4
Это то, что вы ищете для нескольких конфигураций? Взгляните на: Конфигурации сборки