c# 批量注入示例代码
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扩展方法,传递服务类前缀和接口前缀。 - 像往常一样使用依赖注入来获取服务实例。
这个方法提供了一种灵活且类型安全的方式来批量注册服务,并允许您通过属性显式控制每个服务的生命周期。
c# 批量注入示例代码的更多相关文章
- 在.NET Core中批量注入Grpc服务
GRPC 是谷歌发布的一个开源.高性能.通用RPC服务,尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 干脆就用了 HTTP2.还有就是它具有跨平台.跨语言 等特性 ...
- .NET 使用自带 DI 批量注入服务(Service)和 后台服务(BackgroundService)
今天教大家如何在asp .net core 和 .net 控制台程序中 批量注入服务和 BackgroundService 后台服务 在默认的 .net 项目中如果我们注入一个服务或者后台服务,常规的 ...
- 去掉tppabs冗余代码,怎样批量去掉tppabs代码
去掉tppabs冗余代码,怎样批量去掉tppabs代码 刚用teleport pro拉了一个整站到本地 所有的超链都被强行加了一句tppabs=" 就玩了一把dw的替换功能 查找范围:整 ...
- C/C++ 开源库及示例代码
C/C++ 开源库及示例代码 Table of Contents 说明 1 综合性的库 2 数据结构 & 算法 2.1 容器 2.1.1 标准容器 2.1.2 Lockfree 的容器 2.1 ...
- 看完48秒动画,让你不敢再登录HTTP网站(附完整示例代码)
在我的 单点登录SSO示例代码 一文中,强烈不建议部署HTTP的SSO服务站点. 在此写个基于网络包嗅探的HTTP会话劫持程序,给大家一个直观的危害性展示. 示例中,我在一台Mac上登录58同城,被另 ...
- SmartStore.Net、NopCommerce 全局异常处理、依赖注入、代码研究
以下是本人最近对NopCommerce和SmartStore.net部分代码的研究和总结,主要集中于:依赖注入.异常处理.对象映射.系统缓存.日志这些方面,供大家参考. NOP 3.8 /// < ...
- SQL注入之代码层防御
[目录] 0x0 前言 0x1 领域驱动的安全 1.1 领域驱动的设计 1.2 领域驱动的安全示例 0x2 使用参数化查询 2.1 参数化查询 2.2 Java中的参数化语句 2.3 .NET(C#) ...
- 50.AngularJs directive详解及示例代码
转自:https://www.cnblogs.com/best/tag/Angular/ 本教程使用AngularJs版本:1.5.3 AngularJs GitHub: https://github ...
- mybatis的sql中使用$会出现sql注入示例
mybatis的sql中使用$会出现sql注入示例: 模拟简单登录场景: 页面代码: function login(){ //sql注入 var user = { username : "' ...
- .netcore之DI批量注入(支持泛型) - xms
一旦系统内模块比较多,按DI标准方法去逐个硬敲AddScoped/AddSingleton/AddTransient缺乏灵活性且效率低下,所以批量注入提供了很大的便捷性,特别是对于泛型的服务类,下面介 ...
随机推荐
- 《<吕氏春秋> 刘本》
<<吕氏春秋> 刘本>(卷三) 编者 刘昱合 其他版本 <吕氏春秋>(卷一) <吕氏春秋>(卷二) <<吕氏春秋> 全本>(卷三 ...
- PKUWC2025 游记
哈哈哈哈哈,我糖完了,哈哈哈哈哈. Day \(-998244353\) 被波波抓到机房充军集训去了,听到了很多新奇的算法,然后拼尽全力仍难以 \(AC\)--然后被各种巨佬疯狂单调队列. Day \ ...
- c# 删除文件夹最快的函数方法 无视占用 直接删除
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/17270147.html 代码如下,直接通过cmd调用dos命令进行删除 public stat ...
- Arduino语法--运算符
本节介绍最常用的一些Arduino运算符,包括赋值运算符.算数运算符.关系运算符.逻辑运算符和递增/减运算符. 一. 赋值运算符 =(等于)为指定某个变量的值,例如:A=x,将x变量的值放入A变量. ...
- nginx 如何强制跳转 https
本项目 nginx 作为代理服务 项目上线,客户说要加个安全证书 ,于是安全证书是加上了,可是htttp和https都能访问网站,客户要求不行必须强制用带有https的地址访问 开整 这是 http ...
- redis bind protected-mode
概要 redis bind.protected-mode 配置 安装并启动 yum install -y redis systemctl enable --now redis # 使用 redis-s ...
- 内网环境部署Deepseek+Dify,构建企业私有化AI应用
0.简介 公司为生产安全和保密,内部的服务器不可连接外部网络,为了可以在内网环境下部署,采用的方案为ollama(Docker)+Dify(Docker Compose),方便内网环境下迁移和备份,下 ...
- 使用C#创建一个MCP客户端
前言 网上使用Python创建一个MCP客户端的教程已经有很多了,而使用C#创建一个MCP客户端的教程还很少. 为什么要创建一个MCP客户端呢? 创建了一个MCP客户端之后,你就可以使用别人写好的一些 ...
- git push解决 error src refspec master does not match anyerror
前言 git push origin master git push 时报错: error: src refspec master does not match anyerror: failed to ...
- Ubuntu Nvidia driver驱动安装(新)
前言 英伟达更新了安装驱动的方式,更新一下文档 旧文:Ubuntu Nvidia driver驱动安装及卸载 下载官方驱动安装 1.安装驱动前一定要更新软件列表和安装必要软件.依赖(必须) sudo ...