ASP.NET Core 依赖注入基本用法
ASP.NET Core 依赖注入
ASP.NET Core从框架层对依赖注入提供支持。也就是说,如果你不了解依赖注入,将很难适应 ASP.NET Core的开发模式。本文将介绍依赖注入的基本概念,并结合代码演示如何在 ASP.NET Core中使用依赖注入。
什么是依赖注入?
百度百科对于依赖注入的介绍:
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
从百科的介绍中可以看出,依赖注入和控制反转是一回事,依赖注入是一种新的设计模式,通过正确使用依赖注入的相关技术,可以降低系统耦合度,增加系统的可扩展性。
我们来看一个例子:
public interface IInterfaceA
{ }
public interface IInterfaceB
{ }
public class ClassA : IInterfaceA
{
private IInterfaceB B { get; set; }
public ClassA(IInterfaceB b)
{
this.B = b;
}
}
public class ClassB : IInterfaceB
{ }
这个时候,如果我们想要获取IInterfaceA的实例,如果不采用依赖注入,我们的做法通常是这样的:
IInterfaceB b = new ClassB();
IInterfaceA a = new ClassA(b);
这个时候IInterfaceA的控制权,在实例化的时候就已经被限定死了,没有任何想象空间,就是ClassA的实例,并且我们还要手工的初始化IInterfaceB,同样B的控制权也被限定死了。这样的代码毫无设计、也极不利于扩展。
如果采用依赖注入,我们看一下代码:
var a = container.GetService<IInterfaceA>();
这个时候接口A和B的控制权是由容器来控制的,我们可以通过向容器中注入不同的接口实现来扩展系统的灵活性,由于将控制权交给了IoC容器,我们还可以通过配置的方式灵活的控制对象的生命周期,这一点也是手工创建对象无法实现的。
控制反转的关系图如下(图片来源于官网):

ASP.NET Core中的依赖注入
上面介绍了依赖注入的基本概念,那么在 ASP.NET Core中,我们该如何使用依赖注入呢?在 ASP.NET Core中已经内置了一套依赖注入的容器,我们可以直接使用。
在Startup.ConfigureServices中添加我们要注册的服务和实现,添加的时候可以对服务的生命周期进行相应的配置,然后就可以在PageModel、Controller、Views等需要的地方使用了。
下面的示例将演示如何注册服务,代码来源于官网。首先要定义一个服务接口,并实现这个接口:
public interface IMyDependency
{
Task WriteMessage(string message);
}
public class MyDependency : IMyDependency
{
private readonly ILogger<MyDependency> _logger;
public MyDependency(ILogger<MyDependency> logger)
{
_logger = logger;
}
public Task WriteMessage(string message)
{
_logger.LogInformation(
"MyDependency.WriteMessage called. Message: {MESSAGE}",
message);
return Task.FromResult(0);
}
}
然后我们进行服务注册:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency>();
services.AddMvc();
}
这里我们添加了IMyDependency的注册,同时也添加了使用Mvc所需要的服务的注册。这里有两个问题需要说明:
- AddScoped是添加一个服务注册,Scoped是该服务的生命周期,表示按照作用于创建该服务,如果作用域中多次使用到该服务,则只创建一个对象。比如每一个HTTP请求都是一个作用域,那么在这个请求处理过程中,容器只会创建一个对象。与Scoped对应的还有其它的生命周期,我们将服务的生命周期列举如下:
- Transient:瞬时服务,表示每次使用都会创建新的对象
- Scoped:作用域服务,表示每次请求只创建一个对象。这里需要特殊说明一下,如果你的服务是一个中间件,不受此约束,因为中间件都是强制单例的。如果要在中间件中使用Scoped服务,则需要将服务注入到Invoke或InvokeAsync方法的参数中,此处可以参考 ASP.NET Core 中间件基本用法
- Singleton:单例服务,表示每个应用程序域只会创建一个实力。
- 基于约定,ASP.NET Core推荐我们采用类似于
Add{SERVICE_NAME}的方式添加服务的注册,比如services.AddMvc(),这种方式可以通过扩展方法来实现,代码如下:
namespace Microsoft.Extensions.DependencyInjection
{
public static partial class MyDependencyExtensions
{
public static IServiceCollection AddMyDependency(this IServiceCollection services)
{
return services.AddScoped<IMyDependency, MyDependency>();
}
}
}
使用依赖注入
在了解了依赖注入的基本用法之后,我们现在来了解一下如何将服务注入到Controller、Views中。
在控制器中注入服务
最常规的用法是采用构造函数注入的方式,将一个服务注入到控制器中,代码如下:
public class DefaultController : Controller
{
private readonly ILogger<DefaultController> logger;
public DefaultController(ILogger<DefaultController> logger)
{
this.logger = logger;
}
}
构造函数注入是最常用的注入方式,这种方式要求依赖者提供公有的构造函数,并将依赖项通过构造函数的方式传入依赖者,完成对依赖项的赋值。
除此之外,还可以通过参数注入的方式,将依赖项注入到Action中,这里使用到FromServices特性:
public IActionResult Index([FromServices]ILogger<DefaultController> logger)
{
throw new NotImplementedException();
}
ASP.NET Core 提供了这种支持,但是作者并不推荐这种操作
在视图中注入服务
ASP.NET Core 支持将依赖关系注入到视图,代码如下:
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
string myValue = Configuration["root:parent:child"];
...
}
上面的代码演示了将IConfiguration服务注入到视图中,从而实现在视图中读取配置的功能。
有时候将服务注入到视图中会很有用(例如本地化),但是作者也并不是很推荐这种做法,因为这样做容易造成视图和控制器的边界不清晰。
在PageModel中注入服务
在PageModel中注入服务的方式,与在Controller中注入服务的方式相似:
public class IndexModel : PageModel
{
private readonly IMyDependency _myDependency;
public IndexModel(IMyDependency myDependency)
{
_myDependency = myDependency;
}
}
在main方法中获取服务
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
using (var serviceScope = host.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
try
{
var serviceContext = services.GetRequiredService<MyScopedService>();
// Use the context here
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
}
host.Run();
}
在HttpContext.RequestServices中获取服务
这种方式不利于测试,不推荐此种用法。
虽然优先推荐通过构造函数的方式注入来获取服务,但是很难避免有些时候需要手工获取服务,在使用手工获取服务的时候,我们应当从HttpContext.RequestServices中获取。
使用第三方依赖注入框架
ASP.NET Core内置的依赖注入框架功能有限,当我们想使用第三方框架的特性时,我们可以替换默认依赖注入框架。
ASP.NET Core内置的依赖注入框架未包含的特性:
- 属性注入
- 基于名称的注入
- 子容器
- 自定义生命周期管理
- 对lazy对象初始化的Func支持
如果要是用这些功能,我们可以使用第三方框架。本文采用官方文档中的Autofac框架。
- 首先添加 Autofac、Autofac.Extensions.DependencyInjection 的引用
- 在Startup.ConfigureServices中配置容器,并返回IServiceProvider。在使用第三方容器时,必须返回IServiceProvider。
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Add other framework services
// Add Autofac
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
- 配置Autofac的Module,用来注册服务等
public class DefaultModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<CharacterRepository>().As<ICharacterRepository>();
}
}
参考资料
- https://baike.baidu.com/item/控制反转/1158025
- https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection
- https://docs.microsoft.com/zh-cn/dotnet/standard/modern-web-apps-azure-architecture/architectural-principles
ASP.NET Core 依赖注入基本用法的更多相关文章
- ASP.NET Core 依赖注入最佳实践——提示与技巧
在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇 ...
- ASP.NET Core 依赖注入(构造函数注入,属性注入等)
原文:ASP.NET Core 依赖注入(构造函数注入,属性注入等) 如果你不熟悉ASP.NET Core依赖注入,先阅读文章: 在ASP.NET Core中使用依赖注入 构造函数注入 构造函数注 ...
- ASP.NET Core 依赖注入最佳实践与技巧
ASP.NET Core 依赖注入最佳实践与技巧 原文地址:https://medium.com/volosoft/asp-net-core-dependency-injection-best-pra ...
- # ASP.NET Core依赖注入解读&使用Autofac替代实现
标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...
- 实现BUG自动检测 - ASP.NET Core依赖注入
我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...
- [译]ASP.NET Core依赖注入深入讨论
原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...
- asp.net core 依赖注入几种常见情况
先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...
- ASP.NET Core依赖注入——依赖注入最佳实践
在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...
- 自动化CodeReview - ASP.NET Core依赖注入
自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 我个人比较懒,能自动做的事绝 ...
随机推荐
- W3CPLUS DEMO一些有意思的效果备份
时间轴轮播图: http://www.w3cplus.com/w3cplusDemo/demos/timeline.html css3各种图标效果: http://www.w3cplus.com/w3 ...
- Linux之ssh服务介绍
一.什么是SSH? 简单说,SSH(Secure Shell Protocol)是一种网络协议,用于计算机之间的加密登录.在默认状态下SSH服务提供俩个服务功能,一个是提供类似telnet远程联机服务 ...
- 基于AOP的优惠券发送异常哨兵监控
本文来自网易云社区 作者:王贝 最近总是发现支付发红包优惠券发完的情况,但是发现的比较迟缓,于是乎,想加一个哨兵监控,统计了一下,组内不少需求都有发送优惠券的行为,也是经常遇到发送异常的情况,所以,想 ...
- Leetcode1--->数组中两数之和等于给定数
题目: 给定一个数组nums,目标数target.在数组中找到两数之和为target的数,返回两数的下标举例: Given nums = [2, 7, 11, 15], target = 9, Bec ...
- 装箱I(01背包)
描述 给两个有一定容量的箱子,往里面装宝石(宝石总容量不能超过箱子容量),不同的宝石有不同的容量和价值.求两个箱子里最大宝石的价值. 输入 line 1: Input n; n:表示宝石数量 ...
- .net SignalR 聊天室
代码地址:https://gitee.com/srnsrn/netSignalr.git 运行项目打开多个页面 私密聊天
- mybatis分页方式对比
mybatis有两种分页方法(转自:http://blog.csdn.net/leozhou13/article/details/50394242) 1.内存分页,也就是假分页.本质是查出所有的数据然 ...
- pytorch conditional GAN 调试笔记
推荐的几个开源实现 znxlwm 使用InfoGAN的结构,卷积反卷积 eriklindernoren 把mnist转成1维,label用了embedding wiseodd 直接从tensorflo ...
- HDU-3592 World Exhibition
差分约束. 很容易看出两种约束方式,然后建图.而且题目要求排序不能乱,于是加上第三种约束. 求最长就跑一遍最短路啊就行了. #include <cstdlib> #include < ...
- 算法复习——数位dp
开头由于不知道讲啥依然搬讲义 对于引入的这个问题,讲义里已经很清楚了,我更喜欢用那个建树的理解···· 相当于先预处理f,然后从起点开始在树上走··记录目前已经找到了多少个满足题意的数k,如果枚举到第 ...