我正在使用Ninject 2和Ninject.Web.MVC并使用NinjectHttpApplication
在登录过程中收到以下错误: “单个控制器实例'MySite.Controllers.AccountController'不能用于处理多个请求。如果正在使用自定义控制器工厂,请确保它为每个请求创建一个新的控制器实例。”
我的global.asax有这个:
protected override void OnApplicationStarted()
{
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
protected override IKernel CreateKernel()
{
return new StandardKernel(new MySite.IoCModules.FakeRepositoriesModule(), new MySite.IoCModules.AccountControllerModule());
}
AccountControllerModule如下所示:
public class AccountControllerModule:Module
{
public override void Load()
{
Bind<IFormsAuthentication>().To<FormsAuthenticationService>();
Bind<IMembershipService>().To<AccountMembershipService>();
Bind<MembershipProvider>().ToConstant(Membership.Provider);
}
}
我的猜测是它在RegisterAllControllersIn中设置了生命周期......但我只是不确定......有什么想法可以从这里开始吗?
更新:刚刚看到它发生在HomeController上......它必须尝试用它来制作一个单例或者正确的东西吗?
答案 0 :(得分:3)
Ninject.Web.Mvc的最新版本使用瞬态范围在RegisterAllControllersIn
中注册控制器:
public void RegisterAllControllersIn(Assembly assembly,
Func<Type, string> namingConvention)
{
foreach (Type type in assembly.GetExportedTypes().Where(IsController))
_kernel.Bind<IController>()
.To(type)
.InTransientScope()
.Named(namingConvention(type));
}
我也查看了NinjectControllerFactory
课程。它的CreateController函数非常基本。它在内核上为控制器执行TryGet并返回它返回的内容 - 如果它找不到控制器,它会委托给基类:
public override IController CreateController(RequestContext requestContext,
string controllerName)
{
var controller = Kernel.TryGet<IController>(controllerName.ToLowerInvariant());
if (controller == null)
return base.CreateController(requestContext, controllerName);
var standardController = controller as Controller;
if (standardController != null)
standardController.ActionInvoker = new NinjectActionInvoker(Kernel);
return controller;
}
因此,基于绑定设置并基于工厂,它似乎不是在Singleton范围内创建对象。您可以做的一件事是在创建内核后编写一些调试代码并自己检查绑定以确认范围是什么。我做了一个小实验,并将代码添加到下面的HttpApplication类中。完全披露,这是使用ASP.Net MVC 1.0,所以你的里程可能会有所不同。如果我有机会,我将获得最新的MVC 2预览并尝试相同的实验。
protected void DumpBindings() {
var bindings = Kernel.GetBindings(typeof(IController));
var dummyRequest = new RequestContext(
new HttpContextWrapper(HttpContext.Current),
new RouteData());
foreach (var binding in bindings) {
var scope = "Custom";
if (binding.ScopeCallback == StandardScopeCallbacks.Request)
scope = "Request";
else if (binding.ScopeCallback == StandardScopeCallbacks.Singleton)
scope = "Singleton";
else if (binding.ScopeCallback == StandardScopeCallbacks.Thread)
scope = "Thread";
else if (binding.ScopeCallback == StandardScopeCallbacks.Transient)
scope = "Transient";
HttpContext.Current.Trace.Write(
string.Format(
"Controller: {0} Named: {1} Scope: {2}",
binding.Service.Name,
binding.Metadata.Name,
scope));
var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
var controller1 = controllerFactory.CreateController(
dummyRequest, binding.Metadata.Name);
var controller2 = controllerFactory.CreateController(
dummyRequest, binding.Metadata.Name);
HttpContext.Current.Trace.Write(
string.Format(
"{0} controller1 == {0} controller2 ? {1}",
binding.Metadata.Name,
object.Equals(controller1, controller2)));
}
}
我在RegisterAllControllersIn
致电OnApplicationStarted
之后立即拨打了此电话。它在跟踪输出中创建了以下消息:
控制器:IController命名:home
适用范围:瞬态家用控制器1 ==家庭控制器2?虚假控制器:IController命名:帐户
范围:瞬态账户控制器1 ==帐户控制器2?错误
因此,所有这一切都确认正在使用瞬态范围,并且控制器工厂在请求时返回同一控制器的不同实例。所以,我唯一能想到的是:
答案 1 :(得分:0)
听起来好像正在使用单身人士,好吧。有关how to control activation behaviors using Ninject的文档,请参阅此页面。
请注意,瞬态(非单例)是Ninject的默认行为。