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

如何在ASP.NET Core Web API请求生命周期内共享运行时构造的业务对象?

解决方案:ASP.NET Core 请求生命周期内共享运行时生成的业务对象

针对你遇到的「请求生命周期内共享基于运行时参数生成的业务对象」问题,以下是几种比手动传递更优的实现方案:

方案1:请求作用域工厂类 + 延迟初始化

通过一个请求作用域的工厂类统一管理业务对象的创建和获取,既保证类型安全,又符合依赖注入的设计思想。

实现步骤

  1. 定义工厂接口与实现类,内部缓存初始化后的业务对象
  2. 将工厂注册为请求作用域服务
  3. 控制器中完成对象初始化,其他服务通过工厂获取对象
// 工厂接口
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。

实现步骤

  1. 创建对象访问器,通过IHttpContextAccessor读取HttpContext中的对象
  2. 注册IHttpContextAccessor和访问器为请求作用域服务
  3. 控制器中生成对象并存入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:动作过滤器提前初始化

如果想把对象初始化逻辑从控制器剥离,使用动作过滤器在请求进入控制器前完成对象创建,进一步符合关注点分离原则。

实现步骤

  1. 创建动作过滤器,在OnActionExecuting阶段读取请求参数并初始化对象
  2. 注册过滤器,绑定到目标控制器或全局
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 04:04:52