找回密码
 立即注册
首页 业界区 业界 .Net Minimal APIs实现动态注册服务

.Net Minimal APIs实现动态注册服务

杼氖 2025-7-17 08:34:39
.Net Minimal APIs实现动态注册服务

前言

dotnet Minimal APIs实现动态注册端点
上一篇文章讲解了在.Net Minimal APIs如何动态注册端点,这篇文章来讲解一下如何动态注册服务
文件层级结构如下:
  1. SharpIcoWeb
  2. ├── Endpoints
  3. │   ├── Internal
  4. │   │   ├── EndpointExtensions.cs
  5. │   │   ├── IEndpoint.cs
  6. │   ├── IcoEndpoints.cs
  7. │   ├── testEndpoints.cs
  8. ├── Program.cs
复制代码
需要修改EndpointExtensions动态注册扩展类、IEndpoint端点注册接口和Program.cs配置类来实现端点+服务的自动注册,当然端点类也需要实现IEndpoint接口新增的方法。
回顾

在开始之前回顾一下如何动态注册端点类:
  1. public static class EndpointExtensions
  2. {
  3.     public static void MapAllEndpoints(this IEndpointRouteBuilder app)
  4.     {
  5.         var endpointTypes = Assembly.GetExecutingAssembly()
  6.             .GetTypes()
  7.             .Where(t => typeof(IEndpoint).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);
  8.         foreach (var type in endpointTypes)
  9.         {
  10.             type.GetMethod(nameof(IEndpoint.MapEndpoints))?
  11.             .Invoke(null, new object[] { app });
  12.         }
  13.     }
  14. }
复制代码
代码详解:

主要注册方法在扩展类中,主要分为2步。
查找

第一步: 查找所有实现了IEndpoint的类

  • Assembly.GetExecutingAssembly() - 获取当前正在执行的程序集
  • GetTypes() - 获取程序集中所有的类型
  • Where(...) - 筛选条件:

    • typeof(IEndpoint).IsAssignableFrom(t) - 类型必须实现 IEndpoint 接口
    • !t.IsInterface - 排除接口本身
    • !t.IsAbstract - 排除抽象类(不能被实例化的类)

调用

第二步:对每个端点类,调用它的静态MapEndpoints方法

  • foreach - 遍历前面找到的所有端点类型
  • type.GetMethod(nameof(IEndpoint.MapEndpoints)) - 获取名为"MapEndpoints"的方法

    • nameof(IEndpoint.MapEndpoints) - 安全地获取方法名

  • ?.Invoke(null, new object[] { app }) - 如果方法存在,则调用它

    • null - 表示是静态方法(不需要实例)
    • new object[] { app } - 传递参数(IEndpointRouteBuilder)

开始实现

IEndpoint接口

首先在IEndpoint接口中添加用于服务注册的接口成员。
注意:之前的MapAllEndpoints重命名为UseEndpoints了,这个命名更加清晰。
  1. public interface IEndpoint
  2. {
  3.     static abstract void UseEndpoints(IEndpointRouteBuilder app);
  4.    
  5.     // 新增 IConfiguration configuration 参数可选
  6.     static abstract void AddServices(IServiceCollection services, IConfiguration configuration);
  7. }
复制代码
端点类

在每个端点类中实现AddServices方法。
  1. public class TestEndpoints : IEndpoint
  2. {
  3.     public static void UseEndpoints(IEndpointRouteBuilder app)
  4.     {
  5.         // .....
  6.     }
  7.     public static void AddServices(IServiceCollection services, IConfiguration configuration)
  8.     {
  9.     }
  10. }
  11. public class IcoEndpoints: IEndpoint
  12. {
  13.     public static void UseEndpoints(IEndpointRouteBuilder app)
  14.     {
  15.             // .....
  16.     }
  17.     public static void AddServices(IServiceCollection services, IConfiguration configuration)
  18.     {
  19.         services.AddScoped<IFileService, FileService>();
  20.     }
  21. }
复制代码
扩展类

扩展方法是实现动态注册的关键类。
  1. public static class EndpointExtensions
  2. {
  3.     public static void UseEndpoints<TMarker>(this IEndpointRouteBuilder app)
  4.     {
  5.         UseEndpoints(app, typeof(TMarker));
  6.     }
  7.    
  8.     public static void UseEndpoints(this IEndpointRouteBuilder app, Type typeMarker)
  9.     {
  10.         var endpointTypes = GetEndpointTypes(typeMarker);
  11.         foreach (var type in endpointTypes)
  12.         {
  13.             type.GetMethod(nameof(IEndpoint.UseEndpoints))?
  14.             .Invoke(null, new object[] { app });
  15.         }
  16.     }
  17.     public static void AddEndpoints<TMarker>(this IServiceCollection services, IConfiguration configuration)
  18.     {
  19.         AddEndpoints(services, typeof(TMarker), configuration);
  20.     }
  21.     public static void AddEndpoints(this IServiceCollection services, Type typeMarker, IConfiguration configuration)
  22.     {
  23.         var endpointTypes = GetEndpointTypes(typeMarker);
  24.         foreach (var endpointType in endpointTypes)
  25.         {
  26.             endpointType.GetMethod(nameof(IEndpoint.AddServices))!
  27.                 .Invoke(null, new object[] { services, configuration });
  28.         }
  29.     }
  30.     private static IEnumerable<TypeInfo> GetEndpointTypes(Type typeMarker)
  31.     {
  32.         var endpointTypes = typeMarker.Assembly.DefinedTypes
  33.             .Where(x => !x.IsAbstract && !x.IsInterface &&
  34.                         typeof(IEndpoint).IsAssignableFrom(x));
  35.         return endpointTypes;
  36.     }
  37. }
复制代码
这次在注册的时候使用了泛型方法指定从哪个程序集找端点,如AddEndpoints。
其他的注册端点的代码和之前类似,可以看代码详解。
AddEndpoints用于动态注册服务,与注册端点不同的是注册方法为AddServices,且传递的参数为services, configuration。
  1. endpointType.GetMethod(nameof(IEndpoint.AddServices))!
  2.                 .Invoke(null, new object[] { services, configuration });
复制代码
Program

在Program.cs中添加2行代码就能完成端点和服务的注册。
  1. builder.Services.AddEndpoints<Program>(builder.Configuration);
  2. app.UseEndpoints<Program>();
复制代码
总结

动态注册服务的核心也是通过反射找到注册服务的静态方法并调用它。
使用TMarker泛型类型参数可以定位程序集,控制注册服务的扫描范围。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册