C#DLL構成ファイル


191

DLLにapp.configファイルを追加しようとしていますが、すべての試行が失敗しました。

MusicGenesisによると、「構成情報をDLLに入れる」ことは問題になりません。明らかに私は何か間違ったことをしています...

次のコードは、DLLからConnectionStringを返すはずです。

return ConfigurationManager.AppSettings["ConnectionString"];

ただし、app.configファイルをコンソールアプリケーションにコピーすると、正常に動作します。

何か案は?


参照された投稿によると:DLLの名前がMyDll.dllの場合、構成ファイルはMyDLL.dll.configである必要があります。したがって、dll内から構成設定を読み取る場合、それ自体の構成権を参照する必要がありますか?
MegaByte

11
コードが何を要求するかは関係ありません
-AppDomain

注:「DLLに構成情報を置く」という質問は、アプリの構成コードをライブラリに分離して、メインのアプリコードから分離しておくことに関するものです。これは、個別のDLL専用の構成ファイルとは大きく異なります。
Chris Ammerman、

、[1]私のためのソリューションだった[1] [ここでは、リンクの説明を入力]この記事を参照してください。stackoverflow.com/questions/2389290/...は
dhailis

[現在の設定で動的にマージ別のアプリケーション設定ファイルをロードする方法は?]この記事を参照してください[1] helpfuかもしれません[1]:stackoverflow.com/questions/2389290/...
dhailis

回答:


277

.DLLの.NET構成ファイルを作成することは簡単ではありません。.NET構成メカニズムには多くの機能が組み込まれており、アプリの簡単なアップグレード/更新を容易にし、インストールされたアプリがお互いの設定ファイルを踏みつぶさないように保護します。

DLLの使用方法とアプリケーションの使用方法には大きな違いがあります。同じユーザーの同じマシンにアプリケーションの複数のコピーがインストールされることはほとんどありません。しかし、100個の異なるアプリやライブラリがすべて.NET DLLを利用している場合もあります。

1つのユーザプロファイル内のアプリの異なるコピーに対して個別に設定を追跡する必要はめったにありません一方で、それはだ非常にあなたがお互いに共有設定にDLLのさまざまな用途のすべてをしたいとは考えにくいです。このため、 "通常の"メソッドを使用して構成オブジェクトを取得すると、返されるオブジェクトは、特定のアセンブリではなく、実行中のアプリドメインの構成に関連付けられます。

アプリドメインは、コードが実際にあるアセンブリをロードしたルートアセンブリにバインドされています。ほとんどの場合、これはメインの.EXEのアセンブリであり、.DLLをロードしたものです。アプリケーション内の他のアプリドメインを起動することは可能ですが、そのアプリドメインのルートアセンブリが何であるかに関する情報を明示的に提供する必要があります。

このため、ライブラリ固有の構成ファイルを作成する手順はあまり便利ではありません。これは、特定のアセンブリに関連付けられていない任意のポータブル構成ファイルを作成するために使用するのと同じプロセスですが、.NETのXMLスキーマ、構成セクション、構成要素のメカニズムなどを利用する必要がありExeConfigurationFileMapます。これには、オブジェクトの作成が必要です。、データをロードして設定ファイルが保存される場所を特定し、次にを呼び出しConfigurationManagerます。OpenMappedExeConfiguration新しいConfigurationインスタンスにそれを開く。これがします自動パス生成メカニズムによって提供されるバージョンの保護からあなたを遮断します。

統計的に言えば、おそらくこのライブラリを社内設定で使用しており、1台のマシン/ユーザー内で複数のアプリがそれを利用することはほとんどありません。 しかし、そうでない場合は、覚えておくべきことがあります。DLLに単一のグローバル構成ファイルを使用する場合、それを参照しているアプリに関係なく、アクセスの競合を心配する必要があります。ライブラリを参照する2つのアプリが同時に実行され、それぞれが独自のConfigurationオブジェクトを開いている場合、1つが変更を保存すると、次に他のアプリでデータを取得または保存しようとすると例外が発生します。

これを回避する最も安全で簡単な方法は、DLLをロードしているアセンブリがそれ自体に関するいくつかの情報も提供することを要求するか、参照アセンブリのアプリドメインを調べて検出することです。これを使用して、DLLを参照するアプリごとに個別のユーザー構成ファイルを保持するための、ある種のフォルダー構造を作成します。

あなたがいる場合は、特定のあなたのDLLのために、それが参照されているに関係なく、グローバル設定を持つようにしたい、あなたはむしろ、.NETが自動的に適切なものを考え出すよりも、それのためにあなたの場所を決定する必要があります。また、ファイルへのアクセスの管理についても積極的に取り組む必要があります。Configurationロードまたは保存にかかる時間だけインスタンスを保持し、直前に開いて直後に破棄することで、可能な限りキャッシュする必要があります。そして最後に、ライブラリを使用するアプリの1つによって編集されている間、ファイルを保護するためのロックメカニズムが必要になります。


同期メカニズムはプロセス全体にわたるため、「名前付きイベント」などである必要があると思います
Jacob

8
:/まあ。私たちのものは、別のタイムゾーンの人によって書かれたメイン.exeとさまざまなDLLによって表され、カスタムプラグインフレームワークを介して動的にバインドされたモジュールを備えたモンスターエンタープライズアプリです。これらすべての「複数のアプリがDLLを同時に使用できるようにする必要があります」というpomposityはまったく間違っています。
JohnL4 2013年

さらに、私のキャリアの大部分で、チームが1つのコンテキストでのみ使用できるDLL(またはJAR)を作成する(そして存在する必要がある、またはアプリが失敗する)ため、これらの素敵な汎用共有オブジェクトメカニズムは完全に無視されているのを目にしました)。それらは静的にバインドされているかもしれませんが、それはパスです。
JohnL4 2013年

1
「統計的に言えば、おそらくこのライブラリを社内設定で使用しているため、1台のマシン/ユーザー内で複数のアプリがこのライブラリを利用することはまずありません。」理論と実践の違いは時々私をかなり不機嫌にします。
JohnL4

1
@ Panzercrisis、Visual StudioのSettings.settings機能は、すべてのユーザー設定のバージョン固有のパスを自動的に作成します。参照:stackoverflow.com/questions/35778528/...
Deantwo

101

ルートアプリケーションweb.configまたはapp.configからではなくDLLの構成ファイルから設定を読み取りたい場合は、以下のコードを使用してDLLの構成を読み取ります。

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

マネージC ++ for VS 2008 System :: Configuration :: Configuration ^ appConfig = ConfigurationManager :: OpenExeConfiguration(Assembly :: GetExecutingAssembly()-> Location); String ^ name = appConfig-> AppSettings-> Settings ["name"]-> Value;
Hans

おかげで、これは本当に私の問題を解決しました。私はこの問題に約2日間取り組んできましたが、今まで機能しませんでした。テストをデバッグするときに、ConfigurationManagerがmachine.configから読み取っていた-と思います-引き出された接続文字列はSQLExpressに関するものでした-私がリストしていない接続文字列-です。
yopez83

19

同じ問題があり、数時間ウェブを検索しましたが、解決策が見つからなかったので自分で作成しました。なぜ.net構成システムはそれほど柔軟性がないのかと思いました。

背景:データベースとDAL設定用の独自の構成ファイルをDAL.dllに含めたいです。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の欠如を発見しました(必要なすべてのフィールドはこれらのクラスでプライベートです)
  • ClassLibrary1.dll.configをコピー/書き直して、いくつかのセクションにいくつかのXMLファイルを提供する必要があるため、「configSource」ファイルのリダイレクトを使用できません(これも好きではありませんでした)。
  • 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出力ディレクトリからアプリケーションの出力ディレクトリにコピーするだけです。多分誰かがそれを便利だと思うでしょう。


14

ConfigurationManagerを使用しているときは、プロセス/ AppDomain構成ファイル(app.config / web.config)を読み込んでいると思います。特定の設定ファイルをロードしたい場合は、そのファイルを名前で具体的に要求する必要があります...

あなたは試すことができます:

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

参照された投稿によると:DLLの名前がMyDll.dllの場合、構成ファイルはMyDLL.dll.configである必要があります。したがって、dll内から構成設定を読み取る場合、それ自体の構成権を参照する必要がありますか?
MegaByte

1
いいえ...そうは思いません。"dllから"を選択してもオッズはありません。デフォルトでは、AppDomainに定義されている構成ファイルmy.exe.configを調べています。–
Marc Gravell

1
特に、AppDomain.CurrentDomain.SetupInformation.ConfigurationFile設定。
Marc Gravell

注:OpenExeConfigurationを試しましたが、それが機能するかどうかもわかりません。おそらく、設定をapp.configとマージするだけですか?
Marc Gravell

これ実行できますが、EXEのapp.configファイルと同じ種類のサポートと安全性はありません。私の答えを見てください。
Chris Ammerman、

13

ConfigurationManager.AppSettingsは、特定のDLLではなく、アプリケーションに定義された設定を返します。それらにアクセスできますが、返されるのはアプリケーション設定です。

別のアプリケーションからdllを使用している場合、ConnectionStringはアプリケーションのapp.settingsにあります。


6

私はこれがパーティーに遅れていることを知っていますが、DLLに使用するソリューションを共有したいと思いました。

私はKISSスクールの考え方に詳しいので、.NET DLLがあり、それがどのように機能するか、どこに行くかなどを制御する外部データポイントを格納したい場合は、パブリックプロパティのみを持つ「config」クラスを作成するだけです。必要なすべてのデータポイントを格納し、DLLを再コンパイルして変更を加えないようにDLLの外部で制御できるようにしたいと考えています。次に、.NetのXMLシリアライズを使用して、クラスのオブジェクト表現をファイルに保存およびロードします。

シングルトン、静的ユーティリティクラス、拡張メソッドなど、読み取りとアクセスを処理する方法はたくさんあります。これは、DLLの構造とDLLに最適なメソッドによって異なります。


私もこのアプローチを使用しており、これまでのやり方に満足しています。
デイブ

4

あなたは正しいです、あなたはdllの設定ファイルを読むことができます。私の設定ファイルが問題であることがわかるまで、私はこれに1日苦労しました。以下の私のコードを参照してください。走ることができました。

        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>タグが欠けていることがわかりましたので、見てください、あなたの問題は私のものとは違うかもしれませんが、それほど遠くないかもしれません。


3

アセンブリは一時キャッシュにあるため、パスを組み合わせてdllの構成を取得する必要があります。

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

「Path.Combine(Environment.CurrentDirectory、Assembly.GetExecutingAssembly()。ManifestModule.Name)」の代わりに「Assembly.GetExecutingAssembly()。Location」を使用できます
Cadburry

3

WCFなど、舞台裏で大量の構成を検索するライブラリを使用している場合は、次のようにすることを検討してください。

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

またはPowerShellで:

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

IMOこの手法はコードの匂いであり、アドホックスクリプトでの使用にのみ適しています。量産コードでこれを実行したい場合は、アーキテクチャのレビューが必要です。

以下はお勧めしません:
技術的な好奇心として、テーマのバリエーションを以下に示します。DLLに格納されているクラスの1つの内部に静的コンストラクターを作成し、そこからこの呼び出しを行うことができます。最後の手段として以外は、これを行うことはお勧めしません。


3

完全なソリューションが1か所に見つからないことがよくあり

ます... 1)アプリの構成ファイルを作成し、「yourDllName.dll.config」という名前を付けます
。2)VSソリューションエクスプローラーで上記で作成した構成ファイルを右クリックし、プロパティをクリックします
--- set "Build Action" = Content
--- set "Copy To Output Directory" = Always
3)yourKeyNameとyourKeyValueを含むappSettingsセクションを構成ファイル(yourDllName.dll.config)に追加します

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

4)dll / class / project参照にSystem.Configurationを追加します
。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を実際のアプリケーションに追加するときに、すばらしい参照になります。


3

この構成ファイルは、その動作が開発環境からデプロイメントに変化するため、明らかに混乱するようです。どうやらDLLは独自の構成ファイルを持つことができますが、DLLを(構成ファイルと共に)別の場所にコピーアンドペーストすると、すべてが機能しなくなります。唯一の解決策は、手動でapp.configファイルを単一のファイルにマージすることです。これは、execによってのみ使用されます。たとえば、myapp.exeには、myapp.exeによって使用されるすべてのdllのすべての設定を含むmyapp.exe.configファイルがあります。VS 2008を使用しています。


2

この問題の良い解決策のように見えるものを見つけました。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;

記事にはいくつかの注意点があります。HTH


1

Marcが言うように、これは不可能です(ただし、Visual Studioではクラスライブラリプロジェクトにアプリケーション構成ファイルを追加できます)。

アセンブリ構成ファイルを可能にするように見えるAssemblySettingsクラスをチェックアウトすることもできます。



0

dllの場合、構成はdllではなくアプリケーションによって所有されるため、構成に依存するべきではありません。

これはここで説明されています


0

このコードを使用できます:

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);
    }
}
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.