7

実行時にプラグインをロードして、それらの構成ファイルにアクセスしようとしています。構成ファイルの構成セクションは、ConfigurationElementCollection、ConfigurationElement、およびConfigurationSectionから派生したクラスにマップされます。プラグインとその構成ファイルは、「プラグイン」と呼ばれるサブフォルダー内の場所にあります。

問題は、プラグイン構成データをロードして、それぞれのクラスに正しく逆シリアル化できないように見えることです。

プラグインEmailPlugin.dllのプラグイン構成の例を次に示します。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="EmailConfigurationSection" type="Foo.Plugins.EmailConfigurationSection, EmailPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true"/>
  </configSections>
  <EmailConfigurationSection server="192.168.0.10">
    <EmailSettings>
      <add  keyword="ERROR"
                    sender="error@error.com"
                    recipients="foo@bar.com, wiki@waki.com"
                    subject = "Error occurred"
                    body = "An error was detected"
            />
    </EmailSettings>
  </EmailConfigurationSection>
</configuration>

私はこのコードを使用してこれをロードします:

    private static System.Configuration.Configuration config = null;
    public static System.Configuration.Configuration CurrentConfiguration
    {
        get
        {
            if (config == null)
            {
                Assembly assembly = Assembly.GetAssembly(typeof(EmailPlugin));
                string directory = Path.GetDirectoryName(assembly.CodeBase);
                string filename = Path.GetFileName(assembly.CodeBase);
                string assemblyPath = Path.Combine(directory, filename);
                config = ConfigurationManager.OpenExeConfiguration(new Uri(assemblyPath).LocalPath);
            }

            return config;
        }
    }

これにより、エラーが発生します。

An error occurred creating the configuration section handler for EmailConfigurationSection: Could not load file or assembly 'EmailPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

これを設定ファイルの先頭に追加しました:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
     <probing privatePath="Plugins"/>
  </assemblyBinding>
</runtime>

そのため、DLLは見つかりましたが、取得しようとすると適切なクラスにキャストされません。

EmailConfigurationSection defaults = CurrentConfiguration.Sections["EmailConfigurationSection"] as EmailConfigurationSection;

常にnullを返します。次のコードを使用してXMLを取得できるため、正しい場所と構成ファイルを参照していることがわかります。

var section = CurrentConfiguration.Sections["EmailConfigurationSection"];
string configXml = section.SectionInformation.GetRawXml();

ただし、次のコードで逆シリアル化しようとすると、次のようになります。

var serializer = new XmlSerializer(typeof(EmailConfigurationSection));
object result;

EmailConfigurationSection defaults;
using (TextReader reader = new StringReader(configXml))
{
    defaults = (EmailConfigurationSection)serializer.Deserialize(reader);
}

...例外が発生します:

There was an error reflecting type 'Foo.Plugins.EmailConfigurationSection'.

これは、InnerExceptionの内容です。

You must implement a default accessor on System.Configuration.ConfigurationLockCollection because it inherits from ICollection.

クラスEmailConfigElementCollectionを参照していると思いますが、このクラスにはデフォルトのアクセサーがあるため、メッセージは意味がありません。

    public EmailConfigElement this[int index]
    {
        get
        {
            return (EmailConfigElement)BaseGet(index);
        }
        set
        {
            if (BaseGet(index) != null)
            {
                BaseRemoveAt(index);
            }
            BaseAdd(index, value);
        }
    }

私はこのコードを他のプロジェクトで(個別のDLL /構成を使用しても)正常に使用しましたが、MEFで使用するのはこれが初めてです。誰かが問題が何であるか、または適切な回避策を知っていますか?

.NET4.5を使用しています

4

1 に答える 1

5

私はこれを次の変更で修正しました:

public static System.Configuration.Configuration CurrentConfiguration
{
    get
    {
        if (config == null)
        {
            // Added the next bit
            AppDomain.CurrentDomain.AssemblyResolve += (o, args) =>
            {
                var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
                return loadedAssemblies.Where(asm => asm.FullName == args.Name)
                                           .FirstOrDefault();
            };

            Assembly assembly = Assembly.GetAssembly(typeof(EmailPlugin));
            string directory = Path.GetDirectoryName(assembly.CodeBase);
            string filename = Path.GetFileName(assembly.CodeBase);
            string assemblyPath = Path.Combine(directory, filename);
            config = ConfigurationManager.OpenExeConfiguration(new Uri(assemblyPath).LocalPath);
        }

        return config;
    }
}

私はこの質問からこれを得ました: アセンブリをエクスポートするMEFのカスタム構成セクション。私は実際にそれを以前に試しましたが成功しませんでした。

秘訣は、ランタイムタグをXML構成の一番下に移動する必要があることでした。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="EmailConfigurationSection" type="Foo.Plugins.EmailConfigurationSection, EmailPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true"/>
  </configSections>
  <EmailConfigurationSection server="255.255.255.1">
    <EmailSettings>
      <clear />
      <add  keyword="FOO"
                    sender="foo@foo.com"
                    recipients="me@you.com"
                    subject = "Foo occurred"
                    body = "Hello"
            />
    </EmailSettings>
  </EmailConfigurationSection>
    <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <probing privatePath="Plugins"/>
      </assemblyBinding>
   </runtime>
</configuration>
于 2012-08-15T16:22:51.893 に答える