Конфигурация .NET(app.config/web.config/settings.settings)

У меня есть приложение .NET, которое имеет разные файлы конфигурации для сборки Debug и Release. Например. файл debug app.config указывает на развитие SQL Server, в котором включена отладка, а цель релиза - на Live SQL Server. Существуют и другие настройки, некоторые из которых отличаются от debug/release.

В настоящее время я использую два отдельных файла конфигурации (debug.app.config и release.app.config). У меня есть событие сборки проекта, в котором говорится, что если это сборка релиза, тогда скопируйте файл release.app.config в app.config, иначе скопируйте файл debug.app.config в app.config.

Проблема заключается в том, что приложение, похоже, получает свои настройки из файла settings.settings, поэтому мне нужно открыть settings.settings в Visual Studio, который затем подскажет мне, что настройки изменились, поэтому я принимаю изменения и сохраняю настройки. настройки и должны быть восстановлены, чтобы использовать правильные настройки.

Есть ли лучший/рекомендуемый/предпочтительный метод для достижения подобного эффекта? Или, в равной степени, я подошел к этому совершенно неправильно и есть лучший подход?

Ответ 1

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

Это типы элементов конфигурации, которые я обычно храню на уровне компьютера:

Если каждая среда (разработчик, интеграция, тестирование, сценарий, рабочая среда) имеет свои уникальные настройки в каталоге c:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG, вы можете продвигать свою код приложения между средами без каких-либо модификаций после сборки.

И очевидно, что содержимое каталога CONFIG на уровне машины получает управление версиями в другом хранилище или структуре папок, отличной от вашего приложения. Вы можете сделать ваши файлы .config более удобными для контроля исходного кода благодаря интеллектуальному использованию configSource.

Я занимаюсь этим уже 7 лет на более чем 200 приложениях ASP.NET в 25+ разных компаниях. (Не пытаясь похвастаться, просто хочу сообщить, что я никогда не видел ситуации, когда этот подход не работает.)

Ответ 2

Это может помочь некоторым людям, имеющим дело с Settings.settings и App.config: обратите внимание на атрибут GenerateDefaultValueInCode на панели свойств при редактировании любого из значений в сетке Settings.settings в Visual Studio (Visual Studio 2008 в моем случае).

Если вы установите для GenerateDefaultValueInCode значение True (True здесь по умолчанию!), Значение по умолчанию компилируется в EXE (или DLL), вы можете найти его встроенным в файл, когда открываете его в текстовом редакторе.

Я работал над консольным приложением, и, если я по умолчанию установил EXE файл, приложение всегда игнорировало файл конфигурации, находящийся в том же каталоге! Совсем кошмар и никакой информации об этом по всему интернету.

Ответ 3

Здесь есть связанный с этим вопрос:

Улучшение процесса сборки

Конфигурационные файлы имеют способ переопределить настройки:

<appSettings file="Local.config">

Вместо того, чтобы проверять два файла (или больше), вы проверяете только файл конфигурации по умолчанию, а затем на каждом целевом компьютере вы помещаете файл Local.config с помощью только секции appSettings, которая имеет переопределения для этой конкретной машины.

Если вы используете разделы конфигурации, эквивалент:

configSource="Local.config"

Конечно, рекомендуется создавать резервные копии всех файлов Local.config с других компьютеров и проверять их где-то, но не как часть реальных решений. Каждый разработчик помещает "игнорировать" в файл Local.config, чтобы он не попадал в него, что бы перезаписать все остальные файлы.

(На самом деле вам не нужно называть его "Local.config", это то, что я использую)

Ответ 4

Из того, что я читаю, похоже, что вы используете Visual Studio для своего процесса сборки. Вы думали об использовании MSBuild и Nant вместо этого?

Синтаксис Nant xml немного странный, но как только вы это понимаете, выполнение того, что вы упомянули, становится довольно тривиальным.

<target name="build">
    <property name="config.type" value="Release" />

    <msbuild project="${filename}" target="Build" verbose="true" failonerror="true">
        <property name="Configuration" value="${config.type}" />
    </msbuild>

    <if test="${config.type == 'Debug'}">
        <copy file=${debug.app.config}" tofile="${app.config}" />
    </if>

    <if test="${config.type == 'Release'}">
        <copy file=${release.app.config}" tofile="${app.config}" />
    </if>

</target>

Ответ 5

Мне кажется, что вы можете воспользоваться проектом Visual Studio 2005 для веб-развертывания.

С этим вы можете сообщить об этом, чтобы обновить/изменить разделы вашего файла web.config в зависимости от конфигурации сборки.

Взгляните на эту запись в блоге от Scott Gu для быстрого обзора/примера.

Ответ 6

Раньше мы использовали проекты веб-развертывания, но с тех пор перенаправлялись в NAnt. Вместо того, чтобы разворачивать и копировать разные файлы настроек, мы вставляем значения конфигурации непосредственно в сборку script и внедряем их в наши файлы конфигурации с помощью задач xmlpoke:

  <xmlpoke
    file="${stagingTarget}/web.config"
    xpath="/configuration/system.web/compilation/@debug"
    value="true"
  />

В любом случае ваши файлы конфигурации могут обладать любыми необходимыми значениями разработчика, и они отлично справятся с вашей средой разработки без нарушения ваших производственных систем. Мы обнаружили, что разработчики с меньшей вероятностью произвольно изменяют переменные build script при тестировании, поэтому случайные неправильные конфигурации были реже, чем с другими методами, которые мы пробовали, хотя по-прежнему необходимо добавить каждый var в начале процесса так что значение dev не может быть нажато на prod по умолчанию.

Ответ 7

Мой нынешний работодатель решил эту проблему, предварительно поставив уровень dev (debug, stage, live и т.д.) в файл machine.config. Затем они написали код, чтобы выбрать его и использовать правильный файл конфигурации. Это решило проблему с неправильной строкой соединения после развертывания приложения.

Они только недавно написали центральный веб-сервис, который отправляет правильную строку соединения из значения в значение machine.config.

Это лучшее решение? Наверное, нет, но это работает для них.

Ответ 8

Одним из решений, которые отлично меня работали, является использование WebDeploymentProject. У меня было 2/3 различных файла web.config на моем сайте и в публикации, в зависимости от выбранного режима конфигурации (release/постановка/etc...) я бы скопировал через Web.Release.config и переименовал его в веб. config в событии AfterBuild и удалить те, которые мне не нужны (например, Web.Staging.config).

<Target Name="AfterBuild">
    <!--Web.config -->
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Release.config" DestinationFiles="$(OutputPath)\Web.config" />
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Staging|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Staging.config" DestinationFiles="$(OutputPath)\Web.config" />
    <!--Delete extra files -->
    <Delete Files="$(OutputPath)\Web.Release.config" />
    <Delete Files="$(OutputPath)\Web.Staging.config" />
    <Delete Files="@(ProjFiles)" />
  </Target>

Ответ 10

В нашем проекте есть та же проблема, где нам приходилось поддерживать конфиги для dev, qa, uat и prod. Вот что мы следовали (применимо, только если вы знакомы с MSBuild):

Используйте MSBuild с расширением задач MSBuild Community. Он включает в себя задачу "XmlMassUpdate", которая может "массово обновлять" записи в любом XML файле, как только вы дадите ему правильный узел для запуска.

Для реализации:

1) У вас должен быть один конфигурационный файл, в котором будут ваши записи dev env; это файл конфигурации в вашем решении.

2) У вас должен быть файл Substitutiontions.xml, который содержит только записи, РАЗЛИЧНЫЕ (в основном appSettings и ConnectionStrings) для каждой среды. Записи, которые не изменяются в среде, не нужно помещать в этот файл. Они могут находиться в файле решения web.config и не будут затронуты задачей

3) В своем файле сборки просто вызовите задачу массового обновления XML и укажите подходящую среду в качестве параметра.

Смотрите пример ниже:

    <!-- Actual Config File -->
    <appSettings>
        <add key="ApplicationName" value="NameInDev"/>
        <add key="ThisDoesNotChange" value="Do not put in substitution file" />
    </appSettings>

    <!-- Substitutions.xml -->
    <configuration xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
      <substitutions>
        <QA>
           <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInQA"/>
           </appSettings>            
        </QA>
        <Prod>
          <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInProd"/>
          </appSettings>            
        </Prod>
     </substitutions>
    </configuration>


<!-- Build.xml file-->

    <Target Name="UpdateConfigSections">
            <XmlMassUpdate ContentFile="Path\of\copy\of\latest web.config" SubstitutionsFile="path\of\substitutionFile" ContentRoot="/configuration" SubstitutionsRoot="/configuration/substitutions/$(Environment)" />
        </Target>

замените '$ Environment' на 'QA' или 'Prod' в зависимости от того, что env. Вы строите для. Обратите внимание, что вы должны работать с копией файла конфигурации, а не с самим файлом конфигурации, чтобы избежать возможных ошибок, которые невозможно исправить.

Просто запустите файл сборки, а затем переместите обновленный файл конфигурации в среду развертывания, и все готово!

Для лучшего обзора прочитайте это:

http://blogs.microsoft.co.il/blogs/dorony/archive/2008/01/18/easy-configuration-deployment-with-msbuild-and-the-xmlmassupdate-task.aspx

Ответ 11

Как и вы, я также установил "multi" app.config - например, app.configDEV, app.configTEST, app.config.LOCAL. Я вижу некоторые из предложенных отличных альтернатив, но если вам нравится, как это работает для вас, я бы добавил следующее:

У меня есть
  <appSettings>
      <add key = "Env" value = "[Local] "/> для каждого приложения я добавляю это в пользовательский интерфейс в заголовке: из ConfigurationManager.AppSettings.Get("Env");

Я просто переименую конфигурацию в ту, на которую нацеливаюсь (у меня есть проект с 8 приложениями с большим количеством конфигурации базы данных /wcf против 4 событий). Для развертывания с помощью clickonce в каждом я меняю 4 варианта в проекте и перехожу. (это я бы хотел автоматизировать)

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

Я считаю, что это работает очень хорошо (однажды у меня будет время взглянуть на MSBuild/NAnt)

Ответ 12

Выше написано asp.net, так почему бы не сохранить настройки в базе данных и использовать пользовательский кеш для их получения?

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

Пример пользовательского кэша:

public enum ConfigurationSection
{
    AppSettings
}

public static class Utility
{
    #region "Common.Configuration.Configurations"

    private static Cache cache = System.Web.HttpRuntime.Cache;

    public static String GetAppSetting(String key)
    {
        return GetConfigurationValue(ConfigurationSection.AppSettings, key);
    }

    public static String GetConfigurationValue(ConfigurationSection section, String key)
    {
        Configurations config = null;

        if (!cache.TryGetItemFromCache<Configurations>(out config))
        {
            config = new Configurations();
            config.List(SNCLavalin.US.Common.Enumerations.ConfigurationSection.AppSettings);
            cache.AddToCache<Configurations>(config, DateTime.Now.AddMinutes(15));
        }

        var result = (from record in config
                      where record.Key == key
                      select record).FirstOrDefault();

        return (result == null) ? null : result.Value;
    }

    #endregion
}

namespace Common.Configuration
{
    public class Configurations : List<Configuration>
    {
        #region CONSTRUCTORS

        public Configurations() : base()
        {
            initialize();
        }
        public Configurations(int capacity) : base(capacity)
        {
            initialize();
        }
        public Configurations(IEnumerable<Configuration> collection) : base(collection)
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud; // Db-Access layer

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
        }

        /// <summary>
        /// Lists one-to-many records.
        /// </summary>
        public Configurations List(ConfigurationSection section)
        {
            using (DbCommand dbCommand = _crud.Db.GetStoredProcCommand("spa_LIST_MyConfiguration"))
            {
                _crud.Db.AddInParameter(dbCommand, "@Section", DbType.String, section.ToString());

                _crud.List(dbCommand, PopulateFrom);
            }

            return this;
        }

        public void PopulateFrom(DataTable table)
        {
            this.Clear();

            foreach (DataRow row in table.Rows)
            {
                Configuration instance = new Configuration();
                instance.PopulateFrom(row);
                this.Add(instance);
            }
        }

        #endregion
    }

    public class Configuration
    {
        #region CONSTRUCTORS

        public Configuration()
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud;

        public string Section { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
            Clear();
        }

        public void Clear()
        {
            this.Section = "";
            this.Key = "";
            this.Value = "";
        }
        public void PopulateFrom(DataRow row)
        {
            Clear();

            this.Section = row["Section"].ToString();
            this.Key = row["Key"].ToString();
            this.Value = row["Value"].ToString();
        }

        #endregion
    }
}

Ответ 13

Web.config:

Web.config необходим, если вы хотите разместить свое приложение на IIS. Web.config - это обязательный файл конфигурации для IIS, позволяющий настроить его поведение в качестве обратного прокси-сервера перед Kestrel. Вы должны поддерживать web.config, если хотите разместить его в IIS.

AppSetting.json:

Для всего остального, что не касается IIS, вы используете AppSetting.json. AppSetting.json используется для хостинга Asp.Net Core. ASP.NET Core использует переменную среды "ASPNETCORE_ENVIRONMENT" для определения текущей среды. По умолчанию, если вы запускаете свое приложение без установки этого значения, оно автоматически будет по умолчанию настроено на рабочую среду и использует файл "AppSetting.production.json". Когда вы отлаживаете через Visual Studio, он устанавливает среду разработки, поэтому он использует "AppSetting.json". Посетите этот веб-сайт, чтобы понять, как установить переменную среды хостинга в Windows.

App.config:

App.config - это еще один файл конфигурации, используемый .NET, который в основном используется для Windows Forms, служб Windows, консольных приложений и приложений WPF. При запуске хостинга Asp.Net Core через консольное приложение также используется app.config.


TL; DR

Выбор файла конфигурации определяется средой хостинга, которую вы выбираете для данной услуги. Если вы используете IIS для размещения своей службы, используйте файл Web.config. Если вы используете любую другую среду размещения, используйте файл App.config. См. Настройка служб с использованием файлов конфигурации.  а также проверьте конфигурацию в ASP.NET Core.