Categories
C# Tutorials

Get a service using its name in AspCore

We all know that we can get services by injecting them directly in the constructor of the class and consume them as we want.

but imagine that you are developing an a generic component in which this component receive the name of service that will be used to get some data for this component, so how we can have an instance for that service as we don’t know its type and we only have its name?

By default, .Net allow us to get instances for registered services using the constructor or by using IServiceProvider GetService() and GetRequiredService() methods, but in order to use these methods we have to know the type of the service which it is not the case here!

So the solution for that is to have an extension method that will extends the capabilities of the IServicePrvider that will make us able to something like:

public class MyClass
{
    public MyClass(IServiceProvider serviceProvider)
    {
        var service = serviceProvider.GetServiceByName("MySerice");
    }
}

And once we get an instance for this service then we can use reflection to call a specific method using its name.

For having that functionality we need to create two extension methods:

public static class IServiceProviderExtension
{
    private static ConcurrentDictionary<string, Type> ServicesDictionary { get; set; } = new();

    public static void AddServicesByName(this IServiceCollection services)
    {
        // initialize dictionary
        foreach (var serviceType in services.Select(w => w.ServiceType))
            ServicesDictionary.TryAdd(serviceType.Name, serviceType);
       
    }

    public static object GetServiceByName(this IServiceProvider serviceProvider, string name)
    {
        ArgumentNullException.ThrowIfNull(name);
        if (!ServicesDictionary.ContainsKey(name.Trim()))
            throw new Exception($"No service with name {name} has been registered, make sure that you have called the method {nameof(AddServicesByName)} after adding all the services.");
        return serviceProvider.GetRequiredService(ServicesDictionary[name]);
    }
}

As you can see from the code above, the extension class has an ConcurrentDictionary<string,Type> that will save service names and types. the first extension method AddServicesByName has to be called in program.cs just after adding all the services needed in your app:

and that’s it, now your IServiceProvider can get services by their names like:

public class MyClass
{
    public MyClass(IServiceProvider serviceProvider)
    {
        var service = serviceProvider.GetServiceByName("MySerice");
    }
}

Hope you like this tutorial, and see you next time.

By Mahmoud AL ABSI

IT developer, Physical therapist and a proud father of a great family

Leave a Reply

Your email address will not be published. Required fields are marked *