You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6 WebApi如何缓存程序集版本避免中间件重复反射调用

实现方案

核心逻辑:程序集版本在应用启动后不会发生变化,只需在启动阶段执行1次反射获取版本值,后续所有请求直接复用内存中缓存的字符串即可,完全避免重复反射开销。

方案1:改造现有中间件(改动最小,零额外依赖)

ASP.NET Core 自定义中间件默认是单例生命周期,构造函数仅在应用启动时执行1次,你只需要把反射获取版本的逻辑移到构造函数中存为私有只读字段,不需要额外写静态类就能实现一次获取全局复用。
改造后的中间件代码:

public class CustomHeaderMiddleware
{
    private readonly RequestDelegate _next;
    // 版本字符串仅初始化一次,所有请求复用
    private readonly string _appVersion;

    public CustomHeaderMiddleware(RequestDelegate next)
    {
        _next = next;
        // 仅在中间件实例化(应用启动)时执行1次反射
        _appVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";
    }

    public async Task Invoke(HttpContext context)
    {
        // 直接读取预存的字符串,无反射开销
        context.Response.Headers.TryAdd("Version", _appVersion);
        await _next(context);
    }
}

小提示:把原来的Headers.Add换成Headers.TryAdd,避免后续其他逻辑重复添加同名响应头时抛出异常,容错性更好。

方案2:静态类存储(适合多场景复用版本号)

如果你除了给响应头加版本,还需要在接口返回、日志打印、异常提示等位置用到应用版本,可以定义静态类在启动时初始化一次版本信息,全局任意位置直接访问。
首先定义静态存储类:

public static class AppRuntimeInfo
{
    public static string Version { get; private set; } = "unknown";

    // 启动阶段调用一次即可完成初始化
    public static void Init()
    {
        Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";
    }
}

然后在Program.cs中启动时初始化,中间件直接读取静态值即可:

var builder = WebApplication.CreateBuilder(args);
// 注册控制器、其他服务...
builder.Services.AddControllers();

var app = builder.Build();

// 应用启动时执行一次版本初始化
AppRuntimeInfo.Init();

// 中间件直接复用静态值,无重复反射
app.Use(async (context, next) =>
{
    context.Response.Headers.TryAdd("Version", AppRuntimeInfo.Version);
    await next();
});

// 其他中间件配置:授权、路由映射等
app.UseAuthorization();
app.MapControllers();

app.Run();

方案3:Program.cs 内联实现(最轻量,无需额外类文件)

如果项目比较简单,不想额外新增中间件类或者静态类,可以直接在Program.cs启动阶段获取一次版本号,用内联中间件实现响应头注入,所有逻辑集中在启动文件中。
核心代码如下:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();

// 仅在这里执行1次反射获取版本
var apiVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";

// 内联中间件直接复用局部变量,无额外开销
app.Use(async (context, next) =>
{
    context.Response.Headers.TryAdd("Version", apiVersion);
    await next();
});

app.UseAuthorization();
app.MapControllers();
app.Run();

方案选择参考

  • 方案1改动成本最低,只需要调整现有中间件的几行代码,不需要修改启动注册逻辑
  • 方案2灵活性最高,版本信息可以在整个应用的任意位置复用,适合中大型项目
  • 方案3代码最精简,不需要新增任何额外类文件,适合小型服务或快速验证场景

以上三个方案的反射操作都仅在应用启动阶段执行1次,后续请求处理只是读取内存中的字符串,完全消除了原实现每次请求反射的性能损耗。

内容的提问来源于stack exchange,提问作者Anshul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 12:18:32