Ошибка с AccountController и Ninject 2 и ASP.NET MVC 2 Preview 2 - PullRequest
3 голосов
/ 12 ноября 2009

Я использую 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);
    }
}

My думаю, в том, что у него есть что-то, что нужно сделать в жизненном цикле, установленном во время RegisterAllControllersIn ... но я просто не уверен ... есть идеи, куда идти?

ОБНОВЛЕНИЕ: Просто видел, как это случилось и с HomeController ... он должен пытаться сделать из него синглтон или что-то в этом роде?

Ответы [ 2 ]

3 голосов
/ 12 ноября 2009

Самая последняя версия 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 Named: account
Область применения: временный контроллер аккаунта 1
== контроллер аккаунта2? Неверно

Итак, все, что это делает, это подтверждает, что используется переходная область и что фабрика контроллеров возвращает другой экземпляр того же контроллера по запросу. Итак, единственное, о чем я могу думать, это то, что:

  1. Возможно, вы не используете последние сборки Ninject 2 и Ninject.Web.Mvc
  2. Проблема на уровне MVC - то есть повторное использование контроллера, созданного на заводе
0 голосов
/ 12 ноября 2009

Похоже, что он использует синглтон, все в порядке. См. Эту страницу для документации по как управлять поведением активации с помощью Ninject .

Обратите внимание, что переходный процесс (не одиночный) является поведением по умолчанию для Ninject.

...