Ninject Singleton для хранилища данных MVC - PullRequest
1 голос
/ 09 апреля 2011

В моем приложении MVC3 у меня есть интерфейс IDataRepository, на который ссылаются все мои контроллеры, чтобы дать им доступ к уровню данных.Есть также класс DataRepository, который реализует IDataRepository для определенного источника данных (в моем случае производная среда Entity Framework, полученная из nHydrate).Класс DataRepository принимает один аргумент, который является строкой подключения к базовой базе данных.

Я успешно использовал nInject to для IoC с классами контроллера, используя следующую привязку:

kernel.Bind<IDataRepository>()
    .To<DataRepository>()
    .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());

Сегодня я прочитал о nInject scoping, и я подумал, что было бы полезно упорядочить вещи так, чтобы для каждого запроса создавался только один экземпляр DatabaseRepository (я думаю, что это будет более эффективно, хотя с EF я не уверен).

К сожалению, я не могу понять, как правильно реализовать шаблон.Например, это не работает:

kernel.Bind<DataRepository>()
    .ToSelf()
    .InRequestScope()
    .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());

kernel.Bind<IDataRepository>()
    .To<DataRepository>();

Я думал, что это создаст только один экземпляр DataRepository, который будет использоваться во всех ссылках на IDataRepository.В сообщении об ошибке сообщалось, что не найдено ни одного совпадения для параметра connectionString, а DataRepository не может быть привязан к себе.Я попробовал некоторые варианты, но когда я смог заставить его работать, шаблон синглтона не выполнялся (то есть я мог видеть в отладчике, что создавалось несколько экземпляров DataRepository).

Я пропускаючто-то очевидное здесь:).

--- Приложение --- К сожалению, предложение не препятствует созданию нескольких экземпляров в рамках одного запроса.

Чтобы было понятно, что я пыталсябыл:

public class BaseControllerModule : NinjectModule
{
    public override void Load()
    {
        Bind<IDataRepository>().To<DataRepository>().InRequestScope()
        .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());
    }
}

и то, что я наблюдал, было конструктором:

public DataRepository( string connectionString )
    : base(connectionString)
{
}

- Дополнительная информация # 2 -

Вот схема классов Ninjectрешает для меня:

public class DataRepositoryBase
{
    protected DataRepositoryBase( string connectionString )
    {}
    public static string GetConnectionString() {}
}
public class DataRepository : DataRepositoryBase, IDataRepository
{
    public DataRepository( string connectionString )
        : base(connectionString)
    {}
}

Я пропустил детали реализации, но, надеюсь, это рисует лучшую картину.

Просматривая это, я думаю, что я вызываю проблемы поделая connectionString параметром конструктора как для DataRepository, так и для его базового класса DataRepositoryBase.Разве Ninject не разрешит connectionString в вызове конструктора базового класса?

ps Я запоздало понял, что мне не нужна DataRepositoryBase, потому что его функциональность можно объединить с DataRepository.Я сделал это, но у меня все еще есть конструктор для DataRepository, вызываемый несколько раз в том, что кажется одним запросом.

p2.s.Ради интереса я попытался объявить InSingletonScope () в определении привязки Ninject.Это сработало - конструктор для DataRepository теперь вызывается только один раз при первом обращении к приложению.Но я не думаю, что это хорошая идея иметь синглтоны в приложении MVC.Похоже, что это приведет к тому, что «состояние» приложения будет «заблокировано» в памяти.

--- но дополнительная информация ---

Проблема, похоже, связана с тем, какЯ разработал свое приложение MVC.Я предполагал, что один запрос от браузера обратно на сервер часто приводит к тому, что несколько запросов обрабатываются последовательно (я наблюдаю за событием BeginRequest, запускаемым в классе MvcApplication).Кажется, что каждый раз, когда я перехожу на другой контроллер, генерируется новый запрос (например, через RedirectToAction).Думаю, это имеет смысл, но это означает, что InRequestScope от Ninject не будет делать то, что я хочу.

Но это также заставляет меня задаться вопросом, неправильно ли я спроектировал приложение.Кажется, мне следует сгруппировать все методы действия, которые могут быть вызваны при вызове браузера, в один контроллер.Вместо этого я организовал методы действий по тому, как они вписываются в концептуальную модель моего приложения.

Ответы [ 2 ]

4 голосов
/ 09 апреля 2011

Эти две привязки говорят: Когда запрашивается DataRepository, повторно используйте экземпляр для всех вхождений в запросе и задайте для строки подключения значение DataRepositoryBase.GetConnectionString ().

Но когда запрашивается IDataRepository, создайте новый экземпляр для каждого вхождения и позвольте Ninject решить, что именно он вводит для строки подключения.

То, что вы действительно хотите, можно сделать, добавив InRequestScope к первому фрагменту кода.

1 голос
/ 09 апреля 2011

Разве этого не достаточно, чтобы иметь синглтон?

kernel.Bind<IDataRepository>()
    .To<DataRepository>()
    .InSingletonScope()
    .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());

RequestScope - не одиночка, это означает, что объекты являются отдельными для вызова каждого пользователя.

Кстати, я думаю, что реальный репозиторий не должен быть одноэлементным - он должен скорее следовать шаблону Unit of Work , то есть его время жизни должно представлять одну операцию данных более высокого уровня и само соединение должен быть на более низком уровне, чем хранилище.

...