C# DLL 配置文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/594298/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 09:37:16  来源:igfitidea点击:

C# DLL config file

c#app-config

提问by MegaByte

Im trying to add an app.config file to my DLL, but all attempts have failed.

我试图将 app.config 文件添加到我的 DLL,但所有尝试都失败了。

According to MusicGenesis in 'Putting configuration information in a DLL' this should not be a problem. So obviously I'm doing something wrong...

根据“将配置信息放入 DLL 中中的MusicGenesis,这应该不是问题。所以很明显我做错了什么......

The following code should return my ConnectionString from my DLL:

下面的代码应该从我的 DLL 返回我的 ConnectionString:

return ConfigurationManager.AppSettings["ConnectionString"];

However, when I copy the app.config file to my console application, it works fine.

但是,当我将 app.config 文件复制到我的控制台应用程序时,它工作正常。

Any ideas?

有任何想法吗?

回答by Marc Gravell

When using ConfigurationManager, I'm pretty sure it is loading the process/AppDomainconfiguration file (app.config / web.config). If you want to load a specific config file, you'll have to specifically ask for that file by name...

使用 ConfigurationManager 时,我很确定它正在加载进程/AppDomain配置文件 (app.config/web.config)。如果要加载特定的配置文件,则必须按名称专门询问该文件...

You could try:

你可以试试:

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

回答by Jorge Córdoba

ConfigurationManager.AppSettings returns the settings defined for the application, not for the specific DLL, you can access them but it's the application settings that will be returned.

ConfigurationManager.AppSettings 返回为应用程序定义的设置,而不是为特定的 DLL,您可以访问它们,但将返回应用程序设置。

If you're using you dll from another application then the ConnectionString shall be in the app.settings of the application.

如果您使用来自另一个应用程序的 dll,则 ConnectionString 应位于应用程序的 app.settings 中。

回答by Gerrie Schenck

As Marc says, this is not possible (although Visual Studio allows you to add an application configuration file in a class library project).

正如 Marc 所说,这是不可能的(尽管 Visual Studio 允许您在类库项目中添加应用程序配置文件)。

You might want to check out the AssemblySettingsclass which seems to make assembly config files possible.

您可能想查看AssemblySettings类,它似乎使程序集配置文件成为可能。

回答by Chris Ammerman

It is not trivial to create a .NET configuration file for a .DLL, and for good reason. The .NET configuration mechanism has a lot of features built into it to facilitate easy upgrading/updating of the app, and to protect installed apps from trampling each others configuration files.

为 .DLL 创建 .NET 配置文件并非易事,这是有充分理由的。.NET 配置机制内置了许多功能,以方便应用程序的轻松升级/更新,并保护已安装的应用程序免于相互践踏配置文件。

There is a big difference between how a DLL is used and how an application is used. You are unlikely to have multiple copies of an application installed on the same machine for the same user. But you may very well have 100 different apps or libraries all making use of some .NET DLL.

DLL 的使用方式和应用程序的使用方式之间存在很大差异。您不太可能在同一台计算机上为同一用户安装多个应用程序副本。但是您很可能拥有 100 个不同的应用程序或库,它们都在使用某些 .NET DLL。

Whereas there is rarely a need to track settings separately for different copies of an app within one user profile, it's veryunlikely that you would want all of the different usages of a DLL to share configuration with each other. For this reason, when you retrieve a Configuration object using the "normal" method, the object you get back is tied to the configuration of the App Domain you are executing in, rather than the particular assembly.

虽然有很少需要单独跟踪设置一个用户配置文件中的应用程序的不同副本,这是非常不可能的,你想全部DLL来共享配置彼此的不同用法。出于这个原因,当您使用“正常”方法检索 Configuration 对象时,您返回的对象与您正在执行的应用程序域的配置相关联,而不是特定的程序集。

The App Domain is bound to the root assembly which loaded the assembly which your code is actually in. In most cases this will be the assembly of your main .EXE, which is what loaded up the .DLL. It is possible to spin up other app domains within an application, but you must explicitly provide information on what the root assembly of that app domain is.

App Domain 绑定到根程序集,该程序集加载了代码实际所在的程序集。在大多数情况下,这将是主 .EXE 的程序集,也就是加载 .DLL 的程序集。可以在应用程序中启动其他应用程序域,但您必须明确提供有关该应用程序域的根程序集是什么的信息。

Because of all this, the procedure for creating a library-specific config file is not so convenient. It is the same process you would use for creating an arbitrary portable config file not tied to any particular assembly, but for which you want to make use of .NET's XML schema, config section and config element mechanisms, etc. This entails creating an ExeConfigurationFileMapobject, loading in the data to identify where the config file will be stored, and then calling ConfigurationManager.OpenMappedExeConfigurationto open it up into a new Configurationinstance. This willcut you off from the version protection offered by the automatic path generation mechanism.

因此,创建特定于库的配置文件的过程并不那么方便。它与您用于创建不依赖于任何特定程序集的任意可移植配置文件的过程相同,但您希望使用 .NET 的 XML 架构、配置部分和配置元素机制等。这需要创建一个ExeConfigurationFileMap对象,加载数据以识别配置文件的存储位置,然后调用ConfigurationManager. OpenMappedExeConfiguration将其打开到一个新Configuration实例中。这将使您脱离自动路径生成机制提供的版本保护。

Statistically speaking, you're probably using this library in an in-house setting, and it's unlikely you'll have multiple apps making use of it within any one machine/user. Butif not, there is something you should keep in mind. If you use a single global config file for your DLL, regardless of the app that is referencing it, you need to worry about access conflicts. If two apps referencing your library happen to be running at the same time, each with their own Configurationobject open, then when one saves changes, it will cause an exception next time you try to retrieve or save data in the other app.

从统计上讲,您可能正在内部环境中使用这个库,并且您不太可能在任何一台机器/用户中拥有多个应用程序使用它。 如果没有,您应该记住一些事情。如果您为 DLL 使用单个全局配置文件,无论引用它的应用程序如何,您都需要担心访问冲突。如果引用您的库的两个应用程序碰巧同时运行,每个应用程序都Configuration打开了自己的对象,那么当一个应用程序保存更改时,下次您尝试在另一个应用程序中检索或保存数据时将导致异常。

The safest and simplest way of getting around this is to require that the assembly which is loading your DLL also provide some information about itself, or to detect it by examining the App Domain of the referencing assembly. Use this to create some sort of folder structure for keeping separate user config files for each app referencing your DLL.

解决这个问题的最安全和最简单的方法是要求加载 DLL 的程序集也提供一些关于自身的信息,或者通过检查引用程序集的应用程序域来检测它。使用它来创建某种文件夹结构,以便为引用您的 DLL 的每个应用程序保留单独的用户配置文件。

If you are certainyou want to have global settings for your DLL no matter where it is referenced, you'll need to determine your location for it rather than .NET figuring out an appropriate one automatically. You'll also need to be aggressive about managing access to the file. You'll need to cache as much as possible, keeping the Configurationinstance around ONLY as long as it takes to load or to save, opening immediately before and disposing immediately after. And finally, you'll need a lock mechanism to protect the file while it's being edited by one of the apps that use the library.

如果您确定要为 DLL 进行全局设置,无论它在哪里被引用,您都需要确定它的位置,而不是 .NET 自动找出合适的位置。您还需要积极管理对文件的访问。您需要尽可能多地缓存,Configuration仅在加载或保存所需的时间内保留实例,在此之前立即打开并在之后立即处理。最后,您需要一种锁定机制来保护正在由使用该库的应用程序之一编辑的文件。

回答by kenny

Seems like this config files are really confusing to clarify as their behaviour changes from the dev environment to deployment. Apparently a DLL can have its own config file, but once you copy and paste the dll (together with their config file) elsewhere, the whole thing stopped working. The only solution is to manually merge the app.config files into a single file, which will only be used by the exec. For e.g. myapp.exe will have a myapp.exe.config file that contains all settings for all dlls used by myapp.exe. I'm using VS 2008.

似乎这个配置文件真的很令人困惑,因为它们的行为从开发环境到部署都发生了变化。显然,DLL 可以拥有自己的配置文件,但是一旦您将 dll(连同它们的配置文件)复制并粘贴到其他地方,整个过程就停止了。唯一的解决方案是手动将 app.config 文件合并为一个文件,该文件仅供 exec 使用。例如,myapp.exe 将有一个 myapp.exe.config 文件,其中包含 myapp.exe 使用的所有 dll 的所有设置。我正在使用 VS 2008。

回答by Morbia

if you want to read settings from the DLL's config file but not from the the root applications web.config or app.config use below code to read configuration in the dll.

如果您想从 DLL 的配置文件中读取设置,而不是从根应用程序 web.config 或 app.config 中读取设置,请使用以下代码读取 dll 中的配置。

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

回答by Rodney S. Foley

I know this is late to the party, however I thought I would share the solution I use for DLL's.

我知道这已经晚了,但是我想我会分享我用于 DLL 的解决方案。

I am more of the K.I.S.S. school of thinking, so when I have a .NET DLL that wants to store external data points that control how it works or where it goes, etc. I simply create a "config" class that has only public properties that store all the data points it needs and that I would like to be able to have controlled external to the DLL to prevent recompiling it to make the changes. Then I use .Net's XML Serializing to save and load the object representation of the class to a file.

我更喜欢 KISS 的思想流派,所以当我有一个 .NET DLL 想要存储控制它如何工作或它去哪里等的外部数据点时。我只是创建一个只有公共属性的“配置”类存储它需要的所有数据点,并且我希望能够在 DLL 外部进行控制,以防止重新编译它以进行更改。然后我使用 .Net 的 XML Serializing 将类的对象表示保存并加载到文件中。

There are a lot of ways then to handle reading it and accessing it, from a Singleton, a static utility class, to extension methods, etc. This depends on how your DLL is structured and what method will fit your DLL best.

有很多方法可以处理读取和访问它,从单例、静态实用程序类到扩展方法等。这取决于您的 DLL 的结构方式以及哪种方法最适合您的 DLL。

回答by Lin Song Yang

Since the assembly resides in a temporary cache, you should combine the path to get the dll's config:

由于程序集驻留在临时缓存中,您应该组合路径以获取 dll 的配置:

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

回答by Tommie C.

I've found what seems like a good solution to this issue. I am using VS 2008 C#. My solution involves the use of distinct namespaces between multiple configuration files. I've posted the solution on my blog: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html.

我找到了解决这个问题的好办法。我正在使用 VS 2008 C#。我的解决方案涉及在多个配置文件之间使用不同的命名空间。我已经在我的博客上发布了解决方案:http: //tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html

For example:

例如:

This namespace read/writes dll settings:

此命名空间读/写 dll 设置:

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

This namespace read/writes the exe settings:

此命名空间读取/写入 exe 设置:

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

There are some caveats mentioned in the article. HTH

文章中提到了一些注意事项。HTH

回答by Sven

I had the same problem and searched the web for several hours but I couldn't find any solution so I made my own. I wondered why the .net configuration system is so inflexible.

我遇到了同样的问题并在网上搜索了几个小时,但找不到任何解决方案,所以我自己做了。我想知道为什么 .net 配置系统如此不灵活。

Background: I want to have my DAL.dll to have its own config file for database and DAL settings. I also need the app.config for Enterprise Library and its own configurations. So I need both the app.config and dll.config.

背景:我想让我的 DAL.dll 拥有自己的数据库和 DAL 设置配置文件。我还需要企业库的 app.config 及其自己的配置。所以我需要 app.config 和 dll.config。

What I did not wanted to do is pass-through every property/setting from the app to my DAL layer!

我不想做的是将每个属性/设置从应用程序传递到我的 DAL 层!

to bend the "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" is not possible because I need it for the normal app.config behavior.

弯曲“AppDomain.CurrentDomain.SetupInformation.ConfigurationFile”是不可能的,因为我需要它来实现正常的 app.config 行为。

My requirements/point of views were:

我的要求/观点是:

  • NO manual copy of anything from ClassLibrary1.dll.config to WindowsFormsApplication1.exe.config because this is unreproducible for other developers.
  • retain the usage of strong typing "Properties.Settings.Default.NameOfValue" (Settings behavior) because I think this is a major feature and I didn't want to lose it
  • I found out the lack of ApplicationSettingsBase to inject your own/custom config file or management (all necessary fields are private in these classes)
  • the usage of "configSource" file redirection is not possible because we would have to copy/rewrite the ClassLibrary1.dll.config and provide several XML files for several sections (I also didn't like this)
  • I didn't like to write my own SettingsProvider for this simple task as MSDN suggests because I thought that simply would be too much
  • I only need sections applicationSettings and connectionStrings from the config file
  • 没有手动复制从 ClassLibrary1.dll.config 到 WindowsFormsApplication1.exe.config 的任何内容,因为其他开发人员无法复制。
  • 保留强类型“Properties.Settings.Default.NameOfValue”(设置行为)的用法,因为我认为这是一个主要功能,我不想失去它
  • 我发现缺少 ApplicationSettingsBase 来注入您自己的/自定义配置文件或管理(所有必需的字段在这些类中都是私有的)
  • “configSource”文件重定向的使用是不可能的,因为我们必须复制/重写 ClassLibrary1.dll.config 并为几个部分提供几个 XML 文件(我也不喜欢这样)
  • 我不喜欢像 MSDN 建议的那样为这个简单的任务编写自己的 SettingsProvider,因为我认为这太过分了
  • 我只需要配置文件中的 applicationSettings 和 connectionStrings 部分

I came up with modifying the Settings.cs file and implemented a method that opens the ClassLibrary1.dll.config and reads the section information in a private field. After that, I've overriden "this[string propertyName]" so the generated Settings.Desginer.cs calls into my new Property instead of the base class. There the setting is read out of the List.

我想出了修改 Settings.cs 文件并实现了打开 ClassLibrary1.dll.config 并读取私有字段中的节信息的方法。之后,我覆盖了“this[string propertyName]”,因此生成的 Settings.Desginer.cs 会调用我的新属性而不是基类。在那里从列表中读出设置。

Finally there is the following code:

最后有以下代码:

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;
        }
    }

You just will have to copy your ClassLibrary1.dll.config from the ClassLibrary1 output directory to your application's output directory. Perhaps someone will find it useful.

您只需将 ClassLibrary1.dll.config 从 ClassLibrary1 输出目录复制到应用程序的输出目录。也许有人会发现它很有用。