news 2026/2/22 9:03:24

C#中的服务注册剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#中的服务注册剖析

一、服务注册的核心概念

1. 什么是服务注册?

服务注册是.NET 依赖注入(DI)体系中的核心操作,本质是将服务类型(接口 / 抽象类)与具体实现类型、生命周期绑定,并存储到 DI 容器中的过程。

  • 服务类型:对外暴露的抽象契约(通常是接口 / 抽象类),比如IUserService
  • 实现类型:服务类型的具体实现类,比如UserService
  • DI 容器:存储服务注册信息的 “容器”,程序运行时可从中 “取出”(解析)服务实例。
  • 生命周期:决定 DI 容器创建服务实例的规则,是服务注册的核心属性。
2. 服务的三种核心生命周期
生命周期类型核心特点
适用场景
瞬时(Transient)每次解析都创建全新实例无状态、轻量级服务(如工具类、数据验证器)
作用域(Scoped)同一个作用域内解析多次,返回同一个实例;不同作用域返回不同实例有状态的短期服务(如数据库上下文 DbContext)
单例(Singleton)
整个应用生命周期内,无论解析多少次,都返回同一个实例
无状态、全局复用的服务(如配置管理器、缓存服务)
3. 服务注册的核心价值
  • 解耦:调用方只依赖抽象(接口),不依赖具体实现,符合 “依赖倒置原则”;
  • 可替换:修改实现类时,只需修改注册逻辑,无需改动调用代码;
  • 自动管理生命周期:DI 容器自动创建、销毁实例,无需手动new和释放;
  • 简化测试:可轻松替换为模拟(Mock)服务,方便单元测试。

二、服务注册的核心用法

.NET 提供了IServiceCollection接口作为服务注册的入口,核心注册方法如下:

注册方法用途示例
AddTransient<TService, TImplementation>()注册瞬时服务services.AddTransient<IUserService, UserService>()
AddScoped<TService, TImplementation>()注册作用域服务services.AddScoped<IOrderService, OrderService>()
AddSingleton<TService, TImplementation>()注册单例服务services.AddSingleton<ICacheService, CacheService>()
AddSingleton<TService>(instance)注册已实例化的单例services.AddSingleton<ICacheService>(new CacheService())
Add<TService>()简写(默认瞬时)services.Add<UserService>()

三、控制台案例

步骤 1:创建控制台项目(环境准备)
  1. 打开 Visual Studio/VS Code,创建.NET 8(或更高版本)控制台项目;
  2. 确保项目文件(.csproj)包含Microsoft.Extensions.DependencyInjection包(默认已包含,若缺失可通过 NuGet 安装):
    <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <!-- 若缺失依赖,添加以下包引用 --> <ItemGroup> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" /> </ItemGroup> </Project>
    步骤 2:定义服务接口和实现类

先定义 3 个不同生命周期的服务:

using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; // ====================== 1. 定义服务接口(抽象契约) ====================== /// <summary> /// 瞬时服务接口:用户服务 /// </summary> public interface IUserService { // 获取服务实例ID(用于验证生命周期) Guid GetServiceInstanceId(); // 模拟业务方法:获取用户名 string GetUserName(int userId); } /// <summary> /// 作用域服务接口:订单服务 /// </summary> public interface IOrderService { Guid GetServiceInstanceId(); // 模拟业务方法:获取订单号 string GetOrderNo(int orderId); } /// <summary> /// 单例服务接口:缓存服务 /// </summary> public interface ICacheService { Guid GetServiceInstanceId(); // 模拟业务方法:设置缓存 void SetCache(string key, string value); // 模拟业务方法:获取缓存 string? GetCache(string key); } // ====================== 2. 实现服务类 ====================== /// <summary> /// 用户服务实现(瞬时) /// </summary> public class UserService : IUserService { // 每个实例唯一ID,用于验证生命周期 private readonly Guid _instanceId; // 构造函数:创建实例时生成唯一ID public UserService() { _instanceId = Guid.NewGuid(); Console.WriteLine($"【UserService】实例已创建,ID:{_instanceId}"); } public Guid GetServiceInstanceId() => _instanceId; public string GetUserName(int userId) { return userId switch { 1 => "张三", 2 => "李四", _ => "未知用户" }; } } /// <summary> /// 订单服务实现(作用域) /// </summary> public class OrderService : IOrderService { private readonly Guid _instanceId; public OrderService() { _instanceId = Guid.NewGuid(); Console.WriteLine($"【OrderService】实例已创建,ID:{_instanceId}"); } public Guid GetServiceInstanceId() => _instanceId; public string GetOrderNo(int orderId) { return $"ORDER_{orderId}_{DateTime.Now:yyyyMMdd}"; } } /// <summary> /// 缓存服务实现(单例) /// </summary> public class CacheService : ICacheService { private readonly Guid _instanceId; // 模拟缓存存储 private readonly Dictionary<string, string> _cacheDict = new(); public CacheService() { _instanceId = Guid.NewGuid(); Console.WriteLine($"【CacheService】实例已创建,ID:{_instanceId}"); } public Guid GetServiceInstanceId() => _instanceId; public void SetCache(string key, string value) { _cacheDict[key] = value; Console.WriteLine($"【CacheService】缓存已设置:{key} = {value}"); } public string? GetCache(string key) { _cacheDict.TryGetValue(key, out var value); return value; } }
步骤 3:服务注册与解析

编写主程序,完成服务注册、不同生命周期的解析验证:

/// <summary> /// 主程序 /// </summary> class Program { static void Main(string[] args) { Console.WriteLine("===== .NET服务注册与依赖注入演示 ====="); Console.WriteLine(); // ====================== 步骤1:创建服务集合(ServiceCollection),用于注册服务 ====================== // IServiceCollection是服务注册的容器,本质是存储服务描述的列表 var services = new ServiceCollection(); // ====================== 步骤2:注册服务(核心操作) ====================== Console.WriteLine("【第一步】开始注册服务..."); // 1. 注册瞬时服务:每次解析都创建新实例 services.AddTransient<IUserService, UserService>(); // 2. 注册作用域服务:同一个作用域内实例唯一 services.AddScoped<IOrderService, OrderService>(); // 3. 注册单例服务:整个应用生命周期内实例唯一 // 方式1:通过类型注册(推荐,容器自动创建实例) services.AddSingleton<ICacheService, CacheService>(); // 方式2:直接注册已实例化的单例(适用于需要手动初始化的场景) // var cacheInstance = new CacheService(); // services.AddSingleton<ICacheService>(cacheInstance); Console.WriteLine("【第一步】服务注册完成!"); Console.WriteLine(); // ====================== 步骤3:构建服务提供器(ServiceProvider),用于解析服务 ====================== // ServiceProvider是DI容器的核心,负责根据注册信息创建/解析服务实例 using var serviceProvider = services.BuildServiceProvider(); // ====================== 步骤4:验证不同生命周期的服务特性 ====================== Console.WriteLine("【第二步】验证瞬时服务(Transient)特性:每次解析都是新实例"); VerifyTransientService(serviceProvider); Console.WriteLine(); Console.WriteLine("【第三步】验证作用域服务(Scoped)特性:同作用域内实例唯一,不同作用域不同实例"); VerifyScopedService(serviceProvider); Console.WriteLine(); Console.WriteLine("【第四步】验证单例服务(Singleton)特性:全局唯一实例"); VerifySingletonService(serviceProvider); Console.WriteLine(); Console.WriteLine("【第五步】服务依赖注入演示(服务嵌套调用)"); VerifyServiceDependency(serviceProvider); Console.WriteLine(); Console.WriteLine("===== 演示结束 ====="); Console.ReadLine(); } #region 辅助方法:验证不同生命周期的服务 /// <summary> /// 验证瞬时服务:每次解析都是新实例 /// </summary> private static void VerifyTransientService(IServiceProvider serviceProvider) { // 第一次解析瞬时服务 var userService1 = serviceProvider.GetRequiredService<IUserService>(); Console.WriteLine($"第一次解析IUserService,实例ID:{userService1.GetServiceInstanceId()}"); Console.WriteLine($"业务方法调用:用户1的名称 = {userService1.GetUserName(1)}"); // 第二次解析瞬时服务(应该是新实例) var userService2 = serviceProvider.GetRequiredService<IUserService>(); Console.WriteLine($"第二次解析IUserService,实例ID:{userService2.GetServiceInstanceId()}"); Console.WriteLine($"业务方法调用:用户2的名称 = {userService2.GetUserName(2)}"); // 验证:两次解析的实例ID是否不同(瞬时服务特性) Console.WriteLine($"瞬时服务验证结果:两次实例是否相同? {userService1.GetServiceInstanceId() == userService2.GetServiceInstanceId()}"); } /// <summary> /// 验证作用域服务:同作用域内实例唯一,不同作用域不同实例 /// </summary> private static void VerifyScopedService(IServiceProvider serviceProvider) { // 作用域1:创建第一个作用域 using (var scope1 = serviceProvider.CreateScope()) { var scopeProvider1 = scope1.ServiceProvider; // 作用域1内第一次解析 var orderService1_1 = scopeProvider1.GetRequiredService<IOrderService>(); Console.WriteLine($"作用域1 - 第一次解析IOrderService,实例ID:{orderService1_1.GetServiceInstanceId()}"); Console.WriteLine($"业务方法调用:订单1的编号 = {orderService1_1.GetOrderNo(1)}"); // 作用域1内第二次解析(应该是同一个实例) var orderService1_2 = scopeProvider1.GetRequiredService<IOrderService>(); Console.WriteLine($"作用域1 - 第二次解析IOrderService,实例ID:{orderService1_2.GetServiceInstanceId()}"); Console.WriteLine($"作用域1内验证:两次实例是否相同? {orderService1_1.GetServiceInstanceId() == orderService1_2.GetServiceInstanceId()}"); } // 作用域2:创建第二个作用域 using (var scope2 = serviceProvider.CreateScope()) { var scopeProvider2 = scope2.ServiceProvider; // 作用域2内解析(应该是新实例) var orderService2 = scopeProvider2.GetRequiredService<IOrderService>(); Console.WriteLine($"作用域2 - 解析IOrderService,实例ID:{orderService2.GetServiceInstanceId()}"); Console.WriteLine($"业务方法调用:订单2的编号 = {orderService2.GetOrderNo(2)}"); } } /// <summary> /// 验证单例服务:全局唯一实例 /// </summary> private static void VerifySingletonService(IServiceProvider serviceProvider) { // 第一次解析单例服务 var cacheService1 = serviceProvider.GetRequiredService<ICacheService>(); cacheService1.SetCache("user_1", "张三"); Console.WriteLine($"第一次解析ICacheService,实例ID:{cacheService1.GetServiceInstanceId()}"); Console.WriteLine($"缓存读取:user_1 = {cacheService1.GetCache("user_1")}"); // 第二次解析单例服务(应该是同一个实例) var cacheService2 = serviceProvider.GetRequiredService<ICacheService>(); Console.WriteLine($"第二次解析ICacheService,实例ID:{cacheService2.GetServiceInstanceId()}"); Console.WriteLine($"缓存读取(复用第一次设置的值):user_1 = {cacheService2.GetCache("user_1")}"); // 在作用域内解析单例(仍然是同一个实例) using (var scope = serviceProvider.CreateScope()) { var cacheService3 = scope.ServiceProvider.GetRequiredService<ICacheService>(); Console.WriteLine($"作用域内解析ICacheService,实例ID:{cacheService3.GetServiceInstanceId()}"); Console.WriteLine($"缓存读取:user_1 = {cacheService3.GetCache("user_1")}"); } // 验证:所有解析的实例ID是否相同 var isSame = cacheService1.GetServiceInstanceId() == cacheService2.GetServiceInstanceId(); Console.WriteLine($"单例服务验证结果:所有实例是否相同? {isSame}"); } /// <summary> /// 验证服务依赖注入:一个服务依赖另一个服务 /// </summary> private static void VerifyServiceDependency(IServiceProvider serviceProvider) { // 先注册一个依赖其他服务的新服务 // 定义一个业务服务,依赖IUserService和ICacheService services.AddTransient<IBusinessService, BusinessService>(); // 注意:这里需要先把services变量改为类级别的静态变量,或重新注册 // 重新构建服务提供器(因为新增了注册) using var newServiceProvider = services.BuildServiceProvider(); var businessService = newServiceProvider.GetRequiredService<IBusinessService>(); businessService.DoBusiness(1); } #endregion } // ====================== 补充:服务依赖的示例 ====================== /// <summary> /// 业务服务接口(依赖其他服务) /// </summary> public interface IBusinessService { void DoBusiness(int userId); } /// <summary> /// 业务服务实现(构造函数注入IUserService和ICacheService) /// </summary> public class BusinessService : IBusinessService { // 依赖的服务通过构造函数注入(DI容器自动解析) private readonly IUserService _userService; private readonly ICacheService _cacheService; // 构造函数注入是.NET DI的默认方式(推荐) public BusinessService(IUserService userService, ICacheService cacheService) { _userService = userService; _cacheService = cacheService; Console.WriteLine($"【BusinessService】实例已创建,依赖的IUserService实例ID:{userService.GetServiceInstanceId()}"); Console.WriteLine($"【BusinessService】实例已创建,依赖的ICacheService实例ID:{cacheService.GetServiceInstanceId()}"); } public void DoBusiness(int userId) { var userName = _userService.GetUserName(userId); _cacheService.SetCache($"business_user_{userId}", userName); Console.WriteLine($"【BusinessService】业务处理完成:用户{userId}的名称是{userName},已缓存"); } }
步骤 4:代码关键说明
  1. 服务注册核心

    • ServiceCollection是 “注册清单”,通过AddXxx方法将服务类型与实现类型、生命周期绑定;
    • BuildServiceProvider()将注册清单转换为可解析服务的ServiceProvider(DI 容器)。
  2. 服务解析方法

    • GetRequiredService<T>():强制解析服务,若服务未注册则抛出异常(推荐);
    • GetService<T>():解析服务,若未注册则返回null
    • CreateScope():创建作用域,作用域内解析的 Scoped 服务实例唯一。
  3. 依赖注入方式

    • 示例中BusinessService通过构造函数注入依赖的IUserServiceICacheService,这是.NET DI 的默认且推荐的方式;
    • DI 容器会自动解析依赖链:解析IBusinessService时,先解析其构造函数中的IUserServiceICacheService,再创建BusinessService实例。
步骤 5:运行结果分析

运行程序后,会看到以下关键输出:

  • 瞬时服务:两次解析的IUserService实例 ID 完全不同;
  • 作用域服务:同一个作用域内两次解析的IOrderService实例 ID 相同,不同作用域 ID 不同;
  • 单例服务:无论直接解析还是在作用域内解析,ICacheService的实例 ID 始终相同,且缓存数据可复用;
  • 依赖注入BusinessService创建时,DI 容器自动注入依赖的服务实例,无需手动new

四、扩展知识点

  1. 服务注册的其他方式
    • 泛型服务注册:services.AddTransient(typeof(IGenericService<>), typeof(GenericService<>))
    • 工厂模式注册:services.AddTransient<IUserService>(sp => new UserService("自定义参数"))
  2. 服务生命周期注意事项
    • 禁止在 “短生命周期服务” 中注入 “长生命周期服务”(如 Scoped 服务注入 Singleton 服务),会导致 Scoped 服务被 “提升” 为 Singleton,引发线程安全问题;
    • 瞬时服务可注入任意生命周期的服务,单例服务只能注入单例服务。
  3. 控制台项目 vs Web 项目
    • Web 项目中,每个 HTTP 请求对应一个作用域(Scoped),因此 Scoped 服务默认在单个请求内唯一;
    • 控制台项目需手动创建作用域(CreateScope()),否则解析 Scoped 服务会抛出异常。

总结

  1. 核心概念:服务注册是将 “抽象服务类型 - 具体实现类型 - 生命周期” 绑定并存储到 DI 容器的过程,目的是解耦和自动管理实例;
  2. 核心操作:通过ServiceCollectionAddTransient/AddScoped/AddSingleton完成注册,通过ServiceProvider解析服务;
  3. 生命周期关键:瞬时(每次新实例)、作用域(同作用域唯一)、单例(全局唯一),需根据业务场景选择。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/21 4:21:58

需求波动剧烈怎么办?:用多Agent协同预测应对不确定性

第一章&#xff1a;供应链 Agent 的需求预测在现代供应链管理中&#xff0c;准确的需求预测是优化库存、降低运营成本和提升客户满意度的核心。传统的统计方法如移动平均和指数平滑已难以应对复杂多变的市场环境。随着人工智能的发展&#xff0c;基于 Agent 的智能预测系统逐渐…

作者头像 李华
网站建设 2026/2/17 4:49:13

SD模型实战:用快马平台5分钟搭建AI艺术生成器

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个基于Stable Diffusion的AI艺术生成网站。功能需求&#xff1a;1. 用户输入文字提示词生成艺术作品 2. 可选择不同艺术风格&#xff08;写实、动漫、油画等&#xff09;3. 生…

作者头像 李华
网站建设 2026/2/21 11:29:05

游戏 AI 训练资源稀缺预警:2024年最值得收藏的5个开源框架推荐

第一章&#xff1a;游戏 AI 训练资源稀缺的现状与挑战在当前人工智能技术高速发展的背景下&#xff0c;游戏 AI 的训练却面临严重的资源瓶颈。与图像识别、自然语言处理等领域相比&#xff0c;可用于训练游戏 AI 的高质量数据集和计算资源明显不足&#xff0c;这极大地限制了模…

作者头像 李华
网站建设 2026/2/21 2:02:24

【量子 Agent 算法优化终极指南】:揭秘下一代智能体高效决策核心机制

第一章&#xff1a;量子 Agent 算法优化的核心理念量子 Agent 算法优化是一种融合量子计算原理与智能体学习机制的前沿技术&#xff0c;旨在通过量子态叠加、纠缠和干涉等特性提升传统强化学习的探索效率与收敛速度。其核心在于将 Agent 的策略空间映射至量子希尔伯特空间&…

作者头像 李华
网站建设 2026/2/20 12:06:58

医疗康复Agent方案调整实战手册(基于10万+病例数据验证)

第一章&#xff1a;医疗康复Agent方案调整实战手册概述在医疗康复领域&#xff0c;智能Agent的应用正逐步改变传统康复流程的执行方式。本手册聚焦于实际场景中Agent行为策略的动态调整机制&#xff0c;旨在为开发与运维人员提供一套可落地的方案优化路径。通过结合患者康复数据…

作者头像 李华