如何在不注册服务的情况下注入服务?
我的意思是,在过去,一些DI框架会自动为Service
注册IService
。
在我有十几项服务的情况下,基本上每一项服务都是痛苦的。这是否支持在asp.net核心默认DI框架中?
答案 0 :(得分:4)
我想你喜欢它与Autofac一起使用的方式:
var assembly = typeof(MyModule).Assembly;
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
但是您不希望因某些原因切换到Autofac(例如,您希望使用外部库的扩展来注册其依赖项)。 所以我的建议是创建一些使用反射的扩展:
public static IServiceCollection AddSingletonsByConvention(this IServiceCollection services, Assembly assembly, Func<Type, bool> interfacePredicate, Func<Type, bool> implementationPredicate)
{
var interfaces = assembly.ExportedTypes
.Where(x => x.IsInterface && interfacePredicate(x))
.ToList();
var implementations = assembly.ExportedTypes
.Where(x => !x.IsInterface && !x.IsAbstract && implementationPredicate(x))
.ToList();
foreach (var @interface in interfaces)
{
var implementation = implementations.FirstOrDefault(x => @interface.IsAssignableFrom(x));
if (implementation == null) continue;
services.AddSingleton(@interface, implementation);
}
return services;
}
public static IServiceCollection AddSingletonsByConvention(this IServiceCollection services, Assembly assembly, Func<Type, bool> predicate)
=> services.AddSingletonsByConvention(assembly, predicate, predicate);
现在,您可以通过以下简单代码注册所有服务:
var assembly = typeof(MyType).Assembly;
services.AddSingletonsByConvention(assembly, x => x.Name.EndsWith("Service"));
随意自定义这些扩展程序以满足您的需求。 例如,如果您没有找到某些服务的实现,那么您可以触发异常,如果这会让您感觉更安全一些。
答案 1 :(得分:1)
开箱即用的DI不支持它,也不打算这样做。内置的IoC容器在设计上保持简单,允许基本依赖注入,适用于大多数情况。
如果您需要按惯例注册,装配扫描或装饰器支持等高级功能,则必须使用第三方IoC容器,如Autofac,SimpleInjector,Castle Windsor。
答案 2 :(得分:1)
答案 3 :(得分:0)
如果愿意,可添加到@cherepets的答案中
您可以使用此功能:
public void AddTransientsByConvention(IServiceCollection services, Assembly[] assemblies, Func<Type, bool> myPredicate)
{
List<Type> interfaces = new List<Type>();
List<Type> implementations = new List<Type>();
foreach (var assembly in assemblies)
{
interfaces.AddRange(assembly.ExportedTypes.Where(x => x.IsInterface && myPredicate(x)));
implementations.AddRange(assembly.ExportedTypes.Where(x => !x.IsInterface && !x.IsAbstract && myPredicate(x)));
}
foreach (var @interface in interfaces)
{
var implementation = implementations
.FirstOrDefault(x => @interface.IsAssignableFrom(x) &&
$"I{x.Name}" == @interface.Name );
if (implementation == null)
throw new Exception($"Couldn't find implementation for interface {@interface}");
services.AddTransient(@interface, implementation);
}
}
然后在您的ConfigureServicescs中这样调用它:
var assemblyOne = Assembly.GetAssembly(typeof(IMyRepository));
var assemblyTwo = Assembly.GetAssembly(typeof(IMyBusinessLogic));
var assemblyThree = Assembly.GetExecutingAssembly();
AddTransientsByConvention(services,
new [] { assemblyOne, assemblyTwo , assemblyThree },
x => x.Namespace.StartsWith("CompanyName"));