2012-12-15 16 views
5

Sto usando Ninject insieme a ASP.NET MVC 4. Sto utilizzando i repository e voglio fare un'iniezione del costruttore per passare nel repository a uno dei controller.Ninject: parametro Costruttore

Questa è la mia interfaccia Repository:

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(); 
} 

Il AzureTableStorageRepository sotto è un'implementazione di 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; 
    } 

Nota il parametro tableName necessaria perché stavo usando un repository tavolo generica a persistere i dati a Azzurro.

E infine ho il seguente controller.

public class CategoriesController : ApiController 
{ 
    static IRepository<Category> _repository; 

    public CategoriesController(IRepository<Category> repository) 
    { 
     if (repository == null) 
     { 
      throw new ArgumentNullException("repository"); 
     } 

     _repository = repository; 
    } 

Ora voglio iniettare un repository nel controller. Così ho creato un modulo che contiene le associazioni:

/// <summary> 
/// Ninject module to handle dependency injection of repositories 
/// </summary> 
public class RepositoryNinjectModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IRepository<Category>>().To<AzureTableRepository<Category>>(); 
    } 
} 

Il caricamento del modulo si fa nel 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); 
    } 

Il DependencyResolver è stato creato perché di DependencyResolver Ninject implementa System.Web.Mvc.IDependencyResolver e questo non può essere assegnato a GlobalConfiguration.Configuration dell'applicazione WebApi.

Quindi con tutto questo a posto, la parte Ninject sta effettivamente iniettando il tipo giusto nel controller ma Ninject non può iniettare il parametro tableName nel costruttore di AzureTableRepository.

Come potrei essere in grado di fare questo in questo caso? Ho consultato molti articoli e la documentazione di ninject per vedere come usare i parametri, ma non riesco a farlo funzionare.

Qualsiasi aiuto sarebbe apprezzato.

risposta

10

userei il metodo WithConstructorArgument() come ...

Bind<IRepository<Category>>().To<AzureTableRepository<Category>>() 
    .WithConstructorArgument("tableName", "categories"); 

Il resto del disegno repository è probabilmente un'altra domanda. IMHO Sembra un grande no no per creare un tavolo o fare un sollevamento pesante in un ctor.

+0

Penso che rimuoverò la creazione, ... dal contructor perché non è davvero una buona pratica fare molta inizializzazione nel ctor. Thx! –

0

Nel frattempo ho giocato con i provider per provare a fare il trucco e sembra funzionare.

Non so se questa è una buona idea o se è eccessivo, ma qui è quello che ho fatto: Ho creato una classe fornitore generico:

public abstract class NinjectProvider<T> : IProvider 
{ 
    public virtual Type Type { get; set; } 
    protected abstract T CreateInstance(IContext context); 

    public object Create(IContext context) 
    { 
     throw new NotImplementedException(); 
    } 

    object IProvider.Create(IContext context) 
    { 
     throw new NotImplementedException(); 
    } 

    Type IProvider.Type 
    { 
     get { throw new NotImplementedException(); } 
    } 
} 

E poi ho realizzato che uno in AzureTableRepositoryProvider. (T per sostenere avere lo stesso repository per più tipi di entità.)

public class AzureTableRepositoryProvider<T> : Provider<AzureTableRepository<T>> where T : TableServiceEntity 
{ 
    protected override AzureTableRepository<T> CreateInstance(IContext context) 
    { 
     string tableName = ""; 

     if (typeof(T).Name == typeof(Category).Name) 
     { 
      // TODO Get the table names from a resource 
      tableName = "categories"; 
     } 
     // Here other types will be addedd as needed 

     AzureTableRepository<T> azureTableRepository = new AzureTableRepository<T>(tableName); 

     return azureTableRepository; 
    } 
} 

Utilizzando questo fornitore posso passare nel nome tabella di destra per il repository con cui lavorare. Ma per me rimangono due domande:

  1. Questa buona pratica o possiamo fare le cose molto più semplice?
  2. Nella classe NinjectProvider ho due casi notImplementedException. Come potrei risolverli? Ho usato codice di esempio dal seguente link ma non funziona in quanto il provider è astratto e il codice non ha un corpo per il metodo di creazione ...enter link description here
Problemi correlati