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

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

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

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

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


person Gavin    schedule 25.09.2008    source источник
comment
Я хочу отключить отладку в окнах, я попытался снять все флажки в настройках отладки, но все же я мог отлаживать выпуск bin Release exe .. Кто-нибудь, помогите мне в этом ..   -  person Vinoth Narayan    schedule 07.05.2020


Ответы (13)


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

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

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

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

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

person Portman    schedule 07.01.2009
comment
Как насчет ситуации, когда вы не контролируете веб-сервер и, следовательно, не можете изменить конфигурацию на уровне машины? Примеры включают сторонний веб-сервер или веб-сервер, совместно используемый несколькими отделами предприятия. - person RationalGeek; 26.01.2010
comment
Не сработает. Но в эпоху виртуальных машин, Amazon EC2 и серверов Dell за 400 долларов, действительно ли кто-нибудь делает что-нибудь серьезное с общими машинами? Совершенно не пытаясь быть бессердечным - я действительно думаю, что если вы работаете на общем веб-сервере, вам следует переоценить. - person Portman; 27.01.2010
comment
Большинство корпораций, в которых я работал с внутренними сайтами, размещают несколько приложений на одном сервере - в этом случае необходимо будет провести повторную оценку на корпоративном уровне. - person MPritchard; 18.02.2010
comment
Несколько приложений на одном сервере - это нормально, если все приложения находятся в одной среде. То есть вам не нужен LIVE-экземпляр App1 на том же сервере, что и DEV-экземпляр App2. Например, ваши настройки SMTP будут общими для всех ваших приложений. В производственной среде вы указываете на настоящий почтовый сервер; в процессе разработки вы указываете файл на диске. - person Portman; 18.02.2010
comment
Я знаю, что это сработает, но это все еще противоречит тому, что я бы рекомендовал при попытке автоматизировать развертывание. Я думаю, что настройки зависят от приложения, они должны контролироваться версией вместе с приложением и развиваться вместе с ним. Если полагаться на конфигурацию машины, то она просто сдвигается, а, на мой взгляд, все усложняется. Мне нравится собирать вместе вещи, которые меняются, и использовать их вместе. Если я добавлю новый параметр для Dev, мне, вероятно, понадобится эквивалентный для prod. - person Miguel Madero; 30.03.2012
comment
на сегодняшний день, кроме настроек SMTP, все связанные теперь мертвы. Было бы здорово обновить. - person kmonsoor; 18.07.2016

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

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

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

person Roman    schedule 26.08.2009
comment
Именно это случилось со мной в минувшие выходные. Я вытащил много волос, пытаясь понять, почему мое приложение игнорирует мой файл app.config! Предполагается, что он подключен к веб-службе, а URL-адрес службы находится в моем app.config. Без моего ведома, когда я создал веб-ссылку, она также создала файл Settings.Settings И жестко запрограммировала значение по умолчанию в код. Даже когда я наконец выяснил (и удалил) файл настроек, это значение по умолчанию осталось в жестком коде и было встроено в exe. ОЧЕНЬ РАЗДРАЖАЕТ !! Благодаря этому сообщению теперь я могу избавиться от этой функции - person Mike K; 01.03.2010
comment
+1 Этот ответ является критическим: если вы хотите, чтобы ваши настройки попали в файл app.config, установите для его атрибута GenerateDefaultValueInCode значение False (по умолчанию - True). - person Sabuncu; 21.06.2013

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

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

В файлах конфигурации есть возможность переопределить настройки:

<appSettings file="Local.config">

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

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

configSource="Local.config"

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

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

person Eric Z Beard    schedule 25.09.2008

Из того, что я читаю, похоже, что вы используете 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>
person Steven Williams    schedule 25.09.2008


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

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

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

person jasondoucette    schedule 25.09.2008

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

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

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

person Hector Sosa Jr    schedule 25.09.2008
comment
На самом деле я думаю, что это чертовски элегантно, так как мне нравится, чтобы различные версии конфигурации были видны в решении, даже если они не работают. - person annakata; 12.01.2009
comment
Это очень интригующее решение. Хотел бы посмотреть на пример этого в действии. - person Mike K; 01.03.2010

Одно из решений, которое меня отлично сработало, заключалось в использовании WebDeploymentProject. У меня было 2/3 разных файла web.config на моем сайте, и при публикации, в зависимости от выбранного режима конфигурации (выпуск / постановка / и т. Д.), Я копировал через Web.Release.config и переименовывал его в web. 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>
person Adam Vigh    schedule 25.09.2008

Здесь вы найдете другое решение: Лучший способ для переключения конфигурации между средами разработки / UAT / Prod в ASP.NET?, который использует XSLT для преобразования файла web.config.

Есть также несколько хороших примеров использования NAnt.

person Aaron Powell    schedule 25.09.2008

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

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

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

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

2) Вам нужен файл Substitutions.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 < / а>

person Punit Vora    schedule 18.06.2009

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

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

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

Моя единственная проблема - не забыть «очистить все» после изменения, поскольку старая конфигурация «застревает» после ручного переименования. (Что, я думаю, исправит проблему с настройками).

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

person Tony Trembath-Drake    schedule 26.02.2009

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.

person Alper Ebicoglu    schedule 10.09.2018

Выше указано 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
    }
}
person Prisoner ZERO    schedule 24.05.2011