ASP.NET Core依赖注入(DI)讲解

ASP.NET Core的底层设计支持和使用依赖注入。ASP.NET Core 应用程序可以利用内置的框架服务将服务注入到启动类的方法中,并且应用程序服务也可以配置注入。由ASP.NET Core 提供的默认服务容器提供了最小功能集,并不是取代其他容器。

1.浅谈依赖注入

依赖注入(Dependency injection,DI)是一种实现对象和依赖者之间松耦合的技术,将类用来执行其操作的这些对象以注入的方式提供给该类,而不是直接实例化依赖项或者使用静态引用。一般情况,类会通过构造函数声明器2依赖关系,允许他们遵循显示依赖原则。这种方法称为“构造函数注入”。

当类的设计使用DI思想时,他们的耦合更加松散,因为他们没有对他们的合作者直接硬编码的依赖。这遵循“依赖倒置原则”,其中指出,高层模块不应该依赖于底层模块:两者都依赖于抽象。

类要求在他们构造时向其提供抽象(通常是接口),而不是引用特定的实现。提取接口的依赖关系和提供接口的实现作为参数也是“策略设计模式”的一个示例。

当一个类被用来创建类及其相关的依赖关系时,这个成为容器(containers),或者称为控制反转(Inversion of Control, IoC)容器,或者依赖注入容器。容器本质上是一个工厂,负责提供向它请求的类型的实例。如果一个给定类型声明它具有依赖关系,并且容器已经被配置为其提供依赖关系,那么它将把创建依赖关系作为创建请求实例的一部分。除了创建对象的依赖关系外,容器通常还会管理应用程序中对象的生命周期。

ASP.NET Core 包含一个默认支持构造函数注入的简单内置容器,ASP.NET 的容器指的是它管理的类型services,可以在Startup类的ConfigureServices方法中配置内置容器的服务。

2. 使用ASP.NET Core提供的服务

Startup类的ConfigureServices方法负责定义应用程序将使用的服务,包括平台自带的功能,比如,Entity Framework Core 和 ASP.NET Core MVC。除了IServiceCollection提供的几个服务之外,可以使用一些扩展方法(AddDbContext,AddMvc,AddTransient等)向容器添加和注册额外服务:

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddDbContext<AccessManagementContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                providerOptions => providerOptions.EnableRetryOnFailure()));
            services.AddTransient<ICompanyServices, CompanyServices>();

        }

ASP.NET Core 提供的功能和中间件,遵循约定使用一个单一的AddService扩展方法来注册所有该功能所需的服务。

3.注册自己的服务

我们可以按照 services.AddTransient<ICompanyServices, CompanyServices>(); 这种写法注册自己的服务。第一个范型类型表示将要从容器中请求的类型(通常是一个接口)。第二个范型类型表示将由容器实例化并且用于完成请求的具体类型。

AddTransient 方法用于将抽象类型映射到为每一个需要它的对象分别实例化的具体服务。为注册的每一个服务选择合适的生命周期很重要,后面会介绍到。

下面是示例是注册自己的服务:

1.接口

public interface IAccountServices
    {
        Task<List<AccountViewModel>> GetList();
    }

2.实现类

public class AccountServices:IAccountServices
    {
        AccessManagementContext _context;
        public AccountServices(AccessManagementContext context)
        {
            _context = context;//在构造函数中注入
        }

        public async Task<List<Account>> GetList()
        {
            try
            {
                var query = _context.Account.ToListAsync();
                 return query ;
            }
            catch (Exception ex)
            {
                return null;
            }

        }
}

3.在ConfigureServices中注册自定义的服务和EF上下文AccessManagementContext

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddDbContext<AccessManagementContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                providerOptions => providerOptions.EnableRetryOnFailure()));
            services.AddTransient<IAccountServices,AccountServices>();

        }

4.在Controller构造函数中依赖注入

public class AccountController : Controller
    {
        private IAccountServices _accountServices;
        public AccountController(IAccountServices accountServices)
        {
            _accountServices = accountServices;
        }
        // GET: Account
        public async Task<ActionResult> Index()
        {
            var vms = await _accountServices.GetList();
            return View(vms);
        }

4.服务的生命周期和注册选项

ASP.NET 服务生命周期:

  • 1.Transient 瞬时
    Transient 生命周期服务在他们每次请求时被创建。适合轻量级,无状态的服务。
  • 2.Scoped 作用域
    Scoped生命周期在每次请求时创建一次。
  • 3.Singleton 单例
    Singleton 生命周期服务在它们第一次请求时创建,并且每个后续请求使用相同的实例。

服务可以用多种方式在容器中注册,除了之前的注册方法,还可以指定一个工厂,它将被用来创建需要的实例。后面会详细介绍其他的注册方法。

下面用一个简单的示例介绍每个生命周期:

1.创建接口:

namespace MVCTest.Interfaces
{
    public interface IOperation
    {
        /// <summary>
        /// 唯一标识
        /// </summary>
        Guid OperationId { get;  }
    }

    public interface IOperationTransient: IOperation
    {
    }

    public interface IOperationScoped : IOperation
    {
    }

    public interface IOperationSingleton : IOperation
    {
    }

    public interface IOperationInstance : IOperation
    {
    }
}

2.实现类

/// <summary>
    /// 实现所有接口
    /// </summary>
    public class Operation: IOperation, IOperationTransient,
        IOperationScoped, IOperationSingleton, IOperationInstance
    {
        public Operation()
        {
            OperationId = Guid.NewGuid();
        }
        public Operation(Guid operationId)
        {
            if (operationId == null)
            {
                OperationId = Guid.NewGuid();
            }
            OperationId = operationId;
        }

        public Guid OperationId { get; }
    }

3.注册到容器

public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IOperationTransient, Operation>();
            services.AddScoped<IOperationScoped, Operation>();
            services.AddSingleton<IOperationSingleton, Operation>();
            services.AddSingleton<IOperationInstance, Operation>();
            services.AddTransient<OperationServices, OperationServices>();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

4.上面还注册了 OperationServices ,用来测试单例模式(单例生命周期服务中所有请求使用第一次实例化的服务)和 作用域生命周期服务在每次请求时只创建一次,不管几个地方用到实例

public class OperationServices
    {
        public IOperationTransient OperationTransient { get;  }
        public IOperationScoped OperationScoped { get;  }
        public IOperationSingleton OperationSingleton { get;  }
        public IOperationInstance OperationInstance { get;  }

        public OperationServices(IOperationTransient operationTransient,
            IOperationScoped operationScoped,
            IOperationSingleton operationSingleton,
            IOperationInstance operationInstance)
        {
            OperationTransient = operationTransient;
            OperationScoped = operationScoped;
            OperationSingleton = operationSingleton;
            OperationInstance = operationInstance;
        }
    }

5.在Controller中使用

public class OperationController : Controller
    {
        public IOperationTransient OperationTransient { get; }
        public IOperationScoped OperationScoped { get; }
        public IOperationSingleton OperationSingleton { get; }
        public IOperationInstance OperationInstance { get; }
        public OperationServices _operationServices;

        public OperationController(IOperationTransient operationTransient,
            IOperationScoped operationScoped,
            IOperationSingleton operationSingleton,
            IOperationInstance operationInstance,
            OperationServices operationServices)
        {
            OperationTransient = operationTransient;
            OperationScoped = operationScoped;
            OperationSingleton = operationSingleton;
            OperationInstance = operationInstance;
            _operationServices = operationServices;
        }
        // GET: Operation
        public ActionResult Index()
        {
            ViewBag.OperationTransient = OperationTransient;
            ViewBag.OperationScoped = OperationScoped;
            ViewBag.OperationSingleton = OperationSingleton;
            ViewBag.OperationInstance = OperationInstance;
            ViewBag._operationServices = _operationServices;
            return View();
        }
}

6.Index显示

@{
    ViewData["Title"] = "Index";
}

<div>
    <h1>Controller Operations</h1>
    <h2>OperationTransient: @ViewBag.OperationTransient.OperationId</h2>
    <h2>OperationScoped: @ViewBag.OperationScoped.OperationId</h2>
    <h2>OperationSingleton: @ViewBag.OperationSingleton.OperationId</h2>
    <h2>OperationInstance: @ViewBag.OperationInstance.OperationId</h2>
</div>
<div>
    <h1>Services Operations</h1>
    <h2>OperationTransient: @ViewBag._operationServices.OperationTransient.OperationId</h2>
    <h2>OperationScoped: @ViewBag._operationServices.OperationScoped.OperationId</h2>
    <h2>OperationSingleton: @ViewBag._operationServices.OperationSingleton.OperationId</h2>
    <h2>OperationInstance: @ViewBag._operationServices.OperationInstance.OperationId</h2>
</div>

7.运行结果

可以看到,单例生命周期服务每一次请求的标识一样。作用域生命周期的服务,在一次请求中使用的同一个实例,第二次请求创建新的实例。

5.请求服务

来自HttpContext的一次ASP.NET 请求中,可用的服务是通过RequestServices集合公开的。

请求服务将你配置的服务和请求描述为应用程序的一部分。在子的对象指定依赖之后,这些满足要求的对象可通过查找RequestServices中对应的类型得到,而不是ApplicationServices。

6.设计依赖注入服务

在自定义的服务中,避免使用静态方法和直接实例化依赖的类型,而是通过依赖注入请求它。(New is Glue)

如果类有太多的依赖关系被注入时,通常表明你的类试图做的太多(违反了单一职责原则),需要转移一些职责。

同样,Controller类应该重点关注UI,因此业务逻辑和数据访问等细节应该在其他类中。

7.使用Autofac容器

Autofac

到此这篇关于ASP.NET Core依赖注入(DI)的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解ASP.NET Core 在 JSON 文件中配置依赖注入

    前言 在上一篇文章中写了如何在MVC中配置全局路由前缀,今天给大家介绍一下如何在在 json 文件中配置依赖注入. 在以前的 ASP.NET 4+ (MVC,Web Api,Owin,SingalR等)时候,都是提供了专有的接口以供使用第三方的依赖注入组件,比如我们常用的会使用 Autofac.Untiy.String.Net 等,这些第三放依赖注入组件基本上都提供了一套配置注入或者配置生命周期的方式,除了直接配置到类里面之外,还提供了要么使用 xml 文件,要么使用 json 等,那么在新的

  • 详解ASP.NET Core 中的框架级依赖注入

    1.ASP.NET Core 中的依赖注入 此示例展示了框架级依赖注入如何在 ASP.NET Core 中工作. 其简单但功能强大,足以完成大部分的依赖注入工作.框架级依赖注入支持以下 scope: Singleton - 总是返回相同的实例 Transient - 每次都返回新的实例 Scoped - 在当前(request)范围内返回相同的实例 假设我们有两个要通过依赖注入来进行工作的工件: PageContext - 自定义请求上下文 Settings - 全局应用程序设置 这两个都是非常

  • 理解ASP.NET Core 依赖注入(Dependency Injection)

    目录 依赖注入 什么是依赖注入 依赖注入有什么好处 ASP.NET Core内置的依赖注入 服务生存周期 服务释放 TryAdd{Lifetime}扩展方法 解析同一服务的多个不同实现 Replace && Remove 扩展方法 Autofac 服务解析和注入 构造函数注入 方法注入 属性注入 一些注意事项 框架默认提供的服务 依赖注入 什么是依赖注入 简单说,就是将对象的创建和销毁工作交给DI容器来进行,调用方只需要接收注入的对象实例即可. 微软官方文档-DI 依赖注入有什么好处 依赖

  • ASP.NET Core 过滤器中使用依赖注入知识点总结

    如何给过滤器ActionFilterAttribute也用上构造函数注入呢? 一般自定义的过滤器直接用特性方式标识就能使用 [ContentFilter] 因为构造函数在使用的时候要求传参,然后我们可以使用这个 ServiceFilter 在ASP.NET Core里,我们可以使用ServiceFilter来完成这个需求. ServiceFilter允许我们解析一个已经添加IoC容器的服务,因此我们需要把ContentFilter注册一下. services.AddScoped<ContentF

  • ASP.NET Core依赖注入系列教程之控制反转(IoC)

    前言 ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化",我们将这些标准化的组件称为服务,ASP.NET在内部专门维护了一个DI容器来提供所需的服务.要了解这个DI容器以及现实其中的服务提供机制,我们先得知道什么是DI(Dependence Injection),而一旦我们提到DI,又不得不说IoC(Inverse of Control). 一.流程控

  • ASP.NET Core依赖注入详解

    目录 一.什么是依赖注入 二.使用框架提供的服务 三.注册服务 四.生命周期 五.请求服务 六.设计你的依赖服务 ASP.NET Core的底层设计支持和使用依赖注入.ASP.NET Core应用程序可以利用内置的框架服务将它们注入到启动类的方法中,并且应用程序服务能够配置注入.由ASP.NET Core提供的默认服务容器提供了最小功能集,并不是要取代其它容器. 一.什么是依赖注入 依赖注入(Dependency injection,DI)是一种实现对象及其合作者或依赖项之间松散耦合的技术.将类

  • 详解asp.net core 依赖注入

    前言 好久没有写微博了,因为前段时间由于家庭原因决定从工作了3年多的北京转移到上海去.依赖注入在学习net core的时候也有写过类似的东西,只是实践的较少,结果来到上海新公司系统框架涉及到了这块知识点,所以在了解完自己的项目之后决定做一些相关的总结.接下来就让我们先来了解hewi依赖注入. 什么是依赖注入 依赖注入,全称是"依赖注入到容器", 容器(IOC容器)是一个设计模式,它也是个对象,你把某个类(不管有多少依赖关系)放入这个容器中,可以"解析"出这个类的实例

  • ASP.NET Core MVC创建控制器与依赖注入讲解

    默认的IControllerActivator 在 ASP.NET Core 中,当 MVC 中间件接收到请求时,通过路由选择要执行的控制器和操作方法.为了实际的执行操作, MVC 中间件必须创建所选控制器的实例. 创建控制器的过程依赖众多不同的提供者和工厂类,但最终是由实现IControllerActivator接口的实例来决定的.实现类只需要实现两个方法: public interface IControllerActivator { object Create(ControllerCont

  • ASP.NET Core依赖关系注入

    1.前言 面向对象设计(OOD)里有一个重要的思想就是依赖倒置原则(DIP),并由该原则牵引出依赖注入(DI).控制反转(IOC)及其容器等老生常谈的概念,初学者很容易被这些概念搞晕(包括我在内),在学习Core依赖注入服务之前,下面让我们先了解下依赖倒置原则(DIP).依赖注入(DI).控制反转(IOC)等概念,然后再深入学习Core依赖注入服务. 2.依赖倒置原则(DIP) 高层模块不依赖于低层模块的实现,而低层模块依赖于高层模块定义的接口.通俗来讲,就是高层模块定义接口,低层模块负责实现.

  • ASP.NET Core MVC 依赖注入View与Controller

    目录 一.ASP.NET Core MVC 之依赖注入 View 1.填充查找数据 2.重写服务 二. ASP.NET Core MVC 之依赖注入 Controller 1.构造函数注入 2.使用 FromServices 操作注入 3.在控制器中访问设置 一.ASP.NET Core MVC 之依赖注入 View ASP.NET Core 支持在试图中使用依赖注入.这将有助于提供视图专用的服务,比如本地化或者仅用于填充视图元素的数据.应尽量保持控制器和视图之间的关注点分离.视图所显示的大部分

  • ASP.NET Core  依赖注入框架的使用

    目录 一.IoC框架 二.IoC-Autofac 三..NET Core中自带DI的使用 四.Autofac 使用 五.批量注入 前言: 还记得上篇文章中ASP.NET Core 依赖注入详细最后提及到,假如服务越来越多怎么处理呢,本篇文章将会带来解决办法.这篇是接上一篇文章的,概念方面的可以参考上一篇文章. 一.IoC框架 先说说常见的Ioc框架吧. Autofac: 目前net用的比较多,好多大佬的项目比较优先选择的框架. Ninject: 已经很少用了,还时在很早的文章中见过. Unity

  • ASP.NET Core依赖注入系列教程之服务的注册与提供

    前言 在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core中的DI容器体现为一个实现了IServiceProvider接口的对象. ServiceProvider与ServiceDescriptor 服务的注册与提供     利用ServiceProvider来提供服务     提供一个服务实例的集合     获取ServiceProvider自身对

  • ASP.NET Core 依赖注入详细

    目录 一.控制反转 二.好莱坞法则 三.流程控制 四.三种依赖注入方式 1.构造器注入 2.属性注入 3.方法注入 五.生命周期 六.ASP.Net Core 中自带的注入 前言: ASP.NET Core 应用在启动过程中会依赖各种组件提供服务,而这些组件会以接口的形式标准化,这些组件这就是我们所说的服务,ASP.NET Core框架建立在一个底层的依赖注入框架之上,它使用容器提供所需的服务.要了解依赖注入容器以及它的机制,我们需要了解什么是依赖注入. 一.控制反转 说道依赖注入就不得不提控制

  • ASP.NET Core实现自动依赖注入

    在开发.NET Core web服务的时候,我们习惯使用自带的依赖注入容器来进行注入. 于是就会经常进行一个很频繁的的重复动作:定义一个接口->写实现类->注入 有时候会忘了写Add这一步,看到屏幕上的报错一脸懵逼,然后瞬间反应过来忘了注入了.赶紧补上serviceCollection.AddXXX这句话 虽然说有很多开源框架已经实现了类似的工作,比如AutoFac,Unity等依赖注入框架.但是这些库都太庞大了,我个人还是喜欢轻量级的实现. 定义一个枚举 [AttributeUsage(At

随机推荐