你是否还在为每次新增服务都要手动在Program.cs
中添加注册代码而烦恼?随着项目规模的扩大,服务注册的代码越来越冗长,维护成本也越来越高。据统计,一个中等规模的.NET项目平均需要注册50+个服务,传统方式下仅服务注册代码就占据了启动文件的80%篇幅!
今天我们来探讨一个更优雅的解决方案:基于特性(Attribute)的自动服务注册,让你彻底告别手动注册的烦恼,让代码更简洁、更易维护。
在传统的.NET依赖注入中,我们需要在Program.cs
或Startup.cs
中逐一注册每个服务:
C#// 传统注册方式 - 冗长且容易遗漏
services.AddScoped<IUserService, UserService>();
services.AddSingleton<ICacheService, CacheService>();
services.AddTransient<IEmailService, EmailService>();
services.AddScoped<IDataRepository, DataRepository>();
// ... 50+个服务的注册代码
痛点总结:
通过自定义特性标记需要注册的服务,在启动时通过反射自动扫描并注册,实现**"声明式"**的服务注册。
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace AppDIAttr
{
/// <summary>
/// 服务注册特性 - 支持自定义生命周期
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class AutoRegisterAttribute : Attribute
{
public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Scoped;
public AutoRegisterAttribute(ServiceLifetime lifetime = ServiceLifetime.Scoped)
{
Lifetime = lifetime;
}
}
}
设计亮点:
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace AppDIAttr
{
/// <summary>
/// 增强版自动服务注册 - 支持特性控制
/// </summary>
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddAutoRegisteredServices(
this IServiceCollection services,
params Assembly[] assemblies)
{
foreach (var assembly in assemblies)
{
// 🏷️ 只注册标记了AutoRegister特性的类
var typesToRegister = assembly.GetTypes()
.Where(type => type.IsClass
&& !type.IsAbstract
&& type.GetCustomAttribute<AutoRegisterAttribute>() != null);
foreach (var type in typesToRegister)
{
var attribute = type.GetCustomAttribute<AutoRegisterAttribute>();
var interfaces = type.GetInterfaces().Where(i => !i.IsGenericTypeDefinition);
// 🎯 根据特性指定的生命周期注册服务
if (interfaces.Any())
{
foreach (var @interface in interfaces)
{
RegisterService(services, @interface, type, attribute.Lifetime);
}
}
else
{
RegisterService(services, type, type, attribute.Lifetime);
}
}
}
return services;
}
private static void RegisterService(IServiceCollection services, Type serviceType,
Type implementationType, ServiceLifetime lifetime)
{
switch (lifetime)
{
case ServiceLifetime.Singleton:
services.AddSingleton(serviceType, implementationType);
break;
case ServiceLifetime.Transient:
services.AddTransient(serviceType, implementationType);
break;
default:
services.AddScoped(serviceType, implementationType);
break;
}
Console.WriteLine($"🚀 已注册 {lifetime} 服务: {serviceType.Name} -> {implementationType.Name}");
}
}
}
核心逻辑解析:
AutoRegisterAttribute
的类C#/// <summary>
/// 缓存服务 - 单例模式,全局共享
/// </summary>
[AutoRegister(ServiceLifetime.Singleton)]
public class CacheService : ICacheService
{
private readonly Dictionary<string, object> _cache = new();
private readonly ILogger<CacheService> _logger;
public CacheService(ILogger<CacheService> logger)
{
_logger = logger;
_logger.LogInformation("💾 CacheService 实例已创建 (Singleton)");
}
public void Set(string key, object value)
{
_cache[key] = value;
_logger.LogInformation($"📝 缓存已设置: {key}");
}
public T Get<T>(string key)
{
if (_cache.TryGetValue(key, out var value))
{
_logger.LogInformation($"📖 缓存命中: {key}");
return (T)value;
}
_logger.LogInformation($"❌ 缓存未命中: {key}");
return default(T);
}
public void Remove(string key)
{
_cache.Remove(key);
_logger.LogInformation($"🗑️ 缓存已删除: {key}");
}
}
/// <summary>
/// 数据仓储服务 - 请求作用域
/// </summary>
[AutoRegister(ServiceLifetime.Scoped)]
public class DataRepository : IDataRepository
{
private readonly ILogger<DataRepository> _logger;
private static readonly List<User> _users = new(); // 模拟数据库
public DataRepository(ILogger<DataRepository> logger)
{
_logger = logger;
_logger.LogInformation("🗄️ DataRepository 实例已创建 (Scoped)");
}
// 实现具体的数据操作方法...
}
/// <summary>
/// 邮件服务 - 瞬时模式,每次使用创建新实例
/// </summary>
[AutoRegister(ServiceLifetime.Transient)]
public class EmailService : IEmailService
{
private readonly ILogger<EmailService> _logger;
public EmailService(ILogger<EmailService> logger)
{
_logger = logger;
_logger.LogInformation("📧 EmailService 实例已创建 (Transient)");
}
// 实现邮件发送逻辑...
}
C#using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace AppDIAttr
{
internal class Program
{
static async Task Main(string[] args)
{
Console.OutputEncoding=System.Text.Encoding.UTF8;
Console.WriteLine("🎯 自动服务注册演示程序");
Console.WriteLine("==========================\n");
// 创建Host Builder
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
// 🚀 自动注册所有标记了AutoRegister特性的服务
Console.WriteLine("📋 开始自动服务注册:");
services.AddAutoRegisteredServices(Assembly.GetExecutingAssembly());
// 注册应用程序主类
services.AddScoped<Application>();
Console.WriteLine("\n✅ 服务注册完成!\n");
})
.Build();
// 创建作用域并运行应用程序
using var scope = host.Services.CreateScope();
var app = scope.ServiceProvider.GetRequiredService<Application>();
await app.RunAsync();
Console.WriteLine("\n🎉 程序执行完成,按任意键退出...");
Console.ReadKey();
}
}
}
C#// ❌ 错误:只扫描当前程序集
services.AddAutoRegisteredServices(Assembly.GetExecutingAssembly());
// ✅ 正确:扫描所有相关程序集
services.AddAutoRegisteredServices(
Assembly.GetExecutingAssembly(),
Assembly.GetAssembly(typeof(SomeServiceInOtherAssembly))
);
C#// ⚠️ 注意:确保接口和实现类的命名符合约定
public interface IUserService { }
public class UserService : IUserService { } // ✅ 标准命名
public interface IDataAccess { }
public class SqlDataAccess : IDataAccess { } // ✅ 也可以
C#// ⚠️ 当前实现不支持泛型接口,需要特殊处理
public interface IRepository<T> { }
public class UserRepository : IRepository<User> { } // 需要手动注册
方式 | 启动时间增加 | 代码行数减少 | 维护成本 |
---|---|---|---|
传统手动注册 | 0ms | 0% | 高 |
自动注册 | 5-10ms | 80%+ | 低 |
通过特性驱动的自动服务注册,我们实现了:
这种方式特别适合中大型项目和团队协作开发,让你的C#项目更加优雅和易维护。
💭 互动话题:
觉得这个技巧有用吗?点赞支持并转发给更多.NET开发同行吧!让我们一起写出更优雅的C#代码!
🔖 收藏本文,下次项目重构时直接使用这套解决方案!
相关信息
通过网盘分享的文件:AppDIAttr.zip 链接: https://pan.baidu.com/s/1h_zuODJ5S4jkcwDSdf-qdQ?pwd=ppvx 提取码: ppvx --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!