Ошибка с AccountController и Ninject 2 и ASP.NET MVC 2 Preview 2

Я использую 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 ... он должен пытаться сделать из него синглтон или что-то в этом роде?


person Webjedi    schedule 12.11.2009    source источник
comment
Странный. Что произойдет, если вы создадите новый проект MVC, а затем добавите к нему Ninject 2 без какого-либо DI в ваших контроллерах ... та же ошибка?   -  person Charlino    schedule 12.11.2009
comment
Создание нового приложения MVC и подключение Ninject 2 делает то же самое после щелчка мышью. Появится представление Home / Index, но если вы нажмете на вкладку Home, оно взорвется: Один экземпляр контроллера MvcApplication1.Controllers.HomeController не может использоваться для обработки нескольких запросов. Если используется фабрика настраиваемых контроллеров, убедитесь, что она создает новый экземпляр контроллера для каждого запроса.   -  person Webjedi    schedule 12.11.2009
comment
Интересно, что в том новом проекте MVC, который я создал, я создал HomeModule, который выполнял Bind ‹HomeController› () .To ‹HomeController› () .InTransientScope (); и загрузил это с ядром, и это сработало ... возможно, я неправильно понимаю RegisterAllControllers ...   -  person Webjedi    schedule 12.11.2009


Ответы (2)


Самая последняя версия 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
Область применения: Transient home controller1
== home controller2? False Controller: IController Named: account
Область: Transient account controller1
== account controller2? Ложь

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

  1. Возможно, вы не используете последние сборки Ninject 2 и Ninject.Web.Mvc
  2. Проблема находится на уровне MVC, т.е. он повторно использует контроллер, созданный фабрикой.
person Peter Meyer    schedule 12.11.2009
comment
Я как раз возвращался, чтобы обновить, что моя сборка была старой ... она пришла из экспериментальной ветки предыдущей системы управления версиями ... понятия не имела, что она была на Git ... вздох ... Новая сборка все исправила. ..как это почти всегда бывает. :-) - person Webjedi; 12.11.2009
comment
Да, я довольно долго играл с этой экспериментальной веткой, пока не нашел ее и на github. Удачи! - person Peter Meyer; 12.11.2009