2008-10-01 6 views
22

ConfigurationManager.AppSettings [ "mysettingkey"]을 사용하여 실제로 설정을 가져 오는 앱을 가져갈 수있는 방법을 실제로 갖고 싶다면 app.config 파일 대신 중앙 데이터베이스에서 가져온 설정을 실제로 가져야합니다. 이런 종류의 일을 처리하기 위해 사용자 지정 구성 섹션을 만들 수 있지만, 내 팀의 다른 개발자가 새 DbConfiguration 사용자 지정 섹션을 사용하도록 코드를 변경해야하는 것은 정말로 원하지 않습니다. AppSettings를 항상 가지고있는 방식으로 호출 할 수 있지만 중앙 데이터베이스에서로드되도록 할 수 있습니다.ConfigurationManager.AppSettings를 재정의 할 수있는 방법이 있습니까?

아이디어가 있으십니까?

답변

22

프레임 워크를 해킹하는 데 신경 쓰지 않고 응용 프로그램이 실행되는 .net 프레임 워크 버전 (예 : 웹 응용 프로그램 또는 인트라넷 응용 프로그램)을 가정하면 다음과 같이 시도 할 수 있습니다.

using System; 
using System.Collections.Specialized; 
using System.Configuration; 
using System.Configuration.Internal; 
using System.Reflection; 

static class ConfigOverrideTest 
{ 
    sealed class ConfigProxy:IInternalConfigSystem 
    { 
    readonly IInternalConfigSystem baseconf; 

    public ConfigProxy(IInternalConfigSystem baseconf) 
    { 
     this.baseconf = baseconf; 
    } 

    object appsettings; 
    public object GetSection(string configKey) 
    { 
     if(configKey == "appSettings" && this.appsettings != null) return this.appsettings; 
     object o = baseconf.GetSection(configKey); 
     if(configKey == "appSettings" && o is NameValueCollection) 
     { 
     // create a new collection because the underlying collection is read-only 
     var cfg = new NameValueCollection((NameValueCollection)o); 
     // add or replace your settings 
     cfg["test"] = "Hello world"; 
     o = this.appsettings = cfg; 
     } 
     return o; 
    } 

    public void RefreshConfig(string sectionName) 
    { 
     if(sectionName == "appSettings") appsettings = null; 
     baseconf.RefreshConfig(sectionName); 
    } 

    public bool SupportsUserConfig 
    { 
     get { return baseconf.SupportsUserConfig; } 
    } 
    } 

    static void Main() 
    { 
    // initialize the ConfigurationManager 
    object o = ConfigurationManager.AppSettings; 
    // hack your proxy IInternalConfigSystem into the ConfigurationManager 
    FieldInfo s_configSystem = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic); 
    s_configSystem.SetValue(null, new ConfigProxy((IInternalConfigSystem)s_configSystem.GetValue(null))); 
    // test it 
    Console.WriteLine(ConfigurationManager.AppSettings["test"] == "Hello world" ? "Success!" : "Failure!"); 
    } 
} 
+6

사적인 반사 ... 매우 장난 꾸러기. –

+0

.net 프레임 워크 버전은 위의 예와 특별히 관련이 있습니까? 즉 .... 내가 비슷한 예제를 시도하고 있지만 SetValue 값을 설정하는 것, 결국 구성 설정을 검색하려고하면 실패합니다 - 그래서, 어떤 경우 위의 코드가 작동하지 않을 수 있습니다? 감사합니다. –

+2

's_configSystem' 비공개 필드는'ConfigurationManager'의 구현 세부 사항이며, 향후 프레임 워크 릴리스에서 변경 될 수도 있고 전혀 존재하지 않을 수도 있습니다 (예 : mono는 [configSystem] (https : // github. co.kr/mono/mono/blob/effa4c07ba850bedbe1ff54b2a5df281c058ebcb/mcs/class/System.Configuration/System.Configuration/ConfigurationManager.cs # L48)를 사용하십시오. –

0

확실하지는 않지만 응용 프로그램 시작시 AppSettings의 Add 메서드를 사용하여 DB 설정을 추가 할 수 있습니다.

1

리디렉션의 한 계층을 추가해야합니까? ConfigurationManager.AppSettings [ "key"]는 항상 구성 파일을 조사합니다. 당신은 ConfigurationFromDatabaseManager을 할 수 있지만 다른 호출 구문을 사용하여 발생합니다 :

ConfigurationFromDatabaseManager.AppSettings["key"] instead of ConfigurationSettings["key"]. 
+2

내가 질문에 대한 이유가 전부입니다 기존의 사용을 오버라이드 (override) 할 필요가 생각 코드를 통해 광범위한 코드 기반 변경의 필요성을 제거합니다. 하지만 잘못 될 수 있습니다. –

+1

그러나 Azure 포털을 통해 응용 프로그램 설정을 지정할 수있는 Azure 웹 응용 프로그램을 만들지 않는 한이 솔루션 만 존재합니다. –

-1

그것은이 Machine.config의 appSettings는 정의 섹션의에 AllowOverride 속성을 설정하여 .NET 3.5이에서 할 수있는 방법이 나타납니다. 이렇게하면 자신의 app.config 파일에서 전체 섹션을 무시하고이를 처리 할 새 유형을 지정할 수 있습니다.

+3

나는 이것이 질문의 요점을 놓쳤다 고 생각한다. 필자가 읽은 것은 app.config를 사용하여 app.config를 재정의하는 것이 아니라 app.config를 사용하여 machine.config를 재정의하는 방법입니다. –

0

나는 응용 프로그램 시작을 작성하고 데이터베이스의 설정을 응용 프로그램 도메인에로드하려고합니다. 따라서 앱은 구성이 어떻게 생성되는지에 대해 아무 것도 모릅니다. machiene.config를 사용하면 dll-hell 2.0으로 바로 이어집니다. 당신이 당신에게 디스크에 수정 된 설정 파일을 저장할 수있는 경우

+0

당신이 말하는이 어플리케이션 스타터 란 무엇입니까? –

0

- 당신은 다른 응용 프로그램 도메인에서 다른 설정 파일을로드 할 수

AppDomain.CreateDomain("second", null, new AppDomainSetup 
{ 
    ConfigurationFile = options.ConfigPath, 
}).DoCallBack(...);