After using other DI containers like Microsoft Unity, StructureMap and Autofac, I'm now using the built-in Microsoft.Extensions.DependencyInjection DI container most of the time. The default DI container lacks some more advanced features that these other containers have, but for most use cases it is sufficient.
Most of the time when registering a type as a service, you want to register it with the interface it implements:
serviceCollection.AddTransient<IProductService, ProductService>(); | |
serviceCollection.AddTransient<IOrderService, OrderService>(); |
To simplify this I created an extension method AsImplementedInterfaces
that register a type with all its interfaces:
/// <summary> | |
/// Register all interfaces for a type. | |
/// </summary> | |
/// <returns>The original <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />.</returns> | |
public static IServiceCollection AsImplementedInterfaces(this IServiceCollection services) | |
{ | |
var lastRegistration = services.LastOrDefault(); | |
if (lastRegistration != null) | |
{ | |
var implementationType = GetImplementationType(lastRegistration); | |
// We except that this method is called when a service is registered as a concrete type. | |
// If this is not the case, we bail out | |
if (lastRegistration.ServiceType != implementationType) | |
return services; | |
var interfaces = lastRegistration.ServiceType.GetInterfaces(); | |
foreach (var @interface in interfaces) | |
{ | |
// Register all interfaces proxying to our specific registration | |
services.Add(new ServiceDescriptor( | |
@interface, | |
provider => provider.GetService(implementationType), | |
lastRegistration.Lifetime)); | |
} | |
return services; | |
} | |
return services; | |
} | |
private static Type? GetImplementationType(ServiceDescriptor descriptor) | |
{ | |
if (descriptor.ImplementationType != null) | |
{ | |
return descriptor.ImplementationType; | |
} | |
if (descriptor.ImplementationInstance != null) | |
{ | |
return descriptor.ImplementationInstance.GetType(); | |
} | |
if (descriptor.ImplementationFactory != null) | |
{ | |
return descriptor.ImplementationFactory.GetType().GenericTypeArguments[1]; | |
} | |
return null; | |
} |
To use this method, you call any of the Add
methods on the IServiceProvider
and call the AsImplementedInterfaces
method afterwards:
serviceCollection.AddTransient<OrderService>().AsImplementedInterfaces(); | |
serviceCollection.AddTransient<ProductService>().AsImplementedInterfaces(); | |
Feel free to use it in your own projects...
Remark: If you are looking for some other convenience methods that can help you when using the default DI container, check out Scrutor.