背景叙述

在前面几篇 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 程序员 去尝试的一门新技术。

相关参考

MEF 插件式开发之 DotNetCore 中强大的 DI的更多相关文章

  1. MEF 插件式开发之 DotNetCore 初体验

    背景叙述 在传统的基于 .Net Framework 框架下进行的 MEF 开发,大多是使用 MEF 1,对应的命名空间是 System.ComponentModel.Composition.在 Do ...

  2. MEF 插件式开发之 WPF 初体验

    MEF 在 WPF 中的简单应用 MEF 的开发模式主要适用于插件化的业务场景中,C/S 和 B/S 中都有相应的使用场景,其中包括但不限于 ASP.NET MVC .ASP WebForms.WPF ...

  3. Android安全开发之WebView中的地雷

    Android安全开发之WebView中的地雷 0X01 About WebView 在Android开发中,经常会使用WebView来实现WEB页面的展示,在Activiry中启动自己的浏览器,或者 ...

  4. JavaEE开发之Spring中的多线程编程以及任务定时器详解

    上篇博客我们详细的聊了Spring中的事件的发送和监听,也就是常说的广播或者通知一类的东西,详情请移步于<JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换&g ...

  5. Android插件化开发之OpenAtlas生成插件信息列表

    上一篇文章.[Android插件化开发之Atlas初体验]( http://blog.csdn.net/sbsujjbcy/article/details/47446733),简单的介绍了使用Atla ...

  6. MEF 插件式开发 - 小试牛刀

    原文:MEF 插件式开发 - 小试牛刀 目录 MEF 简介 实践出真知 面向接口编程 控制反转(IOC) 构建入门级 MEF 相关参考 MEF 简介 Managed Extensibility Fra ...

  7. MEF 插件式开发 - WPF 初体验

    原文:MEF 插件式开发 - WPF 初体验 目录 MEF 在 WPF 中的简单应用 加载插件 获取元数据 依赖注入 总结 MEF 在 WPF 中的简单应用 MEF 的开发模式主要适用于插件化的业务场 ...

  8. JavaEE开发之Spring中Bean的作用域、Init和Destroy方法以及Spring-EL表达式

    上篇博客我们聊了<JavaEE开发之Spring中的依赖注入以及AOP>,本篇博客我们就来聊一下Spring框架中的Bean的作用域以及Bean的Init和Destroy方法,然后在聊一下 ...

  9. JavaEE开发之Spring中的条件注解组合注解与元注解

    上篇博客我们详细的聊了<JavaEE开发之Spring中的多线程编程以及任务定时器详解>,本篇博客我们就来聊聊条件注解@Conditional以及组合条件.条件注解说简单点就是根据特定的条 ...

随机推荐

  1. API网关设计(一)之Token多平台身份认证方案(转载)

    原文:https://segmentfault.com/a/1190000018535570?utm_source=tag-newest 概述 今天咱们面对移动互联网的发展,系统一般是多个客户端对应一 ...

  2. MySQL--事务隔离级别RR和RC的异同

    在MySQL中,事务隔离级别RC(read commit)和RR(repeatable read)两种事务隔离级别基于多版本并发控制MVCC(multi-version concurrency con ...

  3. 背水一战 Windows 10 (68) - 控件(控件基类): UIElement - Pointer 相关事件, Tap 相关事件, Key 相关事件, Focus 相关事件

    [源码下载] 背水一战 Windows 10 (68) - 控件(控件基类): UIElement - Pointer 相关事件, Tap 相关事件, Key 相关事件, Focus 相关事件 作者: ...

  4. 深圳scala-meetup-20180902(2)- Future vs Task and ReaderMonad依赖注入

    在对上一次3月份的scala-meetup里我曾分享了关于Future在函数组合中的问题及如何用Monix.Task来替代.具体分析可以查阅这篇博文.在上篇示范里我们使用了Future来实现某种non ...

  5. 在Shell脚本中获取指定进程的PID

    注意这条命令用反引号(Tab上面的那个键)括起来,作用类似于${ } processId = ` ps -ef | grep fms.jar | grep -v grep | awk '{print ...

  6. HoloLens开发手记 - 使用Visual Studio Using Visual Studio

    不论你是否使用DirectX或Unity来开发全息应用,你都会使用Visual Studio 2015来进行调试和部署应用.在本部分,你将会学习以下内容: 如何通过Visual Studio将你的应用 ...

  7. LeetCode--No.002 Add Two Numbers

    Add Two Numbers Total Accepted: 160702 Total Submissions: 664770 Difficulty: Medium You are given tw ...

  8. Java异步执行多个HTTP请求的例子(需要apache http类库)

    直接上代码 package org.jivesoftware.spark.util; import java.io.IOException; import java.util.concurrent.C ...

  9. 转载 Python中关键字global与nonlocal的区别

    转载自CSDN 雁丘1990, 原文地址: https://blog.csdn.net/xcyansun/article/details/79672634 这篇文章写的很赞, 条理清晰, 分析循序渐进 ...

  10. python itchat+机器人web api实现个人微信机器人

    模块 itchat 功能 实现微信回复机器人(调用图灵机器人api) 代码 #!/usr/bin/env python3 # -*- coding: utf-8 -*- #Author:Eric im ...