上篇说到利用接口来定义生命周期
通过反射获取继承接口的相关实现
并以此来完成对应生命周期的注入
但随着框架搭建,已经不止业务接口层和业务实现层需要添加到IOC了
使用仓储模式后还多了仓储接口层和仓储实现层,原有的方法需要扩展
结构如下
- IDataService 业务接口(包含三个生命周期接口)
- DataService 业务实现
- IRepository 仓储接口(新增三个生命周期接口)
- Repository 仓储实现
原先的逻辑是定义三个接口在IDataService层下
/// <summary>
/// 单例
/// </summary>
public interface ISingleton
{
}
/// <summary>
/// 瞬时
/// </summary>
public interface ITransient
{
}
/// <summary>
/// 作用域
/// </summary>
public interface IScoped
{
}
引用关系是不支持仓储层调用业务层的
所以必须在仓储接口层也重复添加这三个接口(后续可能优化)
扩展之后代码逻辑如下
/// <summary>
/// 自动注入
/// </summary>
public static class AutoDI
{
/// <summary>
/// 通过命名空间注入
/// </summary>
/// <param name="services"></param>
/// <param name="namespaceType"></param>
/// <returns>IServiceCollection</returns>
public static IServiceCollection AddService(this IServiceCollection services, string namespaceType)
{
Type? singletonType = namespaceType == nameof(IDataService) ? typeof(IDataService.DI.ISingleton) : typeof(IRepository.DI.ISingleton);
Type? transientType = namespaceType == nameof(IDataService) ? typeof(IDataService.DI.ITransient) : typeof(IRepository.DI.ITransient);
Type? scopedType = namespaceType == nameof(IDataService) ? typeof(IDataService.DI.IScoped) : typeof(IRepository.DI.IScoped);
if (namespaceType == nameof(IRepository))
{
services.AddScoped(typeof(Repository.BaseRepository<>));
}
return AddDataServiceOrRepository(services, singletonType, transientType, scopedType);
}
/// <summary>
/// 注入接口和仓储类
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>将服务添加到</param>
/// <param name="singletonType">单例</param>
/// <param name="transientType">瞬时</param>
/// <param name="scopedType">作用域</param>
/// <returns>IServiceCollection</returns>
public static IServiceCollection AddDataServiceOrRepository(IServiceCollection services, Type? singletonType, Type? transientType, Type? scopedType)
{
// 获取实现了三个生命周期接口的程序集
var allTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes().Where(t =>
t.GetInterfaces().Contains(transientType) ||
t.GetInterfaces().Contains(singletonType) ||
t.GetInterfaces().Contains(scopedType)));
// class的程序集
var implementTypes = allTypes.Where(x => x.IsClass).ToArray();
// 接口的程序集
var interfaceTypes = allTypes.Where(x => x.IsInterface).ToArray();
foreach (var implementType in implementTypes)
{
var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
// class有接口,用接口注入
if (interfaceType != null)
{
// 判断用什么方式注入
if (interfaceType.GetInterfaces().Contains(singletonType))
{
// 单例
services.AddSingleton(interfaceType, implementType);
}
else if (interfaceType.GetInterfaces().Contains(transientType))
{
// 瞬时
services.AddTransient(interfaceType, implementType);
}
else if (interfaceType.GetInterfaces().Contains(scopedType))
{
// 作用域
services.AddScoped(interfaceType, implementType);
}
}
else // class没有接口,直接注入class
{
// 判断用什么方式注入
if (implementType.GetInterfaces().Contains(singletonType))
{
// 单例
services.AddSingleton(implementType);
}
else if (implementType.GetInterfaces().Contains(transientType))
{
// 瞬时
services.AddTransient(implementType);
}
else if (implementType.GetInterfaces().Contains(scopedType))
{
// 作用域
services.AddScoped(implementType);
}
}
}
return services;
}
}
Program注册服务
var builder = WebApplication.CreateBuilder(args);
// 自动注入接口实现类和仓储实现类
builder.Services.AddService(nameof(IDataService));
builder.Services.AddService(nameof(IRepository));
需要调用两次并且传入不同命名空间
而且代码逻辑有点混乱不是很好阅读
优化一下
/// <summary>
/// 自动注入
/// </summary>
public static class AutoDI
{
/// <summary>
/// 通过命名空间注入
/// </summary>
/// <param name="services"></param>
/// <param name="namespaceType"></param>
public static void AddService(this IServiceCollection services, string namespaceType)
{
Type singletonType = null;
Type transientType = null;
Type scopedType = null;
switch (namespaceType)
{
case nameof(IDataService):
singletonType = typeof(IDataService.DI.ISingleton);
transientType = typeof(IDataService.DI.ITransient);
scopedType = typeof(IDataService.DI.IScoped);
break;
case nameof(IRepository):
singletonType = typeof(IRepository.DI.ISingleton);
transientType = typeof(IRepository.DI.ITransient);
scopedType = typeof(IRepository.DI.IScoped);
services.AddScoped(typeof(Repository.BaseRepository<>));
break;
default:
break;
}
services.AddDataServiceOrRepository(singletonType, transientType, scopedType);
}
/// <summary>
/// 注入接口和仓储类
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>将服务添加到</param>
/// <param name="singletonType">单例</param>
/// <param name="transientType">瞬时</param>
/// <param name="scopedType">作用域</param>
public static void AddDataServiceOrRepository(this IServiceCollection services, Type? singletonType, Type? transientType, Type? scopedType)
{
// 获取实现了三个生命周期接口的程序集
var allTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes().Where(t =>
t.GetInterfaces().Contains(singletonType) ||
t.GetInterfaces().Contains(transientType) ||
t.GetInterfaces().Contains(scopedType)));
// 实现类的程序集
var implementationTypes = allTypes.Where(x => x.IsClass).ToArray();
// 服务接口的程序集
var serviceTypes = allTypes.Where(x => x.IsInterface).ToArray();
foreach (var implementationType in implementationTypes)
{
var serviceType = serviceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementationType));
if (implementationType.GetInterfaces().Contains(singletonType))
{
// 单例
services.AddFromLifeTime(serviceType, implementationType, ServiceLifetime.Singleton);
}
else if (implementationType.GetInterfaces().Contains(transientType))
{
// 瞬时
services.AddFromLifeTime(serviceType, implementationType, ServiceLifetime.Transient);
}
else if (implementationType.GetInterfaces().Contains(scopedType))
{
// 作用域
services.AddFromLifeTime(serviceType, implementationType, ServiceLifetime.Scoped);
}
}
}
/// <summary>
/// 通过生命周期注入接口和实现类
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>将服务添加到</param>
/// <param name="serviceType">要注册的服务类型(Interface)</param>
/// <param name="implementationType">服务的实现类型(Class)</param>
/// <param name="lifetime">注入生命周期</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <returns>IServiceCollection</returns>
public static IServiceCollection AddFromLifeTime(this IServiceCollection services, Type serviceType, Type implementationType, ServiceLifetime lifetime)
{
switch (lifetime)
{
// 单例
case ServiceLifetime.Singleton:
services.AddSingleton(serviceType ?? implementationType, implementationType);
break;
// 瞬时
case ServiceLifetime.Transient:
services.AddTransient(serviceType ?? implementationType, implementationType);
break;
// 作用域
case ServiceLifetime.Scoped:
services.AddScoped(serviceType ?? implementationType, implementationType);
break;
default:
throw new ArgumentOutOfRangeException(nameof(lifetime), lifetime, null);
}
return services;
}
}
AddService方法原先是三元运算符,代码可能比较简洁但是不能一目了然
AddDataServiceOrRepository修改了部分命名,并且拆出了一个新的方法AddFromLifeTime
AddFromLifeTime根据生命周期枚举来完成对应的注入,无需判断接口是否为空,为空则注入实现类