-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

1

Autofac は、解決方法がわかっている依存関係が最も多いコンストラクターを選択します。登録されているように見えMyComponentますが、正しく登録されていません。何を指定someNumberすべきかを指定していません。言い換えれば、試してみResolve<MyComponent>()ただけでも同じ問題が発生する可能性がありMyControllerます。これは根本的な問題ではありません。

これを処理するにはいくつかの方法があります。最も簡単なのは、デフォルトのコンストラクターを追加することですMyComponent

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

2番目に簡単なのは、MyComponent登録を調整することです

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

デフォルトのコンストラクターを明示的に使用するために、次のように登録を記述することもできます。

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

MyComponentAutofac にまったく登録されないようにコードを変更することもできます。その場合、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 に答える