C# 在MVC中,对于具有多个构造函数的控制器,我如何指示要调用哪个构造函数?

C# 在MVC中,对于具有多个构造函数的控制器,我如何指示要调用哪个构造函数?,c#,asp.net-mvc,dependency-injection,tdd,C#,Asp.net Mvc,Dependency Injection,Tdd,通常情况下,我希望控制器中有多个构造函数,因为其中一个构造函数最适合在单元测试期间手动注入依赖项,另一个最适合使用IOC容器注入依赖项 在MVC 3中使用标准服务定位器或DependencyResolver时,是否有任何方法向控制器工厂指示在激活控制器时使用哪个构造函数 我不希望使用特定于IOC框架的属性之一,因为我希望代码保持独立于IOC容器 更新: 似乎大多数答案都表明有多个构造函数是不好的做法。我并不完全同意这一点,但是,出现这种情况是因为我试图为映射/转换层找到一个好的解决方案,我在中询

通常情况下,我希望控制器中有多个构造函数,因为其中一个构造函数最适合在单元测试期间手动注入依赖项,另一个最适合使用IOC容器注入依赖项

在MVC 3中使用标准服务定位器或DependencyResolver时,是否有任何方法向控制器工厂指示在激活控制器时使用哪个构造函数

我不希望使用特定于IOC框架的属性之一,因为我希望代码保持独立于IOC容器

更新: 似乎大多数答案都表明有多个构造函数是不好的做法。我并不完全同意这一点,但是,出现这种情况是因为我试图为映射/转换层找到一个好的解决方案,我在中询问了这个问题,但没有得到一个好的答案

我的代码如下所示:

public class SomeController : Controller
{
    private ISomeService _SomeService;
    private IEntityConverter _EntityConverter;

    // this would be used during unit tests when mocking the entity converter 
    public SomeController(ISomeService someService, IEntityConverter entityConverter)
    {
        _SomeService = someService;
        _EntityConverter = entityConverter;
    }

    // this would be used when injecting via an IOC container, where it would be tedious
    // to always specify the implementations for the converters
    public SomeController(ISomeService someService)
        : this(someService, new EntityConverter())
    {
    }

    public ActionResult Index(SomeViewModel someViewModel)
    {
        if (!ModelState.IsValid)
            return View(someViewModel);
        else
        {
            ServiceInput serviceInput = _EntityConverter.ConvertToServiceInput(someViewModel);
            _SomeService.DoSomething(serviceInput);
            return View("Success");
        }
    }
}
在这个非常简单的示例中,我使用一个接口在视图模型和作为服务层输入的实体之间进行转换

我更喜欢使用接口,因为这种转换可以模拟,而不是使用静态方法。但是,我觉得在IOC容器中总是要指定这些转换实现的实现是什么是很乏味的,因为这些转换接口的实现就在接口旁边


这可能不是最好的解决方案。我愿意接受更好的选择。

也许我误解了你的问题,但我不确定你为什么要测试不同的构造函数。测试应该测试实际将要使用的内容

对于您的测试,您应该模拟您的依赖项,以便它们不需要IoC容器

使用:

控制器:

public SomeController(IService1 service1, IService2 service2)
{
    // Do some cool stuff
}
试验方法:

[Test]
public void Some_Action_In_SomeController_Should_Do_Something()
{
    var service1Mock = new Mock<IService1>();
    var service2Mock = new Mock<IService2>();
    var controller = new SomeController(service1Mock.Object, service2Mock.Object);

    controller.Action();

    // Assert stuff
}
[测试]
public void Some Action In Some controller应该做些什么()
{
var service1Mock=new Mock();
var service2Mock=new Mock();
var controller=newsomecontroller(service1Mock.Object、service2Mock.Object);
controller.Action();
//断言材料
}

也许我误解了你的问题,但我不确定你为什么要测试不同的构造函数。测试应该测试实际将要使用的内容

对于您的测试,您应该模拟您的依赖项,以便它们不需要IoC容器

使用:

控制器:

public SomeController(IService1 service1, IService2 service2)
{
    // Do some cool stuff
}
试验方法:

[Test]
public void Some_Action_In_SomeController_Should_Do_Something()
{
    var service1Mock = new Mock<IService1>();
    var service2Mock = new Mock<IService2>();
    var controller = new SomeController(service1Mock.Object, service2Mock.Object);

    controller.Action();

    // Assert stuff
}
[测试]
public void Some Action In Some controller应该做些什么()
{
var service1Mock=new Mock();
var service2Mock=new Mock();
var controller=newsomecontroller(service1Mock.Object、service2Mock.Object);
controller.Action();
//断言材料
}
。您的类应该有一个关于它需要什么依赖项的单一定义。该定义位于构造函数中,因此它应该只有一个公共构造函数

    private readonly HttpContextBase _httpContextBase;

    public HttpContextCache()
    {
        _httpContextBase = new HttpContextWrapper(HttpContext.Current);
    }

    public HttpContextCache(HttpContextBase httpContextBase)
    {
        _httpContextBase = httpContextBase;
    }
我必须说我不喜欢使用模拟框架。我发现,良好的应用程序设计和单元测试使我不必同时使用模拟框架(当然,里程数可能会有所不同)

帮助我的一个技巧是允许通过不验证构造函数参数将
null
引用注入构造函数。在被测类不使用依赖项的情况下,这对于单元测试非常方便,而在生产环境中,您仍然可以保证不注入null,因为IOC容器永远不会将null注入构造函数(或者至少我知道的容器都不会注入null)。

<。您的类应该有一个关于它需要什么依赖项的单一定义。该定义位于构造函数中,因此它应该只有一个公共构造函数

    private readonly HttpContextBase _httpContextBase;

    public HttpContextCache()
    {
        _httpContextBase = new HttpContextWrapper(HttpContext.Current);
    }

    public HttpContextCache(HttpContextBase httpContextBase)
    {
        _httpContextBase = httpContextBase;
    }
我必须说我不喜欢使用模拟框架。我发现,良好的应用程序设计和单元测试使我不必同时使用模拟框架(当然,里程数可能会有所不同)


帮助我的一个技巧是允许通过不验证构造函数参数将
null
引用注入构造函数。在被测类不使用依赖项的情况下,这对于单元测试非常方便,而在生产环境中,您仍然可以保证不注入null,因为IOC容器永远不会将null注入构造函数(或者至少我知道的任何容器).

似乎是一种代码味道,您需要一个显式的构造函数来进行测试。如果测试ctor工作,但生产ctor不工作怎么办?好像是虫子爬进来的门。对于测试来说,尽可能使用与真实客户机相同的路径是理想的

两者有什么不同


另外,如果您正在使用某种基于属性的DI(例如MEF),我也不会太担心解耦。拥有一个额外的属性(和相应的引用)不应该是那么大的打击。。。除非你预见到未来IOC技术的变化。

似乎是一种代码味道,你需要一个显式的构造函数来进行测试。如果测试ctor工作,但生产ctor不工作怎么办?好像是虫子爬进来的门。对于测试来说,尽可能使用与真实客户机相同的路径是理想的

两者有什么不同


另外,如果您正在使用某种基于属性的DI(例如MEF),我也不会太担心解耦。拥有一个额外的属性(和相应的引用)不应该是那么大的打击。。。除非您预见到未来IOC技术将发生变化。

这一切都与您的服务定位器有关,否则您需要在注册类型的位置对其进行配置

下面是使用Unity时使用默认无参数构造函数的示例

请注意,默认情况下,服务定位器将使用最特定的常量