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);
}
}
}
}
}