Explicitly instantiating a C# class that uses DI - why doesn't it work?

Viewed 745

I'm using ASP.NET Core Web API. I am having a hard time wrapping my head around instantiating a non-controller class that uses DI. There are a multitude of SO articles related to this, but none that have answered my question (as far as I can understand). These are the most popular and relevant:

Net Core Dependency Injection for Non-Controller

Dependency Injection without a Controller

ASP.NET 5 Non-Controller DI injection

My use case (a contrived example):

I have a class SpeechWriter that has a dependency on IRandomTextService:

public class SpeechWriter
{
    private readonly IRandomTextService _textService;
    
    // Constructor with Text Service DI
    public SpeechWriter(IRandomTextService textService)
    {
        _textService = textService;
    }

    public string WriteSpeech()
    {
        var speech = _textService.GetText(new Random().Next(5,50));

        return speech;
    }
}

IRandomTextService interface:

public interface IRandomTextService
{
    public string GetText(int wordCount);
}

and the implementation:

public class RandomTextService : IRandomTextService
{
    public string GetText(int wordCount)
    {
        return Lorem.Words(wordCount);
    }
}

IRandomTextService is registered as a service in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddScoped<IRandomTextService, RandomTextService>();
}

In my controller action, if I want to instantiate a SpeechWriter like this:

public IActionResult Index()
{
    var speech = new SpeechWriter();

    return Ok(speech.WriteSpeech());
}

I can't do it because an argument (the injected service) is expected.

SpeechWriter requires the RandomTextService as a parameter

The only way I can seem to get DI to inject RandomTextService in SpeechWriter is if SpeechWriter itself is a service and injected in the controller:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddScoped<IRandomTextService, RandomTextService>();
    services.AddScoped<SpeechWriter>();
}
public class EchoController : ControllerBase
{
    private readonly SpeechWriter _speechWriter;
    
    public EchoController(SpeechWriter speechWriter)
    {
        _speechWriter = speechWriter;
    }
    
    
    public IActionResult Index()
    {
        return Ok(_speechWriter.WriteSpeech());
    }
}

Is there any way to get RandomTextService injected when SpeechWriter is instantiated as in my first example, like this?

var speech = new SpeechWriter();

If not, what is it about DI that I'm missing? My actual application is more complex than this and I would effectively have to create a chain of DI and services all the way back up to the controller. I could use the ServiceProvider "anti-pattern", but I prefer not to do that because I'd be passing ServiceProvider all over the place.

Please help educate me!

Thanks.

0 Answers
Related