如何在ASP.NET Core Web API请求生命周期内共享运行时构造的业务对象?
解决方案:ASP.NET Core 请求生命周期内共享运行时生成的业务对象
针对你遇到的「请求生命周期内共享基于运行时参数生成的业务对象」问题,以下是几种比手动传递更优的实现方案:
方案1:请求作用域工厂类 + 延迟初始化
通过一个请求作用域的工厂类统一管理业务对象的创建和获取,既保证类型安全,又符合依赖注入的设计思想。
实现步骤
- 定义工厂接口与实现类,内部缓存初始化后的业务对象
- 将工厂注册为请求作用域服务
- 控制器中完成对象初始化,其他服务通过工厂获取对象
// 工厂接口 public interface IBusinessObjectFactory { void Initialize(string userName); MyBusinessObject GetInstance(); } // 工厂实现(请求作用域内单例) public class BusinessObjectFactory : IBusinessObjectFactory { private MyBusinessObject _instance; public void Initialize(string userName) { // 这里写基于UserName生成业务对象的逻辑 _instance = new MyBusinessObject { UserName = userName, // 其他属性生成逻辑 }; } public MyBusinessObject GetInstance() { return _instance ?? throw new InvalidOperationException("业务对象未初始化"); } } // 注册服务 services.AddScoped<IBusinessObjectFactory, BusinessObjectFactory>(); // 控制器中使用 [ApiController] [Route("api/[controller]")] public class MyController : ControllerBase { private readonly IBusinessObjectFactory _factory; private readonly IServiceA _serviceA; private readonly IServiceB _serviceB; public MyController(IBusinessObjectFactory factory, IServiceA serviceA, IServiceB serviceB) { _factory = factory; _serviceA = serviceA; _serviceB = serviceB; } [HttpPost] public IActionResult Post([FromBody] RequestDto dto) { _factory.Initialize(dto.UserName); // 服务内部通过工厂获取对象 _serviceA.Process(); _serviceB.Handle(); return Ok(); } } // 服务A中使用 public class ServiceA : IServiceA { private readonly IBusinessObjectFactory _factory; public ServiceA(IBusinessObjectFactory factory) { _factory = factory; } public void Process() { var businessObj = _factory.GetInstance(); // 业务逻辑处理 } }
方案2:HttpContext.Items 临时存储
利用ASP.NET Core内置的HttpContext.Items(请求作用域内的键值对存储)存放对象,通过一个包装类封装获取逻辑,避免直接在服务中操作HttpContext。
实现步骤
- 创建对象访问器,通过
IHttpContextAccessor读取HttpContext中的对象 - 注册
IHttpContextAccessor和访问器为请求作用域服务 - 控制器中生成对象并存入
HttpContext.Items,服务通过访问器获取
// 对象访问器接口 public interface IBusinessObjectAccessor { MyBusinessObject Get(); } // 访问器实现 public class BusinessObjectAccessor : IBusinessObjectAccessor { private readonly IHttpContextAccessor _httpContextAccessor; private const string Key = "MyBusinessObject"; public BusinessObjectAccessor(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public MyBusinessObject Get() { if (_httpContextAccessor.HttpContext?.Items.TryGetValue(Key, out var obj) == true && obj is MyBusinessObject businessObj) { return businessObj; } throw new InvalidOperationException("业务对象未初始化"); } } // 注册服务 services.AddHttpContextAccessor(); services.AddScoped<IBusinessObjectAccessor, BusinessObjectAccessor>(); // 控制器中使用 [HttpPost] public IActionResult Post([FromBody] RequestDto dto) { var businessObj = new MyBusinessObject { UserName = dto.UserName, // 生成逻辑 }; HttpContext.Items["MyBusinessObject"] = businessObj; _serviceA.Process(); _serviceB.Handle(); return Ok(); } // 服务B中使用 public class ServiceB : IServiceB { private readonly IBusinessObjectAccessor _accessor; public ServiceB(IBusinessObjectAccessor accessor) { _accessor = accessor; } public void Handle() { var businessObj = _accessor.Get(); // 业务逻辑处理 } }
方案3:动作过滤器提前初始化
如果想把对象初始化逻辑从控制器剥离,使用动作过滤器在请求进入控制器前完成对象创建,进一步符合关注点分离原则。
实现步骤
- 创建动作过滤器,在
OnActionExecuting阶段读取请求参数并初始化对象 - 注册过滤器,绑定到目标控制器或全局
public class BusinessObjectInitFilter : IActionFilter { private readonly IBusinessObjectFactory _factory; public BusinessObjectInitFilter(IBusinessObjectFactory factory) { _factory = factory; } public void OnActionExecuting(ActionExecutingContext context) { // 从请求参数中获取UserName if (context.ActionArguments.TryGetValue("dto", out var dtoObj) && dtoObj is RequestDto dto) { _factory.Initialize(dto.UserName); } } public void OnActionExecuted(ActionExecutedContext context) { // 可选:清理资源 } } // 注册过滤器 services.AddScoped<BusinessObjectInitFilter>(); // 控制器上标记使用过滤器 [ServiceFilter(typeof(BusinessObjectInitFilter))] public class MyController : ControllerBase { private readonly IServiceA _serviceA; private readonly IServiceB _serviceB; public MyController(IServiceA serviceA, IServiceB serviceB) { _serviceA = serviceA; _serviceB = serviceB; } [HttpPost] public IActionResult Post([FromBody] RequestDto dto) { // 无需手动初始化,过滤器已完成 _serviceA.Process(); _serviceB.Handle(); return Ok(); } }
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 请求作用域工厂类 | 类型安全、便于单元测试、逻辑清晰 | 需要额外定义工厂类 |
| HttpContext.Items | 实现简单、无需额外类 | 存在类型转换、依赖HttpContext细节 |
| 动作过滤器 | 剥离初始化逻辑、符合关注点分离 | 过滤器逻辑与业务耦合度较高 |
内容的提问来源于stack exchange,提问作者Yatish
相关产品推荐
相关产品推荐

