Skip to content

Commit

Permalink
Improve DependencyInjection.AutoActivationExtensions (#4219)
Browse files Browse the repository at this point in the history
- Avoid calling MakeGenericType when possible.

- Delete the now-useless Hosting.StartupINitialization component.

Co-authored-by: Martin Taillefer <mataille@microsoft.com>
  • Loading branch information
geeknoid and Martin Taillefer authored Jul 27, 2023
1 parent f7daf49 commit 1c4812d
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 857 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,26 @@ public static IServiceCollection Activate<TService>(this IServiceCollection serv
{
_ = Throw.IfNull(services);

return services.Activate(typeof(TService));
_ = services.AddHostedService<AutoActivationHostedService>()
.AddOptions<AutoActivatorOptions>()
.Configure(ao =>
{
var constructed = typeof(IEnumerable<TService>);
if (ao.AutoActivators.Contains(constructed))
{
return;
}
if (ao.AutoActivators.Remove(typeof(TService)))
{
_ = ao.AutoActivators.Add(constructed);
return;
}
_ = ao.AutoActivators.Add(typeof(TService));
});

return services;
}

/// <summary>
Expand All @@ -46,7 +65,26 @@ public static IServiceCollection AddActivatedSingleton<TService, TImplementation
_ = Throw.IfNull(services);
_ = Throw.IfNull(implementationFactory);

return services.AddSingleton<TService, TImplementation>(implementationFactory).Activate(typeof(TService));
return services
.AddSingleton<TService, TImplementation>(implementationFactory)
.Activate<TService>();
}

/// <summary>
/// Adds an auto-activated singleton service of the type specified in TService with an implementation
/// type specified in TImplementation to the specified <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <typeparam name="TService">The type of the service to add.</typeparam>
/// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
/// <returns>A reference to this instance after the operation has completed.</returns>
public static IServiceCollection AddActivatedSingleton<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
return services
.AddSingleton<TService, TImplementation>()
.Activate<TService>();
}

/// <summary>
Expand All @@ -60,7 +98,9 @@ public static IServiceCollection AddActivatedSingleton<TService, TImplementation
public static IServiceCollection AddActivatedSingleton<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory)
where TService : class
{
return services.AddActivatedSingleton(typeof(TService), implementationFactory);
return services
.AddSingleton<TService>(implementationFactory)
.Activate<TService>();
}

/// <summary>
Expand All @@ -72,11 +112,13 @@ public static IServiceCollection AddActivatedSingleton<TService>(this IServiceCo
public static IServiceCollection AddActivatedSingleton<TService>(this IServiceCollection services)
where TService : class
{
return services.AddActivatedSingleton(typeof(TService));
return services
.AddSingleton<TService>()
.Activate<TService>();
}

/// <summary>
/// Adds an autoactivated singleton service of the type specified in serviceType to the specified
/// Adds an auto-activated singleton service of the type specified in serviceType to the specified
/// <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
Expand All @@ -87,26 +129,13 @@ public static IServiceCollection AddActivatedSingleton(this IServiceCollection s
_ = Throw.IfNull(services);
_ = Throw.IfNull(serviceType);

return services.AddSingleton(serviceType).Activate(serviceType);
}

/// <summary>
/// Adds an autoactivated singleton service of the type specified in TService with an implementation
/// type specified in TImplementation to the specified <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <typeparam name="TService">The type of the service to add.</typeparam>
/// <typeparam name="TImplementation">The type of the implementation to use.</typeparam>
/// <returns>A reference to this instance after the operation has completed.</returns>
public static IServiceCollection AddActivatedSingleton<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
return services.AddActivatedSingleton(typeof(TService), typeof(TImplementation));
return services
.AddSingleton(serviceType)
.Activate(serviceType);
}

/// <summary>
/// Adds an autoactivated singleton service of the type specified in serviceType with a factory
/// Adds an auto-activated singleton service of the type specified in serviceType with a factory
/// specified in implementationFactory to the specified <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
Expand All @@ -119,11 +148,13 @@ public static IServiceCollection AddActivatedSingleton(this IServiceCollection s
_ = Throw.IfNull(serviceType);
_ = Throw.IfNull(implementationFactory);

return services.AddSingleton(serviceType, implementationFactory).Activate(serviceType);
return services
.AddSingleton(serviceType, implementationFactory)
.Activate(serviceType);
}

/// <summary>
/// Adds an autoactivated singleton service of the type specified in serviceType with an implementation
/// Adds an auto-activated singleton service of the type specified in serviceType with an implementation
/// of the type specified in implementationType to the specified <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
Expand All @@ -136,7 +167,9 @@ public static IServiceCollection AddActivatedSingleton(this IServiceCollection s
_ = Throw.IfNull(serviceType);
_ = Throw.IfNull(implementationType);

return services.AddSingleton(serviceType, implementationType).Activate(serviceType);
return services
.AddSingleton(serviceType, implementationType)
.Activate(serviceType);
}

/// <summary>
Expand Down Expand Up @@ -199,7 +232,7 @@ public static void TryAddActivatedSingleton<TService>(this IServiceCollection se
{
_ = Throw.IfNull(services);

services.TryAddAndActivate(ServiceDescriptor.Singleton(typeof(TService), typeof(TService)));
services.TryAddAndActivate<TService>(ServiceDescriptor.Singleton<TService, TService>());
}

/// <summary>
Expand All @@ -217,7 +250,7 @@ public static void TryAddActivatedSingleton<TService, TImplementation>(this ISer
{
_ = Throw.IfNull(services);

services.TryAddAndActivate(ServiceDescriptor.Singleton(typeof(TService), typeof(TImplementation)));
services.TryAddAndActivate<TService>(ServiceDescriptor.Singleton<TService, TImplementation>());
}

/// <summary>
Expand All @@ -234,27 +267,16 @@ public static void TryAddActivatedSingleton<TService>(this IServiceCollection se
_ = Throw.IfNull(services);
_ = Throw.IfNull(implementationFactory);

services.TryAddAndActivate(ServiceDescriptor.Singleton(typeof(TService), implementationFactory));
}

private static void TryAddAndActivate(this IServiceCollection services, ServiceDescriptor descriptor)
{
if (services.Any(d => d.ServiceType == descriptor.ServiceType))
{
return;
}

services.Add(descriptor);
_ = services.Activate(descriptor.ServiceType);
services.TryAddAndActivate<TService>(ServiceDescriptor.Singleton<TService>(implementationFactory));
}

[UnconditionalSuppressMessage(
"Trimming",
"IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
Justification = "Addressed with [DynamicallyAccessedMembers]")]
private static IServiceCollection Activate(this IServiceCollection services, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type serviceType)
internal static IServiceCollection Activate(this IServiceCollection services, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type serviceType)
{
_ = services.AddHostedServiceIfNotExist()
_ = services.AddHostedService<AutoActivationHostedService>()
.AddOptions<AutoActivatorOptions>()
.Configure(ao =>
{
Expand All @@ -276,23 +298,26 @@ private static IServiceCollection Activate(this IServiceCollection services, [Dy
return services;
}

// exclude from coverage until https://github.com/microsoft/codecoverage/issues/38 is addressed
[ExcludeFromCodeCoverage]
private static IServiceCollection AddHostedServiceIfNotExist(this IServiceCollection services)
private static void TryAddAndActivate<TService>(this IServiceCollection services, ServiceDescriptor descriptor)
where TService : class
{
#if NETFRAMEWORK
var autoActivationHostedServiceType = typeof(AutoActivationHostedService);
if (services.Any(d => d.ServiceType == descriptor.ServiceType))
{
return;
}

services.Add(descriptor);
_ = services.Activate<TService>();
}

// This loop is needed only for older .NET versions where there's no check
// if the service was already added to the IServiceCollection.
foreach (var service in services)
private static void TryAddAndActivate(this IServiceCollection services, ServiceDescriptor descriptor)
{
if (services.Any(d => d.ServiceType == descriptor.ServiceType))
{
if (service.ImplementationType == autoActivationHostedServiceType)
{
return services;
}
return;
}
#endif
return services.AddHostedService<AutoActivationHostedService>();

services.Add(descriptor);
_ = services.Activate(descriptor.ServiceType);
}
}

This file was deleted.

This file was deleted.

21 changes: 0 additions & 21 deletions src/ToBeMoved/Hosting.StartupInitialization/IStartupInitializer.cs

This file was deleted.

This file was deleted.

Loading

0 comments on commit 1c4812d

Please sign in to comment.