NLog Target Extension(その3)

NLog.config
<nlog>
    <extensions>
        <add assembly="Mandarine"/>
    </extensions>
    <targets>
        <target name="target1" 
                type="IsolatedStorage" 
                layout="${longdate} ${callsite} ${level} ${message}"/>
    </targets>
    <rules>
        <logger name="*" minlevel="Debug" writeTo="target1" />
    </rules>
</nlog>
#if !WINDOWS_PHONE
                string assemblyFile = addElement.GetOptionalAttribute("assemblyFile", null);
                if (assemblyFile != null)
                {
                    try
                    {
#if SILVERLIGHT
                                var si = Application.GetResourceStream(new Uri(assemblyFile, UriKind.Relative));
                                var assemblyPart = new AssemblyPart();
                                Assembly asm = assemblyPart.Load(si.Stream);
#else
:

アセンブリのロードが省かれている。これでは外部アセンブリを扱えない。

Windows PhoneではAssemblyPart#Loadがサポートされていないのが問題なのだが、ここでやりたいことは設定ファイル(NLog.Config)のextension要素中のassembly属性で指定されたアセンブリをロードすること、そしてロードしたアセンブリからNLogのTargetととなる型(IsolatedStorageTargetクラス)をロードすることなので、他のAPIで代替えしてみることにした。

Windows PhoneではサポートされていないAssemblyPartからのロード (XmlLoggingConfiguration.cs)
string assemblyName = addElement.GetOptionalAttribute("assembly", null);
var si = Application.GetResourceStream(new Uri(assemblyName + ".dll", UriKind.Relative));
var assemblyPart = new AssemblyPart();
Assembly asm = assemblyPart.Load(si.Stream);
this.configurationItemFactory.RegisterItemsFromAssembly(asm, prefix);
Windows Phoneでも可能なAssemblyから直接ロードする方法
string assemblyName = addElement.GetOptionalAttribute("assembly", null);
var asm = Assembly.Load(assemblyName);
this.configurationItemFactory.RegisterItemsFromAssembly(asm, prefix);

これで末行のconfigurationItemFactory.RegisterItemsFromAssemblyにより型の情報が登録されるので、IsolatedStorageTargetクラスをNLogのターゲットして使えるようになった。

なお、Windows Phoneのようにセキュリティの制限を厳しくしなければならいなプラットホームの場合、Assembly.Loadでどんなアセンブリでもロードできる訳ではない。これは推測だがロードできるのはDeployment.Current.Partsで取得できるAssemblyPartに属するアセンブリに限られるだろう。


次回ではNLogを使って実際にログを出力してみよう。


追記:
Windows Phone でのアセンブリのデマンド ロードは以下のイディオムで実行するようだ。

var parts = Deployment.Current.Parts;
foreach (var part in parts)
{
    var assemblyName = part.Source.Replace(".dll", string.Empty);
    var assembly = Assembly.Load(assemblyName);
}

やはりDeployment.Parts、つまりAssemblyPartCollection列挙されるAssemblyPartで示されるアセンブリだけが対象のようだ。