代码之家  ›  专栏  ›  技术社区  ›  Webjedi

AccountController和Ninject 2和ASP.NET MVC 2预览2出错

  •  3
  • Webjedi  · 技术社区  · 16 年前

    我正在使用ninject 2和ninject.web.mvc并使用ninjecthttp应用程序

    在登录过程中接收到以下错误: “控制器'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());
            }
    

    AccountController模块如下所示:

     public class AccountControllerModule:Module
    {
        public override void Load()
        {
            Bind<IFormsAuthentication>().To<FormsAuthenticationService>();
            Bind<IMembershipService>().To<AccountMembershipService>();
            Bind<MembershipProvider>().ToConstant(Membership.Provider);
        }
    }
    

    我的 猜测 它是否有一些事情要在registerallcontrollersin期间进行生命周期设置……但我只是不确定……有什么想法从这里开始?

    最新消息:我也看到了主控器发生的事……它一定是想让它成为一个单打或是什么?

    2 回复  |  直到 16 年前
        1
  •  3
  •   Peter Meyer    16 年前

    最新版本的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;
    }
    

    因此,基于绑定设置和工厂,它似乎不是在单例范围内创建对象。您可以做的一件事是在创建内核之后编写一些调试代码,并自己检查绑定以确认作用域是什么。我做了一个小实验,并将代码添加到我的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)));
      }
    }
    

    我打电话给 注册所有控制器 OnApplicationStarted . 它在跟踪输出中创建了以下消息:

    控制器:IController,名称:Home
    范围:临时家庭控制器1
    ==家庭控制器2?错误控制器:IController已命名:帐户
    范围:临时账户管理员1
    ==账户管理员2?假

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

    1. 也许您没有使用最新版本的ninject 2和ninject.web.mvc。
    2. 问题在于MVC级别——即,它重用工厂创建的控制器
        2
  •  0
  •   Craig Stuntz    16 年前

    听起来像是单件的,好吧。有关以下方面的文档,请参阅本页 how to control activation behaviors using Ninject .

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