首页
视频
资源
登录
原
ASP.NET Core 依赖注入(基础)[学习笔记]
5488
人阅读
2020/5/8 10:21
总访问:
2614162
评论:
4
收藏:
0
手机
分类:
.net后台框架
![.netcore](https://img.tnblog.net/arcimg/hb/c857299a86d84ee7b26d181a31e58234.jpg ".netcore") >#ASP.NET Core 依赖注入(基础)[学习笔记] [TOC] <br/> 环境准备 ------------ <br/> >###项目结构 ![项目结构](https://img.tnblog.net/arcimg/hb/47dce22bf65747918a15d5b6c00b5b0b.png "项目结构") >###服务类 <br/> ><font style="color:#2ecc71;font-weight:bold;">GenericService.cs</font> ```csharp public interface IGenericService<T> { } public class GenericService<T> : IGenericService<T> { public T Data { get; private set; } public GenericService(T data) { this.Data = data; } } ``` ><font style="color:#2ecc71;font-weight:bold;">IService.cs</font> ```csharp public interface IService { Guid GetId(); } ``` ><font style="color:#2ecc71;font-weight:bold;">MyScopedService.cs</font> ```csharp public interface IMyScopedService { } public class MyScopedService : IMyScopedService { } ``` ><font style="color:#2ecc71;font-weight:bold;">MySingletonService.cs</font> ```csharp public interface IMySingletonService { } public class MySingletonService : IMySingletonService { } ``` ><font style="color:#2ecc71;font-weight:bold;">MyTransientService.cs</font> ```csharp public interface IMyTransientService { } public class MyTransientService : IMyTransientService { } ``` ><font style="color:#2ecc71;font-weight:bold;">OrderService.cs</font> ```csharp public interface IOrderService { } public class OrderService : IOrderService { } public class OrderServiceEx : IOrderService { } ``` >###控制器类 ><font style="color:#2ecc71;font-weight:bold;">WeatherForecastController.cs</font> ```csharp [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet("GetService")] public int GetService([FromServices]IMySingletonService singleton1, [FromServices]IMySingletonService singleton2, [FromServices]IMyTransientService transient1, [FromServices]IMyTransientService transient2, [FromServices]IMyScopedService scoped1, [FromServices]IMyScopedService scoped2) { Console.WriteLine($"singleton1:{singleton1.GetHashCode()}"); Console.WriteLine($"singleton2:{singleton2.GetHashCode()}"); Console.WriteLine($"transient1:{transient1.GetHashCode()}"); Console.WriteLine($"transient2:{transient2.GetHashCode()}"); Console.WriteLine($"scoped1:{scoped1.GetHashCode()}"); Console.WriteLine($"scoped2:{scoped2.GetHashCode()}"); Console.WriteLine($"========GetService 请求结束======="); return 1; } [HttpGet("GetService2")] public int GetService2([FromServices]IMySingletonService singleton1, [FromServices]IMySingletonService singleton2, [FromServices]IMyTransientService transient1, [FromServices]IMyTransientService transient2, [FromServices]IMyScopedService scoped1, [FromServices]IMyScopedService scoped2) { Console.WriteLine($"singleton1:{singleton1.GetHashCode()}"); Console.WriteLine($"singleton2:{singleton2.GetHashCode()}"); Console.WriteLine($"transient1:{transient1.GetHashCode()}"); Console.WriteLine($"transient2:{transient2.GetHashCode()}"); Console.WriteLine($"scoped1:{scoped1.GetHashCode()}"); Console.WriteLine($"scoped2:{scoped2.GetHashCode()}"); Console.WriteLine($"========GetService 2 请求结束======="); return 1; } /// <summary> /// 获取 Service /// </summary> /// <param name="services"></param> /// <returns></returns> [HttpGet("GetServiceList")] public int GetServiceList([FromServices]IEnumerable<IOrderService> services) { foreach (var item in services) { Console.WriteLine($"Get Servic instances:{item.ToString()}:{item.GetHashCode()}"); } return 1; } ``` <br/> 依赖注入 ------------ <br/> >###介绍 <br/> >参考jesse大佬的:https://www.cnblogs.com/jesse2013/p/di-in-aspnetcore.html 依赖:依赖于抽象,而不是具体的实现。 注入:注入体现的是一个IOC(控制反转的的思想)。 >>容器:统一管理依赖的地方,大部分容器的内部实现方式,都是工厂模式+反射 IOC:我的理解是实例化不由自身来决定了,而是交给容器来进行实例了。举例: Userinfo user = 容器.create("user") as Userinfo; DI :通过容器实例对象时,给对象赋值 >(有意见请评论) <br/> >###注册服务不同生命周期的服务 <br/> ><font style="color:#2ecc71;font-weight:bold;">Startup.cs</font> ```csharp #region 注册服务不同生命周期的服务 services.AddSingleton<IMySingletonService, MySingletonService>(); services.AddScoped<IMyScopedService, MyScopedService>(); services.AddTransient<IMyTransientService, MyTransientService>(); #endregion ``` | 注册方式 | 效果 | | ------------ | ------------ | | Singleton | 单例,永远都是那一个固定的实例进行注入 | | Transient | 注入的实例永远不同 | | Scoped | 请求的方法不同,注入的实例就不相同 | >结果 ![生命周期](https://img.tnblog.net/arcimg/hb/449cded1218448d4bd5a9af65b429372.png "生命周期") <br/> >###花式注册 ```csharp services.AddSingleton<IOrderService>(new OrderService()); //直接注入实例 //services.AddSingleton<IOrderService, OrderServiceEx>(); //services.AddSingleton<IOrderService, OrderService>(); //services.AddSingleton<IOrderService, OrderService>(); //工厂模式 //services.AddSingleton<IOrderService>(serviceProvider => //{ // return new OrderServiceEx(); //}); //services.AddScoped<IOrderService>(serviceProvider => //{ // return new OrderServiceEx(); //}); ``` <br/> >###尝试注册 ```csharp //我们的服务已经注册过了,就不能再注册了 //services.TryAddSingleton<IOrderService, OrderServiceEx>(); //相同类型的服务接口,如果实现不同则可以注册进去 //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService, OrderServiceEx>()); //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService, OrderServiceEx>()); //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService>(new OrderServiceEx())); //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService>(p => //{ // return new OrderServiceEx(); //})); ``` >尝试注入 ![尝试注入](https://img.tnblog.net/arcimg/hb/f58b2322a9c041d88bb6dce1bdc6c597.png "尝试注入") >实现不同就尝试注册 ![实现不同就尝试注册](https://img.tnblog.net/arcimg/hb/34a7ec66a60445f5897f02d1ad20f412.png) >###移除和替换注册 ```csharp //替换 services.Replace(ServiceDescriptor.Singleton<IOrderService, OrderServiceEx>()); //删除 services.RemoveAll<IOrderService>(); ``` >替换 ![替换](https://img.tnblog.net/arcimg/hb/39cacc512ff541a6866e0686a60ec7b6.png "替换") >移除 ![移除](https://img.tnblog.net/arcimg/hb/54bfec3483374f57a036f9dc11c4906e.png "移除") >###注册泛型模板 ```csharp services.AddSingleton(typeof(IGenericService<>), typeof(GenericService<>)); ``` >###Scoped变Singleton的问题 tn>在一个需要注入`Singleton`单例注入的服务中,如果该服务的注入是`Scoped`,那么该服务的注入会变成`Singleton`一样的生命周期,在规定内释放的时候无法进行释放。 解决这个的方式是使用`ServiceProvider`的扩展`BuildServiceProvider`方法,该方法对其注入有严格的验证,我们来分析一下该方法。 ![](https://img.tnblog.net/arcimg/hb/e9159f2ba90d4caa824781919f64cba6.png) ![](https://img.tnblog.net/arcimg/hb/67158487dd3a4697a88b000824378abf.png) >该扩展有3个重载方法;我们发现都是通过配置选项`ServiceProviderOptions`对服务范围进行的检验,我们接着来看`ServiceProviderOptions`配置类中的属性 ![](https://img.tnblog.net/arcimg/hb/8e8fbf28c1be4c51848776f7e8738e1b.png) >我们只看重要的两个属性`ValidateScopes`与`ValidateOnBuild`。表示 | 属性 | 描述 | | ------------ | ------------ | | `ValidateScopes` | 当设置为`True`时开启针对范围的检测。 | | `ValidateOnBuild` | 当设置为`True`时检测构造是否能够提供服务。 | >`ValidateScopes`属性的示例 ```csharp public interface ITest { } public interface IBoobar { } public class Test : ITest { } public class Boobar : IBoobar { public Boobar(ITest test) { _test = test; } public ITest _test { get; } } ``` ```csharp var services = new ServiceCollection(); // 创建单例ITest services.AddSingleton<ITest, Test>(); // 添加范围注册 services.AddScoped<IBoobar, Boobar>(); var root = services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true }); // 获取服务 root.GetService<IBoobar>(); ``` ![](https://img.tnblog.net/arcimg/hb/922c46821d714fd6819c8e7488995674.png) tn>我们可以看到它直接抛出`InvalidOperationException`异常,无法解析...;当我们反转一下注册的方式,它是以单例模式`Transient`为主,如果需要提供的服务不是`Transient`是`Scoped`将会注册失败 ```csharp var services = new ServiceCollection(); // 创建单例ITest services.AddScoped<ITest, Test>(); // 添加范围注册 services.AddSingleton<IBoobar, Boobar>(); var root = services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true }); // 子容器获取ITest服务成功 root.CreateScope().ServiceProvider.GetService<ITest>(); // 子容器获取IBoobar服务失败 root.CreateScope().ServiceProvider.GetService<IBoobar>(); // 根容器获取失败 root.GetService<ITest>(); // 根容器获取失败 root.GetService<IBoobar>(); ``` >`ValidateOnBuild`属性的示例 ```csharp public class Boobar : IBoobar { private Boobar() { } } static void Main(string[] args) { var services = new ServiceCollection(); // 添加单例注册 services.AddSingleton<IBoobar, Boobar>(); var root = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true }); // 根容器获取失败 root.GetService<IBoobar>(); } ``` >在服务注册时,便报错了。因为`Boobar`只有一个私有构造,无法进行实例。 ![](https://img.tnblog.net/arcimg/hb/019f9a35d3dc422ab7255e294ff2878d.png) <br/> 项目地址 ------------ <br/> >GitHub: https://github.com/AiDaShi/GeekTimeLearning <br/> 简单的依赖注入的架构 ------------ <br/> ![](https://img.tnblog.net/arcimg/hb/3dd358b93a654f6c86b6b621373d2e93.png) <br/> 课程推荐 ------------ <br/> ![](https://img.tnblog.net/arcimg/hb/6bb0a226374d487bb01aa9c586a1a9ff.jpeg)
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
👈{{preArticle.title}}
👉{{nextArticle.title}}
评价
{{titleitem}}
{{titleitem}}
{{item.content}}
{{titleitem}}
{{titleitem}}
{{item.content}}
尘叶心繁
这一世以无限游戏为使命!
博主信息
排名
6
文章
6
粉丝
16
评论
8
文章类别
.net后台框架
168篇
linux
17篇
linux中cve
1篇
windows中cve
0篇
资源分享
10篇
Win32
3篇
前端
28篇
传说中的c
4篇
Xamarin
9篇
docker
15篇
容器编排
101篇
grpc
4篇
Go
15篇
yaml模板
1篇
理论
2篇
更多
Sqlserver
4篇
云产品
39篇
git
3篇
Unity
1篇
考证
2篇
RabbitMq
23篇
Harbor
1篇
Ansible
8篇
Jenkins
17篇
Vue
1篇
Ids4
18篇
istio
1篇
架构
2篇
网络
7篇
windbg
4篇
AI
18篇
threejs
2篇
人物
1篇
嵌入式
2篇
python
13篇
HuggingFace
8篇
pytorch
9篇
opencv
6篇
Halcon
1篇
最新文章
最新评价
{{item.articleTitle}}
{{item.blogName}}
:
{{item.content}}
关于我们
ICP备案 :
渝ICP备18016597号-1
网站信息:
2018-2024
TNBLOG.NET
技术交流:
群号656732739
联系我们:
contact@tnblog.net
欢迎加群
欢迎加群交流技术