ASP.NET Core如何注入多个服务实现类

 更新时间:2021年09月09日 11:35:32   作者:东邪独孤  
这篇文章主要介绍了ASP.NET Core如何注入多个服务实现类的相关资料,需要的朋友可以参考下面文章的具体内容

前言:

依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是:俺要啥,你就给俺送啥过来。服务类型的实例转由容器自动管理,无需我们在代码中显式处理。

因此,有了依赖注入后,你的编程思维就得变一变了。在过去,许多功能性的类型(比如一个加密解密的类),我们都喜欢将其定义为静态(static),而有了依赖注入,你就要避免使用静态类型,应该交由服务容器帮你管理,只要你用好了,你会发现依赖注入是很方便的。

依赖注入的初级玩法,也是比较标准的玩法,此种玩法有两种模式:

  1. 十代单传模式:一个接口对应一个类,比如先定义接口 IA、IB,随后,类A实现 IA,类B 实现 IB。一对一。也可以是抽象类(或基类)E,然后 F 继承 E 类。
  2. 断子绝孙模式:直接就写一个类,不考虑派生,直接就添加到服务容器中。

来,看个例子。

1、定义个接口

    public interface IPlayGame
    {
        void Play();
    }


然后,写一个类来实现它。

    public class NBPlayGame : IPlayGame
    {
        public void Play()
        {
            Console.WriteLine("全民打麻药。");
        }
    }

我们知道,所谓服务类,其实就是普通类,这些类一般用于完成某些功能,比如计算 MD5 值。接着呢,还记得 Startup 类有个 ConfigureServices 方法吧,对,就在这厮里面把我们刚刚那个服务进行注册(就是添加到 ServiceCollection 集合中)。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IPlayGame, NBPlayGame>();
        }


添加的时候很简单,类型一对一,IPlayGame 接口与 NBPlayGame 类对应。添加时有三种方法你可以调用,实际上对应着,服务类在容器中的生命周期。

  • AddSingleton:单个实例,这是寿命最长的,与天同寿。整个应用程序中仅用一个实例。
  • AddTransient:这个是最短命的,可能是天天晚上加班熬夜,死得很快。此种情况下,服务类的实例是用的时候创建,用完后直接销毁。
  • AddScoped:这个比较难理解。它的生命周期在单个请求内,包括客户端与服务器之间随后产生的子请求,反正只要请求的会话结束了,就会清理。

2、注入服务

比如在中间件,在控制器,或者在其他服务类的构造函数上(中间件是在 Invoke / InvokeAsync 方法上)进行实例接收。

现在来用一下,写一个中间件。

    public class TestMiddleware
    {
        public TestMiddleware(RequestDelegate next) { }

        public Task InvokeAsync(HttpContext context, IPlayGame game)
        {
            game.Play();
            return Task.CompletedTask;
        }
    }

已注册的服务会注入到 InvokeAsync 方法的参数中。注意第一个参数是 HttpContext,这是必须参数,后面的是注入的参数。

最后,在 Startup 类的 Configure 方法中就可以 use 这个中间件了。

        public void Configure(IApplicationBuilder app)
        {
            app.UseMiddleware<TestMiddleware>();
        }
 

运行后,Play 方法调用,在控制台中输出以下结果

 3、功能类

 也称“断子绝孙”模式,不使用接口规范,直接写功能类。

    public class DoSomething
    {
        public string GetMessage() => "你好,刚才 Boss 找你。";
    }

注册服务时更简单。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<DoSomething>();
        }

在 Configure 方法中进行注入。

        public void Configure(IApplicationBuilder app, DoSomething thing)
        {
            Console.WriteLine(thing.GetMessage());
        }


运行后,输出结果如下

 

 在容器中,使用 ServiceDescriptor 类来存储服务类型相关的信息。其中,ServiceType 表示的是服务的类型,如果服务是有接口与实现类的,那么这个属性指的是接口的类型,实现类的类型信息由 ImplementationType 属性存储。如果没有接口,直接只定义类型,那么这个类型的信息就存到 ServiceType 属性上,ImplementationType 属性不使用。

上面这些例子中,ServiceType 是 IPlayGame 接口相关信息,ImplementationType 是 NBPlayGame 类的信息。如果像上面 DoSomething 类的情况,则 ServiceType 为 DoSomething 相关的信息,ImplementationType 为空。

 4、高级类

接下来,咱们看高级玩法。

定义一个接口。

    public interface IDemoService
    {
        string Version { get; }
        void Run();
    }


然后,有两个类实现这个接口。

    public class DemoService1 : IDemoService
    {
        public string Version => "v1";

        public void Run()
        {
            Console.WriteLine("第一个服务实现类。");
        }
    }

    public class DemoService2 : IDemoService
    {
        public string Version => "v2";

        public void Run()
        {
            Console.WriteLine("第二个服务实现类。");
        }
    }

然后,我们注册服务。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IDemoService, DemoService1>();
            services.AddTransient<IDemoService, DemoService2>();
        }


然后我们照例,接收注入,咱们依旧使用中间件的方法参数接收。

    public class DemoMiddleware
    {
        public DemoMiddleware(RequestDelegate next)
        {
            // 由于程序约定,此构造函数必须提供。
        }

        public async Task InvokeAsync(HttpContext context, IDemoService sv)
        {
            await context.Response.WriteAsync(sv.Version);
        }
    }

然后,在 Startup.Configure 方法中使用该中间件。

        public void Configure(IApplicationBuilder app, DoSomething thing)
        {
            app.UseMiddleware<DemoMiddleware>();
        }


运行之后,你发现问题了,看看输出。

 

 出事了,参数仅能接收到最后注册的实现类型实例,也就是 DemoService2 类。所以就看到网上有不少朋友发贴问了,.NET Core 是不是不支持多个服务实现类的注入?这难倒了很多人。

实话告诉你,Core Core 兄是支持注入多个实现类的实例的。

下面,老周介绍两种解决方法(其实有三种,还有一种不太好弄,尤其是你对 Core 兄不熟的时候,所以我说两种,基本够用)。

方法一、接收 IServiceProvider 类型的注入。

        public async Task InvokeAsync(HttpContext context, IServiceProvider provider)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var sv in provider.GetServices<IDemoService>())
            {
                sb.Append($"{sv.Version}<br/>");
            }
            await context.Response.WriteAsync(sb.ToString());
        }

只要能接收到 IServiceProvider 所引用的实例,就能通过 GetServices 方法获取多个服务实例。

方法二,这种方法老周很推荐,更简单,直接注入 IEnumerable<T> 类型,本例中就是 IEnumerable<IDemoService>。

        public async Task InvokeAsync(HttpContext context, IEnumerable<IDemoService> svs)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var sv in svs)
            {
                sb.Append($"{sv.Version}<br/>");
            }
            await context.Response.WriteAsync(sb.ToString());
        }

IEnumerable<T> 的妙处就是可以 foreach ,这样你也能访问多个实例,而且必要时还可以联合 LINQ 一起耍。

运行结果如下。

 

到此这篇关于ASP.NET Core如何注入多个服务实现类的文章就介绍到这了,更多相关ASP.NET Core何注多个服务实现类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#中string与byte[]的转换帮助类-.NET教程,C#语言

    C#中string与byte[]的转换帮助类-.NET教程,C#语言

    在写c#程序时,string和byte[]之间的转换比较烦,在移植一些老程序时感觉很不好。我在c#中使用des和tripledes时移植一块老代码时也遇到了同样的情况。为了下次不为同样的事情烦恼,就写了下面的帮助类。
    2008-03-03
  • asp.net 获取数据库连接字符串

    asp.net 获取数据库连接字符串

    本文主要介绍了asp.net获取数据库连接字符串的具体实现代码,具有一定参考价值,需要的朋友可以看下
    2016-12-12
  • 认识ASP.NET配置文件Web.config

    认识ASP.NET配置文件Web.config

    Web.config文件是一个XML文本文件,它用来储存 ASP.NET Web 应用程序的配置信息(如最常用的设置ASP.NET Web 应用程序的身份验证方式),它可以出现在应用程序的每一个目录中
    2006-07-07
  • .net中线程同步的典型场景和问题剖析

    .net中线程同步的典型场景和问题剖析

    在使用多线程进行编程时,有一些经典的线程同步问题,对于这些问题,.net提供了多种不同的类来解决
    2012-11-11
  • Oracle中TO_DATE格式介绍

    Oracle中TO_DATE格式介绍

    Oracle中TO_DATE格式介绍;可供需求的朋友参考
    2012-11-11
  • .NET 6 中的隐式命名空间引用

    .NET 6 中的隐式命名空间引用

    这篇文章小编主要向大家介绍的是介绍了.NET 6 中的隐式命名空间引用,其正式版发布之前会专注于各种测试和 BUG 修复,下面就由小编来详细介绍吧,感兴趣的小伙伴可以参考下文
    2021-09-09
  • asp.net创建事务的方法

    asp.net创建事务的方法

    本篇文章主要对asp.net创建事务的方法进行实例介绍,具有很好的参考价值,需要的朋友一起来看下吧
    2016-12-12
  • ASP.NET webUploader上传大视频文件相关web.config配置

    ASP.NET webUploader上传大视频文件相关web.config配置

    本文主要介绍了webUploader上传大视频文件相关web.config的配置。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • 从零开始学ASP.NET-基础篇

    从零开始学ASP.NET-基础篇

    从零开始学ASP.NET-基础篇...
    2006-07-07
  • .NET 6 即将到来的新特性  隐式命名空间引用

    .NET 6 即将到来的新特性 隐式命名空间引用

    ASP.NET 现在我们还是需要手动加命名空间引用,在以后的版本中可能就不需要手动加命名空间的引用了,本文就来介绍.NET 6即将到来的新特性--隐式命名空间引用,,需要的朋友可以参考下面文章内容
    2021-09-09

最新评论