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

相关文章
相关标签/搜索