0

As I am learning about Dependency Injection, so I have also shared my understanding (Please correct me wherever you guys feel to do so). The concept behind the following sample is to check the advantage of using Dependency Injection as it helps in implementing loose coupling in the application which will further prevent me from making lots of changes in the project in the case when concrete definitions (classes) tend to change in future.

IEmailService - Interface:

public interface IEmailService
{
    void SendMail();
}

EmailService - Class inheriting above interface

public class EmailService : IEmailService
{
    public EmailService(string emailFrom, string emailTo)
    {

    }

    public void SendMail()
    {
        // Code here 
    }
}

HomeController

public class HomeController : Controller
{
    private IEmailService _service;

    public HomeController(IEmailService service)
    {
       _service = service;
    }

    public IActionResult Index()
    {
        _service.SendMail();
        return View();
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   // Add framework services.
   ...
   services.AddTransient<IEmailService, EmailService>();
   ...
}

Practical assumption

I assume that earlier there was no parameterized constructor in the EmailService class, but in future, I feel like I need to add a parameterized constructor but it shouldn't have an impact on those controllers (like HomeController) which are using abstraction (interfaces) to access them indirectly.

Unfortunately, when I am running the above code, I am getting the following exception which seems to disappear if I am removing the parameterized constructor from EmailService class.

InvalidOperationException: Unable to resolve service for type 'System.String' while attempting to activate 'DependencyInjectionDemo.Services.EmailService'.

5
  • I would move string emailFrom, string emailTo to SendMail() method, since this looks more like the method's responsibility. Then DI will work again. Also, everything that you want DI framework to inject should be registered in ConfigureServices Commented May 16, 2017 at 8:15
  • Good point @Ignas :) but suppose there are global variables defined in the class EmailService which need to be initialized within the constructor. By the way, this code is just for learning purpose. So I am trying to find the right way to encounter such issues, instead of finding a workaround. Commented May 16, 2017 at 8:16
  • "As I am learning about Dependency Injection". Pro tip: read this introductionary chapter of THE book about Dependency Injection. Commented May 16, 2017 at 8:35
  • Thanks @Steven, I will check it out :) Commented May 16, 2017 at 8:40
  • If you are looking for a way to play more with DI, you can add something like IHtmlRenderer etc. to your EmailService constructor. Commented May 16, 2017 at 8:55

1 Answer 1

4

You can register your EmailService using a lambda:

services.AddTransient<IEmailService>(_ => new EmailService("from@", "to@"));

emailFrom and emailTo however seem runtime data, which means that the Controller might be responsible of supplying this information to the IEmailService. Since the EmailService is decoupled from the controller, it means that the controller is not responsible of its creation.

In general, you should prevent needing to initialize your components (EmailService in your case) with runtime data, as explained here, the advice is:

Don't inject runtime data into application components during construction; it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration. My advice is to let runtime data flow through the method calls of constructed object graphs.

In your case this basically means changing the IEmailService abstraction to the following:

public interface IEmailService
{
    void SendMail(string emailFrom, string emailTo);
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your comment :).Meanwhile, I am getting what all you have suggested to me. Can you please redirect me to a practical example where interfaces help in minimal code maintainability (actually what I was trying to achieve in my sample code above) using DI in ASP.NET Core.
@AjendraPrasad: I'm not sure what you're asking here. Your own question is a practical minimal example of where interfaces help. The IEmailService is a practical example.
Sorry for not being clear to you. What I was trying to say is that when I am injecting IEmailService in my HomeController, how the actual implementation in EmailService could change (if it is not by adding parameterized constructor at least) to get me feel like thank god I used DI for loose coupling and hence I don't need to change my code due to changes in concrete class definition. Hope you got it :)
your suggestion perfectly answered my question, as far as it is about to see a clear advantage of using DI, I found this link codearsenal.net/2015/03/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.