2012-12-15 71 views
5

我正在使用Ninject和ASP.NET MVC 4.我正在使用存儲庫,並且想要執行構造函數注入以將存儲庫傳遞給其中一個控制器。Ninject:構造函數參數

這是我的倉庫接口:

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

AzureTableStorageRepositoryIRepository<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; 
    } 

注意的tablename參數需要的,因爲我使用的是通用的表存儲庫數據持久化到Azure上。

最後我有以下控制器。

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

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

     _repository = repository; 
    } 

現在我想注入一個存儲庫到控制器。所以我創建了一個包含綁定的模塊:

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

模塊的裝載動作完成的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); 
    } 

DependencyResolver的形成是因爲Ninject的DependencyResolver實現System.Web.Mvc.IDependencyResolver,這不能被分配到WebApi應用程序的GlobalConfiguration.Configuration

因此,所有這一切,Ninject部分實際上是在Controller中注入正確的類型,但Ninject無法在構造函數AzureTableRepository中注入tableName參數。

在這種情況下,我該如何做到這一點?我已經諮詢了很多文章和ninject文檔,看看我可以如何使用參數,但我似乎無法得到它的工作。

任何幫助,將不勝感激。

回答

10

我會使用的方法WithConstructorArgument()像...

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

庫設計的其餘部分可能是另外一個問題。恕我直言,這似乎是一個很大的不得不創建一個表或在ctor中做任何繁重的工作。

+0

我想我會從構造器中刪除創建,因爲在ctor中執行大量初始化確實不是一個好習慣。 Thx! –

0

與此同時,我一直在與提供商玩弄嘗試和伎倆,它似乎工作。

我不知道這是好主意,或者如果它是矯枉過正,但這裏是我做了什麼: 我創建了一個通用的提供者類:

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

然後我實現了一個在AzureTableRepositoryProvider。 (T,以支持具有多個實體類型相同的存儲庫。)

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

通過使用此提供我可以在右邊的表名傳遞存儲庫的工作。但對我來說,還有兩個問題:

  1. 這是一個好的做法還是我們可以做的事情更簡單?
  2. 在NinjectProvider類中,我有兩個notImplementedException情況。我怎麼解決這些問題?我使用了以下鏈接的示例代碼,但由於提供程序是抽象的,代碼沒有創建方法的主體,因此不起作用...enter link description here