private ILoginService<ApplicationUser> _loginService;
public AccountController()
{
_loginService = new EFLoginService()
}
public
AccountController(ILoginService<ApplicationUser> loginService)
{
_loginService = loginService;
}
把依赖的创建丢给其它人,自己只负责使用,其它人丢给你依赖的这个过程理解为注入。
var controller = new AccountController(new EFLoginService());
controller.Login(userName, password);
// 用Redis来替换原来的EF登录
var controller = new AccountController(new RedisLoginService());
controller.Login(userName, password);
var serviceCollection = new ServiceCollection()
.AddTransient<ILoginService, EFLoginService>()
.AddSingleton<ILoginService, EFLoginService>()
.AddScoped<ILoginService, EFLoginService>();
public interface IServiceCollection : IList<ServiceDescriptor>
{
}
我们上面的AddTransient、AddSignletone和Scoped方法是IServiceCollection的扩展方法, 都是往这个List里面添加ServiceDescriptor。
private static IServiceCollection Add(
IServiceCollection collection,
Type serviceType,
Type implementationType,
ServiceLifetime lifetime)
{
var descriptor =
new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(descriptor);
return collection;
}
public enum ServiceLifetime
{
Singleton,
Scoped,
Transient
}
public interface IOperation
{
Guid OperationId { get; }
}
public interface IOperationSingleton : IOperation { }
public interface IOperationTransient : IOperation{}
public interface IOperationScoped : IOperation{}
我们的 Operation实现很简单,可以在构造函数中传入一个Guid进行赋值,如果没有的话则自已New一个 Guid。
public class Operation :
IOperationSingleton,
IOperationTransient,
IOperationScoped
{
private Guid _guid;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Operation</span><span class="hljs-params">()</span> </span>{
_guid = Guid.NewGuid();
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Operation</span><span class="hljs-params">(Guid guid)</span>
</span>{
_guid = guid;
}
<span class="hljs-keyword">public</span> Guid OperationId => _guid;
}
在程序内我们可以多次调用ServiceProvider的GetService方法,获取到的都是同一个实例。
var services = new ServiceCollection();
// 默认构造
services.AddSingleton<IOperationSingleton, Operation>();
// 自定义传入Guid空值
services.AddSingleton<IOperationSingleton>(
new Operation(Guid.Empty));
// 自定义传入一个New的Guid
services.AddSingleton <IOperationSingleton>(
new Operation(Guid.NewGuid()));
var provider = services.BuildServiceProvider();
// 输出singletone1的Guid
var singletone1 = provider.GetService<IOperationSingleton>();
Console.WriteLine($"signletone1: {singletone1.OperationId}");
// 输出singletone2的Guid
var singletone2 = provider.GetService<IOperationSingleton>();
Console.WriteLine((<span class="hljs-string">"signletone2: {singletone2.OperationId}"</span>);
Console.WriteLine()"singletone1 == singletone2 ? : { singletone1 == singletone2 }");
我们对IOperationSingleton注册了三次,最后获取两次,大家要注意到我们获取到的始终都是我们最后一次注册的那个给了一个Guid的实例,前面的会被覆盖。
这次我们获取到的IOperationTransient为两个不同的实例。
var services = new ServiceCollection();
services.AddTransient<IOperationTransient, Operation>();
var provider = services.BuildServiceProvider();
var transient1 = provider.GetService<IOperationTransient>();
Console.WriteLine($"transient1: {transient1.OperationId}");
var transient2 = provider.GetService<IOperationTransient>();
Console.WriteLine((<span class="hljs-string">"transient2: {transient2.OperationId}"</span>);
Console.WriteLine()"transient1 == transient2 ? :
{ transient1 == transient2 }");
var services = new ServiceCollection()
.AddScoped<IOperationScoped, Operation>()
.AddTransient<IOperationTransient, Operation>()
.AddSingleton<IOperationSingleton, Operation>();
接下来我们用ServiceProvider.CreateScope方法创建一个Scope
var provider = services.BuildServiceProvider();
using (var scope1 = provider.CreateScope())
{
var p = scope1.ServiceProvider;
<span class="hljs-keyword">var</span> scopeobj1 = p.GetService<IOperationScoped>();
<span class="hljs-keyword">var</span> transient1 = p.GetService<IOperationTransient>();
<span class="hljs-keyword">var</span> singleton1 = p.GetService<IOperationSingleton>();
<span class="hljs-keyword">var</span> scopeobj2 = p.GetService<IOperationScoped>();
<span class="hljs-keyword">var</span> transient2 = p.GetService<IOperationTransient>();
<span class="hljs-keyword">var</span> singleton2 = p.GetService<IOperationSingleton>();
Console.WriteLine(
$<span class="hljs-string">"scope1: { scopeobj1.OperationId },"</span> +
$<span class="hljs-string">"transient1: {transient1.OperationId}, "</span> +
$<span class="hljs-string">"singleton1: {singleton1.OperationId}"</span>);
Console.WriteLine($<span class="hljs-string">"scope2: { scopeobj2.OperationId }, "</span> +
$<span class="hljs-string">"transient2: {transient2.OperationId}, "</span> +
$<span class="hljs-string">"singleton2: {singleton2.OperationId}"</span>);
}
接下来
scope1: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient1: fb35f570-713e-43fc-854c-972eed2fae52,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient2: 2766a1ee-766f-4116-8a48-3e569de54259,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
如果再创建一个新的Scope运行,
scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient2: 74c37151-6497-4223-b558-a4ffc1897d57,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
三、DI在ASP.NET Core中的应用
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ILoginService<ApplicationUser>,
EFLoginService>();
services.AddMvc();
)
ASP.NET Core的一些组件已经提供了一些实例的绑定,像AddMvc就是Mvc Middleware在 IServiceCollection上添加的扩展方法。
public static IMvcBuilder AddMvc(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
<span class="hljs-keyword">var</span> builder = services.AddMvcCore();
builder.AddApiExplorer();
builder.AddAuthorization();
AddDefaultFrameworkParts(builder.PartManager);
...
}
private ILoginService<ApplicationUser> _loginService;
public AccountController(
ILoginService<ApplicationUser> loginService)
{
_loginService = loginService;
}
我们只要在控制器的构造函数里面写了这个参数,ServiceProvider就会帮我们注入进来。这一步是在Mvc初始化控制器的时候完成的,我们后面再介绍到Mvc的时候会往细里讲。
@using MilkStone.Services;
@model MilkStone.Models.AccountViewModel.LoginViewModel
@inject ILoginService<ApplicationUser> loginService
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
@loginService.GetUserName()
</body>
</html>
HttpContext.RequestServices.GetService<ILoginService<ApplicationUser>>();
builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
这会给我们的初始化带来一些便利性,我们来看看如何替换Autofac到ASP.NET Core。我们只需要把Startup类里面的 ConfigureService的 返回值从 void改为 IServiceProvider即可。而返回的则是一个AutoServiceProvider。
public IServiceProvider ConfigureServices(
IServiceCollection services){
services.AddMvc();
// Add other framework services
<span class="hljs-comment">// Add Autofac</span>
<span class="hljs-keyword">var</span> containerBuilder = <span class="hljs-keyword">new</span> ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
<span class="hljs-keyword">var</span> container = containerBuilder.Build();
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> AutofacServiceProvider(container);
}
<div class="section section-blog-info">
<div class="row">
<div class="col-md-6">
<div class="entry-categories">分类: <span class="label label-primary"><a href="http://www.jessetalk.cn/category/tech/">技术随笔</a></span> </div>
<div class="entry-tags">标签:<span class="entry-tag"><a href="http://www.jessetalk.cn/tag/asp-net-core/" rel="tag">asp.net core</a></span><span class="entry-tag"><a href="http://www.jessetalk.cn/tag/di/" rel="tag">DI</a></span></div> </div>
<div class="col-md-6">
<div class="entry-social">
<a target="_blank" rel="tooltip" data-original-title="分享到 Facebook" class="btn btn-just-icon btn-round btn-facebook" href="https://www.facebook.com/sharer.php?u=http://www.jessetalk.cn/2017/11/06/di-in-aspnetcore/">
<i class="fa fa-facebook"></i>
</a>
<a target="_blank" rel="tooltip" data-original-title="分享至微博" class="btn btn-just-icon btn-round btn-twitter" href="http://twitter.com/share?url=http://www.jessetalk.cn/2017/11/06/di-in-aspnetcore/&text=%E4%BA%86%E8%A7%A3ASP.NET%20Core%20%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%EF%BC%8C%E7%9C%8B%E8%BF%99%E7%AF%87%E5%B0%B1%E5%A4%9F%E4%BA%86">
<i class="fa fa-twitter"></i>
</a>
<a rel="tooltip" data-original-title=" Share on Email" class="btn btn-just-icon btn-round" href="mailto:?subject=了解ASP.NET%20Core%20依赖注入,看这篇就够了&body=http://www.jessetalk.cn/2017/11/06/di-in-aspnetcore/">
<i class="fa fa-envelope"></i>
</a>
</div>
</div> </div>
<hr>
15 条评论
dp · 2017年11月25日 下午12:54
好文!!!
w3i · 2017年12月11日 下午5:48
用心!
52dotnet · 2017年12月13日 下午10:13
总算治好了我对依赖注入的多年不理解,收藏了!
尼古拉屎找死 · 2017年12月17日 上午10:47
写的不错,继续加油!!
陈家涛 · 2017年12月20日 上午9:54
看不懂,太抽象了
长空 · 2017年12月22日 下午11:01
文章是极好的,讲的还是很透彻的。
从其他地方看过来的,网站做的非常好啊!正是我很喜欢的极简风格。。我自己的网站用的模版,有点搓的样子。
MD文档的渲染的样式可以调整下,不如你在博客上的显示效果。。
Hei幕。 · 2018年1月9日 下午8:56
看完了 会点基本的
hdgao · 2018年1月27日 下午4:08
能否将这节的实际演示的例子给我发一份到我的邮箱,想好好参考学习一下,不错写的支持
潇洒走一回 · 2018年2月7日 下午4:48
好文,看了那么多依赖注入思想的文章,你这里讲解得最简易,最易懂。对于NET Core DI的这个,还得继续看看。
xiaocui · 2018年4月11日 下午6:01
讲的通俗易懂,很不错。
低级码农 · 2018年5月9日 下午10:44
感谢博主,解决了我好多疑问。
华仔 · 2018年5月25日 下午4:59
身边有工作六七年的同事还个东西搞不清楚。 这句话有别字
鸟窝 · 2018年5月27日 下午6:03
如何实现,在asp.net core中不使用autofac,而实现属性注入??我们都知道.net core中默认注入方式是构造函数注入,但是总感觉构造函数注入,没有属性注入方便,求解!
低级码农 · 2018年6月12日 下午11:33
如果熟悉Autofac的同学可能会这下面这样的代码有“映象”。 有错别字哦
niunan · 2018年7月3日 下午6:51
支持fcrf