关于C#:相当于库(dll)的”app.config”

Equivalent to 'app.config' for a library (DLL)

对于库(dll),是否有等同于app.config的库?如果不是,存储特定于库的配置设置的最简单方法是什么?请考虑该库可能在不同的应用程序中使用。


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

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

 title= title=

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

现在要从该文件中读取,必须具有以下功能:

1
2
3
4
5
6
7
8
9
10
11
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;
}

并使用它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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");
    ...
}

为了使configurationManager类可用,还必须添加对System.Configuration命名空间的引用。

在构建项目时,除了dll之外,您还将拥有DllName.dll.config文件,这是您必须使用dll本身发布的文件。

以上是基本的示例代码,对于那些对全比例示例感兴趣的人,请参考另一个答案。


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

解决方案是:您不需要将app.config文件放入类库的项目中。将app.config文件放入引用类的应用程序中图书馆的DLL。

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

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

现在,假设我们有一个名为myapp.exe的Windows应用程序,引用myclasses.dll。它将包含一个app.config,其中包含一个这样的条目AS:

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

XML文件最适合app.config。使用XML序列化/反序列化为需要。你可以随心所欲地称呼它。如果配置为"静态"而且不需要更改,您也可以将其作为嵌入的资源。

希望它能给你一些建议


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

也就是说,从应用程序的配置文件(特别是类库中的appSettings部分)获取配置不是一个好的实践。如果您的库需要参数,那么调用您的库的任何人都应该将它们作为构造函数、工厂方法等中的方法参数传递。这可以防止调用应用程序意外地重用类库所期望的配置项。

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

您可以在msdn上了解有关自定义配置部分的更多信息,而且PhilHaack有一篇关于它们的好文章。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
}

为了做点什么,我把最上面的答案重构成一个类。用法如下:

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

如果在Visual Studio中将设置添加到类库项目中(项目属性、设置),它将向项目中添加app.config文件,其中包含相关的usersettings/applicationsettings部分,以及settings.settings文件中这些设置的默认值。

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

我认为生成此文件的主要原因是为了将设置复制/粘贴到宿主应用程序的配置文件中。


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

1
2
3
4
5
6
7
8
9
[TestClass]
[DeploymentItem("MyProject.Cache.dll.config")]
public class CacheTest
{
    .
    .
    .
    .
}

对于大会不能是特定于项目的评论,他们可以并且它提供了很大的灵活性,特别是在与国际奥委会框架合作时。


我也遇到了同样的问题,在向项目中添加应用程序配置文件后,创建了一个静态类Parameters,解决了这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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;
    }
}

然后得到这样的参数:

1
Parameters.GetParameter("keyName");


前言:我使用的是NET 2.0;

伊安妮丝·利奥西斯的解决方案是可以接受的,但我有一些问题。

首先,static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");返回空值。我得换成static AppSettingSection = myDllConfig.AppSettings;

那么,return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);就没有例外。所以我换了它

1
2
3
4
5
6
7
8
try
{
    return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
}
catch (Exception ex)
{
    return default(T);
}

这是非常好的工作,但如果您有一个不同的DLL,您必须重写每次代码为每个程序集。所以,这是我的版本,每次需要的时候都可以实例化一个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
        }
    }
}

配置:

1
 

使用它作为:

1
2
3
4
5
6
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");


我目前正在为一个零售软件品牌创建插件,它实际上是.NET类库。作为一项要求,每个插件都需要使用配置文件进行配置。经过一点研究和测试,我编了下节课。它完美地完成了工作。注意,在我的案例中,我没有实现本地异常处理,因为我在更高的级别捕获异常。

可能需要进行一些调整,以使小数点正确,以防出现小数和双精度,但它对我的文化很有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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文件示例

1
 

用途:

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

影子向导信用&;mattc


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

在我的开发团队里,我总是这样做。


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

如果您的程序集正由多个应用程序使用,那么每个应用程序都需要在其app.config文件中包含这些条目。

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

1
2
3
4
5
6
7
8
9
10
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从应用程序的配置文件中获取其值。如果使用此程序集的任何应用程序在配置文件中缺少该设置,那么您将得到一个异常,很明显是丢失了某些内容。

MissingConfigFileAppSettings是一个自定义异常。您可能想抛出一个不同的异常。

当然,更好的设计是将这些类的方法作为参数提供这些值,而不是依赖配置文件设置。这样,使用这些类的应用程序就可以决定它们提供这些值的位置和方式。


从配置中使用必须非常容易,如下所示:

1
2
3
4
5
6
7
8
var config = new MiniConfig("setting.conf");

config.AddOrUpdate("port","1580");

if (config.TryGet("port", out int port)) // if config exist
{
    Console.Write(port);
}

有关详细信息,请参阅miniconfig


为什么不使用:

  • c用[ProjectNamespace].Properties.Settings.Default.[KeyProperty]。#
  • 用于vb.net的My.Settings.[KeyProperty]

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

[Solution Project]->Properties->Settings


据我所知,您必须将library.config中所需的部分复制并粘贴到applications.config文件中。每个可执行实例只能获得1个app.config。