在.net core中使用依赖注入是很常见的,最常见的我们会使用以下三种
services.AddScoped<TestIBLL, TestBLL>(); services.AddSingleton<TestIBLL, TestBLL>(); services.AddTransient<TestIBLL, TestBLL>();
当我们的业务层内容不多的时候这样写没有什么问题,但是加入有100个BLL呢,那样一个一
个加会很麻烦,每加一个就要多写一次,而且容易忘记漏掉。
那么我们的需求是让希望能够实现批量注入,并且可以按照不同的生命周期去实现自动注入,以避免每加一个业务类,就要写一次services.AddScoped<>();
我将通过反射+特性来实现它。
1.首先新建一个类ServiceAttribute,该类要继承Attribute,定义一个属性LifeTime,用它来接收注入时需要的生命周期,默认等于ServiceLifetime.Scoped,使用ServiceLifetime.Scoped需要导入using Microsoft.Extensions.DependencyInjection命名空间。
/// <summary>
/// 属性形式定义生命周期
/// 默认Scoped
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ServiceAttribute:Attribute
{
public ServiceLifetime LifeTime { get; set; }
public ServiceAttribute(ServiceLifetime serviceLifetime= ServiceLifetime.Scoped)
{
LifeTime = serviceLifetime;
}
}
2.在自己需要注入的业务类中加上ServiceAttribute特性,并给上生命周期,也可以不给,就默认是Scoped
[Service(ServiceLifetime.Scoped)]
public class TestBLL:TestIBLL
{
}
public interface TestIBLL
{
}
3.核心部分,新建一个IServiceCollection的扩展方法类,取名叫ServiceCollectionExpand,定义扩展方法AddBusiness
1.获取当前程序域中的所有程序集,然后获取每个程序集中的所有type,得到其中包含有我们写的ServiceAttribute特性的类。
2.遍历types,得到每一个type所继承的接口数组和它注入的生命周期的值,然后根据生命周期实现注入, service.AddSingleton(,)和service.AddSingleton<>()不同的是传入的参数不同,前者的两个值都是type类型,后者是两个泛型
/// <summary>
/// IServiceCollection扩展类
/// </summary>
public static class ServiceCollectionExpand
{
/// <summary>
/// 按特性中的生命周期注入业务组件
/// </summary>
/// <param name="service"></param>
public static void AddBusiness(this IServiceCollection service)
{
//获取有ServiceAttribute特性的所有类
List<Type> types = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(t => t.IsClass && !t.IsAbstract
&& t.GetCustomAttributes(typeof(ServiceAttribute), false).Length > 0
)
.ToList();
types.ForEach(impl=>
{
//获取该类所继承的所有接口
Type[] interfaces = impl.GetInterfaces();
//获取该类注入的生命周期
var lifetime = impl.GetCustomAttribute<ServiceAttribute>().LifeTime;
interfaces.ToList().ForEach(i =>
{
switch (lifetime)
{
case ServiceLifetime.Singleton:
service.AddSingleton(i,impl);
break;
case ServiceLifetime.Scoped:
service.AddScoped(i, impl);
break;
case ServiceLifetime.Transient:
service.AddTransient(i, impl);
break;
}
});
});
}
}
4.然后在startup类中的configureservices方法中调用扩展方法即可实现自动注入了
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
#region 注册业务组件
services.AddBusiness();
#endregion
}
使用的话,在控制器中和以前一样使用即可。有反射的基础知识再看的话会比较容易明白。
也有很多第三方组件可以实现批量依赖注入,比如autofac,Unity等。