-1

我有一个带有默认构造函数和 DI 构造函数的控制器:

#if PROTOTYPING
public class MyPrototypeController : Controller
{
    MyRandomDataGeneratorComponent generatorSeededTheWayINeed;
    public MyPrototypeController()
        : this(new MyRandomDataGeneratorComponent(DateTime.Now.Millisecond)
        /* whatever seed, I don't care */) {
    }
    public MyPrototypeController(MyRandomDataGeneratorComponent generatorSeededTheWayINeed) {
        /* DI for testing purposes, I need to be able to reproduce the same random situation */
        this.generatorSeededTheWayINeed = generatorSeededTheWayINeed;
    }
}
public class MyRandomDataGeneratorComponent
{
    public MyRandomDataGeneratorComponent(Int32 randomSeed)
    {
        /* use the seed to initialized the random generator */
    }
}
#endif

我希望通过调用默认构造函数来创建控制器。然而 Autofac 认为它非常聪明,以至于它一路走来并使用参数化构造函数,但它无法创建 MyRandomDataGeneratorComponent 因为它无法解析数字。

天知道这有多烦人。

我如何告诉这个框架使用默认构造函数,或者我可以完全为这个控制器禁用它?

4

2 回答 2

2

他们在上面回答了 nemesv 给了你答案:

ContainerBuilder.Register(c => new MyController()).AsSelf(); 是 Autofac 中的“切换到手动模式”。使用它,它会在不改变你的类的情况下工作。

.AsSelf() 是您正在寻找的。

于 2013-07-16T19:43:51.470 回答
1

Autofac 选择具有最多它知道如何解决的依赖关系的构造函数。似乎MyComponent已注册,但注册不正确:您没有指定someNumber应该是什么。换句话说,如果你只是尝试过Resolve<MyComponent>(),你也会遇到同样的问题——MyController这不是根本问题。

有几种方法可以处理这个问题。最简单的方法是添加一个默认构造函数MyComponent

public MyComponent() : this(DateTime.Now.Millisecond) { }

第二个最简单的就是调整MyComponent注册

containerBuilder.Register(c => new MyComponent(DateTime.Now.Milliseconds))
    .AsSelf();

您也可以像这样编写注册,以显式使用默认构造函数:

containerBuilder.Register(c => new MyController())
    .AsSelf();

您也可以更改您的代码,以便MyComponent根本不向 Autofac 注册,然后 Autofac 将不会选择MyController(MyComponent component)构造函数,但这似乎不是最好的解决方案。

编辑

这些测试表明MyRandomDataGeneratorComponent(aka MyComponent) 实际上已注册。如果您需要帮助了解它是如何注册的,请发布您的注册码。

public class MyController
{
    MyRandomDataGeneratorComponent generatorSeededTheWayINeed;
    public MyController()
        : this(new MyRandomDataGeneratorComponent(DateTime.Now.Millisecond)
            /* whatever seed, I don't care */)
    {
    }
    public MyController(MyRandomDataGeneratorComponent generatorSeededTheWayINeed)
    {
        /* DI for testing purposes, I need to be able to reproduce the same random situation */
        this.generatorSeededTheWayINeed = generatorSeededTheWayINeed;
    }
}
public class MyRandomDataGeneratorComponent
{
    public MyRandomDataGeneratorComponent(Int32 randomSeed)
    {
        /* use the seed to initialized the random generator */
    }
}

[TestMethod]
public void example1()
{
    var cb = new ContainerBuilder();
    cb.RegisterType<MyController>().AsSelf();
    var container = cb.Build();

    Assert.IsFalse(container.IsRegistered<MyRandomDataGeneratorComponent>());
    // since MyRandomDataGeneratorComponent is not registered,
    // the default constructor is used
    var instance = container.Resolve<MyController>();
}

[TestMethod]
[ExpectedException(typeof(Autofac.Core.DependencyResolutionException))]
public void example2()
{
    var cb = new ContainerBuilder();
    cb.RegisterType<MyController>().AsSelf();
    cb.RegisterType<MyRandomDataGeneratorComponent>().AsSelf();
    var container = cb.Build();

    Assert.IsTrue(container.IsRegistered<MyRandomDataGeneratorComponent>());
    // since MyRandomDataGeneratorComponent is registered, Autofac
    // uses that constructor, but cannot resolve parameter "randomSeed"
    try
    {
        var instance = container.Resolve<MyController>();
    }
    catch (Autofac.Core.DependencyResolutionException ex)
    {
        Assert.IsTrue(ex.Message.Contains(
            "Cannot resolve parameter 'Int32 randomSeed'"));
        throw;
    }
}
于 2013-07-15T21:20:19.083 回答