10

Ninject.MVC 2.2.0.3 (マージ後) を使用した MVC3 アプリケーションでは、リポジトリをコントローラーに直接注入する代わりに、ビジネスロジックを含むサービスレイヤーを作成し、そこにリポジトリを注入しようとしています。ninject-DependencyResolver を動的オブジェクトとしてサービス層に渡します (mvc も ninject も参照したくないため)。次に、GetService を呼び出して、NinjectHttpApplicationModule で指定したバインディングと有効期間を持つリポジトリを取得します。編集:要するに、失敗しました。

この場合、どのように IoC コンテナーをサービス層に渡すことができますか? (異なるアプローチも大歓迎です。)

編集:これは、回答とコメントをどのように理解するかを示す例です。

サービス ロケーター(アンチ) パターンを避け、代わりに依存性注入を使用する必要があります。たとえば、Northwind で製品とカテゴリの管理サイトを作成するとします。テーブル定義に従って、モデル、リポジトリ、サービス、コントローラー、およびビューを作成します。この時点で、サービスはリポジトリを直接呼び出します。ロジックはありません。機能の柱があり、ビューには生データが表示されます。これらのバインディングは NinjectMVC3 用に構成されています。

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ICategoryRepository>().To<CategoryRepository>();
        kernel.Bind<IProductRepository>().To<ProductRepository>();
    }       

リポジトリ インスタンスは、ProductController 内のコンストラクタ インジェクションの 2 つのレイヤを介して ninject によって作成されます。

private readonly ProductsService _productsService;
public ProductController(ProductsService productsService)
{
    // Trimmed for this post: nullchecks with throw ArgumentNullException 
    _productsService = productsService;
}

および製品サービス:

protected readonly IProductRepository _productRepository;
public ProductsService(IProductRepository productRepository)
{
    _productRepository = productRepository;
}

今のところサービスを分離する必要はありませんが、データベースをモックする準備ができています。
製品/編集でカテゴリのドロップダウンを表示するには、製品に加えてカテゴリを保持する ViewModel を作成します。

public class ProductViewModel
{
    public Product Product { get; set; }
    public IEnumerable<Category> Categories { get; set; }
}

ProductsService を作成するには、CategoriesRepository が必要になりました。

    private readonly ICategoryRepository _categoryRepository;

    // Changed constructor to take the additional repository
    public ProductsServiceEx(IProductRepository productRepository, 
        ICategoryRepository categoryRepository)
    {
        _productRepository = productRepository;
        _categoryRepository = categoryRepository;
    }

    public ProductViewModel GetProductViewModel(int id)
    {
        return new ProductViewModel
                   {
                       Product = _productRepository.GetById(id),
                       Categories = _categoryRepository.GetAll().ToArray(),
                   };
    }

GET Edit-action を変更しreturn View(_productsService.GetProductViewModel(id));、Edit-view をドロップダウンを表示するように変更します。

@model Northwind.BLL.ProductViewModel
...
    @Html.DropDownListFor(pvm => pvm.Product.CategoryId, Model.Categories
        .Select(c => new SelectListItem{Text = c.Name, Value = c.Id.ToString(), Selected = c.Id == Model.Product.CategoryId}))

これに関する1 つの小さな問題であり、私が Service Locator で迷子になった理由は、ProductController の他のアクション メソッドがカテゴリ リポジトリを必要としないことです。必要がない限り作成す​​るのはもったいないし、論理的ではないと思います。何か不足していますか?

4

1 に答える 1

14

あなたはあなたの周りにオブジェクトを渡す必要はありませんあなたはこのようなことをすることができます

// global.aspx


 protected void Application_Start()
        {
            // Hook our DI stuff when application starts
            SetupDependencyInjection();
        }

        public void SetupDependencyInjection()
        {         
            // Tell ASP.NET MVC 3 to use our Ninject DI Container
            DependencyResolver.SetResolver(new NinjectDependencyResolver(CreateKernel()));
        }

        protected IKernel CreateKernel()
        {
            var modules = new INinjectModule[]
                              {
                                 new NhibernateModule(),
                                 new ServiceModule(),
                                 new RepoModule()
                              };

            return new StandardKernel(modules);
        }

それで、これで私はすべてのninjectのものをセットアップします。私は3つのファイルでカーネルを作成し、すべてのバインディングを分割して見つけやすくしています。


私のサービスレイヤークラスでは、必要なインターフェイスを渡すだけです。このサービスクラスは、すべてのサービスレイヤークラスを保持する独自のプロジェクトフォルダーにあり、ninjectライブラリへの参照はありません。

// service.cs

    private readonly IRepo repo;
    // constructor
        public Service(IRepo repo)
        {
            this.repo = repo;
        }

これは私のServiceModuleがどのように見えるかです(global.aspxで作成されたもの)

// ServiceModule()
 public class ServiceModule : NinjectModule
    {
        public override void Load()
        {

           Bind<IRepo>().To<Repo>();


        }

    }       

インターフェイスをリポジトリにバインドする方法をご覧ください。これで、そのインターフェイスを確認するたびに、Repoクラスが自動的にバインドされます。したがって、オブジェクトを渡す必要はありません。

.dllをサービスレイヤーにインポートすることについて心配する必要はありません。たとえば、私は独自のプロジェクトファイルにサービスクラスを持っており、上記のすべて(もちろんサービスクラスを期待)は私のwebuiプロジェクト(私のビューとglobal.aspxがある場所)にあります。

Ninjectは、サービスが別のプロジェクトにあるかどうかを気にしません。これは、webuiプロジェクトで参照されていると思われるためです。

編集

NinjectDependecyResolverを提供するのを忘れました

   public class NinjectDependencyResolver : IDependencyResolver
    {
        private readonly IResolutionRoot resolutionRoot;

        public NinjectDependencyResolver(IResolutionRoot kernel)
        {
            resolutionRoot = kernel;
        }

        public object GetService(Type serviceType)
        {
            return resolutionRoot.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return resolutionRoot.GetAll(serviceType);
        }
    }
于 2011-02-28T23:53:55.550 に答える