.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
相关产品推荐
相关产品推荐

