I have an ASP.NET Core Web application that has an interface in the application that inherits a class from the interface. I am trying to use the interface by dependency injection in the controller constructor, but I always get the following error
An unhandled exception occurred while processing the request. InvalidOperationException: Unable to resolve service for type 'DependenceInjection_Dapper.Services.SendSMS' while attempting to activate 'DependenceInjection_Dapper.Controllers.HomeController'. Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
The interface codes are as follows:
public interface IsmsSender
{
string sendSms();
}
The class codes are as follows:
public class SendSms : IsmsSender
{
public string sendSms()
{
return "send sms";
}
}
And the following code is added in the program.cs
file:
builder.Services.AddTransient<IsmsSender, SendSms>();
Also, the manufacturer of the controller is as follows:
public class HomeController : Controller
{
private readonly IsmsSender _smsSender;
public HomeController(SendSms smsSender)
{
_smsSender = smsSender;
}
public IActionResult Index()
{
ViewBag.send = _smsSender.sendSms();
return View();
}
}
However, I always get an error.
I behaved exactly according to the Microsoft documentation, but the problem was not solved.
CodePudding user response:
You are injecting the concrete type instead of the interface, which is what you registered. Do this instead:
public class HomeController : Controller
{
private readonly IsmsSender _smsSender;
public HomeController(IsmsSender smsSender)
{
_smsSender = smsSender;
}
public IActionResult Index()
{
ViewBag.send = _smsSender.sendSms();
return View();
}
}
Always keep in mind that what matters for the container is the "registration type", not the concrete type. What this line says:
builder.Services.AddTransient<IsmsSender, SendSms>();
Is basically:
Whenever someone asks for an
IsmsSender
, give aSendSms
instance to them
Nothing is said about consumers asking for SendSms
.
It is possible to register the concrete type itself, though that's not usual and not recommended when you already have an abstraction in place: you want to rely on abstractions instead of concrete classes to reduce coupling in your implementation and make it more testable.
To register the concrete class itself, you'd just omit the first generic parameter:
builder.Services.AddTransient<SendSms>();
This now means that people must ask for SendSms
directly, and IsmsSender
won't be resolvable anymore.
CodePudding user response:
The problem comes from your consturctor
public HomeController(SendSms smsSender) { _smsSender = smsSender; }
should be
public HomeController(ISendSms smsSender)
{
_smsSender = smsSender;
}
you registred your ISmendSms as Sendsms in the depenency injection phase.