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