ASPNET5的依賴注入

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的好處了

相關文章
相關標籤/搜索