二.相依性注入(DI)
在第一天有建立了相關的Service及Controller,但你會發現在建構式裡都需要new一個實體物件,但彼此的相依性太重,Controller
相依於Service
,而Service
又相依於UnitOfWork
。
此章節將會介紹如何透過DI來降低它的相依性。
ProductController.cs
/// <summary>
/// Public constructor to initialize product service instance
/// </summary>
public ProductController()
{
_productServices =new ProductServices();
}
ProductServices.cs
/// <summary>
/// Public constructor.
/// </summary>
public ProductServices()
{
_unitOfWork = new UnitOfWork();
}
加入DI套件
切換到WebApi專案
nuget
Unity是由微軟所推出的DI套件
加入 Unity.mvc
加入 Unity.webapi
設定UnityConfig
切至App_Start資料夾
註冊我們需要注入的物件
- ProductServices
- UnitOfWork
UnityConfig.cs
using BusinessServices;
using DataModel;
using Microsoft.Practices.Unity;
using System.Web.Http;
using Unity.WebApi;
namespace WebApi
{
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = BuildUnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
/*
HierarchicalLifetimeManager的用途:
Unity中有一個在管理生命週期的物件叫「ContainerControlledLifetimeManager」,他都會回傳你由`Reslolve`或`ResolveAll`方法所註冊的物件或Type的同一個物件至各自的Class。
但是他們各自有一個子容器,不會共用一個父容器,所以子容器與父容器會有不同的生命週期。
*/
container
.RegisterType<IProductServices, ProductServices>()
.RegisterType<UnitOfWork>(new HierarchicalLifetimeManager());
return container;
}
}
}
註冊Unity
打開Global.asax
namespace WebApi
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
...以下省略
}
}
}
將PdoructController改為DI的方式
namespace WebApi.Controllers
{
public class ProductController : ApiController
{
private readonly IProductServices _productServices;
#region Public Constructor
/******** 未加入DI的版本********************
/// <summary>
/// Public constructor to initialize product service instance
/// </summary>
public ProductController()
{
_productServices = new ProductServices();
}
********************************************/
/// <summary>
/// Public constructor to initialize product service instance
/// </summary>
public ProductController(IProductServices productServices)
{
_productServices = productServices;
}
#endregion
}
...以下省略
}
編譯後,就可立即感受到DI的便利了。
將ProductServices改為DI的方式
同樣的方式,將原本new物件的地方,改由建構式注入
ProductServices.cs
namespace BusinessServices
{
/// <summary>
/// Offers services for product specific CRUD operations
/// </summary>
public class ProductServices : IProductServices
{
private readonly UnitOfWork _unitOfWork;
/******** 未加入DI的版本 ********************
/// <summary>
/// Public constructor.
/// </summary>
public ProductServices()
{
_unitOfWork = new UnitOfWork();
}
*******************************************/
/// <summary>
/// Public constructor.
/// </summary>
public ProductServices(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
}
}