Reputation: 15559
I am using ASP.NET MVC 5, and I am using the default template that MS provides when creating a new project.
I want to add an injected EmailService
into AccountController
:
[Authorize]
public class AccountController : ControllerBase
{
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
private IEmailService _emailService; // <-- added this field to MS template
public AccountController()
{
}
// I have added emailService to constructor parameter
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, IEmailService emailService)
{
UserManager = userManager;
SignInManager = signInManager;
_emailService = emailService;
}
I am using ninject, and this is how I resolve IEmailService
:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IEmailService>().To<MyEmailService>().InRequestScope();
}
Now, my emailService
is not getting injected into AccountController
... so I started debugging the code and noticed that the parameter-less constructor is used to initialize the AccountController
... but the strange thing is, userManager
and signInManager
are still accessible!
For example, I click on Forgot password, the parameter-less constructor initializes AccountController
, and then the following action method is called (which is part of MVC project template):
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
/* UserManager is successfully injected!! */
var user = await UserManager.FindByNameAsync(model.Email);
// some code here to build an email...
/* _emailService is NULL!! */
await _emailService.SendEmailAsync(email);
}
Question 1: How is it possible userManager
and signInManager
are injected through the parameter-less constructor.
Question 2: How can I inject my EmailService
into AccountController
?
Upvotes: 1
Views: 378
Reputation: 15559
This is what I did in the end:
public AccountController(IEmailService emailService)
{
_emailService = emailService;
}
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, IEmailService emailService)
: this(emailService)
{
UserManager = userManager;
SignInManager = signInManager;
}
I didn't change any of the ninject code.
Upvotes: 2
Reputation: 247008
Question 1: How is it possible userManager and signInManager are injected through the parameter-less constructor.
It is not being injected via parameterless constructor. If you check the controller you will see the UserManager
and SignInManager
lazy loading via OWIN context if they were not already set in the constructor.
public ApplicationSignInManager SignInManager {
get {
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set {
_signInManager = value;
}
}
public ApplicationUserManager UserManager {
get {
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set {
_userManager = value;
}
}
That was usually part of the default template.
Question 2: How can I inject my EmailService into AccountController?
Remove the parameter-less constructor and the lazy loading. Then make sure all dependencies are registered in the dependency resolver so that the object graph can be resolved via the IDependencyResolver
used by the framework.
var kernel = new StandardKernel();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver =
new Ninject.Web.WebApi.NinjectDependencyResolver(kernel); //Web API
System.Web.Mvc.DependencyResolver
.SetResolver(new Ninject.Web.Mvc.NinjectDependencyResolver(kernel)); // MVC
return kernel;
Upvotes: 4