ASP.NET Core 依赖注入(DI)
ASP.NET Core的底层设计支持和使用依赖注入。ASP.NET Core 应用程序可以利用内置的框架服务将服务注入到启动类的方法中,并且应用程序服务也可以配置注入。由ASP.NET Core 提供的默认服务容器提供了最小功能集,并不是取代其他容器。
1.浅谈依赖注入
依赖注入(Dependency injection,DI)是一种实现对象和依赖者之间松耦合的技术,将类用来执行其操作的这些对象以注入的方式提供给该类,而不是直接实例化依赖项或者使用静态引用。一般情况,类会通过构造函数声明器2依赖关系,允许他们遵循显示依赖原则。这种方法称为“构造函数注入”。
当类的设计使用DI思想时,他们的耦合更加松散,因为他们没有对他们的合作者直接硬编码的依赖。这遵循“依赖倒置原则”,其中指出,高层模块不应该依赖于底层模块:两者都依赖于抽象。
类要求在他们构造时向其提供抽象(通常是接口),而不是引用特定的实现。提取接口的依赖关系和提供接口的实现作为参数也是“策略设计模式”的一个示例。
当一个类被用来创建类及其相关的依赖关系时,这个成为容器(containers),或者称为控制反转(Inversion of Control, IoC)容器,或者依赖注入容器。容器本质上是一个工厂,负责提供向它请求的类型的实例。如果一个给定类型声明它具有依赖关系,并且容器已经被配置为其提供依赖关系,那么它将把创建依赖关系作为创建请求实例的一部分。除了创建对象的依赖关系外,容器通常还会管理应用程序中对象的生命周期。
ASP.NET Core 包含一个默认支持构造函数注入的简单内置容器,ASP.NET 的容器指的是它管理的类型services,可以在Startup类的ConfigureServices方法中配置内置容器的服务。
2. 使用ASP.NET Core提供的服务
Startup类的ConfigureServices方法负责定义应用程序将使用的服务,包括平台自带的功能,比如,Entity Framework Core 和 ASP.NET Core MVC。除了IServiceCollection提供的几个服务之外,可以使用一些扩展方法(AddDbContext,AddMvc,AddTransient等)向容器添加和注册额外服务:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
}); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<AccessManagementContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
providerOptions => providerOptions.EnableRetryOnFailure()));
services.AddTransient<ICompanyServices, CompanyServices>(); }
ASP.NET Core 提供的功能和中间件,遵循约定使用一个单一的AddService扩展方法来注册所有该功能所需的服务。
3.注册自己的服务
我们可以按照 services.AddTransient<ICompanyServices, CompanyServices>(); 这种写法注册自己的服务。第一个范型类型表示将要从容器中请求的类型(通常是一个接口)。第二个范型类型表示将由容器实例化并且用于完成请求的具体类型。
AddTransient 方法用于将抽象类型映射到为每一个需要它的对象分别实例化的具体服务。为注册的每一个服务选择合适的生命周期很重要,后面会介绍到。
下面是示例是注册自己的服务:
1.接口
public interface IAccountServices
{
Task<List<AccountViewModel>> GetList();
}
2.实现类
public class AccountServices:IAccountServices
{
AccessManagementContext _context;
public AccountServices(AccessManagementContext context)
{
_context = context;//在构造函数中注入
} public async Task<List<Account>> GetList()
{
try
{
var query = _context.Account.ToListAsync();
return query ;
}
catch (Exception ex)
{
return null;
} }
}
3.在ConfigureServices中注册自定义的服务和EF上下文AccessManagementContext
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<AccessManagementContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
providerOptions => providerOptions.EnableRetryOnFailure()));
services.AddTransient<IAccountServices,AccountServices>(); }
4.在Controller构造函数中依赖注入
public class AccountController : Controller
{
private IAccountServices _accountServices;
public AccountController(IAccountServices accountServices)
{
_accountServices = accountServices;
}
// GET: Account
public async Task<ActionResult> Index()
{
var vms = await _accountServices.GetList();
return View(vms);
}
4.服务的生命周期和注册选项
ASP.NET 服务生命周期:
1.Transient 瞬时
Transient 生命周期服务在他们每次请求时被创建。适合轻量级,无状态的服务。
2.Scoped 作用域
Scoped生命周期在每次请求时创建一次。
3.Singleton 单例
Singleton 生命周期服务在它们第一次请求时创建,并且每个后续请求使用相同的实例。
服务可以用多种方式在容器中注册,除了之前的注册方法,还可以指定一个工厂,它将被用来创建需要的实例。后面会详细介绍其他的注册方法。
下面用一个简单的示例介绍每个生命周期:
1.创建接口:
namespace MVCTest.Interfaces
{
public interface IOperation
{
/// <summary>
/// 唯一标识
/// </summary>
Guid OperationId { get; }
} public interface IOperationTransient: IOperation
{
} public interface IOperationScoped : IOperation
{
} public interface IOperationSingleton : IOperation
{
} public interface IOperationInstance : IOperation
{
}
}
2.实现类
/// <summary>
/// 实现所有接口
/// </summary>
public class Operation: IOperation, IOperationTransient,
IOperationScoped, IOperationSingleton, IOperationInstance
{
public Operation()
{
OperationId = Guid.NewGuid();
}
public Operation(Guid operationId)
{
if (operationId == null)
{
OperationId = Guid.NewGuid();
}
OperationId = operationId;
} public Guid OperationId { get; }
}
3.注册到容器
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationInstance, Operation>();
services.AddTransient<OperationServices, OperationServices>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
4.上面还注册了 OperationServices ,用来测试单例模式(单例生命周期服务中所有请求使用第一次实例化的服务)和 作用域生命周期服务在每次请求时只创建一次,不管几个地方用到实例
public class OperationServices
{
public IOperationTransient OperationTransient { get; }
public IOperationScoped OperationScoped { get; }
public IOperationSingleton OperationSingleton { get; }
public IOperationInstance OperationInstance { get; } public OperationServices(IOperationTransient operationTransient,
IOperationScoped operationScoped,
IOperationSingleton operationSingleton,
IOperationInstance operationInstance)
{
OperationTransient = operationTransient;
OperationScoped = operationScoped;
OperationSingleton = operationSingleton;
OperationInstance = operationInstance;
}
}
5.在Controller中使用
public class OperationController : Controller
{
public IOperationTransient OperationTransient { get; }
public IOperationScoped OperationScoped { get; }
public IOperationSingleton OperationSingleton { get; }
public IOperationInstance OperationInstance { get; }
public OperationServices _operationServices; public OperationController(IOperationTransient operationTransient,
IOperationScoped operationScoped,
IOperationSingleton operationSingleton,
IOperationInstance operationInstance,
OperationServices operationServices)
{
OperationTransient = operationTransient;
OperationScoped = operationScoped;
OperationSingleton = operationSingleton;
OperationInstance = operationInstance;
_operationServices = operationServices;
}
// GET: Operation
public ActionResult Index()
{
ViewBag.OperationTransient = OperationTransient;
ViewBag.OperationScoped = OperationScoped;
ViewBag.OperationSingleton = OperationSingleton;
ViewBag.OperationInstance = OperationInstance;
ViewBag._operationServices = _operationServices;
return View();
}
}
6.Index显示
@{
ViewData["Title"] = "Index";
} <div>
<h1>Controller Operations</h1>
<h2>OperationTransient: @ViewBag.OperationTransient.OperationId</h2>
<h2>OperationScoped: @ViewBag.OperationScoped.OperationId</h2>
<h2>OperationSingleton: @ViewBag.OperationSingleton.OperationId</h2>
<h2>OperationInstance: @ViewBag.OperationInstance.OperationId</h2>
</div>
<div>
<h1>Services Operations</h1>
<h2>OperationTransient: @ViewBag._operationServices.OperationTransient.OperationId</h2>
<h2>OperationScoped: @ViewBag._operationServices.OperationScoped.OperationId</h2>
<h2>OperationSingleton: @ViewBag._operationServices.OperationSingleton.OperationId</h2>
<h2>OperationInstance: @ViewBag._operationServices.OperationInstance.OperationId</h2>
</div>
7.运行结果
可以看到,单例生命周期服务每一次请求的标识一样。作用域生命周期的服务,在一次请求中使用的同一个实例,第二次请求创建新的实例。
5.请求服务
来自HttpContext的一次ASP.NET 请求中,可用的服务是通过RequestServices集合公开的。
请求服务将你配置的服务和请求描述为应用程序的一部分。在子的对象指定依赖之后,这些满足要求的对象可通过查找RequestServices中对应的类型得到,而不是ApplicationServices。
6.设计依赖注入服务
在自定义的服务中,避免使用静态方法和直接实例化依赖的类型,而是通过依赖注入请求它。(New is Glue)
如果类有太多的依赖关系被注入时,通常表明你的类试图做的太多(违反了单一职责原则),需要转移一些职责。
同样,Controller类应该重点关注UI,因此业务逻辑和数据访问等细节应该在其他类中。
7.使用Autofac容器
ASP.NET Core 依赖注入(DI)的更多相关文章
- ASP.NET Core依赖注入(DI)
ASP.NET Core允许我们指定注册服务的生存期.服务实例将根据指定的生存时间自动处理.因此,我们无需担心清理此依赖关系,他将由ASP.NET Core框架处理.有如下三种类型的生命周期. 关于依 ...
- # ASP.NET Core依赖注入解读&使用Autofac替代实现
标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...
- [译]ASP.NET Core依赖注入深入讨论
原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...
- ASP.NET Core依赖注入——依赖注入最佳实践
在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...
- ASP.NET Core 依赖注入最佳实践——提示与技巧
在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇 ...
- ASP.NET Core依赖注入最佳实践,提示&技巧
分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...
- ASP.NET Core依赖注入解读&使用Autofac替代实现【转载】
ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Autofac实现和自定义实现扩展方法 3.1 安装Autof ...
- ASP.NET Core 依赖注入基本用法
ASP.NET Core 依赖注入 ASP.NET Core从框架层对依赖注入提供支持.也就是说,如果你不了解依赖注入,将很难适应 ASP.NET Core的开发模式.本文将介绍依赖注入的基本概念,并 ...
- ASP.NET Core 依赖注入(构造函数注入,属性注入等)
原文:ASP.NET Core 依赖注入(构造函数注入,属性注入等) 如果你不熟悉ASP.NET Core依赖注入,先阅读文章: 在ASP.NET Core中使用依赖注入 构造函数注入 构造函数注 ...
随机推荐
- PHP生成excel(1)
先到PHPExcel官网下载PHPExcel类 http://phpexcel.codeplex.com/ 把excel类包含进来,然后直接使用 <?php require "./PH ...
- Spark Streaming性能优化系列-怎样获得和持续使用足够的集群计算资源?
一:数据峰值的巨大影响 1. 数据确实不稳定,比如晚上的时候訪问流量特别大 2. 在处理的时候比如GC的时候耽误时间会产生delay延迟 二:Backpressure:数据的反压机制 基本思想:依据上 ...
- 第8章4节《MonkeyRunner源代码剖析》MonkeyRunner启动执行过程-启动AndroidDebugBridge
上一节我们看到在启动AndroidDebugBridge的过程中会调用其start方法,而该方法会做2个基本的事情: 715行startAdb:开启AndroidDebugBridge 722-723 ...
- java远程调用rmi入门实例
RMI是Java的一组拥护开发分布式应用程序的API.RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol). ...
- Sublime Text2-Control Package---ShinePans
1.打开sublime Text2 2.菜单条中的preference>>BrowsePackages 3.退到上一级打开Installed Packages 4.拷贝文件到此目录 (Pa ...
- YTUOJ-推断字符串是否为回文
题目描写叙述 编敲代码,推断输入的一个字符串是否为回文.若是则输出"Yes",否则输出"No".所谓回文是指順读和倒读都是一样的字符串. 输入 输出 例子输入 ...
- REST – PUT vs POST
REST – PUT vs POST – REST API Tutorial https://restfulapi.net/rest-put-vs-post/ REST – PUT vs POST I ...
- QT实现FTP服务器(一)
QListenSocket类的实现: #include "QListenSocket.h" #include <QTcpSocket> #include <QDe ...
- 深度学习入门-4.1 AND.py 源码分析
源代码 ------------------------------------------------------------------------------------------------ ...
- td 中设置超出宽度显示省略号失效
td测试内容超出显示省略号时,结果没有显示省略号,而是一直往后显示,且超出了td大小,强行挤大了table. 原因是因为td默认不换行. 解决方法: 1.强制td换行. IE加上word-break: ...