最近我转到Ninject 2.0版本并开始收到以下错误:
Error occured: Error activating SomeController More than one matching bindings are available. Activation path: 1) Request for SomeController Suggestions: 1) Ensure that you have defined a binding for SomeController only once.
但是,我找不到某种复制路径。有时它会发生,有时它不会发生。
我正在使用NinjectHttpApplication
进行自动控制器注入。控制器在单独的程序集中定义:
public class App : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
INinjectModule[] modules = new INinjectModule[] {
new MiscModule(),
new ProvidersModule(),
new RepositoryModule(),
new ServiceModule()
};
return new StandardKernel(modules);
}
protected override void OnApplicationStarted()
{
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn("Sample.Mvc");
base.OnApplicationStarted();
}
/* ............. */
}
也许有人熟悉这个错误。
有什么建议吗?
答案 0 :(得分:23)
我最近最终想出了这个问题。显然,NinjectHttpApplication.RegisterAllControllersIn()函数不会执行所需的所有正确绑定。它将您的具体控制器实现绑定到IController请求。例如,如果您有一个名为SampleMvcController的控制器类,它继承自System.Web.Mvc.Controller。它将在应用程序启动期间执行以下命名绑定:
kernel.Bind<IController>().To(SampleMvcController).InTransientScope().Named("SampleMvc");
但是在调试NinjectControllerFactory时,我发现正在为Ninject内核发出请求,要求使用“SampleMvc”的命名绑定返回“SampleMvcController”类的对象,而不是IController的具体实现。
因此,当涉及SampleMvcController的第一个Web请求生成时,它会创建SampleMvcController与其自身的绑定。但这不是线程安全的。因此,如果您同时发出多个Web请求,则绑定可能会多次发生,现在您因为为SampleMvcController进行多次绑定而留下此错误。
您可以在重新启动Web应用程序后立即通过快速刷新MVC URL来验证这一点。
修复:
解决此问题的最简单方法是为控制器绑定创建新的NinjectModule,并在应用程序启动期间加载此模块。在此模块中,您将自动绑定每个已定义的控制器,如下所示:
class ControllerModule : StandardModule {
public override Load() {
Bind<SampleMvcController>().ToSelf();
Bind<AnotherMvcController>().ToSelf();
}
}
但如果您不介意更改Ninject源代码,可以修改RegisterAllControllersIn()函数以自动绑定它遇到的每个控制器。
答案 1 :(得分:16)
我几个月来一直在处理这个问题。我尝试了很多选择,但无法找到解决方案。我知道这是一个线程问题,因为只有当我的网站负载很重时才会发生。就在最近,在ninject源代码中报告并修复了一个错误,解决了这个问题。
以下是对issue的引用。它在Ninject源的2.1.0.70版中得到修复。通过删除行
,关键更改位于KernelBase.cscontext.Plan = planner.GetPlan(service);
并将其替换为
lock (planner)
{
context.Plan = planner.GetPlan(service);
}
要在MVC中使用此新版本,您需要获取Ninject的最新版本,然后获取ninject.web.mvc的最新版本。使用新的Ninject构建构建ninject.web.mvc。
我一直在使用这个新版本大约一个星期,负载很重,没有问题。这是它没有问题的最长时间,所以我认为这是一个解决方案。
答案 2 :(得分:1)
您确定每次调用Kernel
时,是否真的从头开始创建一个全新的OnApplicationStarted
?如果你不是,你实际上是在创建它一次,但可能会运行两次注册位。请记住,您不能保证在给定的AppDomain中只实例化一个App
类。
答案 3 :(得分:1)
我的回答更加明显。
在我的代码重构期间,我已经多次声明了我的一个控制器的绑定。
答案 4 :(得分:0)
我将此添加到我的global.ascx.cs文件中:
public void RegisterAllControllersInFix(Assembly assembly)
{
RegisterAllControllersInFix(assembly, GetControllerName);
}
public void RegisterAllControllersInFix(Assembly assembly, Func<Type, string> namingConvention)
{
foreach (Type type in assembly.GetExportedTypes().Where(IsController))
Kernel.Bind(type).ToSelf();
}
private static bool IsController(Type type)
{
return typeof(IController).IsAssignableFrom(type) && type.IsPublic && !type.IsAbstract && !type.IsInterface;
}
private static string GetControllerName(Type type)
{
string name = type.Name.ToLowerInvariant();
if (name.EndsWith("controller"))
name = name.Substring(0, name.IndexOf("controller"));
return name;
}
然后从我的OnApplicationStarted()方法调用它,如下所示:
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
RegisterAllControllersInFix(Assembly.GetExecutingAssembly());
很难知道这是否能解决这个问题,因为它是间歇性的。