Pro ASP.NET MVC 5 Framework.学習ノートMVCの必須ツール

22079 ワード

各MVCプログラマーの軍火庫には,注入(DI)容器に依存し,ユニットテストフレームワークに依存し,シミュレーションツールの3つのツールがある.
1.サンプルアイテムの準備
ASPを作成する.NET MVC WebアプリケーションのEmptyプロジェクトで、EssentialToolsと名付けられています.
1.1. モデルクラスの作成
Modelsフォルダの下にProductクラスを作成します.
public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

Productコレクションの合計金額を計算するには、Modelsフォルダの下にLinqValue Calculatorのクラスを追加する必要があります.
public class LinqValueCalculator {
    public decimal ValueProducts(IEnumerable<Product> products) {
        return products.Sum(p => p.Price);
    }
}

このクラスは、Linq Sumメソッドを使用して、列挙可能なオブジェクトの各ProductのPrice属性の値を加算するValueProductsというメソッドを定義します.
最後のモデルクラスはShoppingCartで、Productオブジェクトの集合を表し、LinqValue Calculatorを使用して合計値を決定します.
public class ShoppingCart {
    private LinqValueCalculator calc;
    public ShoppingCart(LinqValueCalculator calcParam) {
        calc = calcParam;
    }
    public IEnumerable<Product> Products { get; set; }
    public decimal CalculateProductTotal() {
        return calc.ValueProducts(Products);
    }
}

1.2.コントローラの追加
HomeControllerを追加
public class HomeController : Controller {
    private Product[] products = {
        new Product {Name = "Kayak", Category = "Watersports", Price = 275M},
        new  Product  {Name  =  "Lifejacket",  Category  =  "Watersports", Price = 48.95M},
        new  Product  {Name  =  "Soccer  ball",  Category  =  "Soccer",  Price = 19.50M},
        new  Product  {Name  =  "Corner  flag",  Category  =  "Soccer",  Price = 34.95M}
    };
    public ActionResult Index() {
        LinqValueCalculator calc = new LinqValueCalculator();
        ShoppingCart  cart  =  new  ShoppingCart(calc)  {  Products  = products };
        decimal totalValue = cart.CalculateProductTotal();
        return View(totalValue);
    }
}

1.3.ビューの追加
Indexビューを追加
<p>Total Price is :@Model</p>

2.Ninjectの使用
依存注入(DI)は、MVCプログラム内の各構成要素をデカップリングするために使用される.インタフェースとDIコンテナの組み合わせにより、インタフェースの実装が作成され、オブジェクトのインスタンスが作成されます.コンストラクタに注入します
私は例の中でわざと1つの問題を残して、次に私はそれを説明して、そしてどのように私の好きなNinjectというDI容器でそれを解決するかを示します.
2.1.この問題を理解する
インスタンスアプリケーションでは,DI処理の基本問題として,結合されたクラスのみを作成した.ShoppingCartクラスはLinqValueCalculatorクラスと密接に結合している.HomeControllerクラスは同時にShoppingCartクラスとLinqValue Calculatorクラスと密接に結合している.
これは、LinqValueCalculatorクラスを置き換える場合は、それに密接に結合されたクラスで参照を見つけて変更しなければならないことを意味します.これは小さなプロジェクトにとって問題ではありません.しかし、実際のプロジェクトでは、別のcalculator実装(テストのため、例のため)を切り替えたい場合は、別のクラスを1つのクラスに置き換えるよりも、このような操作は冗長で退屈で、エラーが発生しやすい.
2.1.1.インタフェースを適用
インタフェースで、一部の問題を解決できます.インタフェースは、インスタンスから抽象化された計算機能を定義します.Modelsフォルダにインタフェースを追加します.
public interface IValueCalculator {
    decimal ValueProducts(IEnumerable<Product> products);
}

LinqValueCalculatorクラスで実装します.
public class LinqValueCalculator : IValueCalculator {
    public decimal ValueProducts(IEnumerable<Product> products) {
        return products.Sum(p => p.Price);
    }
}

このインタフェースは、ShoppingCartクラスとLinqValueCalculatorクラスの間の緊密な結合を解読することができます.
public class ShoppingCart {
    private IValueCalculator calc;
    public ShoppingCart(IValueCalculator calcParam) {
        calc = calcParam;
    }
    public IEnumerable<Product> Products { get; set; }
    public decimal CalculateProductTotal() {
        return calc.ValueProducts(Products);
    }
}

ここまで来て、すでにいくつかの進展をしました.ただし、C#はインタフェースの初期化中にインスタンスクラスを作成する必要があります.これは、どのインスタンスクラスを使用するかを知る必要があるためと理解できます.しかし、これは、LinqValueCalculatorオブジェクトを作成するときに、この問題は依然としてHomeControlに存在し、LinqValueCalculatorクラスと密接に結合していることを意味します.
public ActionResult Index() {
     IValueCalculator calc = new LinqValueCalculator();
    ShoppingCart cart = new ShoppingCart(calc) { Products = products };
    decimal totalValue = cart.CalculateProductTotal();
    return View(totalValue);
}

私がNinjectを使用する目的は、インスタンス化したいIValueCalculatorインタフェースの実装を1つの場所で指定することですが、HomeControllerのコードでは、どの実装を使用するかの詳細は表示されません.
これは、LinqValueCalculatorがIvalueCalculatorインタフェースの実装であることをNinjectに伝え、newキーワードではなくNinjectを通じてオブジェクトを取得するようにHomeControllerクラスを使用して更新したいと考えています.
2.2.VSプロジェクトへのNinjectの追加
NuGetパッケージマネージャを使用して、Ninject、Ninjectを追加します.Web.Common,Ninject.MVC 3の3つはプロジェクトにパッケージされています.MVC 3の参照が追加され、エラーが発生します.リファレンスでは、MVC 3のリファレンスを削除すると、MVC 5環境で完璧に動作します.
2.3.Ninjectでスタート
基本的なNinject機能を動作させるには3つのステップがあります.HomeControllerでは、Ninjectへの参照を追加し、Ninject kernelのインスタンスを作成し、Ninjectでインタフェースとインプリメンテーションのバインドを追加し、Ninjectからインタフェースのインプリメンテーションを取得します.
public class HomeController : Controller {
    private Product[] products = {
        new Product {Name = "Kayak", Category = "Watersports", Price = 275M},
        new  Product  {Name  =  "Lifejacket",  Category  =  "Watersports", Price = 48.95M},
        new  Product  {Name  =  "Soccer  ball",  Category  =  "Soccer",  Price = 19.50M},
        new  Product  {Name  =  "Corner  flag",  Category  =  "Soccer",  Price = 34.95M}
    };
    public ActionResult Index() {
        IKernel ninjectKernel = new StandardKernel();
        ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
        IValueCalculator calc = ninjectKernel.Get<IValueCalculator>();
        ShoppingCart  cart  =  new  ShoppingCart(calc)  {  Products  = products };
        decimal totalValue = cart.CalculateProductTotal();
        return View(totalValue);
    }
}

最初のステップはNinjectの準備です.依存を解決し、新しいオブジェクトを作成するために使用されるNinjectkernelのインスタンスを作成します.オブジェクトが必要な場合は、newキーワードではなくkernelを使用します.
IKernel ninjectKernel = new StandardKernel();

StandardKernelクラスの新しいインスタンスを作成することで、Ninjnelインタフェースの実装を作成しました.Ninjectは異なるタイプのkernelを使用するために拡張され、個性化されますが、StandardKernelを内蔵する必要があります.
第2のステップは、Ninject kernelを構成し、各インタフェースのどの実装を使用したいかを理解させることです.
ninjectKernel.Bind< IValueCalculator >().To< LinqValueCalculator >();

NinjectはC#タイプのパラメータを使用して関係を作成します.Bindメソッドのパラメータを、私が使用したいインタフェースに設定し、返された結果でToメソッドを呼び出します.Toメソッドのパラメータを、インスタンス化したいインタフェースの実装クラスに設定します.この声明は、IValueCalculatorインタフェースでの依存性は、LinqValueCalculatorクラスのインスタンスを作成することによって解決されるべきだとNinjectに伝えた.最後に、NinjectのGetメソッドを使用してオブジェクトを作成します.
IValueCalculator calc = ninjectKernel.Get<IValueCalculator>() ;

Getメソッドのパラメータは、私が興味を持っているインタフェースをNinjectに伝え、このメソッドが返した結果は、私がToメソッドで指定した実装の一例です.
2.4.MVC依存注入の設定
上記の3つのステップの結果は,実装クラスがNinjectで設定されたIValueCalculatorインタフェースの要求を履行するためにインスタンス化されなければならないことに関する知識である.もちろん、残りの定義はHomeControllerにあるため、HomeControllerとLinqValueCalculatorクラスが密接に結合していると考えられているため、私たちの応用はまだ改善されていません.
次に,MVCアプリケーションのコア部分にNinjectを埋め込む方法を示す.これにより、Controllerを簡素化し、Ninjectの影響を拡張し、アプリケーション全体を貫くことができます.最後にコントローラから構成を削除します.
2.4.1依存解決者の作成
私が最初に変えたいのは、カスタム依存解決者になることです.MVCフレームワークは、依存解決者を使用して、サービス要求を必要とするクラスのインスタンスを作成する.カスタムソリューションを作成することで、オブジェクトを作成するときにNinjectを使用するMVCフレームワークを確保できます.
解決者を設定するには、フォルダInfrastructure(インフラストラクチャ)を作成し、他のフォルダの下に置くのに適していないクラスを配置します.フォルダの下にNinjectDependencyresolverクラスを作成します.
public class NinjectDependencyResolver : IDependencyResolver {
    private IKernel kernel;
    public NinjectDependencyResolver(IKernel kernelParam) {
        kernel = kernelParam;
        AddBindings();
    }
    public object GetService(Type serviceType) {
        return kernel.TryGet(serviceType);
    }
    public IEnumerable<object> GetServices(Type serviceType) {
        return kernel.GetAll(serviceType);
    }
    private void AddBindings() {
        kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
    }
}

NinjectDependencyResolverクラスはIDependencyResolverインタフェースを実現し、このインタフェースはSystemである.Mvcネーミングスペースの一部であり、MVCフレームワークは必要なオブジェクトを得るために使用されます.MVCフレームワークは、受信された要求にサービスするクラスのインスタンスが必要である場合、GetServiceメソッドまたはGetServicesメソッドを呼び出す.依存解決者のタスクは、TryGetメソッドとGetAllメソッドを実行することによってインスタンスを作成することです.TryGetメソッドはGetメソッドと同様に動作しますが、ここで適切なバインドがない場合はnullを返し、例外を放出するのではなくnullを返します.GetAllメソッドは、複数の異なるインプリメンテーションオブジェクトが使用可能である場合に使用される複数のバインドを単一のタイプにサポートします.
私の依存解決者クラスは、私のNinject bindingを設定する場所でもあります.AddBindingsメソッドでは、BindメソッドとToメソッドを使用して、IValueCalculatorインタフェースとLinqValueCalculatorクラスの関係を構成します.
2.4.2.依存解決者の登録
IDependencyResolverインタフェースを作成するだけでは十分ではありません.NinjectパッケージはApp_Startフォルダの下にNinjectWebCommonというファイルを作成します.プログラムの起動時のautomaticallyの方法を定義し、ASPに統合します.NETリクエストのライフサイクル.NinjectWebCommonクラスのRegisterServicesメソッドで、NinjectDependencyResolverクラスのインスタンスを作成するための宣言を追加しました.システムを使用する.Web.Mvc.DependencyResolverクラスの静的メソッドSetResolverは、MVCフレームワークを使用して解決者を登録します.この声明は、DIをサポートするためにNinjectとMVCフレームワークの間の橋渡しを作成しました.
private static void RegisterServices(IKernel kernel) {
    System.Web.Mvc.DependencyResolver.SetResolver(new EssentialTools.Infrastructure.NinjectDependencyResolver(kernel));
}

2.4.3.ホームコントローラの再構築
最後のステップは、HomeControllerの再構築です.前の章では、先進的なツールを配置しました.
public class HomeController : Controller {
    private IValueCalculator calc;
    private Product[] products = {
        new Product {Name = "Kayak", Category = "Watersports", Price = 275M},
        new  Product  {Name  =  "Lifejacket",  Category  =  "Watersports", Price = 48.95M},
        new  Product  {Name  =  "Soccer  ball",  Category  =  "Soccer",  Price = 19.50M},
        new  Product  {Name  =  "Corner  flag",  Category  =  "Soccer",  Price = 34.95M}
    };
    public HomeController(IValueCalculator calcParam) {
        calc = calcParam;
    }
    public ActionResult Index() {
        ShoppingCart  cart  =  new  ShoppingCart(calc)  {  Products  = products };
        decimal totalValue = cart.CalculateProductTotal();
        return View(totalValue);
    }
}

最も主要な変更は、私がコンストラクタでIValueCalculatorインタフェースの実装を受信させ、HomeControllrクラスを変更し、依存を宣言させることです.Ninjectがcontrollerのインスタンスを作成すると、NinjectDependencyResolverクラスでの私の構成を使用して、controllerにIValueCalculatorインタフェースの実装を提供します.
もう1つの変更は、controllerで説明されているNinjectまたはLinqValue Calculatorクラスを削除することです.最後に,HomeControllerとLinqValueCalculatorクラス間の緊密な結合を破壊した.
注入に依存するコンストラクタ注入の例を作成しました.例示的なアプリケーションを実行し、IEがアプリケーションのルートパスを要求すると、次のことが起こります.
1.MVCフレームワークは要求を受信し、要求がホームコントローラへの加入を希望することを計算する.
2.MVCフレームワークは私にカスタマイズした依存解決者を要求し、依存解決者はGetServiceメソッドのTypeパラメータを使用して、作成するクラスを指定し、HomeControllerクラスの新しいインスタンスを作成します.
3.私の依存解決者はNinjectに新しいHomeControllerクラスを作成し、TypeオブジェクトをTryGetメソッドに渡すように要求した.
4.NinjectはHomeControllerのコンストラクタをチェックし、ビューバインドされたIValueCalculatorインタフェースに依存する宣言があることを発見します.
5.Ninject LinqValueCalculatorクラスのインスタンスを作成し、HomeControllerクラスのハートインスタンスを作成します.
6.NinjectはHomeControllerインスタンスをカスタム依存解決者に渡し、MVCフレームワークに戻します.MVCフレームワークは、要求サービスのためにコントローラのインスタンスを使用する.
私がこんなに細かく分析したのは、あなたが初めてDIを使ったとき、それが少し奇妙で理解しにくいと思ったからです.私がこのようにしたメリットの一つは、プログラム内の任意のコントローラが依存を宣言し、MVCフレームワークがNinjectを使用して解決することです.
最良の部分は、LinqValueCalculatorを他のインプリメンテーションで置き換えたい場合、依存解決者クラスを変更するだけです.これが唯一の場所なので、IValueCalculatorインタフェースを使用する実装を指定しなければなりません.