ASP.NET Core依赖注入解读amp;使用Autofac替代实现

1. 前言

关于IoC模式(控制反转)和DI技术(依赖注入),我们已经见过很多的探讨,这里就不再赘述了。比如说必看的Martin Fowler《IoC 容器和 Dependency Injection 模式》,相关资料链接都附于文章末尾。其中我非常赞同Artech的说法"控制更多地体现为一种流程的控制",而依赖注入技术让我们的应用程序实现了松散耦合。

ASP.NET Core本身已经集成了一个轻量级的IOC容器,开发者只需要定义好接口后,在Startup.cs的ConfigureServices方法里使用对应生命周期的绑定方法即可,常见方法如下

services.AddTransient<IApplicationService,ApplicationService>
services.AddScoped<IApplicationService,ApplicationService>
services.AddSingleton<IApplicationService,ApplicationService>

对于上述的三种DI注入方式,官方也给出了详细的解释,我来简单翻译一下

  • Transient
    Transient 服务在每次请求时被创建,它最好被用于轻量级无状态服务(如我们的Repository和ApplicationService服务)

  • Scoped
    Scoped 服务在每次请求时被创建,生命周期横贯整次请求

  • Singleton
    顾名思义,Singleton(单例) 服务在第一次请求时被创建(或者当我们在ConfigureServices中指定创建某一实例并运行方法),其后的每次请求将沿用已创建服务。如果开发者的应用需要单例服务情景,请设计成允许服务容器来对服务生命周期进行操作,而不是手动实现单例设计模式然后由开发者在自定义类中进行操作。

在这之后,我们便可以将服务通过构造函数注入或者是属性注入的方式注入到Controller,View(通过使用@inject),甚至是Filter中(以前使用Unity将依赖注入到Filter真是一种痛苦)。话不多说,先来体验一把

Tips:Startup.cs是什么,详见ASP.NET Core 介绍和项目解读

2. ASP.NET Core 中的DI方式

大多项目举例依赖注入的生命周期演示时,都会采取可变Guid来作为返回显示,此次示例也会这样处理。我们先定义一个IGuidAppService接口,里面定义基接口和三种注入模式的接口

    public interface IGuidAppService{        
        Guid GuidItem();}  
 
 
   public interface IGuidTransientAppService : IGuidAppService{}    
   
   public interface IGuidScopedAppService : IGuidAppService{}  
   
    public interface IGuidSingletonAppService : IGuidAppService{}

同样的,在GuidAppService中定义其实现类。这里为了直观显示每次请求的返回值,采取如下代码

    public class GuidAppServiceBase : IGuidAppService    {      
      private readonly Guid _item;        public GuidAppServiceBase(){_item = Guid.NewGuid();}    
      
       public Guid GuidItem(){        
          return _item;}}    
          public class GuidTransientAppService : GuidAppServiceBase, IGuidTransientAppService    {}    
          public class GuidScopedAppService : GuidAppServiceBase, IGuidScopedAppService    {}    
          public class GuidSingletonAppService : GuidAppServiceBase, IGuidSingletonAppService    {}

最后是Controller和View视图的代码

    # Controllerpublic class HomeController : Controller{       
    private readonly IGuidTransientAppService _guidTransientAppService; //#构造函数注入//private  IGuidTransientAppService _guidTransientAppService { get; } #属性注入private readonly IGuidScopedAppService _guidScopedAppService;    
        private readonly IGuidSingletonAppService _guidSingletonAppService;        public HomeController(IGuidTransientAppService guidTransientAppService,            IGuidScopedAppService guidScopedAppService, IGuidSingletonAppService guidSingletonAppService)    
   
{_guidTransientAppService = guidTransientAppService;_guidScopedAppService = guidScopedAppService;_guidSingletonAppService = guidSingletonAppService;}    
       public IActionResult Index()  
        
{ViewBag.TransientItem = _guidTransientAppService.GuidItem();ViewBag.ScopedItem = _guidScopedAppService.GuidItem();ViewBag.SingletonItem = _guidSingletonAppService.GuidItem();        
           return View();}}    # Index View <div class="row"><div ><h2>GuidItem Shows</h2><h3>TransientItem: @ViewBag.TransientItem</h3><h3>ScopedItem: @ViewBag.ScopedItem</h3><h3>SingletonItem: @ViewBag.SingletonItem</h3></div> </div>

之后我们打开两个浏览器,分别刷新数次,也只会发现“TransientItem”和“ScopedItem”的数值不断变化,“SingletonItem”栏的数值是不会有任何变化的,这就体现出单例模式的作用了,示例图如下

但是这好像还不够,要知道我们的Scoped的解读是“生命周期横贯整次请求”,但是现在演示起来和Transient好像没有什么区别(因为两个页面每次浏览器请求仍然是独立的,并不包含于一次中),所以我们采用以下代码来演示下(同一请求源)

# 新建GuidItemPartial.cshtml视图,复制如下代码,使用@inject注入依赖
@using DependencyInjection.IApplicationService @inject IGuidTransientAppService TransientAppService @inject IGuidScopedAppService GuidScopedAppServic @inject IGuidSingletonAppService GuidSingletonAppService<div class="row"><div><h2>GuidItem Shows</h2><h3>TransientItem: @TransientAppService.GuidItem()</h3><h3>ScopedItem: @GuidScopedAppServic.GuidItem()</h3><h3>SingletonItem: @GuidSingletonAppService.GuidItem()</h3></div></div># 原先的index视图@{ViewData["Title"] = "Home Page"; }@Html.Partial("GuidItemPartial")@Html.Partial("GuidItemPartial")

依然是 Ctrl+F5 调试运行,可以发现“ScopedItem”在同一请求源中是不会发生变化的,但是“TransientItem”依然不断变化,理论仍然是支持的

3. Autofac实现和自定义实现扩展方法

除了ASP.NETCore自带的IOC容器外,我们还可以使用其他成熟的DI框架,如Autofac,StructureMap等(笔者只用过Unity,Ninject和Castle,Castle也是使用ABP时自带的)。

3.1 安装Autofac

首先在project.json的dependency节点中加入Autofac.Extensions.DependencyInjection引用,目前最新版本是4.0.0-rc3-309

3.2 创建容器并注册依赖

在Startup.cs中创建一个public IContainer ApplicationContainer { get; private set; }对象,并把ConfigureServices返回类型改为IServiceProvider,然后复制以下代码进去,也可以实现相关功能

var builder = new ContainerBuilder();//注意以下写法builder.RegisterType<GuidTransientAppService>().As<IGuidTransientAppService>();
builder.RegisterType<GuidScopedAppService>().As<IGuidScopedAppService>().InstancePerLifetimeScope();
builder.RegisterType<GuidSingletonAppService>().As<IGuidSingletonAppService>().SingleInstance();builder.Populate(services);
this.ApplicationContainer = builder.Build();return new AutofacServiceProvider(this.ApplicationContainer);

值得注意的几点:

  1. 创建Autofac容器时不要忘了将ConfigureServices的返回值修改为IServiceProvider

  2. 对应ASP.NET Core提及的不同的生命周期,Autofac也定义了对应的扩展方法,如InstancePerLifetimeScope等,默认为Transient模式,包括EntityFramwork等Context也是该种模式

  3. Autofac Core不支持从View中注入,但是可以和ASP.NET Core自带IOC容器配合使用

  4. Autofac Core版本和传统的ASP.NET MVC项目版本的区别

4. 参考链接

  • IoC 容器和 Dependency Injection 模式

  • 控制反转—维基百科

  • DependencyInjection-GitHub

  • ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理

  • Dependency Injectionf!


原文地址:http://www.cnblogs.com/Wddpct/p/5764511.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328790.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 中的伪共享详解及解决方案

转载自 Java 中的伪共享详解及解决方案1. 什么是伪共享 CPU 缓存系统中是以缓存行&#xff08;cache line&#xff09;为单位存储的。目前主流的 CPU Cache 的 Cache Line 大小都是 64 Bytes。在多线程情况下&#xff0c;如果需要修改“共享同一个缓存行的变量”&#xff0c;就…

ServletActionContext.getRequest().getSession() 和 ActionContext.getContext().getSession()的区别

ServletActionContext.getRequest().getSession() 和 ActionContext.getContext().getSession() ActionContext.getContext().getSession(); 这个方法获取的session是struts封装过的一个Map类型的session&#xff0c;只能调用put()方法缓存数据。 ServletActionContext.getRe…

弯下腰,拾起你无价的尊严

内容来源于网络&#xff0c;侵删&#xff01; 很久以前&#xff0c;一位挪威青年男子漂洋过海到了法国&#xff0c;他要报考著名的巴黎音乐学院。 考试的时候&#xff0c;尽管他竭力将自己的水平发挥到最佳状态&#xff0c;但主考官还是没能录取他。 身无分文的青年男子来到学…

在离线环境中发布.NET Core至Windows Server 2008

0x00 写在开始 之前一篇博客中写了在离线环境中使用.NET Core&#xff0c;之后一边学习一边写了一些页面作为测试&#xff0c;现在打算发布一下试试。看了下官方给出的发布教程感觉挺详细的了&#xff08;https://docs.asp.net/en/latest/publishing/iis.html&#xff09;&…

输入一个英文句子,翻转句子中单词的顺序 例如输入“I am a student.”,则输出“student. a am I”。

package com.atguigu.java; //输入一个英文句子&#xff0c;翻转句子中单词的顺序&#xff0c;但单词内字符的顺序不变。句子中单词以空格符隔开。 //为简单起见&#xff0c;标点符号和普通字母一样处理。 //例如输入“I am a student.”&#xff0c;则输出“student. a am …

Java 父类子类的对象初始化过程

转载自 Java 父类子类的对象初始化过程摘要: Java基本的对象初始化过程&#xff0c;子类的初始化&#xff0c;以及涉及到父类和子类的转化时可能引起混乱的情况。1. 基本初始化过程&#xff1a;对于一个简单类的初始化过程是&#xff1a;static 修饰的模块&#xff08;static变…

HttpServletRequest中getAttribute()和getParameter()的区别

一、数据据来源不同 HttpServletRequest类有setAttribute()方法&#xff0c;而 没有setParameter()方法get/setParameter是在对你的页面中的表单元素进行操作&#xff0c;获取的是这个表单元素中的值&#xff0c;是某个表单提交过去的数据get/setAttribute是对你页面中自己定义…

使用VS Code开发调试.NET Core 多项目

使用Visual Studio Code(VS Code)开发调试.NET Core和ASP.NET Core 多项目multiple project。 之前讲解过如果使用Visual Studio Code(VS Code) 开发单个.NET Core和ASP.NET Core项目&#xff0c;大家也都知道如何开发。 多项目可能有些人还不大了解&#xff0c;今天给大家介绍…

git 在ssh情况下提交代码

git --version --git版本 用户目录&#xff08;~/&#xff09; vim ~/.gitconfig --编辑用户目录&#xff08;~/&#xff09;下的 .gitconfig文件 --输入i 进入编辑模式 [user] nameRosen email1091947832qq.com [alias] --配置别名 cocheckout 切换分…

如果你也会C#,那不妨了解下F#(1):F# 数据类型

简单介绍 F#&#xff08;与C#一样&#xff0c;念作“F Sharp”&#xff09;是一种基于.Net框架的强类型、静态类型的函数式编程语言。可以说C#是一门包含函数式编程的面向对象编程语言&#xff0c;而F#是一门包含面向对象的函数式编程语言。可以查看官方文档了解更多信息。 本系…

String path = request.getContextPath()和String basePath = request.getScheme()

在JSP当中我们会用此代码来拼接路径&#xff0c;所以此语句是用来拼装当前网页的相对路径的。 <% String path request.getContextPath(); String basePath request.getScheme()"://"request.getServerName()":"request.getServerPort()path"/&…

Java中的函数传递

转载自 Java中的函数传递在C和C中&#xff0c;函数的传递可以通过函数指针来实现。在C#中&#xff0c;函数传递可以通过委托、Action、Func来实现。Java中没有函数指针、没有委托&#xff0c;那函数要如何传递呢&#xff1f; 可以通过以下两种方式实现。 1、通过handler&#…

使用Nginx搭建图片服务器(windows7)

1.进入官网下载nginx压缩包&#xff0c;解压后目录如下 2.在解压后的conf/nginx.conf配置文件中&#xff0c;添加添加或者修改带有颜色地方的代码 #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/e…

配置mybatis-plus逻辑删除

一、在pom文件里导入依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis.plus.boot.starter}</version> </dependency>二、在yml文件或者在properties…

Jexus支持HTTPS协议

众所周知&#xff0c;在HTTPS页面请求HTTP资料的时候&#xff0c;现代浏览器会拦截&#xff0c;提示用户是否继续&#xff0c;或者直接拦截&#xff0c;提示都不出来。 最近给自己做了个快速书签工具&#xff0c;点击书签就直接把书签发送到服务器地址&#xff0c;然后保存到我…

java面向对象高级分层实例_实体类

package bdqn.studentSys.entity; /*** 学生实体类* author Administrator**/ public class Student {private String name;//姓名private String pwd;//密码private int age;//年龄private int stuno;public int getStuno() {return stuno;}public void setStuno(int stuno) {…

虚拟机安装xp经验

虚拟机安装xp经验 1.打开vm软件 2.创建虚拟机 选中单个文件 用pe系统打开 3.用驱动精灵 创建2个分区50g 50g (一定要创建2个gost版要在d盘分配文件夹的)分配8g内存 4核cpu 4.将系统安装到分区上

JAVA实现汉字转换为拼音 pinyin4j/JPinyin

转载自 JAVA实现汉字转换为拼音 pinyin4j/JPinyin在项目中经常会遇到需求用户输入汉字后转换为拼音的场景&#xff0c;比如说通讯录&#xff0c;就会要求按名字首字符发音排序&#xff0c;如果自己写实现这方面的功能是个很好大的工程&#xff0c;还好网上有公开的第三方jar支…

给数据库表字段设置默认值

一、在数据库表中的操作方法 当表中的字段是varchar字段时可以这样设置&#xff1a; 例如我要设置stats&#xff08;状态这个字段默认为"1"&#xff09;&#xff0c;在创建表的时候sql语句可以这样写 stats varchar(1) CHARACTER SET utf8 NOT NULL DEFAULT 1 COMM…

Myeclipse创建第一个web项目

创建web项目 web project 创建java项目 选java project