zoukankan      html  css  js  c++  java
  • MEF接口应用初探

    Managed Extensibility Framework (MEF)

    关于MEF可参看官方文档http://msdn.microsoft.com/zh-cn/library/dd460648.aspx

    本文旨在将MEF应用到普通接口框架内部,构造可插拔,易扩展的接口框架。MEF还有很多其他应用(MVC,Winform)可以构建插件式,可持续的应用

    DEMO

    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

    DEMO

    代码不优,研究学习用0.0

  • 相关阅读:
    利用Azure Backup备份和恢复虚拟机(2)
    不允许保存更改。您所做的更改要求删除并重新创建以下表。您对无法重新创建的表进
    Vi命令
    Vi三种模式详解
    C#从Excel中读取数据为空
    Visual Studio 2012/2010/2008 远程调试
    Beyond Compare 3 设置自动换行
    Text类型的字段进行数据替换
    SQLite 连接两个字符串
    基于虚拟日志压缩的数据同步方案
  • 原文地址:https://www.cnblogs.com/isingel/p/3968134.html
Copyright © 2011-2022 走看看