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

.NET Core API 5下设置可注入填充对象的最优实现方案咨询

.NET Core 5 API 实现请求级自定义对象注入的优化方案

原实现存在的核心问题

  • 你将ValuesObject注册为*Singleton(单例)*存在严重的线程安全隐患:单例是全服务进程共享的实例,高并发场景下多个请求会同时修改同一个对象的属性,导致不同请求拿到的数值互相串改,出现数据混乱。
  • 赋值逻辑耦合在中间件中,后续扩展需要修改中间件代码,不符合开闭原则。

优化实现方案

1. 调整服务生命周期

将ValuesObject的注册生命周期从Singleton改为Scoped(请求域),保证每个请求拿到的是独立的实例,不会互相干扰:

// Startup.cs 或 Program.cs 中服务注册代码
services.AddScoped<ValuesObject>();
// IGetDataBySlug 无状态的话可以保留Singleton,否则也注册为Scoped
services.AddSingleton<IGetDataBySlug, DataGetterImpl>();

2. 优化中间件逻辑

可以将填充逻辑抽离为独立方法,同时增加空值校验,避免空引用异常:

public class SetDataMiddleware
{
    private readonly RequestDelegate _next;

    public SetDataMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Query.TryGetValue("slug", out var slugValue) && !string.IsNullOrEmpty(slugValue))
        {
            FillValuesObject(context, slugValue);
        }

        await _next(context);
    }

    private void FillValuesObject(HttpContext context, string slugValue)
    {
        // 从当前请求的Scoped容器中获取实例
        var objectWithValues = context.RequestServices.GetRequiredService<ValuesObject>();
        var dataGetter = context.RequestServices.GetRequiredService<IGetDataBySlug>();

        var retrievedData = dataGetter.Get(slugValue);
        if (retrievedData?.Address == null) 
        {
            // 可根据业务需求添加降级逻辑,比如赋值默认值、返回400等
            return;
        }

        objectWithValues.Address = new Address
        {
            City = retrievedData.Address.City,
            Street = retrievedData.Address.Street,
            Zipcode = retrievedData.Address.Zipcode,
        };
    }
}

3. 可选更轻量方案(无需中间件)

如果你的ValuesObject仅在Controller/Service中使用,也可以用惰性加载的方式实现,省去中间件配置:

// 注册IHttpContextAccessor
services.AddHttpContextAccessor();
services.AddScoped<ValuesObject>(sp => 
{
    var contextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
    var dataGetter = sp.GetRequiredService<IGetDataBySlug>();
    var context = contextAccessor.HttpContext;
    
    var valuesObj = new ValuesObject();
    if (context == null || !context.Request.Query.TryGetValue("slug", out var slug))
    {
        return valuesObj;
    }

    var data = dataGetter.Get(slug);
    if (data?.Address != null)
    {
        valuesObj.Address = data.Address;
    }
    return valuesObj;
});

这种方式的好处是只有当请求真正用到ValuesObject的时候才会执行查询逻辑,没有用到的请求不会产生额外开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 00:36:04