前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.Net5中WebApi使用MEF2框架的使用

.Net5中WebApi使用MEF2框架的使用

作者头像
Vaccae
发布2021-08-25 10:19:28
9020
发布2021-08-25 10:19:28
举报
文章被收录于专栏:微卡智享微卡智享

本文长度为5669,预计阅读9分钟

前言

最近有个产品需要设计重构,主要后端是C#和前端是Android程序,后端也考虑过微服务,但是觉得根据用户体量来说,有点太重了,但是也是想要团队分工,所以就考虑了MEF的方式,原来MEF的插件方式在《C# MEF插件的使用及Demo分享》的文章中介绍过,不过当时用的是WinForm版本,现在是要在NET5上使用,所以就专门做了DEMO程序来验证可行性。

实现效果

同一个API根据参数不同调用的第一个插件函数。

同一个API根据参数不同调用的第二个插件函数。

关于MEF和MEF2

微卡智享

微软发布了四个版本的 MEF:

  • 随着 .NET Framework 4.0 发布,微软称之为 MEF
  • 随着.NET Framework 4.5 发布,微软让它更好用了,微软称之为 MEF2,但因为接口兼容,也直接称之为 MEF
  • .NET 开发团队觉得 MEF 第一代性能太差,于是通过 NuGet 为移动设备发布了可移植类库,是个轻量级版本,只移植了 .NET Framework 中 MEF2 里 2 的部分;随后 .NET Core 中也加入了 MEF2,也是 .NET Framework 中 MEF2 里 2 的部分
  • Visual Studio 开发团队觉得 .NET Framework 里的 MEF2 性能太差,NuGet 版的 MEF2 功能太少,于是自己又写了一个,微软称之为 VS-MEF

MEF2 是微软后来以 NuGet 包形式发布的 MEF2;适用于 .NET Framework 4.5 及以上、.NET Core 和各种 .NET 移动平台。它的接口相比于 .NET Framework 中原生带的已经变了,中文和英文的参考资料很少,本章Demo也是在网上找了不少,然后自己研究测试后可用的,也算是比较花时间了。

代码实现

微卡智享

01

创建.Net5的WebApi项目

项目是系统默认的生成项目,这里倒是没什么可说的,只不过最后需要将MEF的类做依赖注入,最后再来操作这个。

02

创建Mef接口类

1.创建WebMef.Core的类库

也是新建一个.net5的类库,这个类库里用来写Mef插件的接口

2.添加Mef2的Nuget包

在Nuget包中添加Microsoft.Composition组件。这个组件即为MEF2的组件。

3.创建IMSG接口

创建一个IMsg的接口,里面定义了两个属性和三个函数方法。

代码语言:javascript
复制
namespace WebMef.Core
{
    public interface IMsg
    {
        string InfName { get; }

        int InfCode { get; set; }

        void Send(string msg);

        string Send(string msg, int infcode);

        string Recv(int infcode);
    }
}

03

新建插件类继承接口

  1. 创建Plugin1和Plugin2的两个插件类

然后在右键添加引用中加入刚才创建的WebMef.Core的类库

两个插件的类继承自IMsg,然后写实现方法。

插件1的ReadInf.cs

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebMef.Core;

namespace WebMef.Plugin1
{
    [Export(typeof(IMsg))]
    public class ReadInf : IMsg
    {
        public string InfName { get=> "阅读"; }
        public int InfCode { get ; set; }

        public string Recv(int infcode)
        {
            string msg = "当前页面为:" + InfName + "  序号为:" + infcode;
            return msg;
        }

        public void Send(string msg)
        {
            InfCode++;
        }

        public string Send(string msg, int infcode)
        {
            int oldinfcode = InfCode;
            InfCode += infcode;
            string retmsg = "当前页面为:" + InfName + "  原序号为:" + oldinfcode + "  现序号为:" + InfCode + " 增加了" + infcode;
            return retmsg;
        }
    }
}

插件2的WriteInf.cs

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebMef.Core;

namespace WebMef.Plugin2
{
    [Export(typeof(IMsg))]
    public class WriteInf : IMsg
    {
        public string InfName => "写作";

        public int InfCode { get ; set; }

        public string Recv(int infcode)
        {
            string msg = "页面为:" + InfName + "  序号为:" + infcode;
            return msg;
        }

        public void Send(string msg)
        {
            InfCode++;
        }

        public string Send(string msg, int infcode)
        {
            int oldinfcode = InfCode;
            InfCode += infcode;
            string retmsg = msg + "页面为:" + InfName + "  原号为:" + oldinfcode + "  现号为:" + InfCode + " 增加了" + infcode;
            return retmsg;
        }
    }
}

到这一步,插件的实现就基本完成了,要注意的点就是要在类的前面加上[Export(typeof(IMsg))]

04

创建Mef的注册类

上面几步已经把简单的接口及实现方法都写完了,接下来要在WebMef.Core的类库中创建一个MefRegister注册类。

加载后的组件要加上特性ImportMany,而定义的组合窗口是使用CompositionHost,这里就和最初的Mef完全不一样的了。

加入一个public async Task<string> Start()用于处理WebApi启动时的依赖注册。这个函数比较核心,完整MefRegister代码

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Composition;
using System.Composition.Hosting;
using System.IO;
using System.Runtime.Loader;
using System.Linq;
using System.Composition.Convention;

namespace WebMef.Core
{
    public class MefRegister
    {
        [ImportMany]
        public static IEnumerable<IMsg> Msgs { get; set; }

        //定义组合容器
        private CompositionHost _container;


        public async Task<string> Start()
        {
            var assembiles = Directory.GetFiles(AppContext.BaseDirectory, "*.dll", SearchOption.TopDirectoryOnly)
            .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);

            var conventions = new ConventionBuilder();
            conventions.ForTypesDerivedFrom<IMsg>()
                .Export<IMsg>()
                .Shared();

            _container = new ContainerConfiguration().WithAssemblies(assembiles, conventions).CreateContainer();

            Msgs = _container.GetExports<IMsg>();

            return await Task.FromResult("MEF组件加载完成");
        }

        public void Stop()
        {
            Msgs = null;
            _container.Dispose();
        }
    }
}

05

WebApi启动注入依赖

完成上面的所有步骤后,接下来就是最后一步实现,在WebApi启动时将MEF注入依赖。主要就是修改startup的类。

在ConfigureServices加入 services.AddSingleton<MefRegister>();

将Configure函数的输入参数加上IHostApplicationLifetime这个参数

函数最后再加入上面这段代码,即可实现注入。

startup.cs

代码语言:javascript
复制
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebMef.Core;

namespace WebMefDemo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();

            services.AddSingleton<MefRegister>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostApplicationLifetime appLifetime, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });


            var mefreg = app.ApplicationServices.GetRequiredService<MefRegister>();
            appLifetime.ApplicationStarted.Register(() =>
            {
                mefreg.Start().Wait();
            });

            appLifetime.ApplicationStopped.Register(() =>
            {
                mefreg.Stop();
            });

        }
    }
}

06

ApiConntrol调用

上面都完成后最后一步就是测试调用了。新建一个MefConntrol的类,加入一个Get方法,根据输入的name的名称查找出对应的MEF插件,然后直接调用接口实现的Send方法即可。

代码语言:javascript
复制
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebMef.Core;

namespace WebMefDemo.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class MefController : ControllerBase
    {
        [HttpGet("Msg")]
        public string GetMsgs(string name)
        {
            if (name == null) return "找不到对应的组件";

            var msg = MefRegister.Msgs.FirstOrDefault(t => t.InfName == name);

            string now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            return msg.Send(now, 1);
        }

    }
}

需要注意的是默认的Plugin1和Plugin2两个插件编译生成时并不是默认生成在WebMefDemo的bin下面,需要自己配置输出,或是生成后拷贝到WebMefDemo的bin目录下才能获取到。

最终就实现了MEF2在.net5的webapi中的使用,调用的效果就是文章开头实现的图片。

源码地址

https://github.com/Vaccae/DotNet5WebApiMEF2Demo.git

本文参与?腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-02,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 微卡智享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体同步曝光计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 源码地址
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com