web-dev-qa-db-ja.com

C#DLL構成ファイル

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

' 設定情報をDLLに置く 'のMusicGenesisによると、これは問題ではないはずです。だから明らかに私は何か間違ったことをしています...

次のコードは、DLLからConnectionStringを返す必要があります。

return ConfigurationManager.AppSettings["ConnectionString"];

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

何か案は?

183
MegaByte

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

DLLの使用方法とアプリケーションの使用方法には大きな違いがあります。同じユーザーが同じマシンにアプリケーションの複数のコピーをインストールすることはほとんどありません。ただし、すべてが.NET DLLを使用している100種類のアプリまたはライブラリがある可能性があります。

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

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

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

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

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

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

270
Chris Ammerman

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

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

私は同じ問題を抱えており、数時間ウェブを検索しましたが、解決策が見つからなかったため、独自に作成しました。 .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は、基本クラスではなく新しいプロパティを呼び出します。そこでリストから設定が読み出されます。

最後に、次のコードがあります。

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出力ディレクトリからアプリケーションの出力ディレクトリにコピーするだけです。おそらく誰かが便利だと思うでしょう。

19
Sven

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

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

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

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

別のアプリケーションのdllを使用している場合、ConnectionStringはアプリケーションのapp.settingsに含まれるものとします。

13
Jorge Córdoba

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

私はもっ​​とK.I.S.S.です思考系なので、動作方法や移動先などを制御する外部データポイントを保存する.NET DLLがある場合は、単にパブリックプロパティのみを持つ「config」クラスを作成します必要なすべてのデータポイントを保存し、DLLの外部を制御して、再コンパイルして変更が行われないようにします。次に、.NetのXMLシリアル化を使用して、クラスのオブジェクト表現をファイルに保存およびロードします。

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

5
Rodney S. Foley

あなたは正しいです、あなたは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>タグが含まれていないことがわかったので、周りを見てください。あなたの問題は違うかもしれませんが、私の問題ではありません。

4
mugume david

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

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

この設定ファイルは、動作が開発環境から展開へと変化するにつれて明確にするのが本当に混乱しているようです。どうやらDLLは独自の設定ファイルを持つことができますが、dllを(設定ファイルとともに)他の場所にコピーして貼り付けると、全体が機能しなくなりました。唯一の解決策は、app.configファイルを手動で1つのファイルにマージすることです。このファイルは、execによってのみ使用されます。たとえばmyapp.exeには、myapp.exeが使用するすべてのdllのすべての設定を含むmyapp.exe.configファイルがあります。 VS 2008を使用しています。

3
kenny

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

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

またはPowerShellで:

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

IMOこの手法はコードのにおいであり、実際にはアドホックスクリプトでの使用にのみ適しています。実稼働コードでこれを実行したい場合は、アーキテクチャのレビューをする時間です。

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

3
Paul Williams

この問題の良い解決策と思われるものを見つけました。 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

2
Tommie C.

完全なソリューションが1か所で見つかることはあまりありません...

1)アプリ構成ファイルを作成し、「yourDllName.dll.config」という名前を付けます
2)VS Solution Explorerで上記で作成した構成ファイルを右クリックし、プロパティをクリックします
---「ビルドアクション」=コンテンツの設定
---「出力ディレクトリにコピー」を設定=常に
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)config設定にアクセスするコードに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を追加する際の優れたリファレンスになります。

1
David C Fuchs

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

アセンブリ構成ファイルを作成できると思われる AssemblySettings クラスをチェックアウトすることをお勧めします。

1
Gerrie Schenck

この投稿では、同様の問題が議論され、私の問題を解決します 個別のアプリケーション設定ファイルを動的にロードして現在の設定とマージする方法 はhelpfuかもしれません

0
dhailis

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

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

0
Saravanan

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

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);
    }
}
}
0
David Lopes