Skip to content

Instantly share code, notes, and snippets.

@AntonC9018
Created June 28, 2023 20:09
Show Gist options
  • Save AntonC9018/835650beb22cd4bd10646dd9e257ef06 to your computer and use it in GitHub Desktop.
Save AntonC9018/835650beb22cd4bd10646dd9e257ef06 to your computer and use it in GitHub Desktop.
#nullable enable
using Microsoft.Extensions.DependencyInjection;
public static class ServiceRegistrationHelper
{
/// <summary>
/// Registers the given implementation type under all implementations of a generic service,
/// implemented by the given implementation type.
/// </summary>
/// <returns>True if at least one implementation has been registered</returns>
public static bool RegisterImplementationsOfGenericService<TImplementation>(
this IServiceCollection services,
Type unboundServiceType,
ServiceLifetime lifetime)
where TImplementation : notnull
{
Type implementationType = typeof(TImplementation);
using var implementedServices = implementationType
.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == unboundServiceType)
.GetEnumerator();
if (!implementedServices.MoveNext())
return false;
var firstImpl = implementedServices.Current;
// Register only a single implementation.
if (!implementedServices.MoveNext())
{
var descriptor = new ServiceDescriptor(
firstImpl,
implementationType,
lifetime);
services.Add(descriptor);
return true;
}
// Multiple implementations in one class.
{
var descriptor = new ServiceDescriptor(
implementationType,
implementationType,
lifetime);
services.Add(descriptor);
}
void AddImpl(Type implementedInterface)
{
var descriptor = new ServiceDescriptor(
implementedInterface,
static sp => sp.GetRequiredService<TImplementation>(),
lifetime);
services.Add(descriptor);
}
AddImpl(firstImpl);
do
{
AddImpl(implementedServices.Current);
} while (implementedServices.MoveNext());
return true;
}
public static IServiceCollection RegisterRequiredImplementationsOfGenericService<T>(
this IServiceCollection services,
Type markerServiceType,
Type unboundServiceType,
ServiceLifetime lifetime)
where T : notnull
{
bool registered = services.RegisterImplementationsOfGenericService<T>(
unboundServiceType, lifetime);
if (!registered)
{
throw new InvalidOperationException(
$"{markerServiceType.Name} should only be inherited via {unboundServiceType.Name}");
}
return services;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment