河南赵志愿 發表於 2025-7-15 17:00:00

dotnet Minimal APIs实现动态注册端点

<h1 id="dotnet-minimal-apis实现动态注册端点">dotnet Minimal APIs实现动态注册端点</h1>
<h2 id="前言">前言</h2>
<p>之前使用.Net的Minimal Apis框架开发了SharpIcoWeb图片转ico项目,也是初次使用这个最小Api框架,使用下来的感受就是小项目用起来非常舒服,很轻量。</p>
<p>在之前的项目中,我都是手动去注册端点,比如我创建了一个端点类<code>IcoEndpoints</code></p>
<pre><code class="language-c#">public static class IcoEndpoints
{
    public static void MapIcoEndpoints(this WebApplication app)
    {
      var group = app.MapGroup("/api");
      group.MapGet(...)
    }
}
</code></pre>
<p>然后我会在<code>Program.cs</code>中注册这个端点类</p>
<pre><code class="language-c#">app.MapIcoEndpoints();
</code></pre>
<p>那么如果不想每个端点类都通过手动去注册,就可以使用动态注册的方法,动态注册的原理是通过反射和扩展方法来完成注册。</p>
<h2 id="动态注册">动态注册</h2>
<p>本文就是使用基于接口的自动注册,还可以根据约定端点类命名、特性、标记去实现注册。</p>
<p>文件层级结构如下:</p>
<pre><code class="language-markdown">SharpIcoWeb
├── Endpoints
│   ├── Internal
│   │   ├── EndpointExtensions.cs
│   │   ├── IEndpoint.cs
│   ├── IcoEndpoints.cs
│   ├── testEndpoints.cs
├── Program.cs
</code></pre>
<h3 id="接口类">接口类</h3>
<p>首先目录创建完成后,去创建<code>IEndpoint</code>接口类,让每个端点类就去实现这个接口。</p>
<p>注意:<code>static abstract</code>接口成员需要<code>C# 11+ (.NET 7+)</code> 支持</p>
<pre><code class="language-c#">public interface IEndpoint
{
    static abstract void MapEndpoints(IEndpointRouteBuilder app);
}
</code></pre>
<h3 id="端点类">端点类</h3>
<p>测试端点类</p>
<pre><code class="language-c#">public class TestEndpoints : IEndpoint
{
    public static void MapEndpoints(IEndpointRouteBuilder app)
    {
      app.MapGet("/test", async (context) =&gt;
      {
            await context.Response.WriteAsync("Hello, World!");
      });
    }
}
</code></pre>
<p>图片转Ico端点类</p>
<pre><code class="language-C#">public class IcoEndpoints: IEndpoint
{
    public static void MapEndpoints(IEndpointRouteBuilder app)
    {
      var group = app.MapGroup("/api");

      // 上传图片文件并返回文件名
      group.MapPost("/uploadDownload", UploadDownload)
            .DisableAntiforgery();

      // 获取图片信息
      group.MapGet("/getImageInfo/{filename}", GetImageInfo);

      // 下载文件
      group.MapGet("/downloads/{fileName}", DowloadFile);

      // 上传图片文件并返回文件名和不同尺寸的ICO文件的ZIP文件
      group.MapPost("/uploadDownload/sizes", UploadDownloadSizes)
            .DisableAntiforgery();
    }
}
</code></pre>
<h3 id="扩展方法">扩展方法</h3>
<pre><code class="language-c#">public static class EndpointExtensions
{
    public static void MapAllEndpoints(this IEndpointRouteBuilder app)
    {
      var endpointTypes = Assembly.GetExecutingAssembly()
            .GetTypes()
            .Where(t =&gt; typeof(IEndpoint).IsAssignableFrom(t) &amp;&amp; !t.IsInterface &amp;&amp; !t.IsAbstract);

      foreach (var type in endpointTypes)
      {
            type.GetMethod(nameof(IEndpoint.MapEndpoints))?
            .Invoke(null, new object[] { app });
      }
    }
}
</code></pre>
<h3 id="programcs">Program.cs</h3>
<pre><code class="language-C#">app.MapAllEndpoints();
</code></pre>
<p>完成上述配置就可以实现自动注册端点类了。</p>
<h3 id="测试访问">测试访问</h3>
<pre><code class="language-http">@SharpIcoWeb_HostAddress = http://localhost:5235

### 上传文件并转换为ICO(带尺寸参数)
POST {{SharpIcoWeb_HostAddress}}/api/uploadDownload/sizes
Content-Type: multipart/form-data; boundary=WebAppBoundary

--WebAppBoundary
Content-Disposition: form-data; name="file"; filename="1.png"
Content-Type: image/png

&lt; ./1.png
--WebAppBoundary
Content-Disposition: form-data; name="sizes"

16,32,48,64,128

### 测试端点类访问
GET {{SharpIcoWeb_HostAddress}}/test

</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/3091176/202507/3091176-20250715165950377-1035891856.png"></p>
<p>可以看到新建的test接口也是可以正常访问的。</p>
<h2 id="总结">总结</h2>
<p>实现端点类的自动注册需要使用反射和扩展方法来完成。</p>
<p><code>static abstract</code>接口成员需要<code>C# 11+ (.NET 7+)</code> 支持</p>
<p>可以思考一下如何将服务和端点一起注册</p>
<pre><code class="language-c#">builder.Services.AddScoped&lt;IFileService, FileService&gt;();
</code></pre><br><br>
来源:https://www.cnblogs.com/ZYPLJ/p/18985930
頁: [1]
查看完整版本: dotnet Minimal APIs实现动态注册端点