Ninject:选择错误的构造函数

时间:2012-10-01 23:13:21

标签: asp.net-mvc-3 ninject

我有一个使用Ninject v2.2.1.4的ASP.NET MVC 3应用程序。一切都很好,然后突然我们开始看到Ninject尝试使用带有无参数构造函数的参数的构造函数创建我们的DbContext。这是绑定:

kernel.Bind<MyContext>().ToSelf().InRequestScope();

kernel.Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<MyContext>());
kernel.Bind<DbContext>().ToMethod(ctx => ctx.Kernel.Get<MyContext>());

MyContext是一个DbContext对象,它也实现了IUnitOfWork接口。我已经这样设置了,因此将相同的上下文注入到单个请求中使用的多个存储库中。 MyContext构造函数如下所示:

public MyContext() { }
public MyContext(string connectionString) { }
public MyContext (long accountID) { }
public MyContext (Connection connection) { }

不同的应用程序有不同的构造函数,因为它们都使用相同的MyContext类。查看绑定时,您会想到当请求MyContext类时将调用无参数构造函数,但无论出于何种原因,它都不会。即使没有指定accountID,也会调用具有long accountID参数的那个。这显然是throwns和exception语句,“没有匹配的绑定可用,并且类型不可自绑定”它实际上在尝试生成IUnitOfWork时抛出异常。

如果我注释掉最后三个构造函数,一切正常,并且使用无参数构造函数。如果我注释掉任何两个参数化构造函数,它会尝试使用另一个而不是无参数构造函数。

Ninject提供的建议是:

Suggestions:
  1) Ensure that you have defined a binding for long.
  2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
  3) Ensure you have not accidentally created more than one kernel.
  4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
  5) If you are using automatic module loading, ensure the search path and filters are correct.

我们没有任何关于1的内容,因为我们不想这样做。我不确定2和5是什么意思。我不相信我们已经完成了3而且我们没有做到4。

关于为什么在这种情况下不使用无参数构造函数的任何想法。

2 个答案:

答案 0 :(得分:5)

@ Xander的回答是正确的,但Ninject在V3中有一些非常具体的解决方案。 Ninject通过一个特定的算法对构造函数进行评分,该算法可以找到the most parameters it knows how to resolve as documented in this wiki article [声称为V2.4,实际上是徽章3.0]的算法。 See the code。我认为这也是在维基上。如果不是,有人应该把它放在那里。

RE你所看到的行为的变化,隐含自我约束的可能性正在改变球门柱(在解决期间添加了新的注册),或者你添加了一个使其他构造者之一更具吸引力的Binding

[Inject]属性胜过您所追求的所有其他条件(尽管您实际上并不希望代码中包含特定于容器的属性)。

建议的WithConstructorArgument技术实际上是通过使用ToConstructor来实现的 - 做WCA不会影响选择(我认为你不会对冗余规范抱怨。

真正的底线是,你应该永远不会像@Mark Seemann对this related question的评论中提到的那样混乱。


可悲的是,以上都是谎言。如果您离开v2.2,这个答案将变得正确。如果您不能或不愿意,您需要查看等效的源和测试以找出之前的规则(从内存(以及我的研究中搜索结果中出现的一些谷歌代码),它是基于构造函数计数,但不确定如何消除歧义等分。

非常确定在2.2中,添加[Inject]是最快的出路。

答案 1 :(得分:4)

默认情况下,Ninject和其他类似的IoC框架选择具有最多参数的构造函数。通过WithConstructorArgument扩展方法指定在初始化期间使用的构造函数。

kernel.Bind<DbContext>()
      .WithConstructorArgument("connectionString",
             ConfigurationManager.ConnectionStrings["connection"]
                  .ConnectionString)
      .ToMethod(ctx => ctx.Kernel.Get<MyContext>());

要强制Ninject使用默认构造函数,请在构造函数上放置[Inject]属性:

[Inject]
public MyContext() { }