connectionstrings C#DLL配置文件



c# windows form read app config (13)

我試圖添加一個app.config文件到我的DLL,但所有的嘗試都失敗了。

根據MusicGenesis的“ 將配置信息放入DLL中 ”,這應該不成問題。 所以顯然我做錯了什麼...

下面的代碼應該從我的DLL中返回我的ConnectionString:

return ConfigurationManager.AppSettings["ConnectionString"];

但是,當我將app.config文件複製到我的控制台應用程序時,它工作正常。

有任何想法嗎?


Answer #1

為.DLL創建一個.NET配置文件並不是微不足道的,並且有很好的理由。 .NET配置機制內置了許多功能,以方便升級/更新應用程序,並保護已安裝的應用程序免於踐踏其他配置文件。

如何使用DLL以及如何使用應用程序有很大區別。 您不可能為同一用戶在同一台計算機上安裝多個應用程序副本。 但是,您可能會有100個不同的應用程序或庫全部使用某些.NET DLL。

儘管在一個用戶配置文件中幾乎不需要單獨跟踪應用程序的不同副本的設置,但您可能不希望DLL的所有不同用法彼此共享配置。 因此,使用“普通”方法檢索Configuration對象時,返回的對象與您正在執行的App Domain的配置綁定,而不是特定的程序集。

應用程序域綁定到加載程序集所在的根組件,在大多數情況下,這將是您的主.EXE程序集,它是加載.DLL的程序集。 可以在應用程序中創建其他應用程序域,但必須明確提供有關該應用程序域根組件的信息。

由於所有這些,創建特定於庫的配置文件的過程並不方便。 創建任意可移植配置文件的過程與創建任何特定程序集無關,但您希望使用.NET的XML模式,配置節和配置元素機制等。這需要創建一個ExeConfigurationFileMap對象,加載數據以確定配置文件的存儲位置,然後調用ConfigurationManagerOpenMappedExeConfiguration將其打開成一個新的Configuration實例。 這將使您免受自動路徑生成機制提供的版本保護。

從統計學上講,您可能在內部使用該庫,並且不太可能在任何一台機器/用戶中使用多個應用程序。 但是,如果沒有,你應該記住一些事情。 如果您為DLL使用單個全局配置文件,則無論引用它的應用程序如何,都需要擔心訪問衝突。 如果兩個引用您的庫的應用碰巧同時運行,每個應用都打開自己的Configuration對象,那麼當您保存更改時,下次嘗試在另一個應用中檢索或保存數據時會引發異常。

解決此問題的最安全和最簡單的方法是要求加載DLL的程序集還提供有關其自身的一些信息,或者通過檢查引用程序集的應用程序域來檢測它。 使用它來創建某種文件夾結構,以便為每個引用您的DLL的應用程序保留單獨的用戶配置文件。

如果您確定要為您的DLL提供全局設置而無論它是在哪裡引用的,則需要確定您的位置,而不是.NET自動找出合適的位置。 您還需要積極主動地管理對文件的訪問。 您需要盡可能緩存,只要保存Configuration實例只要加載或保存,立即打開並立即處理即可。 最後,您需要一個鎖定機制來保護該文件,而該文件正由使用該庫的應用程序編輯。


Answer #2

你是正確的,你可以讀取一個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>標記,所以仔細查看,你的問題可能會有所不同,但距離我的距離不遠。


Answer #3

看起來像這個配置文件真的很混亂,以澄清他們的行為從開發環境改變到部署。 顯然一個DLL可以擁有自己的配置文件,但是一旦你複製並粘貼了dll(連同它們的配置文件)在其他地方,整個事情就停止了。 唯一的解決方案是手動將app.config文件合併到一個文件中,這個文件只能被exec使用。 例如,myapp.exe將有一個myapp.exe.config文件,其中包含myapp.exe使用的所有dll的所有設置。 我正在使用VS 2008。

Kenny Liew


Answer #4

你可以使用這個代碼:

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

Answer #5

我遇到了同樣的問題,並在網上搜索了幾個小時,但找不到任何解決方案,因此我創建了自己的解決方案。 我想知道為什麼.net配置系統非常不靈活。

背景:我想讓我的DAL.dll擁有自己的數據庫和DAL設置的配置文件。 我還需要用於Enterprise Library的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調用我的新Property而不是基類。 在那裡從列表中讀出設置。

最後是下面的代碼:

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輸出目錄複製到您的應用程序的輸出目錄。 也許有人會覺得它有用。


Answer #6

如果您想從DLL的配置文件中讀取設置,但不是從根應用程序web.config或app.config中讀取設置,請使用以下代碼讀取dll中的配置。

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

Answer #7

正如Marc所說,這是不可能的(儘管Visual Studio允許您在類庫項目中添加應用程序配置文件)。

您可能想查看AssemblySettings類似乎使彙編配置文件成為可能。



Answer #9

我發現這個問題似乎是一個很好的解決方案。 我正在使用VS 2008 C#。 我的解決方案涉及在多個配置文件之間使用不同的名稱空間。 我已經在我的博客上發布了解決方案: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html : 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;

文中提到了一些警告。 HTH


Answer #10

如果您使用的庫在幕後查找大量的解決方案(如WCF),則可以考慮這樣做:

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

或者在PowerShell中:

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

IMO這種技術是一種代碼味道,它實際上只適用於臨時腳本。 如果你發現自己想要在生產代碼中做到這一點,也許是時候進行架構審查了。

以下是不推薦的:
作為技術好奇心,這是主題的變化。 您可以在DLL中的一個類中創建一個靜態構造函數,並從那裡進行調用。 除了作為最後的手段之外,我不會推薦這樣做。


Answer #11

對於一個DLL,它不應該依賴於配置,因為配置由應用程序擁有,而不是由dll擁有。

這在here解釋


Answer #12

完整的解決方案不常在一個地方找到......

1)創建一個應用程序配置文件,並將其命名為“yourDllName.dll.config”
2)右鍵單擊上面在VS解決方案資源管理器中創建的配置文件,單擊屬性
---設置“Build Action”=內容
---設置“複製到輸出目錄”=始終
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 / class / project引用
5)在你打算訪問配置設置的地方添加使用語句

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添加到你的實際應用程序時,配置文件最終成為一個很好的參考。


Answer #13

由於程序集駐留在臨時緩存中,因此您應該組合路徑以獲取dll的配置:

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




app-config