2009-11-12 99 views
3

我使用Ninject 2和Ninject.Web.MVC和使用NinjectHttpApplication誤差的AccountController和Ninject 2和ASP.NET MVC 2預覽2

在登錄過程中接收到以下錯誤: 「A控制器'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

奇怪。如果你創建一個打擊新的MVC項目的品牌,然後在你的控制器中沒有任何DI的情況下將Ninject 2添加到它,會發生什麼......同樣的錯誤? – Charlino 2009-11-12 03:12:32

+0

創建一個新的MVC應用程序並連接Ninject 2後,點擊後也會發生同樣的事情。首頁/索引視圖出現了,但是如果你點擊主頁選項卡,它會顯示:「控制器'MvcApplication1.Controllers.HomeController'的單個實例不能用於處理多個請求。如果自定義控制器工廠正在使用中,確保它爲每個請求創建一個新的控制器實例。「 – Webjedi 2009-11-12 16:07:16

+0

有趣的是,在我創建的新MVC項目中,我做了一個HomeModule,它完成了Bind ()。並加載內核,它的工作......也許我誤解了RegisterAllControllers ... – Webjedi 2009-11-12 16:17:17

回答

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

我打電話的OnApplicationStarted調用RegisterAllControllersIn以後這個權利。它創造了跟蹤輸出以下消息:

控制器:一個IController命名爲:家庭
範圍:瞬態家庭控制器1
==家庭控制器2?假控制器:IController命名:帳戶
範圍:瞬時帳戶控制器1
==帳戶控制器2?False

因此,所有這些都確認正在使用瞬態示波器,並且控制器工廠在請求時正在返回同一控制器的不同實例。所以,我能想到的唯一的事情就是:

  1. 也許你沒有使用最新的構建Ninject 2和Ninject.Web.Mvc的
  2. 的問題是在MVC水平 - 也就是說,它的重複使用由工廠創建的控制器
+0

我剛剛回來更新,我的構建是舊的......它來自以前的源代碼控制的實驗分支......不知道它在Git上......嘆...新構建固定了一切...因爲它幾乎總是這樣。 :-) – Webjedi 2009-11-12 16:38:32

+0

是的,我在那個實驗分支上玩了很長時間,直到我在github上找到它。祝你好運! – 2009-11-12 16:41:12

0

聽起來像是使用單身,好吧。有關how to control activation behaviors using Ninject的文檔,請參閱此頁面。

請注意,transient(不是單例)是Ninject的默認行爲。

+0

從這篇文章和評論,這個鏈接引用Ninject 1.x文檔。激活範圍在Ninject 2中有不同的控制。 – 2009-11-12 16:35:56

+0

啊。然後他們應該在他們的主頁上修復文檔鏈接。 – 2009-11-12 17:15:11