using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; using System.Reflection; namespace FastGithub { /// /// 服务注册扩展 /// public static class ServiceCollectionExtensions { /// /// 注册程序集下所有服务下选项 /// /// /// 配置 /// public static IServiceCollection AddServiceAndOptions(this IServiceCollection services, Assembly assembly, IConfiguration configuration) { services.AddAttributeServices(assembly); services.AddAttributeOptions(assembly, configuration); return services; } /// /// 添加程序集下ServiceAttribute标记的服务 /// /// /// /// private static IServiceCollection AddAttributeServices(this IServiceCollection services, Assembly assembly) { var implTypes = assembly .GetTypes() .Where(item => item.IsClass && item.IsAbstract == false) .ToArray(); foreach (var implType in implTypes) { var attributes = implType.GetCustomAttributes(false); foreach (var attr in attributes) { var serviceType = attr.ServiceType ?? implType; if (services.Any(item => item.ServiceType == serviceType && item.ImplementationType == implType) == false) { var descriptor = ServiceDescriptor.Describe(serviceType, implType, attr.Lifetime); services.Add(descriptor); } } } return services; } /// /// 添加程序集下OptionsAttribute标记的服务 /// /// /// /// private static IServiceCollection AddAttributeOptions(this IServiceCollection services, Assembly assembly, IConfiguration configuration) { foreach (var optionsType in assembly.GetTypes()) { var optionsAttribute = optionsType.GetCustomAttribute(); if (optionsAttribute != null) { var key = optionsAttribute.SessionKey ?? optionsType.Name; var section = configuration.GetSection(key); OptionsBinder.Create(services, optionsType).Bind(section); } } return services; } /// /// options绑定器 /// private abstract class OptionsBinder { public abstract void Bind(IConfiguration configuration); /// /// 创建OptionsBinder实例 /// /// /// /// public static OptionsBinder Create(IServiceCollection services, Type optionsType) { var binderType = typeof(OptionsBinderImpl<>).MakeGenericType(optionsType); var binder = Activator.CreateInstance(binderType, new object[] { services }); return binder is OptionsBinder optionsBinder ? optionsBinder : throw new TypeInitializationException(binderType.FullName, null); } private class OptionsBinderImpl : OptionsBinder where TOptions : class { private readonly IServiceCollection services; public OptionsBinderImpl(IServiceCollection services) { this.services = services; } public override void Bind(IConfiguration configuration) { this.services.AddOptions().Bind(configuration); } } } } }