C # DLL 구성 파일


191

app.config 파일을 DLL에 추가하려고 시도했지만 모든 시도가 실패했습니다.

' DLL에 구성 정보 넣기 '의 MusicGenesis에 따르면 이것은 문제가되지 않습니다. 분명히 나는 ​​뭔가 잘못하고 있습니다 ...

다음 코드는 DLL에서 ConnectionString을 반환해야합니다.

return ConfigurationManager.AppSettings["ConnectionString"];

그러나 app.config 파일을 콘솔 응용 프로그램에 복사하면 정상적으로 작동합니다.

어떤 아이디어?


참조 된 게시물에 따르면 : dll 이름이 MyDll.dll 인 경우 구성 파일은 MyDLL.dll.config이어야합니다. 따라서 dll 내에서 구성 설정을 읽으면 자체 구성 권한을 참조해야합니까?
MegaByte

11
어떤 코드를 요구하든 상관 없습니다. AppDomain에 지정된 파일을 찾습니다 : AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 설정
Marc Gravell

참고 : "DLL에 구성 정보 입력"질문은 앱의 구성 코드를 라이브러리로 분리하여 기본 앱 코드와 분리되도록하는 것입니다. 이것은 DLL 자체를위한 별도의 구성 파일과는 매우 다릅니다.
Chris Ammerman

이 게시물을 참조 [1] [여기 링크 설명을 입력, 나를위한 솔루션이되었다 [1] : stackoverflow.com/questions/2389290/...은
dhailis

이 게시물 참조 [별도의 Application Settings 파일을 동적으로로드하고 현재 설정과 병합하는 방법?] [1] helpfu [1] : stackoverflow.com/questions/2389290/…
dhailis

답변:


277

.DLL에 대한 .NET 구성 파일을 작성하는 것은 쉬운 일이 아닙니다. .NET 구성 메커니즘에는 앱을 쉽게 업그레이드 / 업데이트하고 설치된 앱이 서로 구성 파일을 짓밟 지 않도록 보호하기 위해 많은 기능이 내장되어 있습니다.

DLL 사용 방법과 응용 프로그램 사용 방법에는 큰 차이가 있습니다. 동일한 사용자에 대해 동일한 시스템에 여러 응용 프로그램 사본이 설치되어 있지 않을 수 있습니다. 그러나 일부 .NET DLL을 사용하는 100 개의 서로 다른 앱이나 라이브러리가있을 수 있습니다.

하나 개의 사용자 프로파일 내 응용 프로그램의 다른 복사본을 별도로 설정을 추적 할 필요가 거의 없다 반면, 그건 아주 당신이 서로 공유 구성에 DLL의 다른 사용법을 모두 원하는 것 같지는. 이러한 이유로 "일반"방법을 사용하여 Configuration 개체를 검색하면 반환 한 개체가 특정 어셈블리가 아닌 실행중인 App Domain의 구성에 연결됩니다.

앱 도메인은 코드가 실제로있는 어셈블리를로드 한 루트 어셈블리에 바인딩됩니다. 대부분의 경우 이는 .DLL을로드 한 기본 .EXE 어셈블리입니다. 응용 프로그램 내에서 다른 응용 프로그램 도메인을 스핀 업할 수 있지만 해당 응용 프로그램 도메인의 루트 어셈블리에 대한 정보를 명시 적으로 제공해야합니다.

이 때문에 라이브러리 특정 구성 파일을 작성하는 절차는 그리 편리하지 않습니다. 그것은 당신이 특정 어셈블리에 연결되지 않은 임의의 휴대용 설정 파일을 만드는 데 사용하는 것과 같은 과정이지만있는 당신은 부와 구성 요소 메커니즘 등 생성이 수반 구성, .NET의 XML 스키마를 사용하려는 ExeConfigurationFileMap객체를 구성 파일을 저장할 위치를 식별하기 위해 데이터를로드 한 다음을 호출 ConfigurationManager합니다. OpenMappedExeConfigurationConfiguration인스턴스 로 엽니 다 . 이 것입니다 자동 경로 생성 메커니즘에 의해 제공되는 버전의 보호에서 당신을 잘라.

통계적으로 말하면, 사내 환경에서이 라이브러리를 사용하고있을 것이므로 한 컴퓨터 / 사용자 내에서 여러 앱을 사용하지는 않을 것입니다. 그러나 그렇지 않은 경우 명심해야 할 것이 있습니다. 참조하는 앱에 관계없이 DLL에 단일 전역 구성 파일을 사용하는 경우 액세스 충돌에 대해 걱정해야합니다. 라이브러리를 참조하는 두 개의 앱이 각각 자체 Configuration개체가 열린 상태 에서 동시에 실행되는 경우 변경 사항을 저장하면 다음에 다른 앱에서 데이터를 검색하거나 저장하려고 할 때 예외가 발생합니다.

이 문제를 해결하는 가장 안전하고 간단한 방법은 DLL을로드하는 어셈블리도 자체에 대한 정보를 제공하거나 참조 어셈블리의 App Domain을 검사하여 감지하는 것입니다. 이를 사용하여 DLL을 참조하는 각 앱에 대해 별도의 사용자 구성 파일을 유지하기위한 일종의 폴더 구조를 만듭니다.

당신이 경우 특정 당신이 참조하는 위치에 상관없이 당신의 DLL에 대한 전역 설정이없는하려면, 당신은 그것을위한 당신의 위치를 결정하지 않고 .NET보다는 자동으로 적절한 일을 파악해야합니다. 또한 파일에 대한 액세스 관리에 적극적이어야합니다. Configuration인스턴스를로드하거나 저장하는 동안 인스턴스를 유지하고 가능한 한 많이 캐시해야합니다. 바로 앞을 열고 즉시 버립니다. 마지막으로 라이브러리를 사용하는 앱 중 하나에서 파일을 편집하는 동안 파일을 보호하려면 잠금 메커니즘이 필요합니다.


동기화 메커니즘은 프로세스 간이기 때문에 "명명 된 이벤트"등이어야한다고 생각합니다.
Jacob

8
: / Meh. 우리는 다른 시간대의 사람들이 작성한 주요 .exe 및 다양한 DLL로 표현되고 사용자 정의 플러그인 프레임 워크를 통해 동적으로 바인딩 된 괴물 엔터프라이즈 응용 프로그램입니다. 이 모든 "여러 개의 앱이 DLL을 동시에 사용할 수 있도록해야합니다"라는 잘못된 생각이 잘못되었습니다.
JohnL4

또한 내 경력의 많은 부분에서 한 가지 컨텍스트에서만 사용할 수 있고 존재하거나 앱이 실패 해야하는 DLL (또는 JAR)을 만드는 팀과 함께이 멋진 일반 공유 객체 메커니즘이 완전히 무시되는 것을 보았습니다. ). 그것들은 정적으로 묶여있을 수도 있지만, 그것은 지나친 것입니다.
JohnL4

1
"통계적으로 말하면, 사내 환경에서이 라이브러리를 사용하고있을 것입니다. 한 대의 컴퓨터 / 사용자 내에서 여러 개의 앱을 사용하지는 않을 것입니다." 이론과 실습의 차이는 때때로 때때로 심술 gets습니다.
JohnL4

1
@Panzercrisis, Visual Studio의 Settings.settings 기능은 모든 사용자 설정에 대한 버전 별 경로를 자동으로 만듭니다. 참조 : stackoverflow.com/questions/35778528/...
Deantwo

101

루트 응용 프로그램 web.config 또는 app.config가 아닌 DLL의 구성 파일에서 설정을 읽으려면 아래 코드를 사용하여 dll의 구성을 읽으십시오.

var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;

VS 2008 시스템 용 관리되는 C ++에서 : System :: Configuration :: Configuration ^ appConfig = ConfigurationManager :: OpenExeConfiguration (Assembly :: GetExecutingAssembly ()-> Location); String ^ name = appConfig-> AppSettings-> 설정 [ "name"]-> Value;
한스

고마워, 이것은 정말로 내 문제를 해결했다. 나는이 문제를 약 이틀 동안 다루어 왔으며 지금까지는 작동하지 않았습니다. 테스트를 디버깅 할 때 ConfigurationManager는 machine.config에서 읽었습니다. 연결 문자열은 SQLExpress-연결 문자열이 나열하지 않았기 때문입니다.
yopez83

19

나는 같은 문제를 겪었고 몇 시간 동안 웹을 검색했지만 해결책을 찾지 못해 스스로 만들었습니다. .net 구성 시스템이 왜 그렇게 융통성이 없는지 궁금했습니다.

배경 : 데이터베이스 및 DAL 설정을위한 자체 구성 파일을 갖도록 DAL.dll을 갖고 싶습니다. 또한 엔터프라이즈 라이브러리 및 자체 구성을위한 app.config가 필요합니다. 따라서 app.config와 dll.config가 모두 필요합니다.

내가 원하지 않는 것은 앱에서 내 DAL 레이어로 모든 속성 / 설정을 전달하는 것입니다!

정상적인 app.config 동작에 필요하기 때문에 "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile"을 구부릴 수 없습니다.

내 요구 사항 / 관점은 다음과 같습니다.

  • 다른 개발자는 재현 할 수 없으므로 ClassLibrary1.dll.config에서 WindowsFormsApplication1.exe.config로 수동 복사 할 수 없습니다.
  • 이것이 중요한 기능이라고 생각하고 잃고 싶지 않기 때문에 강력한 타이핑 "Properties.Settings.Default.NameOfValue"(설정 동작)의 사용법을 유지하십시오.
  • 자체 / 사용자 정의 구성 파일 또는 관리를 주입 할 ApplicationSettingsBase가 부족하다는 것을 알았습니다 (필수 필드는 모두이 클래스에서 비공개입니다)
  • ClassLibrary1.dll.config를 복사 / 재 작성하고 여러 섹션에 대해 여러 XML 파일을 제공해야하므로 "configSource"파일 리디렉션을 사용할 수 없습니다 (이 또한 마음에 들지 않았습니다)
  • MSDN이 제안한 것처럼이 간단한 작업에 대해 내 자신의 SettingsProvider를 작성하고 싶지 않았습니다.
  • 구성 파일의 applicationSettings 및 connectionStrings 섹션 만 필요합니다.

Settings.cs 파일을 수정하고 ClassLibrary1.dll.config를 열고 개인 필드에서 섹션 정보를 읽는 방법을 구현했습니다. 그런 다음 "this [string propertyName]"을 재정 의하여 생성 된 Settings.Desginer.cs가 기본 클래스 대신 새 속성을 호출합니다. 설정이 목록에서 읽 힙니다.

마지막으로 다음 코드가 있습니다.

internal sealed partial class Settings
{
    private List<ConfigurationElement> list;

    /// <summary>
    /// Initializes a new instance of the <see cref="Settings"/> class.
    /// </summary>
    public Settings()
    {
        this.OpenAndStoreConfiguration();
    }

    /// <summary>
    /// Opens the dll.config file and reads its sections into a private List of ConfigurationElement.
    /// </summary>
    private void OpenAndStoreConfiguration()
    {
        string codebase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
        Uri p = new Uri(codebase);
        string localPath = p.LocalPath;
        string executingFilename = System.IO.Path.GetFileNameWithoutExtension(localPath);
        string sectionGroupName = "applicationSettings";
        string sectionName = executingFilename + ".Properties.Settings";
        string configName = localPath + ".config";
        ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
        fileMap.ExeConfigFilename = configName;
        Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

        // read section of properties
        var sectionGroup = config.GetSectionGroup(sectionGroupName);
        var settingsSection = (ClientSettingsSection)sectionGroup.Sections[sectionName];
        list = settingsSection.Settings.OfType<ConfigurationElement>().ToList();

        // read section of Connectionstrings
        var sections = config.Sections.OfType<ConfigurationSection>();
        var connSection = (from section in sections
                           where section.GetType() == typeof(ConnectionStringsSection)
                           select section).FirstOrDefault() as ConnectionStringsSection;
        if (connSection != null)
        {
            list.AddRange(connSection.ConnectionStrings.Cast<ConfigurationElement>());
        }
    }

    /// <summary>
    /// Gets or sets the <see cref="System.Object"/> with the specified property name.
    /// </summary>
    /// <value></value>
    public override object this[string propertyName]
    {
        get
        {
            var result = (from item in list
                         where Convert.ToString(item.ElementInformation.Properties["name"].Value) == propertyName
                         select item).FirstOrDefault();
            if (result != null)
            {
                if (result.ElementInformation.Type == typeof(ConnectionStringSettings))
                {
                    return result.ElementInformation.Properties["connectionString"].Value;
                }
                else if (result.ElementInformation.Type == typeof(SettingElement))
                {
                    return result.ElementInformation.Properties["value"].Value;
                }
            }
            return null;
        }
        // ignore
        set
        {
            base[propertyName] = value;
        }
    }

ClassLibrary1 출력 디렉토리에서 애플리케이션의 출력 디렉토리로 ClassLibrary1.dll.config를 복사하면됩니다. 아마도 누군가가 유용하다고 생각할 것입니다.


14

ConfigurationManager를 사용할 때 프로세스 / AppDomain구성 파일 (app.config / web.config)을 로드하고 있다고 확신합니다 . 특정 구성 파일을로드하려면 해당 파일을 이름별로 요청해야합니다.

시도해 볼 수 있습니다 :

var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]

참조 된 게시물에 따르면 : dll 이름이 MyDll.dll 인 경우 구성 파일은 MyDLL.dll.config이어야합니다. 따라서 dll 내에서 구성 설정을 읽으면 자체 구성 권한을 참조해야합니까?
MegaByte

1
아니요. 그렇게 생각하지 않습니다. "dll에서"는 승산하지 않습니다. 기본적으로 AppDomain에 대해 정의 된 구성 파일을보고 있습니다. my.exe.config
Marc Gravell

1
특히 AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 설정입니다.
Marc Gravell

참고 : OpenExeConfiguration을 사용해 보았는데도 잘 작동하지 않습니다. 아마도 설정을 app.config와 병합합니까?
Marc Gravell

그것은 할 수 있지만 EXE 파일에 대한 app.config 파일 등의 지원과 안전의 같은 종류의 ... 할 수. 내 대답을 참조하십시오.
Chris Ammerman 2016 년

13

ConfigurationManager.AppSettings는 특정 DLL이 아니라 응용 프로그램에 대해 정의 된 설정을 반환합니다.이 설정에는 액세스 할 수 있지만 반환되는 응용 프로그램 설정입니다.

다른 응용 프로그램에서 dll을 사용하는 경우 ConnectionString은 응용 프로그램의 app.settings에 있어야합니다.


6

나는 이것이 파티에 늦었다는 것을 알고 있지만 DLL에 사용하는 솔루션을 공유 할 것이라고 생각했습니다.

나는 KISS 사고에 더 가깝기 때문에 어떻게 작동하는지 또는 어디로 가는지를 제어하는 ​​외부 데이터 포인트를 저장하려는 .NET DLL이있을 때 단순히 공용 속성 만있는 "config"클래스를 만듭니다. 필요한 모든 데이터 포인트를 저장하고 변경을 위해 다시 컴파일하지 않도록 DLL 외부에서 제어 할 수 있기를 바랍니다. 그런 다음 .Net의 XML Serializing을 사용하여 클래스의 객체 표현을 저장하고 파일로로드합니다.

정적 유틸리티 클래스 인 Singleton에서 확장 메서드에 이르기까지 읽기 및 액세스를 처리하는 방법에는 여러 가지가 있습니다. 이는 DLL의 구성 방식과 DLL에 가장 적합한 방법에 따라 다릅니다.


나는이 접근법도 사용하고 있으며 지금까지의 방식에 만족합니다.
Dave

4

맞습니다. dll의 구성 파일을 읽을 수 있습니다. 내 구성 파일이 문제라는 것을 알 때까지 하루 동안이 문제로 어려움을 겪었습니다. 아래 코드를 참조하십시오. 달릴 수있었습니다.

        ExeConfigurationFileMap map = new ExeConfigurationFileMap();
        map.ExeConfigFilename = Assembly.GetExecutingAssembly().Location + ".config";
        Configuration libConfig = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
        AppSettingsSection section = (libConfig.GetSection("appSettings") as AppSettingsSection);
        Console.WriteLine(section.Settings["dnd_shortcodes"].Value);

Plugin1.dll.config모습은 아래와 같습니다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <appSettings>
  <add key="cmd_location" value="http://..."/>
  <add key="dnd_shortcodes" value="142,145,146,157,165,167,168,171,173,176,178,404,40"/>
 </appSettings>
</configuration>

내 구성 파일에 <appSettings>태그 가 없다는 것을 알았습니다. 문제를 둘러 보았을 때 문제가 다를 수 있었지만 그렇게 멀지는 않았습니다.


3

어셈블리가 임시 캐시에 상주하므로 경로를 결합하여 dll 구성을 가져와야합니다.

var appConfig = ConfigurationManager.OpenExeConfiguration(
    Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));

"Path.Combine (Environment.CurrentDirectory, Assembly.GetExecutingAssembly (). ManifestModule.Name)"대신 "Assembly.GetExecutingAssembly (). Location"
Cadburry

3

WCF와 같은 비하인드 스토리를 많이 찾는 라이브러리를 사용하는 경우 다음을 수행하는 것이 좋습니다.

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config");

또는 PowerShell에서 :

[AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config")

IMO이 기술은 코드 냄새이며 애드혹 스크립팅에만 사용하기에 적합합니다. 프로덕션 코드에서이 작업을 수행하려는 경우 아키텍처 검토가 필요할 수 있습니다.

다음은 권장하지 않습니다.
기술적 호기심으로 테마에 대한 변형이 있습니다. DLL에 포함 된 클래스 중 하나 안에 정적 생성자를 만들고 여기에서 호출 할 수 있습니다. 마지막 수단을 제외 하고는이 작업을 수행하지 않는 것이 좋습니다.


3

전체 솔루션을 한곳에서 찾을 수없는 경우 ...

1) 앱 구성 파일을 생성하고 이름을 "yourDllName.dll.config"로 지정하십시오.
2) VS 솔루션 탐색기에서 위에서 생성 한 구성 파일을 마우스 오른쪽 버튼으로 클릭하고 속성을 클릭하십시오
--- set "Build Action"= Content
--- set "Copy to Output Directory"= Always
3) yourKeyName 및 yourKeyValue를 사용하여 구성 파일 (yourDllName.dll.config)에 appSettings 섹션을 추가하십시오.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="yourKeyName" value="yourKeyValue"/>
  </appSettings>
</configuration>

4) dll / class / project 참조에 System.Configuration 추가
5) 구성 설정에 액세스하려는 코드에 using 문을 추가하십시오.

using System.Configuration;
using System.Reflection;

6) 가치에 접근하기

string keyValue = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["yourKeyName"].Value;

7) 기뻐, 작동

IMHO, 이것은 새로운 dll / 라이브러리를 개발할 때만 사용해야합니다.

#if (DEBUG && !FINALTESTING)
   string keyValue = ConfigurationManager.OpenExeConfiguration...(see 6 above)
#else
   string keyValue = ConfigurationManager.AppSettings["yourKeyName"];
#endif

구성 파일은 실제 응용 프로그램에 dll의 appSettings를 추가 할 때 훌륭한 참조가됩니다.


3

이 구성 파일은 동작이 개발 환경에서 배포로 변경됨을 명확히하기 위해 혼란 스럽습니다. 분명히 DLL에는 자체 구성 파일이있을 수 있지만 일단 dll을 구성 파일과 함께 복사하여 붙여 넣으면 모든 것이 작동하지 않습니다. 유일한 해결책은 app.config 파일을 단일 파일로 수동으로 병합하는 것입니다.이 파일은 exec에서만 사용됩니다. 예를 들어 myapp.exe에는 myapp.exe에서 사용하는 모든 dll에 대한 모든 설정이 포함 된 myapp.exe.config 파일이 있습니다. VS 2008을 사용하고 있습니다.


2

이 문제에 대한 좋은 해결책처럼 보입니다. VS 2008 C #을 사용하고 있습니다. 내 솔루션에는 여러 구성 파일 사이에 고유 한 네임 스페이스를 사용하는 것이 포함됩니다. 내 블로그에 솔루션을 게시했습니다 : http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html .

예를 들면 다음과 같습니다.

이 네임 스페이스는 dll 설정을 읽거나 씁니다.

var x = company.dlllibrary.Properties.Settings.Default.SettingName;
company.dlllibrary.Properties.Settings.Default.SettingName = value;

이 네임 스페이스는 exe 설정을 읽거나 씁니다.

company.exeservice.Properties.Settings.Default.SettingName = value;
var x = company.exeservice.Properties.Settings.Default.SettingName;

이 기사에는 몇 가지주의 사항이 있습니다. HTH


1

Marc가 말했듯이 이것은 불가능합니다 (Visual Studio에서는 응용 프로그램 구성 파일을 클래스 라이브러리 프로젝트에 추가 할 수 있지만).

어셈블리 구성 파일을 가능하게 하는 AssemblySettings 클래스 를 확인하십시오 .



0

dll의 경우 구성이 dll이 아닌 응용 프로그램이 소유하므로 구성에 의존해서는 안됩니다.

여기에 설명되어 있습니다


0

이 코드를 사용할 수 있습니다 :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace GClass1
{
[Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface _GesGasConnect
{
    [DispId(1)]
    int SetClass1Ver(string version);


}

[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("InterfacesSMS.Setting")]
public class Class1 : _Class1
{
    public Class1() { }


    public int SetClass1(string version)
    {
        return (DateTime.Today.Day);
    }
}
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.