I am registering all of my services to ServiceCollection using reflection and that's why I am using ServiceDescriptor. Although it is working fine for Concrete type but not working for Generic type.
For example:
Generic Service Type:
public interface IRepository<T>
where T: class
{
string Welcome(string name);
}
Generic Implementaion Type:
public class EfCoreRepository<T> : IRepository<T>
where T : class
{
public string Welcome(string name)
{
return $"Welcome! {name}";
}
}
Adding to ServiceCollection as follows:
Type serviceType = Getting Type of IRepository<T> using reflection.
Type implementationType = Getting Type of EfCoreRepository<T> using reflection.
serviceCollection.Add(new ServiceDescriptor(serviceType, implementationType , ServiceLifetime.Scoped));
Throwing the following exception:
ArgumentException: Cannot instantiate implementation type 'Demo.Implementations.EfCoreRepository
1[T]' for service type 'Demo.GenericServices.IRepository1[T]'.
If I remove the generics it works fine.
Please help me in this regard. Thank you.
@Tratcher should this be transferred to the dotnet/runtime repo?
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.
What types did you pass to ServiceDescriptor? Specifically, the real code for this:
C#
Type serviceType = Getting Type of IRepository<T> using reflection.
Type implementationType = Getting Type of EfCoreRepository<T> using reflection.
serviceCollection.Add(new ServiceDescriptor(serviceType, implementationType , ServiceLifetime.Scoped));
You need to either pass a closed generic or an open generic type
@davidfowl
What types did you pass to ServiceDescriptor?
The service type is typeof(IRepository<T>) and the implementation type is typeof(EfCoreRepository<T>) which is getting using reflection at runtime.
Please look at the error message:
ArgumentException: Cannot instantiate implementation type 'Demo.Implementations.EfCoreRepository1[T]' for service type 'Demo.GenericServices.IRepository1[T]'.
What is the T? Can you show all of the code? It is it in a generic class, or a generic method?
@davidfowl Please read the original question thoroughly. I have explained everything clearly with real examples where it is also said that what is T. By the way, 'T' is the generic type with class constraint.
@davidfowl Please read the original question thoroughly. I have explained everything clearly with real examples where it is also said that what is T. By the way, 'T' is the generic type with class constraint.
Sorta, you're missing some code. I'd like something runnable.
If that isn't possible I can guess what you want:
C#
serviceCollection.Add(new ServiceDescriptor(typeof(IRepository<>), typeof(EfCoreRepository<>) , ServiceLifetime.Scoped));
@davidfowl Okay. Here is my repository: https://github.com/TanvirArjel/AspNetCore.ServiceRegistration.Dynamic/blob/master/src/AspNetCore.ServiceRegistration.Dynamic/ServiceCollectionExtensions.cs#L73
You can download the full repository and run it on your side.
The GetInterfaces() method for a type with IsGenericTypeDefinition == true returns the list of types with IsGenericTypeDefinition == false, so the typeof(IType<T>) != typeof(Type<T>).GetInterfaces()[0]
Accordingly, you need to normalize the interface type by calling the serviceType.GetGenericTypeDefinition() here https://github.com/TanvirArjel/AspNetCore.ServiceRegistration.Dynamic/blob/master/src/AspNetCore.ServiceRegistration.Dynamic/ServiceCollectionExtensions.cs#L73 like this, for example
var isGenericTypeDefinition = implementation.IsGenericType && implementation.IsGenericTypeDefinition;
var service = isGenericTypeDefinition
&& serviceType.IsGenericType
&& serviceType.IsGenericTypeDefinition == false
&& serviceType.ContainsGenericParameters
? serviceType.GetGenericTypeDefinition()
: serviceType;
serviceCollection.Add(new ServiceDescriptor(service, implementation, lifetime));

@rameel Thank you so much from the bottom of my heart for your contribution. My issue has been solved.
Most helpful comment
The
GetInterfaces()method for a type withIsGenericTypeDefinition == truereturns the list of types withIsGenericTypeDefinition == false, so thetypeof(IType<T>) != typeof(Type<T>).GetInterfaces()[0]Accordingly, you need to normalize the interface type by calling the
serviceType.GetGenericTypeDefinition()here https://github.com/TanvirArjel/AspNetCore.ServiceRegistration.Dynamic/blob/master/src/AspNetCore.ServiceRegistration.Dynamic/ServiceCollectionExtensions.cs#L73 like this, for example