.NET CORE 依赖注入 实践总结

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介:

.NET CORE 依赖注入 实践总结

知识点回顾
依赖包。 Microsoft.Extensions.DependencyInjection.Abstractions
核心对象和方法。
IServiceCollection。注入对象的容器。注意它只存储对象的元数据,并不保存实例对象。
IServiceProvider。注入对象的提供者。它负责提供具体的对象实例。在架构中,IServiceProvider有2种身份,一种是Root ServiceProvider,由service.BuildServiceProvider()创建,生命周期贯穿整个应用程序,AddSingleton对象保存在这里。另外一种则是普通IServiceProvider,由IServiceScope创建,生命周期即为AddScoped的生命周期。AddScope 的对象保存在这里。普通ServiceProvider由Root ServiceProvider创建的IServiceScope创建。
IServiceScope。表某一个生命周期范围。由ServiceProvider.CreateScope()创建。
注入方式,知识点一。
注入功能默认在Startup类中的ConfigureServices方法中。
注入方式,知识点二。支持以下三种方式
AddScoped。生命周期为Scoped类型。例如在web框架中,即表示一次Request请求范围内。
AddSingleton。单例,应用程序全局使用同一个实例。
AddTransient。即时的,即对象每次使用都会重新实例化。
注入方式,知识点三。提供多种注入技巧,以Transient为例
实例注入。AddTransient(this IServiceCollection services)。
泛型注入。AddTransient(this IServiceCollection services)。
工厂注入。AddTransient(this IServiceCollection services, Func implementationFactory)。
TryAddXXX。仅当XXX尚未注册实现时,注册该服务。此方法用来避免在容器中注册一个实例的两个副本。
获取实例的方法 GetService和GetRequiredService的区别,前置如果service不存在会返回NULL,后者会直接抛出异常。根据需要选择GetRequiredService,可能会让你的代码变得简洁一点。
WHY 依赖注入
这里只谈益处。

使用接口或基类抽象化依赖关系实现,明确各个类之间的依赖关系。
生命周期的统一管理,尤其对于某些类被多处依赖,关系会变得分散难以管理,依赖注入容器可以解决这点。
非常利于单元测试。
最佳实践
部分来自官方文档的一些建议

对于需要注入为单例的实例,不要依赖Scoped实例。会触发 .NET CORE作用域验证失败。
不要从Root IServiceProvider解析有作用域的实例,这样会导致该作用域的实例变成单一实例。同样会触发作用域验证失败。
对于Asp.Net Core,尽量通过构造函数而不是HttpContext.RequestServices获取实例,这样更易于单元测试。
需要对某个组件服务或是一些服务集合(包括其依赖注入时),使用约定的 Add{SERVICE_NAME} 扩展方法来注册该服务所需的所有服务。
若必须要从IServiceProvider中解析实例(如在单元测试中),请通过using (var scope = ServiceProvider.CreateScope()){ }方式创建作用域来获取实例。
代码中避免设计有状态的、静态类和成员。可以考虑设计注入为单一实例。
代码中避免在服务中直接实例化以来类。尽量采用依赖注入的方式
注意以下两种方式注入的区别,后者的实例化不是服务容器创建的,所有容器不会处理实例的Dispose !!

public class Service1 : IDisposable {}
public class Service2 : IDisposable {}

//方式一
public void ConfigureServices(IServiceCollection services)
{

services.AddSingleton<Service1>();
services.AddSingleton<IService2>(sp => new Service2());

}

//方式二
public void ConfigureServices(IServiceCollection services)
{

services.AddSingleton<Service1>(new Service1());
services.AddSingleton(new Service2());

}

延伸上一点,对于复杂对象的创建,尽量采用提供的工厂注入方式。注意工厂注入的参数是IServiceProvider,可以通过它获取你需要的实例对象。
继续延伸上一点,不要在ConfigureServices方法中 通过collection.BuildServiceProvider()来获取IServiceProvider。这个创建的是一个Root IServiceProvider。单例会实例化一次,然后ConfigureServices方法结束后框架会再次调用collection.BuildServiceProvider(),单例又会重新实例化一次。
不支持基于async/await和Task的服务解析。C# 不支持异步构造函数;因此建议模式是在同步解析服务后使用异步方法
避免在容器中直接存储数据和配置。配置应使用NET CORE的选项模型。
避免使用服务定位器模式。例如直接注入IServiceProvider来获取多个需要的服务。PS,如果你的服务依赖项过多,应该考虑分割成几个小功能服务了。
引入第三方IOC框架
.NET CORE 3.x版本后,引入第三方IOC框架的方式变更了,这里不再贴出2.x的方式。以Autofac框架为例。

Program.cs

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>()
                        .ConfigureLogging((hostingContext, logging) =>
                        {
                            logging.ClearProviders();
                            logging.AddConsole();
                            logging.AddNLog();
                        });
            });

Startup.cs

    
     //原来的 ConfigureServices保留,也可以使用原来的框架继续注入

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddMemoryCache();
        services.Configure<List<string>>(Configuration.GetSection("BlackPhoneList"));
        services.Configure<Dictionary<string, string>>(Configuration.GetSection("BusinessMessages"));
    }
    //增加ConfigureContainer(ContainerBuilder builder) 方式,使用Autofac框架注入
    public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterType<PhoneBlackListValidator>().Named<IPhoneValidator>("PHONE_BLACKLIST").SingleInstance();
        builder.RegisterType<PhonePerDayCountValidator>().Named<IPhoneValidator>("PHONE_PERDAYCOUNT").SingleInstance();
        builder.RegisterType<UniqueIdPerDayCountValidator>().Named<IUniqueIdValidator>("UNIQUEID_PERDAYCOUNT").SingleInstance();

        //可遍历类型注入,注意 只支持IEnumerable\IList\ICollection 类型
        builder.RegisterType<MessageSendValidator>().As<IMessageSendValidator>().SingleInstance();
    }

3.x 主要是在IServiceCollection和IServiceProvider之间增加了一个 ContainerBuilder 容器适配,使得第三方IOC框架引入更加合理了。具体实现原理可以网上源码查找。

特别关注-线程安全
创建线程安全的单一实例服务。 如果单例服务依赖于一个Transient服务,那么Transient服务可能也需要线程安全,具体取决于单例使用它的方式。
工厂注入方式的Func不需要是线程安全的,框架保证它由单个线程调用一次。
原文地址https://www.cnblogs.com/gt1987/p/12973001.html

相关文章
|
1月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
|
2月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
2月前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
99 3
|
1月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
1月前
|
开发框架 缓存 算法
开源且实用的C#/.NET编程技巧练习宝库(学习,工作,实践干货)
开源且实用的C#/.NET编程技巧练习宝库(学习,工作,实践干货)
|
1月前
|
Cloud Native API C#
.NET云原生应用实践(一):从搭建项目框架结构开始
.NET云原生应用实践(一):从搭建项目框架结构开始
|
2月前
|
开发框架 NoSQL .NET
利用分布式锁在ASP.NET Core中实现防抖
【9月更文挑战第5天】在 ASP.NET Core 中,可通过分布式锁实现防抖功能,仅处理连续相同请求中的首个请求,其余请求返回 204 No Content,直至锁释放。具体步骤包括:安装分布式锁库如 `StackExchange.Redis`;创建分布式锁服务接口及其实现;构建防抖中间件;并在 `Startup.cs` 中注册相关服务和中间件。这一机制有效避免了短时间内重复操作的问题。
|
3月前
|
jenkins 测试技术 持续交付
解锁.NET项目高效秘籍:从理论迷雾到实践巅峰,持续集成与自动化测试如何悄然改变游戏规则?
【8月更文挑战第28天】在软件开发领域,持续集成(CI)与自动化测试已成为提升效率和质量的关键工具。尤其在.NET项目中,二者的结合能显著提高开发速度并保证软件稳定性。本文将从理论到实践,详细介绍CI与自动化测试的重要性,并以ASP.NET Core Web API项目为例,演示如何使用Jenkins和NUnit实现自动化构建与测试。每次代码提交后,Jenkins自动触发构建流程,通过编译和运行NUnit测试确保代码质量。这种方式不仅节省了时间,还能快速发现并解决问题,推动.NET项目开发迈向更高水平。
51 8
|
3月前
|
Kubernetes 监控 Devops
【独家揭秘】.NET项目中的DevOps实践:从代码提交到生产部署,你不知道的那些事!
【8月更文挑战第28天】.NET 项目中的 DevOps 实践贯穿代码提交到生产部署全流程,涵盖健壮的源代码管理、GitFlow 工作流、持续集成与部署、容器化及监控日志记录。通过 Git、CI/CD 工具、Kubernetes 及日志框架的最佳实践应用,显著提升软件开发效率与质量。本文通过具体示例,助力开发者构建高效可靠的 DevOps 流程,确保项目成功交付。
76 0
|
3月前
|
Java Spring UED
Spring框架的异常处理秘籍:打造不败之身的应用!
【8月更文挑战第31天】在软件开发中,异常处理对应用的稳定性和健壮性至关重要。Spring框架提供了一套完善的异常处理机制,包括使用`@ExceptionHandler`注解和配置`@ControllerAdvice`。本文将详细介绍这两种方式,并通过示例代码展示其具体应用。`@ExceptionHandler`可用于控制器类中的方法,处理特定异常;而`@ControllerAdvice`则允许定义全局异常处理器,捕获多个控制器中的异常。
52 0

热门文章

最新文章

下一篇
无影云桌面