ASP.NET5设计的时候就是以DI为基础的,它可以利用内建的框架在Startup类的方法中,把依赖注入进去。应用服务也可以被配置的注入。默认的服务容器提供一些基本的功能,它并不打算代替现代主流的DI框架。

1. 什么是Dependency Injection?

DI的概念相信大家已经了解了,不了解的可以查一下资料。我们来讲一讲ASP.NET 5内建的DI容器。

ASP.NET5包含一个简单的内建容器,它的表现形式是IServiceProvider接口, 默认支持构造函数的注入,ASP.NET通过它注入相关的服务类。ASP.NET的容器引用的类型,在它里面叫做服务,在下面的内容当中,服务就当然于ASP.NET Ioc容器当中管理的类型。你可以通过Startup类中的CongureServices注入内建的服务。

2. 构架提供的服务

Startup类中的ConfigureServices方法定义了应用程序需要的服务,像Entity Framework, MVC等,它由IServiceCollection的扩展方法来添加. 例如:

public void ConfigureServices(IServiceCollection services)

{

  services.AddEntityFramework().AddSqlServer().AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

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

ASPNET5的依赖注入的更多相关文章

  1. ASPNET5 依赖注入(Dependency Injection)

    依赖注入一直是asp.net web框架(Web API,SignalR and MVC)中不可或缺的一部分,但是在以前,这个框架都是各自升级,都有各自的依赖注入实现方式,即使Katana项目想通过O ...

  2. webapi - 使用依赖注入

    本篇将要和大家分享的是webapi中如何使用依赖注入,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity:由于快过年这段时间打算 ...

  3. ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入

    原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...

  4. 在WPF中使用依赖注入的方式创建视图

    在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...

  5. MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息

    MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...

  6. .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整-控制反转和依赖注入的使用

    再次调整项目架构是因为和群友dezhou的一次聊天,我原来的想法是项目尽量做简单点别搞太复杂了,仅使用了DbContext的注入,其他的也没有写接口耦合度很高.和dezhou聊过之后我仔细考虑了一下, ...

  7. ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法

    在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...

  8. ASP.NET Core中如影随形的”依赖注入”[上]: 从两个不同的ServiceProvider说起

    我们一致在说 ASP.NET Core广泛地使用到了依赖注入,通过前面两个系列的介绍,相信读者朋友已经体会到了这一点.由于前面两章已经涵盖了依赖注入在管道构建过程中以及管道在处理请求过程的应用,但是内 ...

  9. 模拟AngularJS之依赖注入

    一.概述 AngularJS有一经典之处就是依赖注入,对于什么是依赖注入,熟悉spring的同学应该都非常了解了,但,对于前端而言,还是比较新颖的. 依赖注入,简而言之,就是解除硬编码,达到解偶的目的 ...

随机推荐

  1. Facebook IV Winner's Interview: 1st place, Peter Best (aka fakeplastictrees)

    Facebook IV Winner's Interview: 1st place, Peter Best (aka fakeplastictrees) Peter Best (aka fakepla ...

  2. JavaScript Maintainable

    1. Avoid conflict with Native Variable namespace

  3. iOS开发学习--纯代码 UIScrollView 无限循环的实现——代码类封装

    一个简单的利用UIScrollView 实现的无线滚动banner,下面的代码实现,因为封装问题,对两个及一下的view 支持出了一点问题(view是传参进来的,不可以生成两份),但是原理是正确的,智 ...

  4. QT中关闭应用程序和窗口的函数(quit(),exit()以及close()的区别)

    使用QT编辑界面,其中带来很大方便的一点就是Qt中自带丰富的.种类齐全的类及其功能函数,程序员可以在编辑程序的过程中简单地直接调用.关于窗口关闭的操作,在这里指出常用的三个槽,即quit(),exit ...

  5. Maven实战五

    转载:http://www.iteye.com/topic/1123232 我们项目中用到的jar包可以通过依赖的方式引入,构建项目的时候从Maven仓库下载即可. 1. 依赖配置    依赖可以声明 ...

  6. mysq 日期相减

    mysql> desc test200; +---------------+----------+------+-----+---------+-------+ | Field | Type | ...

  7. Record Locks

    Record Locks 记录锁: 记录锁是一个锁在一个Index记录上,比如 SELECT c1 FOR UPDATE FROM t WHERE c1 = 10; 阻止任何其他事务inserting ...

  8. 图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

    4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status ...

  9. 网络流(最大流) CQOI 2015 BZOJ 3931 网络吞吐量

    3931: [CQOI2015]网络吞吐量 Description 路由是指通过计算机网络把信息从源地址传输到目的地址的活 动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器 ...

  10. 在ASP.Net MVC 中,如何在Global.asax中配置一个指向Area内部的默认Route

    ASP.Net MVC 中配置Route的时候可以设置一个默认的Route. 比如我要在输入http://localhost的时候默认进入http://localhost/home/index.可以在 ...