相当于库(DLL)的“ app.config”


149

有相当于app.config库(DLL)的东西吗?如果不是,最简单的方法是存储特定于库的配置设置?请考虑该库可能在​​不同的应用程序中使用。

Answers:


161

可以有单独的配置文件,但是您必须“手动”读取它,ConfigurationManager.AppSettings["key"]它将仅读取正在运行的程序集的配置。

假设您使用Visual Studio作为IDE,则可以右键单击所需项目→添加→新建项目→应用程序配置文件

这将添加App.config到项目文件夹中,将您的设置放在<appSettings>部分的下面。如果您不使用Visual Studio并手动添加文件,请确保使用以下名称:DllName.dll.config使用以下,否则以下代码将无法正常工作。

现在从这个文件中读取具有这样的功能:

string GetAppSetting(Configuration config, string key)
{
    KeyValueConfigurationElement element = config.AppSettings.Settings[key];
    if (element != null)
    {
        string value = element.Value;
        if (!string.IsNullOrEmpty(value))
            return value;
    }
    return string.Empty;
}

并使用它:

Configuration config = null;
string exeConfigPath = this.GetType().Assembly.Location;
try
{
    config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
}
catch (Exception ex)
{
    //handle errror here.. means DLL has no sattelite configuration file.
}

if (config != null)
{
    string myValue = GetAppSetting(config, "myKey");
    ...
}

您还必须添加对System.Configuration命名空间的引用,以使ConfigurationManager类可用。

生成项目时,除了DLL外, DllName.dll.config文件,那就是您必须与DLL本身一起发布的文件。

上面是基本的示例代码,对于那些感兴趣的完整示例,请参考此其他答案


1
@罗德尼(Rodney)尝试更改string exeConfigPath = this.GetType().Assembly.Location;为以下内容:string exeConfigPath = @"C:\MyFolder\DllFolder\ExeName.exe";
影子巫师为您而耳(

1
如果dll被Resharper单元测试工具复制到某个未知文件夹中,怎么办呢?
2013年

11
其他实现此目的的提示:要通过引用应用程序自动生成DllName.dll.config,我只需将app.config重命名为DllName.dll.config,然后将“复制到输出目录”属性更改为“始终复制” 。另外,我需要连接字符串,可以使用config.ConnectionStrings.ConnectionStrings [connStringName] .ConnectionString进行检索。
杰夫·G

2
app.cfg文件名对于读取appcfg值非常重要,文件名应为“ DLL_NAME.DLL.CONFIG”
SaddamBinSyed

2
更正我的最后评论。在我的VS2017解决方案中,通过从测试和DLL项目中删除我的新的,无效的App.config文件,然后将其重新添加到测试项目中,它突然开始工作!我的App.config设置现在自动包含在DLL.configs中。终于解脱了!
Zeek2

30

不幸的是,每个可执行文件只能有一个app.config文件,因此,如果将DLL链接到您的应用程序中,则它们将不能拥有自己的app.config文件。

解决方案是: 您无需将App.config文件放入类库的项目中。
您将App.config文件放在引用类库的dll的应用程序中。

例如,假设我们有一个名为MyClasses.dll的类库,它使用app.config文件,如下所示:

string connect = 
ConfigurationSettings.AppSettings["MyClasses.ConnectionString"];

现在,假设我们有一个名为MyApp.exe的Windows应用程序,它引用了MyClasses.dll。它将包含一个App.config,其条目如下:

<appSettings>
    <add key="MyClasses.ConnectionString"
         value="Connection string body goes here" />
</appSettings>

要么

xml文件最适合app.config。根据需要使用xml序列化/反序列化。您可以将其命名为任何您想要的东西。如果您的配置是“静态的”并且不需要更改,则还可以将其作为嵌入式资源添加到项目中。

希望它能给点想法


6
ConfigurationSettings现在已过时并替换为ConfigurationManager,所以等效项应为ConfigurationManager.AppSettings
Gone Coding 2013年

2
否决票。问题是每个dll而不是每个应用程序。最好的解决方案:stackoverflow.com/a/5191101/2935383
上升者

3
我怀疑这种建议在不知道可执行文件调用它们的后期绑定dll的情况下是行不通的。
beanmf '18年

9

配置文件是应用程序范围而不是程序集范围的。因此,您需要将库的配置部分放在使用库的每个应用程序的配置文件中。

也就是说,从应用程序的配置文件(尤其appSettings是类)中的类库中获取配置不是一个好习惯。如果您的库需要参数,则无论谁调用您的库,都应该将它们作为方法参数传递给构造函数,工厂方法等。这样可以防止调用应用程序意外重用类库期望的配置条目。

也就是说,XML配置文件非常方便,因此,我发现的最佳折衷方案是使用自定义配置部分。您可以将库的配置放在XML文件中,该文件会由框架自动读取和解析,从而避免了潜在的事故。

您可以在MSDN上了解有关自定义配置部分的更多信息,Phil Haack对此也有不错的文章


7
“从类库中的配置文件中获取配置不是一个好习惯” –我对此表示强烈反对。例如,DAL类库通常应从应用程序配置文件中获取配置数据(例如连接字符串),而不是从BLL层传递此信息。任何使用配置(例如ASP.NET成员资格)的Framework类都以这种方式工作。

我略微修改了答案。我仍然支持我所说的内容,但是您是对的,我从未打算暗示根本不应该使用配置文件。我的意思是appSettings,自定义部分不是基于约定的,而是一种不错的选择。毕竟,ASP.NET Membership几乎使用了什么。
madd0 2011年

5
public class ConfigMan
{
    #region Members

    string _assemblyLocation;
    Configuration _configuration;

    #endregion Members

    #region Constructors

    /// <summary>
    /// Loads config file settings for libraries that use assembly.dll.config files
    /// </summary>
    /// <param name="assemblyLocation">The full path or UNC location of the loaded file that contains the manifest.</param>
    public ConfigMan(string assemblyLocation)
    {
        _assemblyLocation = assemblyLocation;
    }

    #endregion Constructors

    #region Properties

    Configuration Configuration
    {
        get
        {
            if (_configuration == null)
            {
                try
                {
                    _configuration = ConfigurationManager.OpenExeConfiguration(_assemblyLocation);
                }
                catch (Exception exception)
                {
                }
            }
            return _configuration;
        }
    }

    #endregion Properties

    #region Methods

    public string GetAppSetting(string key)
    {
        string result = string.Empty;
        if (Configuration != null)
        {
            KeyValueConfigurationElement keyValueConfigurationElement = Configuration.AppSettings.Settings[key];
            if (keyValueConfigurationElement != null)
            {
                string value = keyValueConfigurationElement.Value;
                if (!string.IsNullOrEmpty(value)) result = value;
            }
        }
        return result;
    }

    #endregion Methods
}

为了做某事,我将最佳答案重构为一堂课。用法类似于:

ConfigMan configMan = new ConfigMan(this.GetType().Assembly.Location);
var setting = configMan.GetAppSetting("AppSettingsKey");

4

如果将设置添加到Visual Studio中的类库项目(“项目属性”,“设置”),它将使用相关的userSettings / applicatioNSettings部分以及来自Settings.settings的这些设置的默认值将app.config文件添加到项目中。文件。

但是,此配置文件将在运行时不使用-而是类库使用其宿主应用程序的配置文件。

我相信生成此文件的主要原因是可以将设置复制/粘贴到主机应用程序的配置文件中。


4

我目前正在为零售软件品牌创建插件,它们实际上是.net类库。根据需要,每个插件都需要使用配置文件进行配置。经过一些研究和测试,我编译了以下课程。它完美地完成了工作。请注意,我没有实现本地异常处理,因为我会在更高级别捕获异常。

在小数和双精度的情况下,可能需要进行一些调整才能使小数点正确,但对我的CultureInfo来说效果很好...

static class Settings
{
    static UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
    static Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(uri.Path);
    static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");
    static NumberFormatInfo nfi = new NumberFormatInfo() 
    { 
        NumberGroupSeparator = "", 
        CurrencyDecimalSeparator = "." 
    };

    public static T Setting<T>(string name)
    {
        return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
    }
}

App.Config文件示例

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

用法:

  somebooleanvar = Settings.Setting<bool>("Enabled");
  somestringlvar = Settings.Setting<string>("ExportPath");
  someintvar =     Settings.Setting<int>("Seconds");
  somedoublevar =  Settings.Setting<double>("Ratio");

归功于Shadow Wizard和MattC


1
这应该是公认的答案。非常紧凑,“开箱即用”。好东西
nmarler '19

2

为了回答最初的问题,我通常将配置文件添加到测试项目中作为链接。然后,您可以使用DeploymentItem属性将其添加到测试运行的Out文件夹中。

[TestClass]
[DeploymentItem("MyProject.Cache.dll.config")]
public class CacheTest
{
    .
    .
    .
    .
}

为了回应有关装配体不能特定于项目的评论,装配体可以并且可以提供极大的灵活性,特别是。在使用IOC框架时。


2

Parameters在将应用程序配置文件添加到项目后,我遇到了相同的问题并通过创建静态类解决了该问题:

public static class Parameters
{
    // For a Web Application
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config");

    // For a Class Library
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", "LibraryName.dll.config");

    public static string GetParameter(string paramName)
    {
        string paramValue = string.Empty;

        using (Stream stream = File.OpenRead(PathConfig))
        {
            XDocument xdoc = XDocument.Load(stream);

            XElement element = xdoc.Element("configuration").Element("appSettings").Elements().First(a => a.Attribute("key").Value == paramName);
            paramValue = element.Attribute("value").Value;
        }

        return paramValue;
    }
}

然后获取这样的参数:

Parameters.GetParameter("keyName");

1
辉煌!这帮助我使Windows Application Driver自动化测试在目标计算机上运行。就我而言,这些dll来自一个测试项目。我唯一要添加的是,在Win App Driver(以及可能的其他形式的自动化测试)中,BaseDirectory实际上是输出文件夹,它每次都会更改。我必须像这样子字符串... AppDomain.CurrentDomain.BaseDirectory.Substring(0,AppDomain.CurrentDomain.BaseDirectory.IndexOf(“ TestResults”))。这样,我可以切掉不需要的输出文件夹,因为我的配置文件与测试dll位于同一文件夹中。
伊万

1

程序集没有自己的app.config文件。他们使用正在使用它们的应用程序的app.config文件。因此,如果程序集期望配置文件中包含某些内容,则只需确保应用程序的配置文件中包含这些条目即可。

如果程序集被多个应用程序使用,则每个应用程序都需要在其app.config文件中具有这些条目。

我建议您做的是在程序集中的类上为这些值定义属性,例如

private string ExternalServicesUrl
{
  get
  {
    string externalServiceUrl = ConfigurationManager.AppSettings["ExternalServicesUrl"];
    if (String.IsNullOrEmpty(externalServiceUrl))
      throw new MissingConfigFileAppSettings("The Config file is missing the appSettings entry for: ExternalServicesUrl");
    return externalServiceUrl;
  }
}

在这里,属性ExternalServicesUrl从应用程序的配置文件中获取其值。如果使用此程序集的任何应用程序缺少配置文件中的该设置,您将得到一个异常o显然有些东西丢失了。

MissingConfigFileAppSettings是自定义异常。您可能要抛出其他异常。

当然,对于这些类的方法,更好的设计是将这些值作为参数提供,而不是依赖于配置文件设置。这样,使用这些类的应用程序可以决定从何处以及如何提供这些值。


请注意以上几点:在.NET程序集DLL上运行xUnit测试时,xUnit将在运行时读取该库的.config。并且它将忽略添加到测试或DLL项目中的任何App.config。
Zeek2

1

使用添加现有项,从dll项目中选择应用程序配置。点击添加之前,请使用添加按钮右侧的向下小箭头“添加为链接”

我一直在我的开发人员中这样做。


1

前言:我正在使用NET 2.0;

Yiannis Leoussis发布的解决方案是可以接受的,但我对此有一些。

首先,static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");返回null。我不得不将其更改为static AppSettingSection = myDllConfig.AppSettings;

然后return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);就没有例外。所以我改变了

try
{
    return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
}
catch (Exception ex)
{
    return default(T);
}

这非常有效,但是如果您使用其他dll,则每次每次汇编代码都必须重写。因此,这是我的版本,用于Class每次需要时实例化。

public class Settings
{
    private AppSettingsSection _appSettings;
    private NumberFormatInfo _nfi;

    public Settings(Assembly currentAssembly)
    {
        UriBuilder uri = new UriBuilder(currentAssembly.CodeBase);
        string configPath = Uri.UnescapeDataString(uri.Path);
        Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(configPath);
        _appSettings = myDllConfig.AppSettings;
        _nfi = new NumberFormatInfo() 
        { 
            NumberGroupSeparator = "", 
            CurrencyDecimalSeparator = "." 
        };
    }


    public T Setting<T>(string name)
    {
        try
        {
            return (T)Convert.ChangeType(_appSettings.Settings[name].Value, typeof(T), _nfi);
        }
        catch (Exception ex)
        {
            return default(T);
        }
    }
}

对于配置:

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

用作:

Settings _setting = new Settings(Assembly.GetExecutingAssembly());

somebooleanvar = _settings.Setting<bool>("Enabled");
somestringlvar = _settings.Setting<string>("ExportPath");
someintvar =     _settings.Setting<int>("Seconds");
somedoublevar =  _settings.Setting<double>("Ratio");

请检查删除的投票。我的错误是在编写答案时发送了答案。
Matteo Gaggiano,2015年

0

据我所知,您必须将所需的部分从库.config复制并粘贴到应用程序.config文件中。每个可执行实例仅获得1个app.config。


如果您使用的是自定义配置节,则可以使用configSource属性:<MySection configSource =“ mysection.config” />且仅使用dll复制配置文件
2011年

我按要求添加了新问题,例如有关函数始终返回空字符串和邮件服务器设置> stackoverflow.com/questions/25123544/…和> stackoverflow.com/questions/25138788/…, 所以我希望有人像我一样答复将值硬编码到DLL中几乎快到了!
MonkeyMagix

0

为什么不使用:

  • [ProjectNamespace].Properties.Settings.Default.[KeyProperty] 对于C#
  • My.Settings.[KeyProperty] 对于VB.NET

您只需要在设计时通过以下方式直观地更新这些属性:

[Solution Project]->Properties->Settings


这将自动为dll创建一个配置文件。但是您无法在运行时从配置文件中读取修改后的值。最后,它将显示调用应用程序的值。另请参阅@Joe答案
教皇代码

如果为用户配置而配置,则为否。这个想法是编辑用户的需求,在运行时配置它们,然后保存它们。然后,当用户使用库时,它将加载配置,并保存在其各自的用户路径中,但仅对他有效。
Pedro Mora '18

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.