循序渐进学.Net Core Web Api开发系列【11】:依赖注入
系列目录
本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi
一、概述
本篇介绍如何采用依赖注入的方式创建和使用对象,主要从应用层面进行描述,不涉及具体的内部原理。
二、演练
假设要做一个日志服务的类,它实现在控制台打印出带时间信息的日志信息。
首先定义该服务的接口与实现类。
public interface ILogService
{
void LogInfomation(string info);
} public class MyLogService : ILogService
{
void ILogService.LogInfomation(string info)
{
Console.WriteLine($" ==> MyLogService : {DateTime.Now.ToString()}:{info}");
}
}
注册该服务
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddCors(); services.AddSingleton<ILogService, MyLogService>();
}
注册成功,我们在Controller中使用该服务:
public class ArticleController : Controller
{
private readonly ILogService _myLog; public ArticleController(ILogService myLog)
{
_myLog = myLog;
} [HttpGet("logger")]
public void TestLogger(string logger)
{
_myLog.LogInfomation("hahaha");
return;
}
}
简单分析一下:
1、首先通过services.AddSingleton方法向依赖注入容器登记注册MyLogService;
2、在构建Controller时,根据其构造函数类型遍历其输入参数,在依赖注入容器中找到该对象并作为实参传递给构造方法。
三、生命周期问题
注册一个服务,根据生命周期需要的不同,有下面三种方式:
services.AddSingleton<ILogService, MyLogService>(); services.AddScoped<ILogService, MyLogService>(); ervices.AddTransient<ILogService, MyLogService>();
三种注册方式分别对应三种生命周期
1)Singleton:单例服务,从当前服务容器中获取这个类型的实例永远是同一个实例;
2)Scoped:每个作用域生成周期内创建一个实例;
3)Transient:每一次请求服务都创建一个新实例;
对我们的日志进行改造,让其在构建时生成一个ID,通过观察其guid变化可以理解这三种生命周期的区别。
public class MyLogService : ILogService
{
public Guid _guid; public MyLogService()
{
_guid = Guid.NewGuid();
} void ILogService.LogInfomation(string info)
{
Console.WriteLine($" ==> MyLogService : My Guid is :{_guid}");
Console.WriteLine($" ==> MyLogService : {DateTime.Now.ToString()}:{info}");
}
}
四、通过扩展方法注册服务
通过对IServiceCollection增加扩展方法来注册服务
public static class MyLogServiceCollectionExtensions
{
public static void AddMyLog(this IServiceCollection services)
{
services.AddSingleton<ILogService, MyLogService>();
}
}
这样,使用者的注册代码可以修改为:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddCors();
services.AddMyLog();
}
可见AddMvc、AddCors等也是向容器注入服务。
public static IMvcBuilder AddMvc(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
IMvcCoreBuilder mvcCoreBuilder = MvcCoreServiceCollectionExtensions.AddMvcCore(services);
MvcApiExplorerMvcCoreBuilderExtensions.AddApiExplorer(mvcCoreBuilder);
MvcCoreMvcCoreBuilderExtensions.AddAuthorization(mvcCoreBuilder);
MvcServiceCollectionExtensions.AddDefaultFrameworkParts(mvcCoreBuilder.PartManager);
MvcCoreMvcCoreBuilderExtensions.AddFormatterMappings(mvcCoreBuilder);
MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(mvcCoreBuilder);
MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(mvcCoreBuilder);
MvcRazorPagesMvcCoreBuilderExtensions.AddRazorPages(mvcCoreBuilder);
TagHelperServicesExtensions.AddCacheTagHelper(mvcCoreBuilder);
MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(mvcCoreBuilder);
MvcJsonMvcCoreBuilderExtensions.AddJsonFormatters(mvcCoreBuilder);
MvcCorsMvcCoreBuilderExtensions.AddCors(mvcCoreBuilder);
return new MvcBuilder(mvcCoreBuilder.Services, mvcCoreBuilder.PartManager);
}
五、几个问题
1、如果多次注册会怎样
可以多次注册同一种生命周期的类,如下是可以的:
services.AddSingleton<ILogService, MyLogService>();
services.AddSingleton<ILogService, MyLogService>();
services.AddSingleton<ILogService, MyLogService>();
但下面这个代码不行:
services.AddSingleton<ILogService, MyLogService>();
services.AddScoped<ILogService, MyLogService>();
2、如何获取已经注册的服务列表
通过ServicesProvider可以获取服务列表
services.AddMyLog();
services.AddMyLog();
services.AddMyLog(); var provider = services.BuildServiceProvider();
var servicesList = provider.GetServices< ILogService >();
foreach (var service in servicesList)
{
Console.WriteLine("service:" + service.ToString());
}
以上代码输出3条记录。
但下面的代码只输出一条记录:
services.AddCors();
services.AddCors();
services.AddCors(); var provider = services.BuildServiceProvider();
var servicesList = provider.GetServices<ICorsService>();
foreach (var service in servicesList)
{
Console.WriteLine("service:" + service.ToString());
}
具体原因看一下源码就清楚了:
public static IServiceCollection AddCors(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
services.TryAdd(ServiceDescriptor.Transient<ICorsService, CorsService>());
return services;
}
public static void TryAdd(this IServiceCollection collection, ServiceDescriptor descriptor)
{
if (!collection.Any((ServiceDescriptor d) => d.ServiceType == descriptor.ServiceType))
{
collection.Add(descriptor);
}
}
所以我们应该按照这个方法修改我们的AddMyLog方法。
循序渐进学.Net Core Web Api开发系列【11】:依赖注入的更多相关文章
- 循序渐进学.Net Core Web Api开发系列【0】:序言与目录
一.序言 我大约在2003年时候开始接触到.NET,最初在.NET framework 1.1版本下写过代码,曾经做过WinForm和ASP.NET开发.大约在2010年的时候转型JAVA环境,这么多 ...
- 循序渐进学.Net Core Web Api开发系列【16】:应用安全续-加密与解密
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 应用安全除 ...
- 循序渐进学.Net Core Web Api开发系列【15】:应用安全
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍W ...
- 循序渐进学.Net Core Web Api开发系列【14】:异常处理
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍异 ...
- 循序渐进学.Net Core Web Api开发系列【13】:中间件(Middleware)
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...
- 循序渐进学.Net Core Web Api开发系列【12】:缓存
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...
- 循序渐进学.Net Core Web Api开发系列【10】:使用日志
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.本篇概述 本篇介 ...
- 循序渐进学.Net Core Web Api开发系列【9】:常用的数据库操作
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇描述一 ...
- 循序渐进学.Net Core Web Api开发系列【8】:访问数据库(基本功能)
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇讨论如 ...
随机推荐
- javaweb购物车实现的几种方式
之前没有接触过购物车的东东,也不知道购物车应该怎么做,所以在查询了很多资料,总结一下购物车的功能实现. 查询的资料,找到三种方法: 1.用cookie实现购物车: 2.用session实现购物车: 3 ...
- 蓝桥杯 算法提高 8皇后·改 -- DFS 回溯
算法提高 8皇后·改 时间限制:1.0s 内存限制:256.0MB 问题描述 规则同8皇后问题,但是棋盘上每格都有一个数字,要求八皇后所在格子数字之和最大. 输入格式 一个8*8 ...
- 转自知乎大神----JS 闭包是什么
大名鼎鼎的闭包!这一题终于来了,面试必问. 请用自己的话简述 什么是「闭包」. 「闭包」的作用是什么. --------------------------------------- 首先来简述什么是 ...
- 一个ssm综合小案例-商品订单管理-第一天
项目需求分析: 功能需求:登录,商品列表查询,修改 项目环境及技术栈: 项目构成及环境: 本项目采用 maven 构建 环境要求: IDEA Version: 2017.2.5 Tomcat Vers ...
- linux离线部署redis及redis.conf详解
一.离线部署redis 由于博主部署的虚拟机没有网络也没有gcc编译器,所以就寻找具备gcc编译器的编译环境把redis编译安装好,Copy Redis安装目录文件夹到目标虚拟机的目录下.copy时r ...
- Linux - 用户操作
常用命令 users # 显示所有的登录用户 groups # 列出当前用户和他所属的组 who -q # 显示所有的登录用户 groupadd # 添加组 useradd user # 建立用户 p ...
- Chrome插件:gitlab activity dashboard background-color
背景 我一般都是在activity dashboard页看同事的提交记录,这样只要我有权限的项目有人提交了我就能够知道,虽然提交的具体代码压根不看.......但至少能够了解各个项目的开发情况(如果大 ...
- C# IEqualityComparer类型参数写法
最近在使用Union.Except时,由于默认的对比不太好使,所以需要自定义对比器,下面附上代码. class MaterialListComparer : IEqualityComparer< ...
- 协议中UART的两种模式 【转】
转自:http://wjf88223.blog.163.com/blog/static/3516800120104179327286/ ^^…… 协议栈中UART有两种模式:1.中断2.DMA 对于这 ...
- asp.net动态增加服务器端控件并提交表单
为什么要用原生的呢? 1.目的 原生出现浏览器兼容性问题 极少,不用测试多浏览兼容性 .需要考虑到市面上的其他垃圾浏览器. 2.性能不好 如果不考虑第一条 你可以换一种方式 直接上代码 .aspx页面 ...