I am using Ninject together with ASP.NET MVC 4. I am using repositories and want to do constructor injection to pass in the repository to one of the controllers.
This is my Repository interface:
public interface IRepository<T> where T : TableServiceEntity
{
void Add(T item);
void Delete(T item);
void Update(T item);
IEnumerable<T> Find(params Specification<T>[] specifications);
IEnumerable<T> RetrieveAll();
void SaveChanges();
}
The AzureTableStorageRepository
below is an implementation of IRepository<T>
:
public class AzureTableRepository<T> : IRepository<T> where T : TableServiceEntity
{
private readonly string _tableName;
private readonly TableServiceContext _dataContext;
private CloudStorageAccount _storageAccount;
private CloudTableClient _tableClient;
public AzureTableRepository(string tableName)
{
// Create an instance of a Windows Azure Storage account
_storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
_tableClient = _storageAccount.CreateCloudTableClient();
_tableClient.CreateTableIfNotExist(tableName);
_dataContext = _tableClient.GetDataServiceContext();
_tableName = tableName;
}
Note the tableName parameter needed because I was using a generic table repository to persist data to Azure.
And finally I have the following controller.
public class CategoriesController : ApiController
{
static IRepository<Category> _repository;
public CategoriesController(IRepository<Category> repository)
{
if (repository == null)
{
throw new ArgumentNullException("repository");
}
_repository = repository;
}
Now I want to inject a repository into the controller. So I have created a module that contains the bindings:
/// <summary>
/// Ninject module to handle dependency injection of repositories
/// </summary>
public class RepositoryNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IRepository<Category>>().To<AzureTableRepository<Category>>();
}
}
The loading of the module is done in the NinjectWebCommon.cs
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
// Load the module that contains the binding
kernel.Load(new RepositoryNinjectModule());
// Set resolver needed to use Ninject with MVC4 Web API
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
}
The DependencyResolver
was created because Ninject's DependencyResolver
implements System.Web.Mvc.IDependencyResolver
and this cannot be assigned to GlobalConfiguration.Configuration
of the WebApi Application.
So with all this in place, the Ninject part is actually injecting the right type in the Controller but Ninject cannot inject the tableName parameter in the constructor of AzureTableRepository
.
How would I be able to do this in this case? I have consulted a lot of articles and the ninject documentation to see how I could use parameters, but I cannot seem to get it working.
Any help would be appreciated.
Meanwhile I have been playing around with Providers to try and do the trick and it seems to work.
I don't know if this is good idea or if it is overkill but here is what I have done: I have created a generic provider class:
And then I implemented that one in the AzureTableRepositoryProvider. (T to support having the same repository for multiple entity types.)
By using this provider I can pass in the right table name for the repository to work with. But for me, two questions remain:
I'd use the
WithConstructorArgument()
method like...The rest of the repository design is probably another question. IMHO It seems like a big no no to create a table or do any heavy lifting in a ctor.