1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
using
Microsoft.Extensions.DependencyInjection;
using
System;
using
System.Linq;
using
System.Reflection;
// 自定义属性来标记服务类型
[AttributeUsage(AttributeTargets.Class, AllowMultiple =
false
, Inherited =
false
)]
public
class
ServiceTypeAttribute : Attribute
{
public
ServiceLifetime Lifetime {
get
; }
public
ServiceTypeAttribute(ServiceLifetime lifetime)
{
Lifetime = lifetime;
}
}
public
static
class
DependencyInjectionExtensions
{
/// <summary>
/// 批量注册服务
/// </summary>
/// <param name="services">IServiceCollection</param>
/// <param name="servicePrefix">服务类的前缀,例如 "Service"</param>
/// <param name="interfacePrefix">接口的前缀,例如 "I"</param>
public
static
void
RegisterServices(
this
IServiceCollection services,
string
servicePrefix,
string
interfacePrefix)
{
if
(services ==
null
)
{
throw
new
ArgumentNullException(nameof(services));
}
// 获取当前程序集中所有类
var
types = Assembly.GetExecutingAssembly().GetTypes();
// 筛选出符合服务命名约定的类
var
serviceTypes = types
.Where(t => t.Name.StartsWith(servicePrefix) && !t.IsInterface && !t.IsAbstract)
.ToList();
// 遍历所有服务类
foreach
(
var
serviceType
in
serviceTypes)
{
// 尝试查找对应的接口
var
interfaceType = types.FirstOrDefault(t => t.Name == interfacePrefix + serviceType.Name.Substring(servicePrefix.Length) && t.IsInterface);
if
(interfaceType !=
null
)
{
// 获取服务类型上的 ServiceTypeAttribute
var
serviceTypeAttribute = serviceType.GetCustomAttribute<ServiceTypeAttribute>();
var
lifetime = serviceTypeAttribute?.Lifetime ?? ServiceLifetime.Scoped;
// 默认使用 Scoped
// 根据不同的生命周期注册服务
switch
(lifetime)
{
case
ServiceLifetime.Singleton:
services.AddSingleton(interfaceType, serviceType);
break
;
case
ServiceLifetime.Scoped:
services.AddScoped(interfaceType, serviceType);
break
;
case
ServiceLifetime.Transient:
services.AddTransient(interfaceType, serviceType);
break
;
default
:
services.AddScoped(interfaceType, serviceType);
// 默认使用 Scoped
break
;
}
}
else
{
// 如果没有找到对应的接口,则可以选择只注册服务本身,或者抛出异常
// 这里选择抛出异常,提示开发者需要有对应的接口
throw
new
InvalidOperationException($
"Service {serviceType.Name} does not have a corresponding interface (expected interface name: {interfacePrefix}{serviceType.Name.Substring(servicePrefix.Length)})"
);
}
}
}
}
// 示例接口和服务
public
interface
IUserService
{
void
DoSomething();
}
[ServiceType(ServiceLifetime.Scoped)]
// 使用属性标记生命周期
public
class
UserService : IUserService
{
public
void
DoSomething()
{
Console.WriteLine(
"UserService.DoSomething() called."
);
}
}
public
interface
IOrderService
{
void
ProcessOrder();
}
[ServiceType(ServiceLifetime.Transient)]
public
class
OrderService: IOrderService
{
public
void
ProcessOrder()
{
Console.WriteLine(
"OrderService.ProcessOrder() called."
);
}
}
public
class
Program
{
public
static
void
Main(
string
[] args)
{
// 创建 ServiceCollection
IServiceCollection services =
new
ServiceCollection();
// 注册服务
services.RegisterServices(
"Service"
,
"I"
);
// 添加其他必要的服务,例如 MVC
services.AddMvc();
// 如果是 ASP.NET Core MVC 项目
// 构建 ServiceProvider
IServiceProvider serviceProvider = services.BuildServiceProvider();
// 从 ServiceProvider 中获取服务并使用
var
userService = serviceProvider.GetService<IUserService>();
userService?.DoSomething();
var
orderService = serviceProvider.GetService<IOrderService>();
orderService?.ProcessOrder();
Console.ReadKey();
}
}
|
代码说明
- ServiceTypeAttribute: 这是一个自定义属性,用于显式指定服务类的生命周期(Singleton、Scoped 或 Transient)。
- RegisterServices 扩展方法:
- 它扩展了
IServiceCollection
,提供了一个便捷的方法来批量注册服务。 servicePrefix
参数指定服务类的前缀(例如,"Service"
)。interfacePrefix
参数指定接口的前缀(例如,"I"
)。- 它使用反射来查找程序集中所有符合命名约定的类(例如,以 "Service" 开头的类)。
- 它假定接口的命名约定是接口前缀 + 服务类名(去掉服务前缀)。 例如,如果服务类是
UserService
,则对应的接口应该是IUserService
。 - 它使用
GetCustomAttribute
方法获取服务类上的ServiceTypeAttribute
属性,并根据属性中指定的生命周期注册服务。 如果未找到此属性,则默认使用Scoped
生命周期。 - 如果找不到与服务类对应的接口,它会抛出一个异常,指示缺少必需的接口。
- 它扩展了
- 示例:
IUserService
和UserService
演示了如何定义一个服务及其接口。IOrderService
和OrderService
演示了另一个服务及其接口,并使用[ServiceType]
特性标记了生命周期- 在
Main
方法中,我们创建了一个ServiceCollection
,调用RegisterServices
方法注册服务,然后从ServiceProvider
中解析并使用这些服务。
使用说明
- 定义您的服务接口和服务类,并确保它们遵循命名约定(例如,
IUserService
和UserService
)。 - 使用
ServiceTypeAttribute
属性标记您的服务类,以指定其生命周期。 如果省略此属性,则默认使用Scoped
生命周期。 - 在您的应用程序的启动配置中(例如,
Main
方法或ConfigureServices
方法中),获取IServiceCollection
的实例,并调用RegisterServices
扩展方法,传递服务类前缀和接口前缀。 - 像往常一样使用依赖注入来获取服务实例。
这个方法提供了一种灵活且类型安全的方式来批量注册服务,并允许您通过属性显式控制每个服务的生命周期。
原创作者: wwwan 转载于: https://www.cnblogs.com/wwwan/p/18868271