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

したがって、バインディングの設定とファクトリに基づくと、シングルトンスコープでオブジェクトを作成していないように見えます。カーネルを作成した後、小さなデバッグコードを記述し、バインディングを自分でチェックして、スコープが何であるかを確認することができます。少し実験をして、以下の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?False Controller:IController Named:account
Scope:Transient account controller1
== account controller2?誤り

したがって、これはすべて、一時スコープが使用されていること、およびコントローラーファクトリが要求されたときに同じコントローラーの別のインスタンスを返していることを確認することです。だから、私が考えることができる唯一のことはそれです:

  1. おそらく、Ninject2とNinject.Web.Mvcの最新ビルドを使用していません
  2. 問題はMVCレベルにあります。つまり、工場で作成されたコントローラーを再利用しています。
于 2009-11-12T16:35:26.647 に答える
0

シングルトンを使用しているようですね。Ninjectを使用してアクティベーション動作を制御する方法に関するドキュメントについては、このページを参照してください。

Ninjectのデフォルトの動作は、トランジェント(シングルトンではない)であることに注意してください。

于 2009-11-12T14:03:24.287 に答える