web-dev-qa-db-ja.com

デフォルトのファイルからではなく、カスタムのapp.configファイルから<runtime>を読み取るようにアプリケーションに指示する方法

ConsoleApp2というアプリを作成しているとしましょう。

私が使用しているいくつかのサードパーティのライブラリのため、私のデフォルトのapp.configファイルは次のようなコードを生成しています

<runtime>
  <assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

これは、私のソリューションが1つのライブラリの異なるバージョンを参照しているため、それを全員に伝える必要があるためです: "ねえ、もしあなたが探しているならoldVersionこのライブラリの場合、newVersion "を使用します。そして、それは大丈夫です。

問題は、いくつかの設定があり、自動生成された設定を削除する別の設定ファイル「test.exe.config」を定義したいことです。

私のアプリに新しい設定ファイルを知らせるために、私は次のようなコードを使用しています

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "test.exe.config");

そして、それは(ほぼ)完全に動作します。そして、そこに「almost」と書いたのは、<appSettings>セクションが正しく読み取られているにもかかわらず、<runtime>セクションがカスタム構成ファイルで見られていないためです。 、しかしアプリは代わりにデフォルトの設定ファイルでそれを探します、それは後でそれを削除できるようにしたいので問題です。

それで、カスタム構成ファイルから<runtime>情報も読み取るようにアプリケーションに指示するにはどうすればよいですか?


問題の再現方法

私の問題を再現する簡単なサンプルは次のとおりです。

ClassLibrary2。Net Framework v4.6)と呼ばれるライブラリを作成します次のような単一のクラス

using Newtonsoft.Json.Linq;
using System;

namespace ClassLibrary2
{
    public class Class1
    {
        public Class1()
        {
            var json = new JObject();
            json.Add("Succeed?", true);

            Reash = json.ToString();
        }

        public String Reash { get; set; }
    }
}

Newtonsoftパッケージへの参照に注意してください。ライブラリにインストールされているものはv10.0.2です。

次に、ConsoleApp2というコンソールアプリケーションを作成します(。Net Framework v4.6Programと呼ばれるクラスを使用し、その内容は次のようになります。

using System;
using System.Configuration;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {

            AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "test.exe.config");

            var AppSettings = ConfigurationManager.AppSettings;

            Console.WriteLine($"{AppSettings.Count} settings found");
            Console.WriteLine($"Calling ClassLibrary2: {Environment.NewLine}{new ClassLibrary2.Class1().Reash}");
            Console.ReadLine();

        }
    }
}

このアプリケーションはNewtonsoftもインストールする必要がありますが、異なるバージョンv12.0.3

アプリケーションをデバッグモードでビルドします。次に、フォルダーConsoleApp2/ConsoleApp2/bin/Debugtest.exe.configという名前のファイルを作成し、次の内容を含めます

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
  </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <appSettings>
    <add key="A" value="1"/>
    <add key="B" value="1"/>
    <add key="C" value="1"/>
  </appSettings>
</configuration>

同じDebugフォルダーには、デフォルトの設定ファイルConsoleApp2.exe.configも含まれていることに注意してください。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
  </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

この時点でアプリケーションを実行すると、問題なくコンパイルされ、次のようなコンソールが表示されます。

enter image description here

(3)の設定がカスタム構成ファイルから正しく読み取られたことに注意してください。ここまでは順調ですね...

ここで、デフォルトの構成ファイルの名前を_ ConsoleApp2.exe.configのように変更し、アプリケーションを再度実行します。 FileLoadExceptionが表示されます。

enter image description here

繰り返しますが、カスタム構成ファイルから<runtime>情報を読み取るようにアプリケーションに指示するにはどうすればよいですか?


根拠

この質問への回答を探している理由は次のとおりです。

アプリケーションをリリースするとき、すべての.exeファイルと.dllファイルを1つのフォルダーに配置し、カスタム構成ファイル(設定などを含む)を別のフォルダーに配置します。クライアントには同様のファイルがあります。

.exeファイルと.dllファイルが含まれるフォルダーでは、できるだけ少なくしようとするため、それを取り除く方法ConsoleApp2.exe.configif可能。今、前述のバインディングはその構成ファイルに記述されているため、その情報をカスタム構成ファイルに移動しようとしましたが、これまでのところ達成できませんでした。バインディングリダイレクトは常にそこから読み取られようとしますConsoleApp2.exe.configなので、削除するとすぐに例外が発生します...

8
Deczaloth

あなたはおそらくconfig transformsを探しています:

背後にある考えは、[複数の構成 Visual StudioでDebug、Release、Production、Test ...を構成マネージャーとデフォルト構成ファイルに加えて、いわゆる変換します。

Note構成マネージャで好きなだけ構成を作成できます。 新しいものを追加するにはソリューション構成([デバッグ]または[リリース]を示すドロップダウン)をクリックし、[構成マネージャー...]を選択します。それを開くと、現在存在するすべての構成のリストが表示されます。コンボボックス「アクティブソリューション構成」をドロップダウンし、「_<New...>_」を選択してさらに追加します。

これらのtransformsは、特定の構成がデフォルトの構成と異なる点を指定します。そのため、デフォルトの構成ですでに指定した内容を繰り返す必要はありません。代わりに、違いを説明するだけです。次に例を示します。

_<configuration>
    <appSettings>
        <add key="ClientSessionTimeout" value="100"
            xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
    </appSettings>
</configuration>
_

これは、キーClientSessionTimeoutによって関連する設定を見つけ、その値を_100_に設定ファイルの元の値を置き換えることによって設定します(これは、追加の変換属性xdt:Transform="SetAttributes" xdt:Locator="Match(key)"が意味するものです)。既存の設定を削除するように指定することもできます(代わりに_xdt:Transform="Remove"_を指定することにより)。

_<add key="UserIdForDebugging" xdt:Transform="Remove" xdt:Locator="Match(key)"/>
_

リリースではなく、デバッグのためだけに存在する必要があるユーザーIDを削除します(使用可能なオプションの詳細については、 here を参照してください-Web.configについて説明しましたが、App.configにも適用できます)。

_App.Config_ファイルに加えて構成ごとに1つのファイルつまり、デバッグには_App.Debug.Config_、リリースには_App.Release.Config_などがあります。VisualStudioのヘルプあなたがそれらを作成します。

StackOverflow herethere で回答を作成済みです。詳しく説明していますので、ご覧ください。

Visual Studioでの表示に問題がある場合は、 こちら をご覧ください。


理由について:

トランスフォームは、デフォルトの構成ファイルにトランスフォームファイルを適用して、完全な構成ファイルを作成しています。結果のファイルはコンパイルされ、他のコンパイル済みファイルと一緒に「bin」フォルダーに入れられます。したがって、構成「リリース」を選択した場合、変換された構成ファイルを含むすべてのファイルが「bin\Release」にコンパイルされます。

構成ファイルの名前は、exeファイルに最後に「.config」を追加したものと同じです(つまり、バイナリフォルダーに「.Release.config」はありませんが、「MySuperCoolApp.exe.config」が作成されます-アプリケーション「MySuperCoolApp.exe」)。

同様に、他の構成についても同じことが言えます。各構成は「bin」内にサブフォルダーを作成します。スクリプトを使用している場合、そのサブフォルダーはビルド後のイベントで$(TargetDir)として参照できます。

6
Matt

構成変換

別の(非ネイティブ)構成ファイルを使用しようとすると問題が発生するため、「適切に」それを置き換えるソリューションを見つけようとしています。私の答えでは、少し後戻りして、なぜそれを置き換えたいのかという理由に焦点を当てたいと思います。質問での説明に基づいて、カスタムアプリケーション設定を定義します。私が正しく理解していれば、それをターゲットプロジェクトにリンクし、「出力にコピー」プロパティを「常に」に設定すると、アプリケーションの近くに表示されます。

あなたの場合、新しい設定ファイルをコピーする代わりに、既存の(ネイティブ)ファイルを変換する方法があります-ConsoleApp2.exe.configXdt変換 を使用します。これを実現するには、変換ファイルを作成し、変換するセクションのみを宣言します。次に例を示します。

<configuration xmlns:xdt="http://schemas.Microsoft.com/XML-Document-Transform">
  <appSettings xdt:Transform="Replace">
    <add key="A" value="1"/>
    <add key="B" value="1"/>
    <add key="C" value="1"/>
  </appSettings>
</configuration>

このようなアプローチの利点は次のとおりです。

  • 柔軟性:変換は非常に 柔軟 です。セクションを置き換えたり、マージしたり、属性を設定/削除したりできます。環境固有(DEV/UAT/PROD)またはビルド固有(デバッグ/リリース)の変換を使用できます。 。
  • 再利用性:一度トランスフォームを定義して、必要なすべてのプロジェクトで再利用します。
  • 細分性:必要なものだけを宣言し、構成全体をコピーして貼り付ける必要はありません。
  • 安全性:nugetとmsbuildに「ネイティブ」構成ファイルを管理させる(バインディングリダイレクトを追加するなど)

このアプローチの唯一の欠点は学習曲線です。構文を学習し、MSBuildで構成に変換を接着する方法を知る必要があります。

.NET Coreは変換をサポートしています ここに例があります web.configの変換を作成する方法ですが、変換を任意の構成に適用できます。

.NETアプリケーション(.NET Coreではない)を開発している場合は、 Slowcheetah を参照することをお勧めします。

変換に関しては多くのリソースと便利なブログがあり、かなり広く使われています。問題が発生する場合はご連絡ください。

私の観点から見ると、config変換は目標を達成するための適切なソリューションであるため、ランタイムを微調整する代わりに検討することを強くお勧めします。

構成セクションの外部化

それでもappSettingsを共通の場所に保持したい場合は、構成セクションを ConfigSource 属性で外部化できます。詳細は this および this スレッドを確認してください:

// ConsoleApp2.exe.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings configSource="../commonConfig/connections.config"/>
</configuration>

// connections.config:
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
<add name="MovieDBContext" 
   connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\Movies.mdf" 
   providerName="System.Data.SqlClient" 
/>
</connectionStrings>

AppSettingsセクションには、別のファイルからパラメーターをマージできるようにする File 属性が含まれています。

このオプションを使用すると、構成の特定のセクションを置き換えることができますが、コンテンツ自体全体を置き換えることはできません。したがって、appSettingsのみが必要な場合、それは完全に適用可能です。appSettingsを含む構成ファイルをユーザーと共有する共通の場所に配置し、構成ファイルをパッチして(fileまたはconfigSource属性を追加)、このセクションをソースしますその場所から。さらにセクションが必要な場合は、それらを別々のファイルとして抽出する必要があります。

4
fenixil

異なる.configファイルでは、デフォルトの入札単価リダイレクトを管理し、他のリダイレクトをアプリケーションパラメータ用に維持できます。これを行うには、 実行時にデフォルトのapp.configを変更する が最適です。

また、自動バインディングリダイレクト生成をシャットダウンして、手作りのapp.configファイルのみを使用することもできます。ここに例があります: 同じサードパーティDLLの2つの異なるバージョンを参照する方法が必要です

編集理論的根拠を考慮して:私が理解しているのであれば、app.exe.configファイルはまったく必要ありません。あなたはすでにカスタム定数をどこかに置いて読むことに成功しています。

バインディングリダイレクトのみが残ります。

ここで行うように、実行時にバインディングリダイレクトを管理することで、それを取り除くことができます: https://stackoverflow.com/a/32698357/361177 コードに構成ファイルを表示させることで、構成可能なバインディングリゾルバー。

ここに私の2セント:実現可能ですが、それだけの価値はないと思います。

編集2このソリューションは有望に見えます https://stackoverflow.com/a/28500477/361177

3
Orace