Problem Registering a Generic Repository with Windsor IoC
- by Robin
I’m fairly new to IoC and perhaps my understanding of generics and inheritance is not strong enough for what I’m trying to do. You might find this to be a mess. I have a generic Repository base class:
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 ...
... }
and a SqlClientRepository that inherits Repository:
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
... }
The Repository class provides some generics methods like Save, Delete, etc, that I want all my repository derived classes to share.
The TEntity parameter is constrained to the IEntity interface:
public interface IEntity
{
int Id { get; set; }
NameValueCollection GetSaveRuleViolations();
NameValueCollection GetDeleteRuleViolations();
}
This allows the Repository class to reference these methods within its Save and Delete methods. Unit tests work fine on mock SqlClientRepository instances as well as live unit tests on the real database. However, in the MVC context:
public class ClientController : Controller
{
private SqlClientRepository _clientRepository;
public ClientController(SqlClientRepository clientRepository)
{
this._clientRepository = clientRepository;
}
public ClientController() { }
// ViewResult methods ...
... }
... _clientRepository is always null. I’m using Windor Castle as an IoC container. Here is the configuration:
<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>
I’ve tried many variations in the Windsor configuration file. I suspect it’s more of a design flaw in the above code. As I'm looking over my code, it occurs to me that when registering components with an IoC container, perhaps service must always be an interface. Could this be it? Does anybody have a suggestion? Thanks in advance.