欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-12 19:50:22
asp.net core依赖注入解读&使用autofac替代实现 1. 前言 2. asp.net core 中的di方式 3. autofac实现和自定义实现扩展方法 3.1 安装auto...
asp.net core依赖注入解读&使用autofac替代实现 1. 前言 2. asp.net core 中的di方式 3. autofac实现和自定义实现扩展方法 3.1 安装autofac 3.2 创建容器并注册依赖 

1. 前言

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

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

services.addtransient

services.addscoped

services.addsingleton

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

transient
transient 服务在每次请求时被创建,它最好被用于轻量级无状态服务(如我们的repository和applicationservice服务) scoped
scoped 服务在每次请求时被创建,生命周期横贯整次请求 singleton
顾名思义,singleton(单例) 服务在第一次请求时被创建(或者当我们在configureservices中指定创建某一实例并运行方法),其后的每次请求将沿用已创建服务。如果开发者的应用需要单例服务情景,请设计成允许服务容器来对服务生命周期进行操作,而不是手动实现单例设计模式然后由开发者在自定义类中进行操作。

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

tips:startup.cs是什么,详见asp.net core 介绍和项目解读

aspnet-core-中的di方式">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视图的代码

    # controller
    public 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 
    
    
        guiditem shows

        transientitem: @viewbag.transientitem

        scopeditem: @viewbag.scopeditem

        singletonitem: @viewbag.singletonitem
    

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

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

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

# 新建guiditempartial.cshtml视图,复制如下代码,使用@inject注入依赖
@using dependencyinjection.iapplicationservice

@inject iguidtransientappservice transientappservice
@inject iguidscopedappservice guidscopedappservic
@inject iguidsingletonappservice guidsingletonappservice


    
        guiditem shows

        transientitem: @transientappservice.guiditem()

        scopeditem: @guidscopedappservic.guiditem()

        singletonitem: @guidsingletonappservice.guiditem()
    


# 原先的index视图
@{
    viewdata["title"] = "home page";
}

@html.partial("guiditempartial")

@html.partial("guiditempartial")

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

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

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().as();
builder.registertype().as().instanceperlifetimescope();
builder.registertype().as().singleinstance();

builder.populate(services);
this.applicationcontainer = builder.build();

return new autofacserviceprovider(this.applicationcontainer);

值得注意的几点:

创建autofac容器时不要忘了将configureservices的返回值修改为iserviceprovider 对应asp.net core提及的不同的生命周期,autofac也定义了对应的扩展方法,如instanceperlifetimescope等,默认为transient模式,包括entityframwork等context也是该种模式 autofac core不支持从view中注入,但是可以和asp.net core自带ioc容器配合使用 autofac core版本和传统的asp.net mvc项目版本的区别