类库的app.config文件配置

99

我发现在VS2008向导生成的类库中没有看到app.config文件。经过我的研究,我发现应用程序只存在一个app.config文件。

在类库中手动添加app.config文件是不好的事情吗?还是有其他方法可以满足类库中需要app.config的目的?

我需要将log4net配置信息存储在app.config文件中。


3
你可以从你的库中读取可执行项目的配置文件。 - Akram Shahda
10个回答

123

一般来说,你不应该将app.config文件添加到类库项目中,因为它需要一些困难的弯曲和扭曲才能使用。这不会对库项目造成任何影响——它只是根本不会起作用。

相反,你应该配置使用你的库的应用程序;所以所需的配置信息应该在那里设置。每个可能使用你的库的应用程序可能有不同的要求,所以这实际上也是有逻辑意义的。


2
我有一个 Selenium WebDriver 类库,我从 NUnit 中运行所有的测试案例。我不想在 NUnit 中设置配置。我该如何弯曲扭曲以完成这个任务? :-) - Entree
3
搞定了......如果使用NUnit,请将您的app.config文件命名为与*.nunit项目文件相同的名称。例如,如果您将项目称为“ClassLibraryA.nunit”,那么请将您的类库配置文件命名为“ClassLibraryA.config”。它们也需要驻留在相同的文件夹/目录中。实际上,NUnit正在使用这个作为主配置文件... ...在.NET选项卡中添加对System.Configuration的引用... ...并使用此代码:string settingValue = ConfigurationManager.AppSettings ["settingName"]; - Entree
2
你会如何建议在进行集成测试时设置事项?对我来说,在测试库中使用app.config文件来存储连接字符串似乎是很合理的选择。 - Tomas Jansson
2
如果您无法配置应用程序,因为您不拥有它,该怎么办? - Voltage Spike
有时候,为了得到另一种视角,您需要将“.config”或“.runsettings”文件添加到类库中,例如UnitTestClassLibrary。最简单的方法是在Class library文件夹中添加一个记事本,并以所需格式保存。然后将其作为现有项目添加到类库中。 - blackman
显示剩余3条评论

54

我不知道为什么还没有人提供这个答案:

同一个库的不同调用者通常会使用不同的配置。这意味着配置必须驻留在可执行应用程序中,而不是类库中。

您可以在类库项目中创建一个 app.config 文件。它将包含您在库中创建的项目的默认配置。例如,如果您在类库中创建了一个 Entity Framework 模型,则它将包含连接字符串。

然而,可执行应用程序调用库时将不会使用这些设置。相反,这些设置可能会从 library.dll.config 文件复制到调用者的 app.config 或 web.config 中,以便它们可以被更改为特定于调用者和被部署到的环境。

这就是 .NET 从第一天开始的工作方式。


2
但是如果我需要从类库调用Web服务功能,该怎么办呢?VS创建了一个默认的app.config,但当尝试调用Web服务函数时,我的应用程序崩溃了——它找不到配置条目... - Laserson
1
你需要将放置在类库 app.config 中的元素复制到调用类库的 app.config 或 web.config 中。这样可以使调用方控制配置。例如,调用方现在可以更改你的类库调用的服务的 URL,而你的类库甚至不会知道这个变化。 - John Saunders
7
@John Saunders: "may need" 正是恰当的措辞。因此,在某些情况下,配置设置仅与每个服务器不同(例如连接字符串),拥有dll自己的配置比为每个使用该dll的程序集复制它多次更方便。 在我看来,Microsoft/.NET 的首选用法并非圣杯。这实际上取决于部署场景中最方便的方式。 没有必要责备Todd,他的意见和你或Microsoft一样重要。 - user1531508
我对这个解决方案非常感兴趣 - 它听起来非常理想。图书馆携带默认设置,而应用程序则具有覆盖它们的能力是有道理的。您能否详细说明一下如何将设置从库的app.config传播到执行程序集的app.config,或者直接向我提供相关资源? - crush
@crush:这就是所谓的“复制粘贴”。.NET 的强类型设置功能可以帮助一些,因为它将默认值嵌入程序集中。 - John Saunders
1
作为一个曾经接手过不想遵循微软/.Net“首选用法”(即最佳实践)的“特殊”代码的人,我会说不。相比之下,遵循最佳实践是一种圣杯。而且,托德的观点并不像微软的观点那样重要。 - RMuesi

53

Jon,很多人提供的意见没有正确回答你的问题。

我会给出我的看法,然后告诉你如何做到正好符合你的要求。

我认为一个程序集为什么不能有自己的配置文件呢?为什么原子性的第一层应该在应用程序级别而不是解决方案级别?这是一个随意的、最佳猜测的决定,也就是个人意见。如果你要编写一个日志记录库,并想包含一个全局使用的配置文件,为什么不能利用内置的设置功能?我们都做过这样的事情……试图为其他开发人员提供“强大”的功能。怎么做呢?通过做出本质上转化为限制的假设。这正是微软在设置框架中所做的,所以你必须“骗一下”它。

直接回答你的问题,只需手动添加配置文件(xml),并将其命名为与你的库相匹配并包含“config”扩展名的名称。例如:

MyDomain.Mylibrary.dll.Config

接下来,使用ConfigurationManager加载文件并访问设置即可:

string assemblyPath = new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath;
Configuration cfg = ConfigurationManager.OpenExeConfiguration(assemblyPath);
string result = cfg.AppSettings.Settings["TEST_SETTING"].Value;

请注意,这完全支持机器配置层次结构,即使您明确选择了应用程序配置文件。换句话说,如果该设置不存在,它将解析更高级别的设置。设置还将覆盖 machine.config 条目。


4
你的观点本身并不重要,事实才是重要的。从一开始,.NET 就是为了让库的调用者确定库中项目的配置而创建的。这是唯一有意义的配置方式,因为库的不同调用者可能需要不同的配置。 - John Saunders
23
“库的不同调用者可能需要不同的配置。”没错,他们“可能”需要不同的配置,你的逻辑在所有需要根据调用者配置的情况下都是完全正确的。但是,在一些情况下,配置是用于类库内部的,并且无论调用者是谁,配置都是完全相同的。如果有10个应用程序使用该库,将完全相同的配置复制粘贴到10个配置文件中肯定是不好的。 - wired_in
4
@ToddBeaulieu:我认为你想要的词是“原子性”。 - nicodemus13
4
在插件架构中,如果所有插件都有自己的配置文件,那确实是有意义的。 - Davatar
4
没人说过它从不改变,只是它并不取决于库的调用者。配置可能会因为你是在调试库还是生产版本中而有所变化。它也可能会因为你正在构建的环境等因素而有所变化。 - wired_in
显示剩余8条评论

10

实际上,您正在实现的类库是从使用它的应用程序中的app.config检索信息,因此,在VS中为.NET实现类库配置的最正确方法是在应用程序中准备app.config 来配置它所消耗的所有内容,如库配置。

我有一点使用log4net的经验,我发现准备应用程序的人总是在主app.config 中拥有一个log4net配置部分。

例如这个配置有一个log4net 部分。


4
+1 确切地说, app.config 是从最终运行的实际程序加载的...而不是单独的类库。很多人不知道这个非常基本的事实,实际上有点令人困惑。 - Andrew Barber
也许有些人来自Java语言,那里你会有一个log4java.properties文件和一个独立的应用程序属性文件。 - Amedio

6
如果您想使用log4Net配置项目日志,同时使用类库,则实际上不需要任何配置文件。您可以在一个类中配置log4net记录器,并将该类用作库。
由于log4net提供了所有配置选项,因此可以轻松完成配置。
请查看以下代码。
public static void SetLogger(string pathName, string pattern)
        {
            Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = pattern;
            patternLayout.ActivateOptions();

            RollingFileAppender roller = new RollingFileAppender();
            roller.AppendToFile = false;
            roller.File = pathName;
            roller.Layout = patternLayout;
            roller.MaxSizeRollBackups = 5;
            roller.MaximumFileSize = "1GB";
            roller.RollingStyle = RollingFileAppender.RollingMode.Size;
            roller.StaticLogFileName = true;
            roller.ActivateOptions();
            hierarchy.Root.AddAppender(roller);

            MemoryAppender memory = new MemoryAppender();
            memory.ActivateOptions();
            hierarchy.Root.AddAppender(memory);

            hierarchy.Root.Level = log4net.Core.Level.Info;
            hierarchy.Configured = true;
      }

现在,您可以直接在Global.asax应用程序启动函数中调用SetLogger并传递所需的路径和模式来设置记录器,而不是调用XmlConfigurator.Configure(new FileInfo("app.config"))。
以下代码可用于记录错误。
        public static void getLog(string className, string message)
        {
            log4net.ILog iLOG = LogManager.GetLogger(className);
            iLOG.Error(message);    // Info, Fatal, Warn, Debug
        }

使用以下代码,您不需要在应用程序web.config或库的app.config中编写任何一行代码。

2
我认为这是最好的答案...与其讨论库是否应允许配置文件...这个答案回答了OP关于使用Log4net的问题。 - saurav
2
尽管问题以log4net作为示例,但实际上问题是关于配置文件的。我认为关于log4net的答案实际上是不相关的。 - binki

4

实际上,在一些罕见情况下,您可以将app.config存储在类库中(通过手动添加),并使用OpenExeConfiguration进行解析。

 var fileMap =
    new ExeConfigurationFileMap {ExeConfigFilename = 
    @"C:\..somePath..\someName.config"};
 System.Configuration.Configuration config =
    ConfigurationManager.OpenMappedExeConfiguration(fileMap, 
    ConfigurationUserLevel.None);

您应该真正估计这个的实际需求。对于抽象数据来说,这不是最好的解决方案,但“配置部分”可能非常有用!

例如,我们通过使用基于通道工厂T的Unity容器和注入工厂,将我们的N-Tier WCF架构解耦,没有任何元数据。我们添加了外部ClassLibrary dll,仅带有[Service Contract]接口和通用app.config,在客户端部分中读取端点,并轻松地在一个地方添加/更改。


3
如果您正在使用跟踪器/记录器,那么确实需要将App.config添加到您的测试类库中。否则,当您通过TestDriven.Net等测试运行程序运行测试时,不会记录任何内容
例如,我在我的程序中使用TraceSource,但是如果我没有在测试类库中添加包含跟踪/日志配置的App.config文件,则运行测试时不会记录任何内容。
否则,将App.config添加到类库中不会有任何作用。

3
您可以通过 Visual Studio 项目属性/设置选项卡来非手动创建 app.config 文件。
当您添加并保存一个设置后,app.config 将自动生成。 此时会在 {yourclasslibrary.Properties} 命名空间中生成一堆代码,其中包含与您的设置对应的属性。这些设置本身将放置在 app.config 的 applicationSettings 设置中。
 <configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
        <section name="ClassLibrary.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
</configSections>
<applicationSettings>
    <ClassLibrary.Properties.Settings>
        <setting name="Setting1" serializeAs="String">
            <value>3</value>
        </setting>
    </BookOneGenerator.Properties.Settings>
</applicationSettings>

如果您添加了一个名为Setting1 = 3的应用程序范围设置,则会创建一个名为Setting1的属性。 这些属性在编译时成为二进制文件的一部分,并且它们被装饰使用一个名为DefaultSettingValueAttribute的属性,其值设置为您在开发时指定的值。
     [ApplicationScopedSetting]
    [DebuggerNonUserCode]
    [DefaultSettingValue("3")]
    public string Setting1
    {
        get
        {
            return (string)this["Setting1"];
        }
    }

因此,当您在类库代码中使用这些属性时,如果运行时配置文件中不存在相应的设置,则它将回退到使用默认值。这样,当您不知道这些东西如何工作时,应用程序不会因缺少设置条目而崩溃,这是非常令人困惑的。 现在,您正在思考如何在部署的库中指定自己的新值并避免使用默认设置值?
这将在我们正确配置可执行文件的app.config时发生。两个步骤。1.我们让它意识到我们将为该类库设置一个设置部分,并且2.通过小修改,我们将类库的配置文件粘贴到可执行文件配置中。(有一种方法可以使类库配置文件保持外部,并且您只需从可执行文件的配置中引用它。
因此,如果您不正确地与父应用程序集成,那么对于类库而言,它的app.config是无用的。 看看我之前写的内容:link

1

当您将类库项目添加到解决方案中时,不会自动添加app.config文件。

据我所知,手动添加没有任何反对意见。我认为这是一种常见用法。

关于log4Net配置,您不必将配置放入app.config中,您可以在项目中拥有一个专用的conf文件以及同时存在一个app.config文件。

此链接http://logging.apache.org/log4net/release/manual/configuration.html将为您提供两种方式的示例(在app.config中的部分和独立的log4net conf文件)


在库项目中添加一个 app.config 不会有任何影响,但也不会被使用。 - Andrew Barber
2
@AndrewBarber 它将用于测试项目。请参见 https://dev59.com/Fm035IYBdhLWcg3wBLNL#31389495 - binki

0
我建议使用Properties.Settings来存储类库中的ConnectionStrings等值。当您尝试添加表适配器时,Visual Studio会建议将所有连接字符串存储在此处。enter image description here 然后,您可以通过在类库中使用此代码来访问它们。
var cs=  Properties.Settings.Default.[<name of defined setting>];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接