Skip to content

Instantly share code, notes, and snippets.

@NikitaChizhov
Created February 11, 2020 20:59
Show Gist options
  • Save NikitaChizhov/fd45a083815ac14007b5d9391ca41814 to your computer and use it in GitHub Desktop.
Save NikitaChizhov/fd45a083815ac14007b5d9391ca41814 to your computer and use it in GitHub Desktop.
internal static class ServiceCollectionsExtensions
{
public static IServiceCollection DecorateWithDispatchProxy<TInterface, TProxy>(this IServiceCollection services)
where TInterface : class
where TProxy : DispatchProxy
{
MethodInfo createMethod;
try
{
createMethod = typeof(TProxy)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.First(info => !info.IsGenericMethod && info.ReturnType == typeof(TInterface));
}
catch (InvalidOperationException e)
{
throw new InvalidOperationException($"Looks like there is no static method in {typeof(TProxy)} " +
$"which creates instance of {typeof(TInterface)} (note that this method should not be generic)", e);
}
var argInfos = createMethod.GetParameters();
// Save all descriptors that needs to be decorated into a list.
var descriptorsToDecorate = services
.Where(s => s.ServiceType == typeof(TInterface))
.ToList();
if (descriptorsToDecorate.Count == 0)
{
throw new InvalidOperationException($"Attempted to Decorate services of type {typeof(TInterface)}, " +
"but no such services are present in ServiceCollection");
}
foreach (var descriptor in descriptorsToDecorate)
{
var decorated = ServiceDescriptor.Describe(
typeof(TInterface),
sp =>
{
var decoratorInstance = createMethod.Invoke(null,
argInfos.Select(
info => info.ParameterType == (descriptor.ServiceType ?? descriptor.ImplementationType)
? sp.CreateInstance(descriptor)
: sp.GetRequiredService(info.ParameterType))
.ToArray());
return (TInterface) decoratorInstance;
},
descriptor.Lifetime);
services.Remove(descriptor);
services.Add(decorated);
}
return services;
}
private static object CreateInstance(this IServiceProvider services, ServiceDescriptor descriptor)
{
if (descriptor.ImplementationInstance != null)
{
return descriptor.ImplementationInstance;
}
if (descriptor.ImplementationFactory != null)
{
return descriptor.ImplementationFactory(services);
}
return ActivatorUtilities.GetServiceOrCreateInstance(services, descriptor.ImplementationType);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment