你是否也有过这样的经历:每次新增一个服务,都要跑到Program.cs
里手动添加一行services.AddScoped<IUserService, UserService>()
?项目越来越大,服务越来越多,光是维护这些注册代码就让人头疼不已...
手动管理依赖注入是最耗时的重无聊工作之一。今天,我们就来彻底解决这个问题!
说到根上就是放射扫描程序集,这块与spring的扫包一回事。
本文将带你掌握C#服务自动注册技术,让你的代码从此告别重复劳动,实现真正的优雅开发。
每新增一个服务,就要手动写一行注册代码:
C#services.AddScoped<IUserService, UserService>();
services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IEmailService, EmailService>();
// 几十个服务下来,手都要写麻了...
新同事加入项目,新增了服务但忘记注册,编译没问题,一运行就炸:
C#System.InvalidOperationException: Unable to resolve service for type 'INewService'
随着项目发展,Program.cs
中的注册代码越来越多,可读性急剧下降,维护起来苦不堪言。
利用反射机制,扫描指定命名空间下的所有类型,根据预设规则自动完成服务注册。简单来说,就是让程序"自己发现"需要注册的服务。
让我们看看这个"神器"是如何工作的:
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace AppAutoDI.Services
{
// ==================== 服务接口定义 ====================
public interface IUserService
{
Task<string> GetUserAsync(int id);
Task CreateUserAsync(string name);
}
public interface IOrderService
{
Task<string> ProcessOrderAsync(int orderId);
Task<decimal> CalculateTotalAsync(int orderId);
}
public interface IEmailService
{
Task SendEmailAsync(string to, string subject, string body);
}
public interface ILoggerService
{
void LogInfo(string message);
void LogError(string message);
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace AppAutoDI.Services
{
// ==================== 服务实现类 ====================
public class UserService : IUserService
{
private readonly ILogger<UserService> _logger;
public UserService(ILogger<UserService> logger)
{
_logger = logger;
}
public async Task<string> GetUserAsync(int id)
{
_logger.LogInformation($"获取用户信息,ID: {id}");
await Task.Delay(100); // 模拟异步操作
return $"用户{id}: 张三";
}
public async Task CreateUserAsync(string name)
{
_logger.LogInformation($"创建用户: {name}");
await Task.Delay(50);
}
}
public class OrderService : IOrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public async Task<string> ProcessOrderAsync(int orderId)
{
_logger.LogInformation($"处理订单,ID: {orderId}");
await Task.Delay(200);
return $"订单{orderId}处理完成";
}
public async Task<decimal> CalculateTotalAsync(int orderId)
{
_logger.LogInformation($"计算订单总价,ID: {orderId}");
await Task.Delay(100);
return 299.99m;
}
}
public class EmailService : IEmailService
{
private readonly ILogger<EmailService> _logger;
public EmailService(ILogger<EmailService> logger)
{
_logger = logger;
}
public async Task SendEmailAsync(string to, string subject, string body)
{
_logger.LogInformation($"发送邮件到: {to}, 主题: {subject}");
await Task.Delay(300);
}
}
public class LoggerService : ILoggerService
{
private readonly ILogger<LoggerService> _logger;
public LoggerService(ILogger<LoggerService> logger)
{
_logger = logger;
}
public void LogInfo(string message)
{
_logger.LogInformation(message);
}
public void LogError(string message)
{
_logger.LogError(message);
}
}
// 无接口的独立服务类
public class ReportService
{
private readonly ILogger<ReportService> _logger;
public ReportService(ILogger<ReportService> logger)
{
_logger = logger;
}
public async Task<string> GenerateReportAsync()
{
_logger.LogInformation("生成报告中...");
await Task.Delay(500);
return "月度销售报告已生成";
}
}
// 数据处理服务(无接口)
public class DataProcessingService
{
private readonly ILogger<DataProcessingService> _logger;
public DataProcessingService(ILogger<DataProcessingService> logger)
{
_logger = logger;
}
public async Task ProcessDataAsync()
{
_logger.LogInformation("处理数据中...");
await Task.Delay(300);
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AppAutoDI.Services;
namespace AppAutoDI
{
// ==================== 业务逻辑处理类 ====================
public class BusinessLogic
{
private readonly IUserService _userService;
private readonly IOrderService _orderService;
private readonly IEmailService _emailService;
private readonly AppAutoDI.Services.ReportService _reportService;
private readonly AppAutoDI.Services.DataProcessingService _dataProcessingService;
public BusinessLogic(
IUserService userService,
IOrderService orderService,
IEmailService emailService,
AppAutoDI.Services.ReportService reportService,
AppAutoDI.Services.DataProcessingService dataProcessingService)
{
_userService = userService;
_orderService = orderService;
_emailService = emailService;
_reportService = reportService;
_dataProcessingService = dataProcessingService;
}
public async Task RunBusinessLogicAsync()
{
Console.WriteLine("🚀 开始执行业务逻辑...\n");
// 用户服务操作
Console.WriteLine("📱 用户服务操作:");
await _userService.CreateUserAsync("李四");
var user = await _userService.GetUserAsync(1001);
Console.WriteLine($"获取用户结果: {user}\n");
// 订单服务操作
Console.WriteLine("🛒 订单服务操作:");
var orderResult = await _orderService.ProcessOrderAsync(2001);
var total = await _orderService.CalculateTotalAsync(2001);
Console.WriteLine($"订单处理结果: {orderResult}");
Console.WriteLine($"订单总价: ¥{total}\n");
// 邮件服务操作
Console.WriteLine("📧 邮件服务操作:");
await _emailService.SendEmailAsync("user@example.com", "订单确认", "您的订单已确认");
Console.WriteLine();
// 报告服务操作
Console.WriteLine("📊 报告服务操作:");
var report = await _reportService.GenerateReportAsync();
Console.WriteLine($"报告结果: {report}\n");
// 数据处理服务操作
Console.WriteLine("🔄 数据处理服务操作:");
await _dataProcessingService.ProcessDataAsync();
Console.WriteLine("数据处理完成\n");
Console.WriteLine("✅ 业务逻辑执行完成!");
}
}
}
C#using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Reflection;
namespace AppAutoDI
{
internal class Program
{
public static async Task Main(string[] args)
{
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine("🎯 自动服务注册演示程序");
// 创建Host建造器
var hostBuilder = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
// 🔧 自动注册服务
RegisterServices(services);
// 注册业务逻辑类
services.AddScoped<BusinessLogic>();
});
// 构建并运行Host
using var host = hostBuilder.Build();
// 获取服务并执行业务逻辑
using var scope = host.Services.CreateScope();
var businessLogic = scope.ServiceProvider.GetRequiredService<BusinessLogic>();
try
{
await businessLogic.RunBusinessLogicAsync();
}
catch (Exception ex)
{
Console.WriteLine($"❌ 执行出错: {ex.Message}");
}
Console.WriteLine("\n按任意键退出...");
Console.ReadKey();
}
/// <summary>
/// 基础版自动服务注册 - 简单高效
/// </summary>
/// <param name="services">服务集合</param>
private static void RegisterServices(IServiceCollection services)
{
Console.WriteLine("🔧 开始自动注册服务...\n");
try
{
// 🔍 加载指定程序集
var assembly = Assembly.GetExecutingAssembly(); // 使用当前程序集
// 🎯 筛选服务类型:排除接口和抽象类
var serviceTypes = assembly.GetTypes()
.Where(type => type.Namespace != null
&& type.Namespace.Contains("AppAutoDI.Services")
&& !type.IsInterface
&& !type.IsAbstract);
int registeredCount = 0;
foreach (var serviceType in serviceTypes)
{
// 🔗 获取当前类型实现的接口
var interfaces = serviceType.GetInterfaces()
.Where(i => i.Namespace != null
&& i.Namespace.Contains("AppAutoDI.Services"));
// ⚡ 注册策略:无接口直接注册,有接口按接口注册
if (!interfaces.Any())
{
services.AddScoped(serviceType);
Console.WriteLine($"✅ 已注册服务: {serviceType.Name}");
registeredCount++;
}
else
{
foreach (var interfaceType in interfaces)
{
services.AddScoped(interfaceType, serviceType);
Console.WriteLine($"✅ 已注册服务: {interfaceType.Name} -> {serviceType.Name}");
registeredCount++;
}
}
}
Console.WriteLine($"\n🎉 服务注册完成!共注册 {registeredCount} 个服务\n");
}
catch (Exception ex)
{
Console.WriteLine($"❌ 服务注册失败: {ex.Message}");
throw;
}
}
}
}
反射操作在应用启动时执行一次,对运行时性能几乎无影响。但如果服务数量巨大(>1000个),建议考虑更高级的方案。
确保只扫描可信的程序集和命名空间,避免意外注册不安全的类型。
建议遵循 IXxxService
+ XxxService
的命名模式,这样自动匹配会更准确。
通过本文的学习,你已经掌握了:
这套自动注册方案能让你的开发效率提升50%以上,尤其在大型项目中效果更加明显。从此告别繁琐的手动注册,让代码变得更加优雅和易维护!
🤔 互动话题:
💡 如果这篇文章对你有帮助,请转发给更多的.NET开发同行,让我们一起写出更优雅的代码!
🔥 想了解更多C#实战技巧?关注我的公众号,每周分享实用的编程干货!
相关信息
通过网盘分享的文件:AppAutoDI.zip 链接: https://pan.baidu.com/s/1JFgj1jZMFr-v-0LJM8Rr-g 提取码: tqcd --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!