.config XML を (メインの実行可能アプリケーションとは) 別のファイルに格納するプラグイン DLL のカスタム構成セクションを作成しました。
カスタム セクション クラスのサンプルを次に示します。
using System;
using System.Configuration;
namespace PluginFramework.MyConfiguration
{
public class MyConfigurationSettings : ConfigurationSection
{
private Configuration _Config = null;
#region ConfigurationProperties
/// <summary>
/// A custom XML section for an application's configuration file.
/// </summary>
[ConfigurationProperty("MyProjects", IsDefaultCollection = true)]
public MyProjectConfigurationCollection MyProjects
{
get { return (MyProjectConfigurationCollection) base["MyProjects"]; }
}
// ...
#endregion
/// <summary>
/// Private Constructor used by our factory method.
/// </summary>
private MyConfigurationSettings () : base () {
// Allow this section to be stored in user.app. By default this is forbidden.
this.SectionInformation.AllowExeDefinition =
ConfigurationAllowExeDefinition.MachineToLocalUser;
}
// ...
#region Static Members
/// <summary>
/// Gets the current applications <MyConfigurationSettings> section.
/// </summary>
/// <param name="ConfigLevel">
/// The <ConfigurationUserLevel> that the config file
/// is retrieved from.
/// </param>
/// <returns>
/// The configuration file's <MyConfigurationSettings> section.
/// </returns>
public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel)
{
string appDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string localDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
System.Configuration.ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany\MyPluginApp\Default.config");
exeMap.RoamingUserConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany\MyPluginApp\Roaming.config");
exeMap.LocalUserConfigFilename = System.IO.Path.Combine(localDataPath, @"MyCompany\MyPluginApp\Local.config");
System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,ConfigLevel);
MyConfigurationSettings myConfigurationSettings = null;
try {
myConfigurationSettings = (MyConfigurationSettings)Config.GetSection("MyConfigurationSettings");
}
catch (System.Exception ex) {
// ConfigurationErrorsException caught here ...
}
if (myConfigurationSettings == null) {
myConfigurationSettings = new MyConfigurationSettings();
Config.Sections.Add("MyConfigurationSettings", myConfigurationSettings); }
}
if(myConfigurationSettings != null) {
myConfigurationSettings._Config = Config;
}
return myConfigurationSettings;
}
#endregion
}
} // PluginFramework.MyConfiguration
初回保存時に生成される .config XML は次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- The exception complains about the following line (assembly attributes are compliant): -->
<section name="MyConfigurationSettings" type="PluginFramework.MyConfiguration.MyConfigurationSettings, PluginFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToLocalUser" />
</configSections>
<MyConfigurationSettings>
<!-- Config properties are serialized fine according MyConfigurationSettings
properties marked with the ConfigurationProperty attribute ... -->
<MyProjects>
<MyProjectConfiguration GUID="{4307AC92-8180-4686-9322-830312ED59AB}">
<!-- ... more complex configuration elements -->
</MyProjectConfiguration>
</MyProjects>
</MyConfigurationSettings>
</configuration>
Config.GetSection()
後続の実行でこの XML を読み込もうとするとConfigurationErrorsException
、XML サンプルでマークされた行で、アセンブリMyPlugin
またはその依存関係の 1 つが見つからないことを示すメッセージが表示されます (元のファイルを投稿していないことをご容赦ください)。例外メッセージですが、私はドイツ語しか持っていません。このテキストがここで役立つとは思えません)。内部例外はSystem.IO
、アセンブリを読み込んでリフレクションを取得して 'MyConfigurationSettings' クラス タイプを解決しようとしているときに発生します。
状況を正確にするために、上記のコードはフレームワーク DLL (アセンブリ) 内に配置され、メイン アプリケーションからロードされた実際のプラグイン DLL によって参照されます。
次の UML ダイアグラムは、いくつかのコンポーネントの関係を示しています。
この問題について少し調べてみたところ、MyConfigurationSettings
クラスをエクスポートするアセンブリ (つまりPluginFramework
) に厳密な名前 (署名) を付け、それを GAC に登録する必要があると感じました。私はまだこれを試していませんでしたが、いくつかの理由でこの手順を避けたいと思います (それが役立つかどうか、問題を解決する唯一の選択肢であるかどうかを知る前に)。
ここに質問があります(申し訳ありませんが、実際には4つの質問をここに配置していますが、それらは非常に強く関連しているため、個別のSO質問を作成することは意味がありません)。
問題のアセンブリに厳密な名前を付けて GAC に登録することで、検索エラーの問題を解決できますか?
愚かなことに、構成管理が不平を言うアセンブリは、ロードされることが保証されています (
Configuration.GetSection()
それ自体を呼び出すため)。アセンブリまたは適切な構成タイプのデシリアライザー/シリアライザーをまたはクラス
に明示的に登録する方法はありますか?ConfigurationManager
Confguration
これは、(プライマリ) アセンブリがメイン アプリから読み込まれる方法によって引き起こされる問題である可能性があると言及しているHans Passant のコメントに関する詳細情報にも興味があります。私はこのメカニズムを制御できません。これが本質的にこの動作を引き起こす場合、合理的な回避策があるかどうか知りたいですか?
もう 1 つのアイデア (上記の方法で解決できない場合) は、構成 XML 形式をネイティブに (XML デシリアライゼーション/シリアライゼーション サポートを使用して) 完全に管理し、どこから構成ファイルをロードしてマージするかということです。これが最も適切なオプションである場合、誰でもこれを効率的に行う方法を示すことができますか (パスの管理とマージに必要最小限のコード)。
更新:
誰もこの質問についてより多くの洞察を与えることができないように思われるため (2 つの回答では実際にはそれ以上理解できません)、4. からオプションに変更し、すべて手動で行います。