ChatGPT解决这个技术问题 Extra ChatGPT

C# DLL 配置文件

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

根据“Putting configuration information in a DLL”中的 MusicGenesis,这应该不是问题。所以很明显我做错了什么......

以下代码应从我的 DLL 中返回我的 ConnectionString:

return ConfigurationManager.AppSettings["ConnectionString"];

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

有任何想法吗?

根据引用的帖子:如果dll的名称是MyDll.dll,那么配置文件应该是MyDLL.dll.config。因此,如果您从 dll 中读取配置设置,它应该引用它自己的配置,对吗?
询问什么代码并不重要 - 它正在寻找为 AppDomain 指定的文件:AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 设置
注意:“将配置信息放入 DLL”问题是关于将应用程序的配置代码分离到一个库中,以使其与主应用程序代码分开。这与单独的、专用于 DLL 的配置文件非常不同。
看到这篇文章 [在此处输入链接描述][1],是我的解决方案 [1]:stackoverflow.com/questions/2389290/…
请参阅这篇文章 [如何动态加载单独的应用程序设置文件并与当前设置合并?][1] 可能会有所帮助 [1]:stackoverflow.com/questions/2389290/…

T
Theo

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

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

尽管很少需要在一个用户配置文件中单独跟踪应用程序的不同副本的设置,但您不太可能希望 DLL 的所有不同用法相互共享配置。出于这个原因,当您使用“正常”方法检索配置对象时,您返回的对象与您正在执行的应用程序域的配置相关联,而不是特定的程序集。

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

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

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

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

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


我认为同步机制应该是一个“命名事件”等,因为它是跨进程的
:/嗯。我们是一个怪物企业应用程序,其主要 .exe 由不同时区的人编写,模块由各种 DLL 表示,并通过自定义插件框架动态绑定。所有这些“您需要确保多个应用程序可以同时使用您的 DLL”的浮夸是完全错误的。
此外,在我职业生涯的大部分时间里,我看到这些可爱的通用共享对象机制被完全忽略,团队创建的 DLL(或 JAR)只能在一种上下文中使用(并且必须存在,否则应用程序将失败) )。它们也可能是静态绑定的,但这已经过去了。
“从统计上讲,您可能在内部环境中使用此库,并且您不太可能在任何一台机器/用户中拥有多个应用程序使用它。”理论和实践之间的差异有时让我很暴躁。
@Panzercrisis,Visual Studio 的 Settings.settings 功能会自动为所有用户设置创建特定于版本的路径。请参阅:stackoverflow.com/questions/35778528/…
M
Morbia

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

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

在 VS 2008 System::Configuration::Configuration^ appConfig = ConfigurationManager::OpenExeConfiguration(Assembly::GetExecutingAssembly()->Location) 的托管 C++ 中; String^ name = appConfig->AppSettings->Settings["name"]->Value;
谢谢,这真的解决了我的问题。我已经处理这个问题大约两天了,直到现在才开始工作。在调试测试时,ConfigurationManager 正在从 machine.config 中读取 - 我认为 - 因为提取的连接字符串是关于 SQLExpress -我没有列出的连接字符串 -。
也为我工作。我将完整的文件名(例如 myDll.dll.config)传递给 OpenExeConfiguration,但这不起作用。 Assembly.GetExecutingAssembly().Location 返回名称和文件扩展名(例如 myDll.dll),这样就可以了。谢谢。
S
Sven

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

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

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

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

我的要求/观点是:

没有从 ClassLibrary1.dll.config 到 WindowsFormsApplication1.exe.config 的任何手动副本,因为这对于其他开发人员来说是不可复制的。

保留强类型“Properties.Settings.Default.NameOfValue”(设置行为)的用法,因为我认为这是一个主要功能,我不想失去它

我发现缺少 ApplicationSettingsBase 来注入您自己的/自定义配置文件或管理(所有必要的字段在这些类中都是私有的)

无法使用“configSource”文件重定向,因为我们必须复制/重写 ClassLibrary1.dll.config 并为多个部分提供多个 XML 文件(我也不喜欢这样)

我不喜欢像 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.dll.config 从 ClassLibrary1 输出目录复制到应用程序的输出目录。也许有人会发现它很有用。


B
BrunoLM

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

你可以试试:

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

根据引用的帖子:如果dll的名称是MyDll.dll,那么配置文件应该是MyDLL.dll.config。因此,如果您从 dll 中读取配置设置,它应该引用它自己的配置,对吗?
不……我不这么认为。 “来自 dll” 没有任何可能性;默认情况下,它正在查看为 AppDomain 定义的配置文件:my.exe.config
特别是 AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 设置。
注意:我尝试了 OpenExeConfiguration,但我也不确定它是否有效。也许只是将配置与 app.config 合并?
可以做到……但不像 EXE 的 app.config 文件那样具有相同的支持和安全性。看我的回答。
J
Jorge Córdoba

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

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


R
Rodney S. Foley

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

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

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


我也使用这种方法,并且对它目前的工作方式感到满意。
m
mugume david

你是对的,你可以读取一个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> 标记,所以环顾四周,您的问题可能有所不同,但与我的问题相差不远。


D
David C Fuchs

完整的解决方案通常不会在一个地方找到...... 1)创建一个应用程序配置文件并将其命名为“yourDllName.dll.config” 2)在VS解决方案资源管理器中右键单击上面创建的配置文件,单击属性---设置“构建操作”= 内容 --- 设置“复制到输出目录”= 始终 3) 使用 yourKeyName 和 yourKeyValue 将 appSettings 部分添加到配置文件 (yourDllName.dll.config)

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

4) 将 System.Configuration 添加到您的 dll/类/项目引用 5) 将 using 语句添加到您打算访问配置设置的代码中

using System.Configuration;
using System.Reflection;

6) 访问值

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

7) 高兴,它有效

恕我直言,这只应在开发新的 dll/库时使用。

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

配置文件最终成为一个很好的参考,当您将 dll 的 appSettings 添加到您的实际应用程序时。


S
Shadow The Kid Wizard

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

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

而不是“Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name)”你可以使用“Assembly.GetExecutingAssembly().Location”
a
afuzzyllama

如果您使用的是在后台查找大量配置的库,例如 WCF,您可以考虑这样做:

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

或在 PowerShell 中:

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

IMO 这种技术是一种代码味道,实际上只适用于临时脚本。如果您发现自己想在生产代码中执行此操作,也许是时候进行架构审查了。

不推荐以下内容:作为技术好奇心,这里是主题的变体。您可以在 DLL 中的一个类中创建一个静态构造函数,然后从那里进行此调用。我不建议这样做,除非作为最后的手段。


A
Appulus

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


a
abatishchev

我发现似乎是解决此问题的好方法。我正在使用 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;

文章中提到了一些注意事项。高温高压


G
Gerrie Schenck

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

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


G
Gerhard Schmeusser

模拟一个“真实的”应用程序配置文件令人困惑。我建议你自己动手,因为使用 LINQ 解析 XML 文件非常容易。

例如,创建一个如下所示的 XML 文件 MyDll.config 并将其与 DLL 一起复制。要使其保持最新,请将其在 Visual Studio 中的属性设置为“复制到输出目录”

<?xml version="1.0" encoding="utf-8" ?>
 <configuration>
  <setting key="KeyboardEmulation" value="Off"></setting>
 </configuration>

在你的代码中这样读:

    XDocument config = XDocument.Load("MyDll.config");
    var settings = config.Descendants("setting").Select(s => new { Key = s.Attribute("key").Value, Value = s.Attribute("value").Value });
    bool keyboardEmulation = settings.First(s => s.Key == "KeyboardEmulation").Value == "On";

C
Community

在这篇文章中讨论了一个类似的问题并解决了我的问题 How to load a separate Application Settings file dynamically and merge with current settings? 可能会有所帮助


虽然这在理论上可以回答问题,但it would be preferable在此处包含答案的基本部分,并提供链接以供参考。
C
Community

对于 dll,它不应该依赖于配置,因为配置属于应用程序而不是 dll。

这在 here 中进行了解释


D
David Lopes

您可以使用以下代码:

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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅