• MEF 插件式开发之 DotNetCore 中强大的 DI


    背景叙述

    在前面几篇 MEF 插件式开发 系列博客中,我分别在 DotNet FrameworkDotNet Core 两种框架下实验了 MEF 的简单实验,由于 DotNet Framework 由来已久,因此基于该框架下衍生出的很多优秀的 MEF 框架较多。但是对于 DotNet Core 来说,情况有所不同,由于它本身对 DI 内置并提供支持,因此我尝试使用它的全新 依赖注入(DI) 来做一些实验。

    动手实验

    要想让程序支持 DI,就需要为项目安装 Package:

    Install-Package Microsoft.Extensions.DependencyInjection -Version 2.1.1 
    

    然后,我们就可以使用强大的 DI 了。

    DotNet Core,所有服务的注册都是统一放到一起的,而这个就是由 ServiceCollection 来接收的;其次,当服务注册完毕后,还需要对服务进行初始化构建,构建后的结果作为一个提供服务者返回,其对应的类型为 ServiceProvider;最后,如果获取某个已经注册的服务的话,可以通过 serviceProvider.GetService() 来获取。

    下面,我分别从下面 4 个方面来体验一下 DotNet Core 中强大的 DI

    注入并设置服务的生命周期

    注册服务需要涉及到服务的生命周期,因此,IServiceCollection 有 3 个不同的扩展方法:

    • AddTransient:每次获取的服务都是新创建的;
    • AddScoped:在一定范围内获取的服务是同一个;
    • AddSingleton:每次获取的服务都是同一个,单例模式的服务;

    示例代码如下所示:

    public interface IBaseSender
    {
        void Send(string message);
    
    }
    
    public interface ITransientSender : IBaseSender { }
    public class TransientSender : ITransientSender
    {
        public void Send(string message) => Console.WriteLine($"{GetHashCode()} {message}");
    }
    
    public interface IScopedSender : IBaseSender { }
    public class ScopedSender : IScopedSender
    {
        public void Send(string message) => Console.WriteLine($"{GetHashCode()} {message}");
    }
    
    public interface ISingletonSender : IBaseSender { }
    public class SingletonSender : ISingletonSender
    {
        public void Send(string message) => Console.WriteLine($"{GetHashCode()} {message}");
    }
    
    class Program
    {
        private static readonly object locker = new object();
        static void Main(string[] args)
        {
            var serviceProvider = new ServiceCollection()
                .AddTransient<ITransientSender, TransientSender>()
                .AddScoped<IScopedSender,ScopedSender>()
                .AddSingleton<ISingletonSender, SingletonSender>()
                .BuildServiceProvider();
    
            using (var scope = serviceProvider.CreateScope())
            {
                for (int i = 0; i < 2; i++)
                {
                    serviceProvider.GetService<ITransientSender>().Send("ITransientSender");
                    scope.ServiceProvider.GetService<IScopedSender>().Send("IScopedSender");
                    serviceProvider.GetService<ISingletonSender>().Send("ISingletonSender");
                }
            }
            Console.WriteLine("***********************************");
            using (var scope = serviceProvider.CreateScope())
            {
                for (int i = 0; i < 2; i++)
                {
                    serviceProvider.GetService<ITransientSender>().Send("ITransientSender");
                    scope.ServiceProvider.GetService<IScopedSender>().Send("IScopedSender");
                    serviceProvider.GetService<ISingletonSender>().Send("ISingletonSender");
                }
            }
    
            Console.ReadKey();
        }
    }
    

    程序输出如下图所示:

    通过上图我们可以了解到,

    • 在相同或不同的作用域内,通过 AddTransient 注册的服务每次都是新创建的;
    • 在相同作用域内,通过 AddScoped 注册的服务每次同一个;在不同请求作用域中,通过 AddScoped 注册的服务每次都是新创建的;
    • 通过 AddSingleton 注册的服务在整个程序生命周期内是同一个;

    需要注意的是,在 ASP.NET Core 中,所有与 EF 相关的服务都应该通过 AddScoped<TInterface,T> 的方式注入。此外,如果想注入泛型的话,可借助 typeof方式来注入。

    构造函数注入

    参数注入

    public interface IBaseSender
    {
        void Send();
    }
    
    public class EmialSender : IBaseSender
    {
        private readonly string _msg;
        public EmialSender(string msg) => _msg = msg;
    
        public void Send() => Console.WriteLine($"{_msg}");
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var serviceProvider = new ServiceCollection()
                .AddSingleton<IBaseSender, EmialSender>(factory => { return new EmialSender("Hello World"); })
                .BuildServiceProvider();
    
            serviceProvider.GetService<IBaseSender>().Send();
    
            Console.ReadKey();
        }
    }
    

    服务注入

    public interface IBaseSender
    {
        void Send();
    }
    
    public class EmialSender : IBaseSender
    {
        private readonly IWorker _worker;
        public EmialSender(IWorker worker) => _worker = worker;
    
        public void Send() =>_worker.Run("Hello World");
    }
    
    public interface IWorker
    {
        void Run(string message);
    }
    
    public class Worker : IWorker
    {
        public void Run(string message)
        {
            Console.WriteLine(message);
        }
    }
    
    class Program
    {
        private static readonly object locker = new object();
        static void Main(string[] args)
        {
            var serviceProvider = new ServiceCollection()
                .AddSingleton<IBaseSender, EmialSender>()
                .AddSingleton<IWorker, Worker>()
                .BuildServiceProvider();
    
            serviceProvider.GetService<IBaseSender>().Send();
    
            Console.ReadKey();
        }
    }
    

    在传统的DotNet 框架下开发,注入是支持 参数、服务和属性的,但是在 DotNet Core 平台下目前只支持前两种注入方式。

    添加日志记录

    DotNet Core 中已经将 Logger 功能集成进来,只需要安装相应的 Package 即可食用。

    Microsoft.Extensions.Logging
    Microsoft.Extensions.Logging.Console
    Microsoft.Extensions.Logging.Debug
    

    示例程序如下所示:

    public interface IBaseSender
    {
        void Send();
    }
    
    public class EmialSender : IBaseSender
    {
        private readonly IWorker _worker;
        private readonly ILogger<EmialSender> _logger;
    
        public EmialSender(IWorker worker, ILogger<EmialSender> logger)
        {
            _worker = worker;
            _logger = logger;
        }
    
        public void Send()
        {
            _worker.Run("Hello World");
            _logger.LogInformation(MethodBase.GetCurrentMethod().Name);
        }
    }
    
    public interface IWorker
    {
        void Run(string message);
    }
    
    public class Worker : IWorker
    {
        public void Run(string message)
        {
            Console.WriteLine(message);
        }
    }
    
    class Program
    {
        private static readonly object locker = new object();
        static void Main(string[] args)
        {
            var serviceProvider = new ServiceCollection()
                .AddSingleton<IBaseSender, EmialSender>()
                .AddSingleton<IWorker, Worker>()
                .AddSingleton(new LoggerFactory().AddConsole().AddDebug())
                .AddLogging()
                .BuildServiceProvider();
    
            serviceProvider.GetService<IBaseSender>().Send();
    
            Console.ReadKey();
        }
    }
    

    总结

    这次做的几个小实验还是很有趣的,体验了一下 DotNet Core 中强大的 DI 功能。和传统的 DotNet Framework 相比,有很多改进的地方,这是值得每一个 DotNet 程序员 去尝试的一门新技术。

    相关参考

  • 相关阅读:
    Pytorch1.0入门实战二:LeNet、AleNet、VGG、GoogLeNet、ResNet模型详解
    Pytorch1.0入门实战一:LeNet神经网络实现 MNIST手写数字识别
    浅谈RNN、LSTM + Kreas实现及应用
    tensorflow 1.12.0 gpu + python3.6.8 + win10 + GTX1060 + cuda9.0 + cudnn7.4 + vs2017)
    高手详解SQL性能优化十条经验
    SQL语句操作符优化
    SQL优化
    34条简单的SQL优化准则
    销售订单无法使用折扣(其他可以正常使用)
    EBS FORM FOLDER 开发,单元格无法使用右键
  • 原文地址:https://www.cnblogs.com/hippieZhou/p/9460223.html
Copyright © 2020-2023  润新知