ちょっと前に twitter で .NET の軽量サーバーって無いの?
てのを見かけて、OWIN Self Host と MEF(DirectoryCatalog) で dll 置くだけで deploy みたいなのが出来るかなーと思ったので試してみました。
MEF はすっかり忘れてたのでこちらをコピペ*1
MEFでディレクトリカタログを追いかける(C# Advent Calender jp:2010 12/02) | kazuk は null に触れてしまった
OWIN Self Host はこちらを参考に
OWIN - Open Web Interface for .NET とは何か? - しばやん雑記
こんな interface を用意して
using Owin; using System; namespace OwinSelfHostCommon { public interface IOwinApp { string Url { get; } Action<IAppBuilder> Startup { get; } } }
メインはこんなの。ほぼコピペ。。
using Microsoft.Owin.Hosting; using OwinSelfHostCommon; using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.IO; namespace OwinSelfHostSample { class Program { static void Main(string[] args) { new Program().Run(); } [ImportMany(AllowRecomposition = true)] private IEnumerable<Lazy<IOwinApp>> _parts; private CompositionContainer _container; private FileSystemWatcher _fsWatcher; private DirectoryCatalog _directoryCatalog; private readonly Dictionary<Type, IDisposable> _startedApps = new Dictionary<Type, IDisposable>(); public void Run() { var aggregateCatalog = new AggregateCatalog(); aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); // ReSharper disable AssignNullToNotNullAttribute string extentionPath = Path.Combine( Path.GetDirectoryName(typeof(Program).Assembly.Location), "../../addin"); // 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) { StartOwinApp(part.Value); } while (Console.ReadLine() != "exit") { foreach (var app in _startedApps.Values) { app.Dispose(); } } } 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) { StartOwinApp(part.Value); } } void StartOwinApp(IOwinApp app) { if (!_startedApps.ContainsKey(app.GetType())) { var startedApp = WebApp.Start(new StartOptions(app.Url), app.Startup); _startedApps.Add(app.GetType(), startedApp); } } } }
IOwinApp の実装クラスの型で、OWIN で実行済みか判断してます。真面目にやるなら、URL のバッティングとかも見る必要あるかな?
IOwinApp を実装したクラスはこんなの。これもコピペ。。
using Owin; using OwinSelfHostCommon; using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; using System.Threading.Tasks; namespace HelloOwin { [Export(typeof(IOwinApp))] public class OwinApp : IOwinApp { public string Url { get { return "http://localhost:8080/"; } } public Action<IAppBuilder> Startup { get { return (app => app.Use<Handler>()); } } } public class Handler { public Handler(Func<IDictionary<string, object>, Task> next) { } public Task Invoke(IDictionary<string, object> environment) { environment["owin.ResponseStatusCode"] = 200; using (var writer = new StreamWriter(environment["owin.ResponseBody"] as Stream)) { return writer.WriteAsync("Hello, OWIN"); } } } }
メインを実行しコンソールが起動したら、IOwinApp を実装したクラスを含んだ dll を 所定のフォルダに配置すると FileSystemWatcher で検知し、Owin でホストします。
課題は、コンソールを止めないと dll の削除や上書きが出来ない事。
という訳で、出来たけど実用するかと言われると…って感じ。
これを全部 PowerShell に出来たらもうちょい面白いかな~。
という訳で、ここらへん見てみる。
PowerShell scripting in MEF-based applications - Ryan Tremblay's Blog - Site Home - MSDN Blogs
How to run PowerShell from node.js