.net core中自动批量向容器中注入服务

引言

.net core 为我们提供了良好的容器机制,并可以简单的在 Configuration 方法中向容器中注入服务,但是当服务比较多的时候,就会使我们的注入过程变得很麻烦,不容易管理,所以就需要我们自己动手写一些代码,实现服务的管理以及自动注入。
关于这篇博客所写的代码,我已经上传至Github,大家可以下载源码观看,如果觉得不错,顺手给个 Star 哦。

实现思路

要实现自动注入,需要做好以下几件事:

  1. 使容器可以自动发现需要注入的服务,并注册服务
  2. 服务需要标记自己需要的生命周期,方便容器注入
  3. 异常的处理

针对以上问题,我需要首先定义一个IServiceCollection的扩展方法,可以在服务中使用我们的服务;其次,需要定义一个枚举,声明服务的生命周期;最后,我们需要定义一个属性,可以在服务类上使用,以便声明服务的声明周期等信息,使容器可以发现服务。

自动注入的实现

生命周期枚举类的定义

要定义生命周期枚举,首先需要了解一下.net 中的生命周期的机制,.net 中具有 3 种生命周期

  1. AddTransient,暂时性生存期;
  2. AddScoped,范围内生存期;
  3. AddSingleton,单例生命期。

关于生命周期方面的知识不属于这篇文章的重点,在此不多做赘述,不太熟悉的可以去微软文档查看。

根据 3 种生命周期,我们可以定义以下一个枚举类:

    /// <summary>
    /// 注入类型
    /// </summary>
    public enum InjectionType
    {
        /// <summary>
        /// Transient
        /// </summary>
        Transient,

        /// <summary>
        /// Scoped
        /// </summary>
        Scoped,

        /// <summary>
        /// Singleton
        /// </summary>
        Singleton
    }

自动注入属性的实现

实现自定义属性,主要是为了使用方便,这样的话我们在服务类的定义时,就可以标记这个服务是用来怎样进行服务注册的,废话不多说,上代码:

    /// <summary>
    /// 服务注入
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class ServiceInjectionAttribute : Attribute
    {
        /// <summary>
        ///
        /// </summary>
        public Type InterfaceType { get; set; }

        /// <summary>
        /// 注入类型
        /// </summary>
        public InjectionType InjectionType { get; }

        /// <summary>
        /// 服务注入
        /// </summary>
        public ServiceInjectionAttribute()
        {
            this.InjectionType = InjectionType.Scoped;
        }

        /// <summary>
        /// 服务注入
        /// </summary>
        /// <param name="injectionType">注入类型</param>
        public ServiceInjectionAttribute(InjectionType injectionType)
        {
            this.InjectionType = injectionType;
        }

        /// <summary>
        /// 服务注入
        /// </summary>
        /// <param name="interfaceType">服务的接口类型</param>
        /// <param name="injectionType">注入的类型</param>
        public ServiceInjectionAttribute(Type interfaceType, InjectionType injectionType)
        {
            this.InterfaceType = interfaceType;
            this.InjectionType = injectionType;
        }
    }

如代码所示,我们自定义的ServiceInjectionAttribute类继承于 C#的Attribute类,并且在上面标记了这个属性类的适用范围,只能标记在类上面。可以注意到,我们这个类有三种类型的构造函数。我们可以根据自己的使用需求来决定使用哪一种构造定义。

在我们的类中,有一个属性为InterfaceType,这个属性是指服务继承的接口类,根据这个属性我们注册服务的时,会使用这个接口进行注入。

在这里面,我们定义了默认的生命周期为Scoped,如果没有定义继承的服务接口,则使用具体服务类所继承的第一个接口进行注册

服务扩展方法的实现

这部份是实现自动注入的核心,它负责容器的组装,自动扫描我们需要注入的服务,代码如下:

        /// <summary>
        /// 服务自动注入
        /// </summary>
        /// <param name="serviceCollection">需要自动注入服务的服务集合</param>
        /// <exception cref="ArgumentOutOfRangeException">指定的注入类型不在可注入的范围内</exception>
        /// <exception cref="NoImplementationInterfaceException">指定注入的类型未实现任何服务</exception>
        /// <exception cref="ArgumentException">输入的参数错误:1、注入的类型未实现指定的服务。2、指定的服务不是Interface类型</exception>
        /// <returns>自动注入服务后的服务集合</returns>
        public static IServiceCollection ServicesAutoInjection(this IServiceCollection serviceCollection)
        {
            var directory = AppDomain.CurrentDomain.BaseDirectory;
            var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
                .Select(Assembly.LoadFrom)
                .SelectMany(a => a.GetTypes());

            Injection(serviceCollection, types);

            return serviceCollection;
        }

在这个方法中我们可以看出,程序会扫描程序运行目录下的所有 Dll,并加载具有我们自定义属性的类,并根据我们标记的生命周期等属性,注入到我们的容器中。

但是,有时候,有一些 Dll 不需要我们扫描注入,需要进行排除,所以在这个基础上,我又封装了一层,可以传入过滤条件,代码如下:

        /// <summary>
        /// 服务自动注入
        /// </summary>
        /// <param name="serviceCollection">需要自动注入服务的服务集合</param>
        /// <param name="selector">应用于每个Assembly的筛选函数</param>
        /// <exception cref="ArgumentOutOfRangeException">指定的注入类型不在可注入的范围内</exception>
        /// <exception cref="NoImplementationInterfaceException">指定注入的类型未实现任何服务</exception>
        /// <exception cref="ArgumentException">输入的参数错误:1、注入的类型未实现指定的服务。2、指定的服务不是Interface类型</exception>
        /// <returns>自动注入服务后的服务集合</returns>
        public static IServiceCollection ServicesAutoInjection(this IServiceCollection serviceCollection, Func<Assembly, bool> selector)
        {
            var directory = AppDomain.CurrentDomain.BaseDirectory;
            var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
                .Select(Assembly.LoadFrom)
                .Where(selector)
                .SelectMany(a => a.GetTypes());

            Injection(serviceCollection, types);

            return serviceCollection;
        }

上述代码中,selector就是我们的过滤条件,它是一个 Func 函数,参数为Assembly类型,我们可以根据类型或者一些信息排除我们不需要的类型,比如根据类的名称等信息。

自动注入的使用

服务的配置

首先需要我们在Startup中的ConfigureServices函数中配置服务,如下所示:

public void ConfigureServices(IServiceCollection services)
{
    // 声明为WebAPI,也可为AddMvc()或者其他
    services.AddControllers();
    // 配置其他服务
    // 配置自动注入服务
    services.ServicesAutoInjection();
    // 配置其他服务
}

标记服务的注入

我们的服务的配置后,接下来的使用就比较简单了,找到我们的实现类,标记上我们自定义的属性标签,然后服务就可以通过我们的服务自动注入啦。

[ServiceInjection(typeof(IService),InjectionType.Scoped)]
public class ServiceImpl : IService
{
	// 业务代码
}

结语

通过我们自定义代码实现,服务就可以很简单的被容器发现并注册了,并且还做了简单的服务排除逻辑,如果代码中有什么出错的地方,欢迎大家批评指正哦。
大家也可以在我的个人博客中阅读我的其他文章。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
.NET Core ,DI(Dependency Injection)容器是一个非常重要的概念。它允许我们通过依赖注入的方式来管理对象的生命周期和解决对象之间的依赖关系。 .NET Core 的 DI容器是通过 Microsoft.Extensions.DependencyInjection NuGet 包提供的。它是一个轻量级的容器,易于使用和扩展。 使用 DI容器的第一步是注册需要注入服务。这通常在应用程序启动时进行。可以使用 AddTransient、AddScoped 或 AddSingleton 方法将服务注册容器,这三个方法分别表示瞬态、作用域和单例生命周期。 然后,可以在需要使用服务的类的构造函数通过依赖注入的方式获取服务。这样,当需要使用服务时,容器自动创建并注入所需的依赖项。 例如,下面是一个简单的示例,演示如何在 .NET Core 使用 DI容器: ```csharp // 注册服务 services.AddTransient<IMyService, MyService>(); // 使用服务 public class MyController { private readonly IMyService _myService; public MyController(IMyService myService) { _myService = myService; } public IActionResult Index() { var result = _myService.DoSomething(); return Ok(result); } } ``` 在上面的示例,我们将 MyService 注册为瞬态服务,并在 MyController 的构造函数注入了该服务。当调用 MyController 的 Index 方法时,MyService 将被自动创建并注入到 MyController 。 总之,DI容器.NET Core 非常重要的一个概念,它可以帮助我们管理对象的生命周期和解决对象之间的依赖关系。在实际应用,我们应该尽可能地使用 DI容器来管理我们的应用程序服务和依赖项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值