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

ASP.NET Core控制器多构造函数冲突问题的解决方法

问题解决:控制器多构造函数导致Swagger报错

问题根源

ASP.NET Core依赖注入容器解析控制器时,要求每个控制器只能有一个可被DI解析的公开构造函数。你新增的测试构造函数和原有构造函数都能被DI容器解析(IMediator已在DI中注册),容器无法确定使用哪个,因此抛出System.InvalidOperationException错误。[FromServices]特性用于标记参数来自DI,无法解决多构造函数的冲突。

解决方案

方案1:合并构造函数(推荐,符合最佳实践)

控制器只保留一个包含所有依赖的公开构造函数,单元测试时对未用到的依赖创建空Mock即可。

修改后的控制器代码

public class ProductController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly IConfiguration _configuration;
    private readonly UserManager<User> _userManager;
    private readonly SignInManager<User> _signInManager;
    private readonly ProductDbContext _productDbContext;
    private readonly IUserService _userService;

    // 仅保留一个公开构造函数,注入所有依赖
    public ProductController(IConfiguration configuration, UserManager<User> userManager, ProductDbContext productDbContext
        , SignInManager<User> signInManager, IUserService userService, IMediator mediator)
    {
        _configuration = configuration;
        _userManager = userManager;
        _productDbContext = productDbContext;
        _signInManager = signInManager;
        _userService = userService;
        _mediator = mediator;
    }

    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> GetAllProducts()
    {
        var products = await _mediator.Send(new GetAllProductsQuery());
        return Ok(products);
    }
}

修改后的单元测试代码

private readonly Mock<IMediator> _mediatorMock;
private readonly ProductController _controller;

public ProductControllerTest()
{
    _mediatorMock = new Mock<IMediator>();
    // 用Mock.Of创建未用到的依赖的空Mock,无需额外配置
    var configMock = Mock.Of<IConfiguration>();
    var userManagerMock = Mock.Of<UserManager<User>>();
    var dbContextMock = Mock.Of<ProductDbContext>();
    var signInManagerMock = Mock.Of<SignInManager<User>>();
    var userServiceMock = Mock.Of<IUserService>();

    _controller = new ProductController(configMock, userManagerMock, dbContextMock, signInManagerMock, userServiceMock, _mediatorMock.Object);
}

[Fact]
public async Task ProductController_GetAllProducts_ShouldReturnStatusCode200()
{
    //arrange
    var expected = new List<ProductModelDTO>();
    _mediatorMock.Setup(m=> m.Send(It.IsAny<GetAllProductsQuery>(), default(CancellationToken))).ReturnsAsync(expected);
    //act
    var result = await _controller.GetAllProducts();
    //assert
    var okResult = result as OkObjectResult;
    okResult?.StatusCode.Should().Be(200);
    okResult?.Value.Should().BeOfType<List<ProductModelDTO>>();
}

方案2:标记主构造函数(不推荐,维护性差)

若不想合并构造函数,可给生产环境用的构造函数添加[ActivatorUtilitiesConstructor]特性,指定DI容器优先使用该构造函数;同时将测试用构造函数设为internal,通过InternalsVisibleTo让测试项目可见。

// 标记生产用构造函数为主构造函数
[ActivatorUtilitiesConstructor]
public ProductController(IConfiguration configuration, UserManager<User> userManager, ProductDbContext productDbContext
    , SignInManager<User> signInManager, IUserService userService)
{
    _configuration = configuration;
    _userManager = userManager;
    _productDbContext = productDbContext;
    _signInManager = signInManager;
    _userService = userService;
}

// 测试用构造函数设为internal
internal ProductController(IMediator mediator)
{
    _mediator = mediator;
}

在API项目的AssemblyInfo.cs中添加:

[assembly: InternalsVisibleTo("YourTestProjectName")]

此方法虽能解决问题,但会模糊控制器的依赖关系,长期维护成本高,不推荐使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 13:33:11