任務16:介紹
1、依賴注入概念詳解
-
從UML和軟件建模來理解
-
從單元測試來理解
2、ASP.NET Core 源碼解析
任務17:從UML角度來理解依賴
1、什麼是依賴
當一個類A完成某個任務需要另一個類B來幫助時,A就對B產生了依賴
例如CustomerController需要對customer進行新增或查找時用到EF,則對EF的Context產生了依賴
var context = new CustomerContext(new DbContextOptions<CustomerContext>{});
2、顯示依賴與隱式依賴
顯示依賴:把一個類用到的所有外部組件放到一個類最上面,在構造函數裏面初始化
private CustomerContext _context;
public CustomerController()
{
_context = new CustomerContext(new DbContextOptions<CustomerContext>{});
}
隱式依賴:需要用到的地方再初始化,不推薦
var context = new CustomerContext(new DbContextOptions<CustomerContext>{});
3、依賴倒置原則
依賴高層業務,不依賴低層業務的具體實現,而依賴於具體的抽象
CustomerController是高層業務的一個組件,依賴於CustomerContext是一個低層數據庫的實現,如果現在需要把EF換成一個內存的實現或者mysql,需要修改CustomerController類,風險很大,所以應該依賴於低層業務的抽象
把低層業務方法抽象,比如查找,新增,抽象出一個接口,當不需要使用EF的時候,使用內存的實現替換
private ICustomerRepository _customerRepository;
public CustomerController()
{
_customerRepository = new EfCustomerRepository(
new CustomerContext(new DbContextOptions<CustomerContext>{}));
}
任務18:控制反轉
實現依賴注入的方式不由自己決定,而是交給一個IOC容器,需要什麼由容器傳入,比如生產環境需要使用EF,則由容器傳入一個EfCustomerRepository,而測試環境需要使用內存級別的,則傳入一個MemoryCustomerRepository
private ICustomerRepository _customerRepository;
public CustomerController(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
任務19:單元測試
var repository = new Data.MemoryCustomerRepository();
var controller = new CustomerController(repository);// 通過外部控制Controller裏面的依賴
var customer = new Model.Customer()
{
FirstName = "Mingson",
LastName = "Zheng",
Phone = "123456789",
};
var result = controller.Add(customer);
Assert.IsType<OkResult>(result);// 正確結果
var resultBad = controller.Add(customer);
Assert.IsType<BadRequestObjectResult>(resultBad);// 錯誤結果
通過單元測試可以得知修改Bug過程中是否誤刪代碼,導致原來通過的測試現在無法通過。
任務20:DI初始化的源碼解讀
Microsoft.AspNetCore.Hosting.WebHostBuilder
/// <summary>
/// Builds the required services and an <see cref="T:Microsoft.AspNetCore.Hosting.IWebHost" /> which hosts a web application.
/// </summary>
public IWebHost Build()
{
......
// 第一步,build
IServiceCollection serviceCollection1 = this.BuildCommonServices(out hostingStartupErrors);
// 第二步,獲取ServiceCollection,ServiceProvider
IServiceCollection serviceCollection2 = serviceCollection1.Clone();
IServiceProvider providerFromFactory = GetProviderFromFactory(serviceCollection1);
......
// 第三步,new一個WebHost,傳入ServiceCollection,ServiceProvider
WebHost webHost = new WebHost(serviceCollection2, providerFromFactory, this._options, this._config, hostingStartupErrors);
......
// 第四步,webHost初始化方法Initialize
webHost.Initialize();
......
}
第一步BuildCommonServices中new一個ServiceCollection就是在startup接口中使用
private IServiceCollection BuildCommonServices(
out AggregateException hostingStartupErrors)
{
......
ServiceCollection services = new ServiceCollection();
// new完之後添加一些初始化操作
......
return (IServiceCollection) services;
}
IStartup接口
namespace Microsoft.AspNetCore.Hosting
{
public interface IStartup
{
IServiceProvider ConfigureServices(IServiceCollection services);
void Configure(IApplicationBuilder app);// 配置管道
}
}
第四步,webHost初始化方法Initialize
public void Initialize()
{
......
this.EnsureApplicationServices();
......
}
private void EnsureApplicationServices()
{
......
this.EnsureStartup();
this._applicationServices = this._startup.ConfigureServices(this._applicationServiceCollection);
}
private void EnsureStartup()
{
if (this._startup != null)
return;
this._startup = this._hostingServiceProvider.GetService<IStartup>();
if (this._startup == null)
throw new InvalidOperationException(string.Format("No startup configured. Please specify startup via WebHostBuilder.UseStartup, WebHostBuilder.Configure, injecting {0} or specifying the startup assembly via {1} in the web host configuration.", (object) "IStartup", (object) "StartupAssemblyKey"));
}
任務21:依賴注入的使用
瞭解ASP.NET Core 依賴注入,看這篇就夠了:
http://www.jessetalk.cn/2017/11/06/di-in-aspnetcore/