如何在c#中通过反射向依赖容器服务注册服务
How to register services with dependency container services by reflection in c#
我有一个接口 IProcessor
和实现该接口的多个处理器:
Processor1 : IProcessor
Processor2 : IProcessor
我想将这些处理器注入到 class 中,例如:IEnumerable<IProcessor>
这样我就可以 运行 它们一个接一个。
我可以用 Microsoft 依赖项注入容器一个一个地注册这些,但我想通过反射来完成,以便自动注册新添加的处理器。
var processorInterface = typeof(IProcessor);
var processors = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => processorInterface.IsAssignableFrom(t) && t.IsClass &&
!t.IsAbstract && t.IsPublic);
foreach (var processor in processors)
{
serviceCollection.AddScoped(processor);
// Below line does not compile of course
//serviceCollection.AddScoped<IProcessor, processor>());
}
但这不起作用,我总是得到一个空列表。
AddScoped
已经存在采用服务和实现类型的重载扩展。
/// Adds a scoped service of the type specified in <paramref name="serviceType"/> with an
/// implementation of the type specified in <paramref name="implementationType"/> to the
/// specified <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <param name="serviceType">The type of the service to register.</param>
/// <param name="implementationType">The implementation type of the service.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
/// <seealso cref="ServiceLifetime.Scoped"/>
public static IServiceCollection AddScoped(
this IServiceCollection services,
Type serviceType,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type implementationType)
{
ThrowHelper.ThrowIfNull(services);
ThrowHelper.ThrowIfNull(serviceType);
ThrowHelper.ThrowIfNull(implementationType);
return Add(services, serviceType, implementationType, ServiceLifetime.Scoped);
}
将其应用于您的示例时看起来像
//...
foreach (var processor in processors) {
serviceCollection.AddScoped(processor);
serviceCollection.AddScoped(processorInterface, processor);
}
//...
我想通过使用属性建议一种不同的方法。
我在这里创建了一个属性,我称之为 InjectableAttribute
:
[AttributeUsage(AttributeTargets.Class)]
public class InjectableAttribute: Attribute
{
public Type ImplementedInterface { get; }
public DependencyInjectionScope Scope { get; }
public InjectableAttribute(Type implementedInterface, DependencyInjectionScope scope = DependencyInjectionScope.Singleton)
{
ImplementedInterface = implementedInterface;
Scope = scope;
}
}
我创建这个枚举也是为了指定依赖的范围:
public enum DependencyInjectionScope
{
Singleton,
PerDependency,
Scoped
}
最后,我创建了这个扩展方法来扫描我的程序集并注入所有具有 InjectableAttribute:
的 classes
namespace Microsoft.Extensions.DependencyInjection
{
public static class DependencyInjectionExtensions
{
public static void RegisterDependencies(this IServiceCollection services, Assembly assembly)
{
var types = assembly
.ExportedTypes
.Where(x => x.GetCustomAttributes(typeof(InjectableAttribute), true).Length > 0)
.ToList();
for (var i = 0; i < types.Count; i++)
{
var currentType = types[i];
var attributes = (InjectableAttribute[])currentType.GetCustomAttributes(typeof(InjectableAttribute),
true);
var attribute = attributes[0];
var implementedInterface = attribute.ImplementedInterface;
switch (attribute.Scope)
{
case DependencyInjectionScope.Scoped:
services.AddScoped(implementedInterface, currentType);
break;
case DependencyInjectionScope.PerDependency:
services.AddTransient(implementedInterface, currentType);
break;
case DependencyInjectionScope.Singleton:
services.AddSingleton(implementedInterface, currentType);
break;
}
}
}
}
}
现在要使用它,这里有一个服务示例 class:
[Injectable(typeof(ICustomerInfoService), DependencyInjectionScope.Scoped)]
public class CustomerInfoService : ICustomerInfoService
{
}
并在我的 ConfigureServices 方法中注册所有内容:
services.RegisterDependencies(typeof(Startup).Assembly);
希望对您有所帮助 :D
我有一个接口 IProcessor
和实现该接口的多个处理器:
Processor1 : IProcessor
Processor2 : IProcessor
我想将这些处理器注入到 class 中,例如:IEnumerable<IProcessor>
这样我就可以 运行 它们一个接一个。
我可以用 Microsoft 依赖项注入容器一个一个地注册这些,但我想通过反射来完成,以便自动注册新添加的处理器。
var processorInterface = typeof(IProcessor);
var processors = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => processorInterface.IsAssignableFrom(t) && t.IsClass &&
!t.IsAbstract && t.IsPublic);
foreach (var processor in processors)
{
serviceCollection.AddScoped(processor);
// Below line does not compile of course
//serviceCollection.AddScoped<IProcessor, processor>());
}
但这不起作用,我总是得到一个空列表。
AddScoped
已经存在采用服务和实现类型的重载扩展。
/// Adds a scoped service of the type specified in <paramref name="serviceType"/> with an
/// implementation of the type specified in <paramref name="implementationType"/> to the
/// specified <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <param name="serviceType">The type of the service to register.</param>
/// <param name="implementationType">The implementation type of the service.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
/// <seealso cref="ServiceLifetime.Scoped"/>
public static IServiceCollection AddScoped(
this IServiceCollection services,
Type serviceType,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type implementationType)
{
ThrowHelper.ThrowIfNull(services);
ThrowHelper.ThrowIfNull(serviceType);
ThrowHelper.ThrowIfNull(implementationType);
return Add(services, serviceType, implementationType, ServiceLifetime.Scoped);
}
将其应用于您的示例时看起来像
//...
foreach (var processor in processors) {
serviceCollection.AddScoped(processor);
serviceCollection.AddScoped(processorInterface, processor);
}
//...
我想通过使用属性建议一种不同的方法。
我在这里创建了一个属性,我称之为 InjectableAttribute
:
[AttributeUsage(AttributeTargets.Class)]
public class InjectableAttribute: Attribute
{
public Type ImplementedInterface { get; }
public DependencyInjectionScope Scope { get; }
public InjectableAttribute(Type implementedInterface, DependencyInjectionScope scope = DependencyInjectionScope.Singleton)
{
ImplementedInterface = implementedInterface;
Scope = scope;
}
}
我创建这个枚举也是为了指定依赖的范围:
public enum DependencyInjectionScope
{
Singleton,
PerDependency,
Scoped
}
最后,我创建了这个扩展方法来扫描我的程序集并注入所有具有 InjectableAttribute:
的 classesnamespace Microsoft.Extensions.DependencyInjection
{
public static class DependencyInjectionExtensions
{
public static void RegisterDependencies(this IServiceCollection services, Assembly assembly)
{
var types = assembly
.ExportedTypes
.Where(x => x.GetCustomAttributes(typeof(InjectableAttribute), true).Length > 0)
.ToList();
for (var i = 0; i < types.Count; i++)
{
var currentType = types[i];
var attributes = (InjectableAttribute[])currentType.GetCustomAttributes(typeof(InjectableAttribute),
true);
var attribute = attributes[0];
var implementedInterface = attribute.ImplementedInterface;
switch (attribute.Scope)
{
case DependencyInjectionScope.Scoped:
services.AddScoped(implementedInterface, currentType);
break;
case DependencyInjectionScope.PerDependency:
services.AddTransient(implementedInterface, currentType);
break;
case DependencyInjectionScope.Singleton:
services.AddSingleton(implementedInterface, currentType);
break;
}
}
}
}
}
现在要使用它,这里有一个服务示例 class:
[Injectable(typeof(ICustomerInfoService), DependencyInjectionScope.Scoped)]
public class CustomerInfoService : ICustomerInfoService
{
}
并在我的 ConfigureServices 方法中注册所有内容:
services.RegisterDependencies(typeof(Startup).Assembly);
希望对您有所帮助 :D