Managed Extensibility Framework (MEF)
关于MEF可参看官方文档http://msdn.microsoft.com/zh-cn/library/dd460648.aspx
本文旨在将MEF应用到普通接口框架内部,构造可插拔,易扩展的接口框架。MEF还有很多其他应用(MVC,Winform)可以构建插件式,可持续的应用
1.项目结构
2.核心接口
接口定义一个方法名,以及请求内容参数
public interface IService { String GetResponse(string method, String input); }
接口实现:
[Export(typeof(IService))]//导出该实现(有导出那肯定有导入,在需要用到的地方导入即可) public class MyService : IService { [ImportMany] IEnumerable<Lazy<IOperation, IOperationData>> operations;//导入部件集合(各个对外接口) public String GetResponse(string method, String input) { try { foreach (Lazy<IOperation, IOperationData> i in operations) { if (i.Metadata.Method.Equals(method)) return i.Value.Operate(input).ToString(); } } catch (Exception ex) { return ex.Message; } return "内部异常"; } }
其中 IOperation,与IOperationData两个接口是各个对外接口部件的契约,实现如下(各个对外接口部件都要实现这两个接口)
public interface IOperation { String Operate(String req); }
public interface IOperationData { String Method { get; } }
2.部件组装
我将组装步骤放在了应用程序启动时,并且定义静态变量缓存无需每次请求都进行组装
public class OnStart { public static CompositionContainer _container;//静态部件容器,最常用容器 [Import(typeof(IService))]//此处需要使用到之前定义的接口所以导入 public IService service; public static IService Service { get; set; }//静态 public OnStart() { if (Service == null) { //一个可变集合目录包含多个部件 var catalog = new AggregateCatalog(); //从同一个程序集内加载部件 //catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); //从文件夹加载部件 DirectoryInfo di = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Apis")); DirectoryInfo[] dis = di.GetDirectories("Service*", SearchOption.TopDirectoryOnly); foreach (DirectoryInfo item in dis) { catalog.Catalogs.Add(new DirectoryCatalog(item.FullName));//从以Service开头的文件夹中加载各个部件(我将每个部件通过单独的文件夹独立) } catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyService).Assembly));//主部件 //catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); // _container.ComposeExportedValue<IService>(new MyService()); //catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Apis"))); //创建部件容器(CompositionContainer最常用) _container = new CompositionContainer(catalog); // _container.SatisfyImportsOnce() //Fill the imports of this object try { //在容器中组合部件 _container.ComposeParts(this); } catch (CompositionException compositionException) { throw; } } Service = service; } }
3.客户端调用
各个部件都组装好后,调用则非常简单,只有一行代码
public class Client { public static string Excute(string service,string request) { return OnStart.Service.GetResponse(service, request); } }
4.部件开发
新建新的类库项目,定义一个Query类,
[Export(typeof(IOperation))] [ExportMetadata("Method", "query")] public class Query : IOperation { public String Operate(String req) { return req + "查询"; } }
右击属性设置一下生成事件
copy "$(TargetDir)" "$(SolutionDir)MefApiApisService2"
这样一个部件就开发完成
5.Host
我通过一个简单的Web(Nancy框架)部署该接口(也可使用控制台,OWin等)
代码如下
public class HostModule : Nancy.NancyModule { public HostModule() { After.AddItemToEndOfPipeline(t => { t.Response.WithContentType("application/json; charset=utf-8"); }); //Post请求 Post["/{Service}"] = p => { try { string service = p.Service.ToString().ToLower().Trim(); string request = string.Empty; using (StreamReader sr = new StreamReader(Request.Body)) { request = sr.ReadToEnd(); } return Client.Excute(service, request); } catch (Exception ex) { return Response.AsJson(new { result = false, msg = ex.Message }); } };
//Get请求 Get["/{Service}"] = p => { try { string service = p.Service.ToString().ToLower().Trim(); string request = Request.Query["request"]; return Client.Excute(service, request); } catch (Exception ex) { return Response.AsJson(new { result = false, msg = ex.Message }); } }; } }
6.结果
http://localhost:9803/query?request=asdfasdf
代码不优,研究学习用0.0