Search code examples
c#inversion-of-control

Why IServiceCollection.AddScoped<TService, TImplementation>() cannot get TImplementation?


Here is a demo run on .net core 3.1 It will invoke HomeController'constructor When build up an object by method provider.GetRequiredService().And HomeController'constructor has to input an object in it which is an instance generated of "GreetingService",obviously.

In the processes of creating an object from container,generated an instance of "GreetingService" seems must and natural.But why we cann't invoke method provider.GetRequiredService() and get the instance?

using System;
using Microsoft.Extensions.DependencyInjection;

namespace DIDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceCollection service = new ServiceCollection();
            service.AddScoped<IGreetingService, GreetingService>();
            service.AddScoped<HomeController>();
            var provider = service.BuildServiceProvider();
            //var result = provider.GetRequiredService<GreetingService>();  why wrong
            var result = provider.GetRequiredService<HomeController>();
            result.Hello("Bob");
        }
    }

    public class HomeController
    {
        private readonly IGreetingService _greetingService;
        public HomeController(IGreetingService greetingService)
        {
            _greetingService = greetingService;
        }

        public string Hello(string name) => _greetingService.Greet(name);
    }

    public interface IGreetingService
    {
        string Greet(string name);
    }

    public class GreetingService : IGreetingService
    {
        public string Greet(string name)
        {
            Console.WriteLine($"Hello,{name}");
            return "Done";
        }
    }
}

Solution

  • This is because you have registered interface - IGreetingService, not the class GreetingService. Next will work:

    var result = provider.GetRequiredService<IGreetingService>();  
    

    If you look at the Add.. methods signature which have 2 generic parameters you will see next:

    public static IServiceCollection AddScoped<TService,TImplementation> (this Microsoft.Extensions.DependencyInjection.IServiceCollection services) where TService : class where TImplementation : class, TService; 
    

    So in you GreetingService case TService is IGreetingService and TImplementation is GreetingService as is described in docs:

    Adds a scoped service of the type specified in TService with an implementation type specified in TImplementation to the specified IServiceCollection.

    And for single generic parameter version:

    public static IServiceCollection AddScoped<TService> (this Microsoft.Extensions.DependencyInjection.IServiceCollection services) where TService : class;
    

    Adds a scoped service of the type specified in TService to the specified IServiceCollection.