3

我正在使用 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 上......它必须试图用它制作一个单例或其他东西吗?

4

2 回答 2

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)));
  }
}

RegisterAllControllersInOnApplicationStarted. 它在跟踪输出中创建了以下消息:

控制器:IController 名称:home
范围:Transient home controller1
== home controller2 ? 假控制器:IController 名称:帐户
范围:瞬态帐户控制器
1 == 帐户控制器 2?错误的

因此,所有这些都是确认正在使用瞬态范围,并且控制器工厂在请求时返回同一控制器的不同实例。所以,我唯一能想到的是:

  1. 也许您没有使用最新版本的 Ninject 2 和 Ninject.Web.Mvc
  2. 问题出在 MVC 级别——即它重用了工厂创建的控制器
于 2009-11-12T16:35:26.647 回答
0

听起来像是在使用单例,好吧。有关如何使用 Ninject 控制激活行为的文档,请参阅此页面。

请注意,瞬态(不是单例)是 Ninject 的默认行为。

于 2009-11-12T14:03:24.287 回答