.NET 구성 (app.config / web.config / settings.settings)


162

디버그 및 릴리스 빌드에 대해 다른 구성 파일이있는 .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 파일에서 설정을 가져 오는 것처럼 보이므로 Visual Studio에서 settings.settings를 열어야 설정이 변경되었다는 메시지가 표시되어 변경 사항을 수락하고 설정을 저장하고 설정을 저장합니다. 올바른 설정을 사용하도록 다시 빌드하십시오.

비슷한 효과를 얻는 데 더 나은 / 권장 / 선호하는 방법이 있습니까? 또는 이와 똑같이 내가 완전히 잘못 접근했으며 더 나은 접근 방식이 있습니까?


Windows에서 디버그를 비활성화하려면 디버그 설정에서 모든 확인란의 선택을 취소하여 시도했지만 여전히 bin 릴리스 exe를 디버깅 할 수 있습니다. 누구나 도와주세요.
Vinoth Narayan

답변:


62

환경에 따라 다를 수있는 구성 은 응용 프로그램 수준이 아닌 시스템 수준 에서 저장해야합니다 . (구성 수준에 대한 자세한 정보)

다음은 일반적으로 컴퓨터 수준에서 저장하는 종류의 구성 요소입니다.

각 환경 (개발자, 통합, 테스트, 스테이지, 라이브)에 c : \ Windows \ Microsoft.NET \ Framework64 \ v2.0.50727 \ CONFIG 디렉토리에 고유 한 설정이있는 경우 환경없이 응용 프로그램 코드 를 승격시킬 수 있습니다. 빌드 후 수정.

그리고 머신 레벨 CONFIG 디렉토리의 내용은 앱의 다른 저장소 또는 다른 폴더 구조에서 버전 제어됩니다. configSource의 지능적인 사용을 통해 .config 파일을보다 소스 제어하기 쉽게 만들 수 있습니다 .

저는 25 개 이상의 회사에서 200 개가 넘는 ASP.NET 응용 프로그램에서 7 년 동안이 일을 해왔습니다. (진정하려고 하지 말고 ,이 방법 이 효과가없는 상황을 본 적이 없다는 것을 알려 드리고자 합니다.)


3
웹 서버를 제어하지 않아서 머신 레벨 구성을 변경할 수없는 상황은 어떻습니까? 예를 들어 타사 웹 서버 또는 기업의 여러 부서간에 공유되는 웹 서버가 있습니다.
RationalGeek

1
작동하지 않습니다. 그러나 가상 머신, Amazon EC2 및 Dell의 400 달러 서버 시대에 공유 머신에서 실제로 심각한 일을하는 사람이 있습니까? 전혀 냉담하지 않으려 고 노력하십시오-공유 웹 서버에서 작업하는 경우 재평가해야한다고 생각합니다.
포트만

7
내부 사이트에서 작업 한 대부분의 회사는 하나의 서버에서 여러 응용 프로그램을 호스팅합니다. 회사 수준에서 재평가를 수행해야합니다.
MPritchard

앱이 모두 동일한 "환경"에있는 한 한 서버의 여러 애플리케이션이 좋습니다. 즉, App2의 DEV 인스턴스와 동일한 서버에서 App1의 LIVE 인스턴스를 원하지 않을 것입니다. 예를 들어 SMTP 설정은 모든 응용 프로그램에서 공유됩니다. 프로덕션 환경에서는 실제 메일 서버를 가리 킵니다. 개발시 디스크의 파일을 가리 킵니다.
포트만

7
이것이 효과가 있다는 것을 알고 있지만 배포를 자동화하려고 할 때 권장하는 것과는 반대입니다. 설정은 응용 프로그램마다 다르며 응용 프로그램과 함께 버전을 제어하고 함께 진화해야한다고 생각합니다. 기계 구성에 의존하면 변화가 일어나기 때문에 더 어려워집니다. 나는 함께 바뀌는 것들을 함께 유지하고 함께 배포하는 것을 좋아합니다. Dev에 새로운 설정을 추가하면 prod에 동등한 설정이 필요할 것입니다.
Miguel Madero 2014 년

52

이것은 Visual Studio (내 경우에는 Visual Studio 2008)의 Settings.settings 표에서 값을 편집하는 동안 Properties.settings 및 App.config : Properties 창에서 GenerateDefaultValueInCode 특성을 감시하는 일부 사람들에게 도움이 될 수 있습니다.

GenerateDefaultValueInCode를 True로 설정하면 (True가 여기에 기본값입니다!) 기본값은 EXE (또는 DLL)로 컴파일되며 일반 텍스트 편집기에서 파일을 열 때 파일에 포함 된 것을 찾을 수 있습니다.

콘솔 응용 프로그램을 작업 중이며 EXE로 기본값을 설정 한 경우 응용 프로그램은 항상 동일한 디렉토리에있는 구성 파일을 무시했습니다! 인터넷 전체에 악몽과 정보가 없습니다.


7
이것은 지난 주말에 나에게 일어난 일입니다. 내 앱이 app.config 파일을 무시하는 것처럼 보이는 이유를 알아 내려고 많은 머리카락을 뽑았습니다! 그것은 웹 서비스에 연결되어 있고 서비스 URL은 내 app.config에 있습니다. 나에게 알 수없는 것은 웹 참조를 만들 때 Settings.Settings 파일을 만들고 기본값을 코드에 하드 코딩했습니다. 마지막으로 설정 파일을 알아 내고 제거했을 때도 해당 기본값은 하드 코드에 남아 있고 exe에 포함되었습니다. 매우 절망! 이 게시물 덕분에 이제는 그 기능을 제거 할 수 있습니다
Mike K

+1이 답변은 매우 중요 합니다. 설정을 app.config 파일로 이동하려면 GenerateDefaultValueInCode 속성을 False (기본값은 True)로 설정하십시오.
Sabuncu

34

관련 질문이 있습니다.

빌드 프로세스 개선

구성 파일에는 설정을 무시하는 방법이 있습니다.

<appSettings file="Local.config">

두 개의 파일 (또는 그 이상)을 체크인하는 대신 기본 구성 파일 만 체크인 한 다음 각 대상 머신에서 해당 특정 머신에 대한 재정의가있는 appSettings 섹션과 함께 Local.config를 배치합니다.

구성 섹션을 사용하는 경우 다음과 같습니다.

configSource="Local.config"

물론 다른 컴퓨터에서 모든 Local.config 파일의 백업 복사본을 만들어 실제 솔루션의 일부가 아닌 다른 곳에서 확인하는 것이 좋습니다. 각 개발자는 Local.config 파일에 "무시"를 적용하여 체크인되지 않으므로 다른 사람의 파일을 덮어 씁니다.

(실제로 "Local.config"라고 부르지 않아도됩니다. 이것이 바로 제가 사용하는 것입니다)


14

내가 읽고있는 내용에서 빌드 프로세스에 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>


8

우리는 웹 배포 프로젝트를 사용했지만 이후 NAnt로 마이그레이션했습니다. 다른 설정 파일을 분기하고 복사하는 대신 현재 구성 값을 빌드 스크립트에 직접 포함시키고 xmlpoke 작업을 통해 구성 파일에 삽입합니다.

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

어느 경우 든 구성 파일은 원하는 개발자 값을 가질 수 있으며 프로덕션 시스템을 손상시키지 않고 개발자 환경에서 제대로 작동합니다. 우리는 개발자가 테스트 할 때 임의로 빌드 스크립트 변수를 변경할 가능성이 적다는 것을 발견했습니다. 따라서 실수로 잘못된 구성은 시도한 다른 기술보다 드물지만 프로세스의 초기에 각 var를 추가해야합니다. dev 값은 기본적으로 prod로 푸시되지 않습니다.


7

현재 고용주는 machine.config 파일에 개발자 수준 (디버그, 스테이지, 라이브 등)을 먼저 배치하여이 문제를 해결했습니다. 그런 다음 코드를 작성하여 올바른 구성 파일을 사용했습니다. 앱이 배포 된 후 잘못된 연결 문자열 문제가 해결되었습니다.

그들은 최근에 machine.config 값의 값에서 올바른 연결 문자열을 다시 보내는 중앙 웹 서비스를 작성했습니다.

이것이 최선의 해결책입니까? 아마 그렇지는 않지만 그것들을 위해 작동합니다.


1
실제로 나는 그것이 구성되어 있지 않더라도 솔루션 내에서 다양한 버전의 구성을 볼 수 있기를 원하기 때문에 꽤 훌륭하다고 생각합니다.
annakata

1
이것은 매우 흥미로운 솔루션입니다. 이 예제를 실제로 살펴보고 싶습니다.
Mike K

5

나에게 잘 맞는 솔루션 중 하나는 WebDeploymentProject를 사용하는 것이 었습니다. 내 사이트에 2/3 개의 다른 web.config 파일이 있었고 선택한 구성 모드 (릴리스 / 준비 / 등 ...)에 따라 게시 할 때 Web.Release.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>


3

우리 프로젝트에는 dev, qa, uat 및 prod에 대한 구성을 유지해야했던 것과 같은 문제가 있습니다. 다음은 우리가 따랐던 것입니다 (MSBuild에 익숙한 경우에만 해당).

MSBuild 커뮤니티 작업 확장과 함께 MSBuild를 사용하십시오. 여기에는 올바른 노드를 시작하면 XML 파일의 항목을 '대량 업데이트'할 수있는 'XmlMassUpdate'작업이 포함됩니다.

구현:

1) 당신의 dev env 엔트리를 가질 하나의 설정 파일이 필요합니다; 이것은 솔루션의 구성 파일입니다.

2) 각 환경에 대해 다른 항목 (주로 appSettings 및 ConnectionStrings) 만 포함하는 'Substitutions.xml'파일이 있어야합니다. 환경 전체에서 변경되지 않은 항목은이 파일에 넣을 필요가 없습니다. 그들은 솔루션의 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'로 바꿉니다. 당신은 건물입니다. 복구 할 수없는 실수를 피하기 위해 실제 구성 파일 자체가 아닌 구성 파일의 사본에서 작업해야합니다.

빌드 파일을 실행 한 다음 업데이트 된 구성 파일을 배포 환경으로 옮기면됩니다.

더 나은 개요를 보려면 다음을 읽으십시오.

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


2

당신도 마찬가지로 'multi'app.config를 설정했습니다-예를 들어 app.configDEV, app.configTEST, app.config.LOCAL. 나는 훌륭한 대안 중 몇 가지가 제안되었지만, 그것이 당신에게 맞는 방식을 원한다면 다음을 추가 할 것입니다.

내가 가지고있는
<appSettings>
<add key = "Env" value = "[Local] "/> 각각의 앱 내가 제목 표시 줄에있는 UI에 이것을 추가 ConfigurationManager.AppSettings.Get ( "봉투")에서;

구성의 이름을 내가 대상으로하는 이름으로 바꿉니다 (4 개의 짝수에 대해 많은 데이터베이스 / wcf 구성이있는 8 개의 앱이있는 프로젝트가 있습니다). clickonce를 사용하여 각 프로젝트에 배포하려면 프로젝트에서 4 가지 사항을 변경하고 진행하십시오. (이것은 자동화하고 싶습니다)

유일한 변경 사항은 수동 구성 이름을 바꾼 후에 이전 구성이 '고정'되었으므로 변경 후 '모두 정리'를 기억하는 것입니다. (설정 문제를 해결한다고 생각합니다. 설정 문제).

나는 이것이 실제로 잘 작동한다는 것을 알았습니다 (하루가 MSBuild / NAnt를 볼 시간이 생길 것입니다)


0

Web.config :

IIS에서 응용 프로그램을 호스팅하려는 경우 Web.config가 필요합니다. Web.config는 IIS에서 Kestrel 앞에서 리버스 프록시로 작동하는 방식을 구성하기위한 필수 구성 파일입니다. IIS에서 web.config를 호스팅하려면 web.config를 유지해야합니다.

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는 Windows Forms, Windows 서비스, 콘솔 앱 및 WPF 응용 프로그램에 주로 사용되는 .NET에서 사용하는 또 다른 구성 파일입니다. 콘솔 응용 프로그램을 통해 Asp.Net Core 호스팅을 시작하면 app.config도 사용됩니다.


TL; DR

구성 파일의 선택은 서비스에 대해 선택한 호스팅 환경에 따라 결정됩니다. IIS를 사용하여 서비스를 호스팅하는 경우 Web.config 파일을 사용하십시오. 다른 호스팅 환경을 사용하는 경우 App.config 파일을 사용하십시오. 구성 파일을 사용하여 서비스 구성 설명서를 참조 하고 ASP.NET Core에서 구성을 확인하십시오 .


0

위의 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
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.