Проблема регистрации общего репозитория с помощью Windsor IoC - PullRequest
0 голосов
/ 07 июня 2010

Я довольно новичок в IoC и, возможно, мое понимание дженериков и наследования недостаточно для того, что я пытаюсь сделать. Вы можете найти это беспорядок. У меня есть общий репозиторий базовый класс:

public class Repository<TEntity> where TEntity : class, IEntity
   {
      private Table<TEntity> EntityTable;
      private string _connectionString;
      private string _userName;
      public string UserName
      {
         get { return _userName; }
         set { _userName = value; }
      }

      public Repository() {}

      public Repository(string connectionString)
      {
         _connectionString = connectionString;
         EntityTable = (new DataContext(connectionString)).GetTable<TEntity>();
      }

      public Repository(string connectionString, string userName)
      {
         _connectionString = connectionString;
         _userName = userName;
         EntityTable = (new DataContext(connectionString)).GetTable<TEntity>();
      }   
// Data access methods ...
 ... }

и репозиторий SqlClientRepository, который наследует репозиторий:

    public class SqlClientRepository : Repository<Client> 
    {     
private Table<Client> ClientTable;
          private string _connectionString;
          private string _userName;

          public SqlClientRepository() {}

          public SqlClientRepository(string connectionString) : base(connectionString)
          {
             _connectionString = connectionString;
             ClientTable = (new DataContext(connectionString)).GetTable<Client>();
          }

          public SqlClientRepository(string connectionString, string userName)
             : base(connectionString, userName)
          {
             _connectionString = connectionString;
             _userName = userName;
             ClientTable = (new DataContext(connectionString)).GetTable<Client>();
          }
    // data access methods unique to Client repository
     ... }

Класс Repository предоставляет несколько обобщенных методов, таких как Save , Delete и т. Д., Которые я хочу, чтобы все классы, производные от моего репозитория, разделяли.

Параметр TEntity ограничен интерфейсом IEntity:

   public interface IEntity
   {
      int Id { get; set; }
      NameValueCollection GetSaveRuleViolations();
      NameValueCollection GetDeleteRuleViolations();
   }

Это позволяет классу репозитория ссылаться на эти методы в своих методах Save и Delete. Модульные тесты отлично работают на экземплярах фиктивных SqlClientRepository, а также на реальных модульных тестах в реальной базе данных. Однако в контексте MVC:

   public class ClientController : Controller
   {
      private SqlClientRepository _clientRepository;

      public ClientController(SqlClientRepository clientRepository)
      {
         this._clientRepository = clientRepository;
      }
      public ClientController() { }
// ViewResult methods ...
... }

... _clientRepository всегда null . Я использую Windor Castle в качестве контейнера IoC. Вот конфигурация:

<component id="ClientRepository" service="DomainModel.Concrete.Repository`1[[DomainModel.Entities.Client, DomainModel]], DomainModel"
       type="DomainModel.Concrete.SqlClientRepository, DomainModel" lifestyle="PerWebRequest">
      <parameters>
        <connectionString>#{myConnStr}</connectionString>
      </parameters>
    </component>

Я пробовал много вариантов в файле конфигурации Windsor. Я подозреваю, что это скорее недостаток дизайна в приведенном выше коде. Когда я просматриваю свой код, мне приходит в голову, что при регистрации компонентов в контейнере IoC, возможно, сервис всегда должен быть интерфейсом. Может ли это быть так? У кого-нибудь есть предложение? Заранее спасибо.

---- ПОПРАВКА ---- ---- 1027 *

В ответ на Ответ 1 я добавил новый пример кода, поскольку он не будет правильно форматироваться в разделах комментариев ниже.

Я могу заставить это работать:

public class ClientController : Controller
   {
      private IClientRepository _clientRepository;
      public ClientController(IClientRepository clientRepository) { ... }
   }

public interface IClientRepository : IRepository<Client>   { ... } 

public class SqlClientRepository : IClientRepository    { ... }

... но теперь я должен дублировать мои методы Save и Delete внутри SqlClientRepository, и преимущества моего общего класса Repository теряются. Как только я пытаюсь и SqlClientRepository снова наследуется от Repository , вот так:

public class SqlClientRepository : Repository<Client>, IClientRepository   { ... }

... возвращает мое нулевое значение для _clientRepository в контроллере. Есть ли способ, которым я могу сделать это, или это невозможно? Я чувствую, что попробовал много вариантов и не могу понять это правильно.

Еще раз спасибо за вашу помощь.

1 Ответ

2 голосов
/ 11 июня 2010

Нет, сервис не должен быть интерфейсом, хотя обычно так и должно быть. Сервис - это то, что компонент предоставляет внешнему миру ( см. Документ , дайте мне знать, если это имеет смысл).

Итак, ваш конструктор ClientController говорит "Я зависим от SqlClientRepository сервиса " Это плохо (потому что сервисы должны быть абстрактными (предпочтительно интерфейсами)), но это помимо точка.

Компонент , который вы регистрируете (с именем ClientRepository), вы регистрируетесь как Repository<Client> service .

Надеюсь, теперь вы видите, в чем проблема. ClientComponent ожидает SqlClientRepository, но зарегистрированный компонент не выставляет себя как SqlClientRepository, а как Repository<Client>, поэтому Виндзор думает: "Хорошо, поскольку у меня нет службы для SqlClientRepository я собираюсь использовать другой конструктор, чтобы создать ClientController " ( см. документ для объяснения того, как Виндзор выбирает, какой конструктор использовать)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...