Decorator registration fails with 5.0.1 and works with 4.1.0
Opened this issue · 2 comments
markuspalme commented
This open generics registration worked with 4.1.0:
foreach (var serviceType in typeof(ICommandHandler<>).Assembly.GetTypes())
{
if (serviceType.IsAbstract || serviceType.IsInterface || serviceType.BaseType == null)
{
continue;
}
foreach (var interfaceType in serviceType.GetInterfaces())
{
if (interfaceType.IsGenericType && typeof(ICommandHandler<>).IsAssignableFrom(interfaceType.GetGenericTypeDefinition()))
{
serviceCollection.AddScoped(interfaceType, serviceType);
break;
}
}
}
serviceCollection.Decorate(typeof(ICommandHandler<>), typeof(CommandLoggingDecorator<>));
With any of the 4.2.x releases (after the big decoration PR) I'm seeing this exception:
System.ArgumentException: Cannot instantiate implementation type 'My.CommandLoggingDecorator`1[TCommand]' for service type 'Type: ICommandHandler`1+Decorated'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.Populate()
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()
at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()
at Program.<Main>$(String[] args) in Program.cs:line 125
Now I've tried my luck again with 5.0.1 but am getting this exception:
Unhandled exception. System.ArgumentException: Type My.ICommandHandler`1[TCommand] contains generic parameters (Parameter 'type')
at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Int32 index)
at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Boolean allowByRef, Boolean allowPointer)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.BuildFactoryExpression(ConstructorInfo constructor, Nullable`1[] parameterMap, Expression serviceProvider, Expression factoryArgumentArray)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateFactoryInternal(Type instanceType, Type[] argumentTypes, ParameterExpression& provider, ParameterExpression& argumentArray, Expression& factoryExpressionBody)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateFactory(Type instanceType, Type[] argumentTypes)
at Scrutor.DecorationStrategy.TypeDecorator(Type serviceType, String serviceKey, Type decoratorType)
at Scrutor.OpenGenericDecorationStrategy.CreateDecorator(Type serviceType, String serviceKey)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions.TryDecorate(IServiceCollection services, DecorationStrategy strategy)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions.Decorate(IServiceCollection services, DecorationStrategy strategy)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions.Decorate(IServiceCollection services, Type serviceType, Type decoratorType)
at My.RegisterCommandHandlers(IServiceCollection serviceCollection)
at Program.<Main>$(String[] args) in Program.cs:line 123
Is this scenario no longer supported?
If helpful I can provide a self-contained example.
markuspalme commented
I managed to get this working again by using this (much more concise) piece of code:
builder.Services.Scan(scan => scan
.FromAssemblyOf<SomeTypeInTheRightAssembly>()
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>)))
.AsImplementedInterfaces()
.WithTransientLifetime());
builder.Services.Decorate(typeof(ICommandHandler<>), typeof(CommandLoggingDecorator<>));
But I decided to keep the issue open because it shows a breaking change nevertheless.
khellang commented
Hmm. I'm not sure whats going on there. It seems like maybe it's registering a generic type without all the geric type arguments?
Anyway, your second working code is what I'd call idiomatic registration code using Scrutor, so if it works, that's good 🤪