ASP.NET5設計的時候就是以DI爲基礎的,它能夠利用內建的框架在Startup類的方法中,把依賴注入進去。應用服務也能夠被配置的注入。默認的服務容器提供一些基本的功能,它並不打算代替現代主流的DI框架。git
1. 什麼是Dependency Injection?github
DI的概念相信你們已經瞭解了,不瞭解的能夠查一下資料。咱們來說一講ASP.NET 5內建的DI容器。json
ASP.NET5包含一個簡單的內建容器,它的表現形式是IServiceProvider接口, 默認支持構造函數的注入,ASP.NET經過它注入相關的服務類。ASP.NET的容器引用的類型,在它裏面叫作服務,在下面的內容當中,服務就固然於ASP.NET Ioc容器當中管理的類型。你能夠經過Startup類中的CongureServices注入內建的服務。框架
2. 構架提供的服務ide
Startup類中的ConfigureServices方法定義了應用程序須要的服務,像Entity Framework, MVC等,它由IServiceCollection的擴展方法來添加. 例如:函數
public void ConfigureServices(IServiceCollection services)測試
{ui
services.AddEntityFramework().AddSqlServer().AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
spa
services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();
設計
servies.AddMvc();
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
3. 註冊你本身的服務
上面的代碼當中:
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
AddTransient方法用來添加抽象類型到具體的類型映射,而且申明瞭它的生命週期,在你註冊服務時,選擇合適的對象生命週期很重要。
咱們來看一個例子:
public class CharactersController : Controller
{
private readonly ICharacterRepository _characterRepository;
public CharactersController(ICharacterRepository characterRepository)
{
_characterRepository = characterRepository;
}
public IActionResult Index()
{
var characters = _characterRepository.ListAll();
return View(characters);
}
}
public interface ICharacterRepository
{
IEnumberable<Character> ListAll();
}
public class CharacterRepository : ICharacterRepository
{
private readonly ApplicationDbContext _dbContext;
public CharacterRepository(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public IEnumerable<Character> ListAll()
{
return _dbContext.Characters.AsEnumberable();
}
}
注意CharacterRepository的構造函數當中須要一個ApplicationDbContext,像它這樣的注入方式並不常見,在每一個申請當中,容器負責提供每個對象的具體依賴對象。
在這個例子當中,ICharacterRepository和ApplicationDbContext都必須在ConfigureServices當中被註冊。
services.AddEntityFramework().AddSqlServer().AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration["Data:DefaultCOnnection:ConnectionString"]));
services.AddScoped<ICharacterRepository, CharacterRepository>();
EntityFramework context 應該被以Scoped的生命週期增長到容器當中,Repositories用到EntityFramework, 因此它應該使用同一個生命週期。
4. 服務的生命週期和註冊選項
ASP.NET 服務能夠配置對象的生命週期以下所示:
Transient
它是意思每一個請求都建立一個新的對象,這個適合輕量的,無狀態的服務。
Scoped
每一個申請只建立一個對象。
Singleton
它是在首次被申請調用時建立一次, 之後全部的請求都會被重用,若是你的應用程序須要單例,推薦使用些方法,而不要本身實現單例模式。
Instance
它與Singleton類似 ,惟一的區別是,Instance在ConfigureServices的時候就建立了,而Singleton要在第一次請求的時候才建立。
5. 請求的服務和應用服務
ASP.NET當中服務在HttpContext的ApplicationServices和RequestServices中可以獲得
RequestServices裏的服務是配置和請求你的應用程序的一部分,ApplicationServices裏的服務是被限制在應用程序啓動的時候的服務,任何Scoped的應用程序都能在RequestServices獲得,可是在ApplicationServices裏得不到。當你的對象申明依賴時,這些依賴在RequestServices裏可以獲得,在ApplicationServices裏得不到,
通常地,你不須要直接用這些屬性,而能夠經過構造函數注入。
6. 用DI設計你的服務
你應該用DI來設計你的應用,不要用函數狀態的靜態方法調用,或者直接地實例化你的服務。用DI ,你的類比較小,並且是靈活的,可測試的。
當你一個類依賴不少的時候,你就要意識到是否違反了單一職責原則。你能夠重構你的代碼,把一些依賴移到其它的新類當中。注意在你Controler 類當中應該注意在UI上面,所以你的業務邏輯和數據訪問經過UI的職責的分來被相應地合理分開。
當用到數據訪問時,你能夠注入EntityFramework的DbContext類型到你的controllers裏面,不過首先你要確保EF在Startup類中被配置了,然而,避免在UI裏直接使用DbContext, 你應該把它放到抽象當中去,例如Repository的接口中去。這樣能夠減小你的應用和數據的耦合。也能使你的應用程序能夠很容易地被測試。
7 替代默認的服務容器
在ASP.NET當中,你能夠很容易地替代內建的服務容器,在ConfigureServices方法當中通常返回void, 可是若是它返回IServiceProvider, 一個不一樣的容器能夠被返回,咱們以autofac爲例。
首選,你必須在project.json加以下的配置:
"dependencies":{
"Autofac": "4.0.0-beta8",
"Autofac.Framework.DependencyInjection": "4.0.0-beta8"
},
接下來,改寫ConfigureServices
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Add Autofac
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return container.Resolve<IServiceProvider>();
}
最後,配置Autofac在DefaultModule裏面
public class DefaultModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<CharacterRepository>.As<ICharacterRepository>();
}
}
如今,Autoface被用來生成你的服務在DI裏面。
ASP.NET 5/DNX Containers
Autofac.Dnx http://autofac.org
StructureMap.Dnx http://structuremap.github.io
8. 建議
* DI用於複雜的依賴,控制器、服務、倉儲等
* 不要直接利用DI存儲數據和配置
* 不要靜態地訪問服務
* 不要在應用程序當中手動使用服務定位
* 不要靜態地訪問HttpContext
記住,不要把DI和static/global對應混用,不然你就感受不到DI的好處了