kazuk は null に触れてしまった
C# / .NET 系技術ネタ縛りでお送りしております
タグアーカイブ: ComposeParts
MEFでディレクトリカタログを追いかける(C# Advent Calender jp:2010 12/02)
2010/12/03
投稿者: : ってタイトルで用意してたんだけど、結果的には追加はいいけど、削除、更新は駄目だったの巻
MEF いいっすよねー。
ロジック殆ど無しのホストに Extensibility で拡張を仕込んでいければ、システムのメンテナンス単位を小さくできる。停止時間を当然に減らせる。
良い事だらけだ!
って感じなんですが、本当に拡張していけるのか試していってという感じ。
Managed Extensibility Framework の概要
MEF では発見可能性、拡張性、および移植性に重点が置かれているのに対し、MAF では拡張機能の特定とアセンブリの読み込みおよびアンロードに重点が置かれています。
InfoQ: CLRが、何回目かの、「最初の」プラグインモデルを採用。
- System.Addin は、使用されなくなったAppDomainを自動的に、アンロードし、メモリを再利用できるように、管理している。
MAF使わないとアンロードできないのか…
そんな事は無い、アセンブリのシャドウコピーがあるじゃないか!
って試したコードが以下。
using System; using System.Collections.Generic; using System.IO; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; namespace MefConsoleApplication { public interface IDoSomething { void DoSomethig(); } public class Program { #pragma warning disable 649 [ImportMany(AllowRecomposition = true)] private IEnumerable<Lazy<IDoSomething>> _parts; #pragma warning restore 649 private CompositionContainer _container; private FileSystemWatcher _fsWatcher; private DirectoryCatalog _directoryCatalog; public void Run() { AggregateCatalog aggregateCatalog = new AggregateCatalog(); aggregateCatalog.Catalogs.Add( new AssemblyCatalog(typeof(Program).Assembly)); // ReSharper disable AssignNullToNotNullAttribute string extentionPath = Path.Combine( Path.GetDirectoryName(typeof(Program).Assembly.Location), "..\\..\\Extentions"); // ReSharper restore AssignNullToNotNullAttribute _fsWatcher = new FileSystemWatcher(extentionPath); _fsWatcher.Changed += FsWatcherChanged; _fsWatcher.EnableRaisingEvents = true; _directoryCatalog = new DirectoryCatalog( extentionPath); _directoryCatalog.Changed += CatalogChanged; aggregateCatalog.Catalogs.Add( _directoryCatalog); aggregateCatalog.Changed += CatalogChanged; _container = new CompositionContainer(aggregateCatalog); _container.ComposeParts(this); foreach (var part in _parts) { part.Value.DoSomethig(); } while (Console.ReadLine() != "exit") { } } void FsWatcherChanged(object sender, FileSystemEventArgs e) { Console.WriteLine("extentions directory changed"); _directoryCatalog.Refresh(); } void CatalogChanged(object sender, ComposablePartCatalogChangeEventArgs e) { Console.WriteLine("catalog changed " + sender.GetType().Name); _container.ComposeParts(this); foreach (var part in _parts) { part.Value.DoSomethig(); } } static void Main() { if (!AppDomain.CurrentDomain.ShadowCopyFiles) { Console.WriteLine("ShadowCopyFilesがオフです"); AppDomainSetup appDomainSetup = new AppDomainSetup(); appDomainSetup.ShadowCopyFiles = "true"; appDomainSetup.ShadowCopyDirectories = Path.GetTempPath(); appDomainSetup.CachePath = Path.GetTempPath(); AppDomain execDomain = AppDomain.CreateDomain("execDomain", AppDomain.CurrentDomain.Evidence, appDomainSetup); execDomain.ExecuteAssembly(typeof(Program).Assembly.Location); return; } Console.WriteLine("ShadowCopyFilesがオンです"); Program prog = new Program(); prog.Run(); } } [Export(typeof(IDoSomething))] public class ImplSomething1 : IDoSomething { public void DoSomethig() { Console.WriteLine("do something 1"); } } }
Main での AppDomainSetup を介して自分を実行し直すって方法で、アプリケーションドメインをシャドウコピー可能にしている。
using System; using System.ComponentModel.Composition; using MefConsoleApplication; namespace ApplicationComponent1 { [Export(typeof(IDoSomething))] public class Class1 : IDoSomething { public void DoSomethig() { Console.WriteLine("extention component1"); } } }
ってアセンブリを放り込むと、ディレクトリの変更を検出して、ちゃんとアセンブリがロードされる。大成功だ。
で、放り込んだもんを削除しようとする。
残念!ってわけで拒否されてしまいました…。
MEF で DirectoryCatalog のChangeを追うには以下が注意事項でございます。
- FileSystemWatcherで監視してないと駄目、_directoryCatalog.Refresh()でカタログを更新する必要がある。
- [ImportMany(AllowRecomposition = true)] 重要、AllowRecompositionをtrueにしないとRejectされる。
- シャドウコピーを有効にしてもアセンブリの削除はできないぜ。
って訳で、長い!なMEFでディレクトリカタログを追ってみたけど失敗した!な記事でございます。
C# Advent Calendar jp: 2010 : ATND の 12/2日分って事で次の日の人よろしく。
有用?よくわかんない記事で済まん。