Home > Mobile >  .net core register generic interface and retrieve them using getservice
.net core register generic interface and retrieve them using getservice

Time:10-15

I have interface IOrder<T> and FurnitureOrder<T> implements it

I need to register multiple implementations like this

services.AddSingleton(IOrder<Chair>, FurnitureOrder<Chair>())
services.AddSingleton(IOrder<Table>, FurnitureOrder<Table>())

Now I have need to retrieve all IOrder services and the types(e.g chair, table) to do some background work on it. Can I get it using GetServices API? if not possible, Please suggest if design changes needed

CodePudding user response:

One way to do it is to introduce some common non-generic interface IOrder and register all services as it (something similar framework does for hosted services registration and execution):

interface IOrder
{
}

interface IOrder<T> : IOrder
{    
}

services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrder, FurnitureOrder<Chair>>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrder, FurnitureOrder<Table>>());

And then you will be able either inject them as IEnumerable<IOrder> into your dependent class or use IServiceProvider.GetServices<IOrder>() call to resolve them.

Also note that next registration also should work:

services.AddSingleton<IOrder, FurnitureOrder<Chair>>()
services.AddSingleton<IOrder, FurnitureOrder<Table>>()

If you need generic registrations also you can automate non-generic registration with something like this (after registering all generic ones):

var serviceDescriptors = services
    .Where(descriptor => descriptor.ServiceType.IsConstructedGenericType)
    .Where(descriptor =>
        descriptor.ServiceType.GetGenericTypeDefinition() == typeof(IOrder<>));
foreach (var sd in serviceDescriptors)
{
    services.TryAddEnumerable(ServiceDescriptor.Transient(typeof(IOrder), 
        p => p.GetService(sd.ServiceType))); // or add desciptor creating new based on existing one  
}

CodePudding user response:

Presume You mean during excecution of ConfigureServices? You could do this:

    services.AddSingleton(typeof(IOrder<Chair>), f => new ChairOrder());

    var listOf = new List<ServiceDescriptor>();
    using var enumerator = services.GetEnumerator();
    while (enumerator.MoveNext())
                    {
                        var interfaceType = enumerator.Current.ServiceType;
                        if (!interfaceType.IsGenericType) continue;
                        if (interfaceType.Name.StartsWith("iorder", System.StringComparison.OrdinalIgnoreCase))
                            listOf.Add(enumerator.Current);                          
                    }
                    var sp = services.BuildServiceProvider();
                    foreach(var serviceDescriptor in listOf)
                    {
                        var interfaceIWant = serviceDescriptor.ServiceType;
                        var objectToUse = sp.GetRequiredService(serviceDescriptor.ServiceType);                            
                        //TODO:
                    }
  • Related