dotNet 整合 Microsoft.Extensions.DependencyInjection 利用反射实现依赖批量注入

前言

框架
.net 8.0
Microsoft.Extensions.DependencyInjection 8.0
创建三个类库项目
ConfigServices
LogServices
MailServices
创建一个控制台项目
ConsoleAppMail

ConfigServices

 namespace ConfigServices.IService
{
    public interface IConfigService
    {
        public string GetValue(string key);
    }
}
 namespace ConfigServices.IService
{
    public class EnvVarConfigServiceImpl : IConfigService
    {
        public string GetValue(string key)
        {
            return Environment.GetEnvironmentVariable(key);
        }
    }
}

LogServices

namespace LogServices.IService
{
    public interface ILogProvider
    {
        public void LogInfo(string message);
        public void LogError(string message);
    }
}
 namespace LogServices.IService
{
    public class LogProviderImpl : ILogProvider
    {
        public void LogInfo(string message)
        {
            Console.WriteLine($"INFO:{message}");
        }

        public void LogError(string message)
        {
            Console.WriteLine($"ERROR:{message}");
        }
    }
}

MailServices

 public interface IMailService
 {
     public void Send(string title, string to, string body);
 }

在邮件服务里面需要引用 LogProvider 和 ConfigService 在这里需要依赖项里面添加项目引用,在 Microsoft.Extensions.DependencyInjection 里面默认是采用构造函数注入,只需要在构造函数中编写就可以了,在创建对象的时候 DependencyInjection 框架会帮助我们实现依赖注入(DI)。

namespace MailServices.IService
{
    public class MailServiceImpl : IMailService
    {
        private readonly ILogProvider log;
        private readonly IConfigService config;
        public MailServiceImpl(ILogProvider log, IConfigService config)
        {
            this.log = log;
            this.config = config;
        }
        public void Send(string title, string to, string body)
        {
            log.LogInfo("准备发送邮件");

            string smtpServer = this.config.GetValue("smtpServer");
            string username = this.config.GetValue("username");
            string password = this.config.GetValue("password");
            Console.WriteLine($"邮件服务器地址{smtpServer},{username},{password}");
            Console.WriteLine("发邮件!");
            log.LogInfo("邮件发送完成");
        }
    }
}

ConsoleAppMail

在控制台项目相当于我们的启动项, 需要告诉 DependencyInjection 框架那些类需要注入到容器中。

单个注入

单个注入比较麻烦,假如有100个service 就需要在Main 函数里面写100个,所以就有了通过反射的方式来批量注入。

using ConfigServices.IService;
using LogServices.IService;
using MailServices.IService;
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleAppMail
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ServiceCollection services = new ServiceCollection();
            services.AddScoped<ILogProvider,LogProviderImpl>();
            services.AddScoped<IConfigService,EnvVarConfigServiceImpl>();
            services.AddScoped<IMailService,MailServiceImpl>();
            using (var sp = services.BuildServiceProvider())
            {
                var mailService = sp.GetRequiredService<IMailService>();
                mailService.Send("hello", "hshd@163.com", "你好 朋友");
            }
            Console.ReadLine();
        }
    }
}

批量注入

通过反射可以批量读取程序集信息,将对应的接口和对应的实现类注入到IOC 容器中。

using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace ConsoleAppMail.util
{
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 批量注册指定程序集中的所有实现了接口的类到 ServiceCollection
        /// </summary>
        /// <param name="services">ServiceCollection 实例</param>
        /// <param name="assembly">要扫描的程序集</param>
        public static IServiceCollection RegisterServicesFromAssembly(this IServiceCollection services, Assembly assembly)
        {
             
            var types = assembly.GetTypes()
                .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Any()); // 筛选出实现接口的类
            foreach (var type in types)
            {
                var serviceInterface = type.GetInterfaces().FirstOrDefault();
                if (serviceInterface != null)
                {
                    services.AddScoped(serviceInterface, type); // 注册为 Scoped 生命周期
                }
            }
            return services;
        }
    }
}

 static void Main(string[] args)
 {

     var assembly1 = Assembly.Load("ConfigServices");
     var assembly2 = Assembly.Load("LogServices");
     var assembly3 = Assembly.Load("MailServices");


     ServiceCollection services = new ServiceCollection();
     // 批量注册当前程序集中的服务
     services.RegisterServicesFromAssembly(assembly1);
     services.RegisterServicesFromAssembly(assembly2);
     services.RegisterServicesFromAssembly(assembly3);

     using (var sp = services.BuildServiceProvider())
     {
         var mailService = sp.GetRequiredService<IMailService>();
         mailService.Send("hello", "hshd@163.com", "你好 朋友");

     }
     Console.ReadLine();
 }

通过该例子可以了解一哈 DependencyInjection 框架的基本使用方式,使用前需要了解一下依赖注入(DI)和IOC 容器的知识。

posted @ 2024-11-05 14:49  茶凡_Matrix  阅读(20)  评论(0编辑  收藏  举报