How do I inject Identity classes with Ninject? - asp.net-mvc

I'm trying to use UserManager in a class, but I'm getting this error:
Error activating IUserStore{ApplicationUser}
No matching bindings are available, and the type is not self-bindable.
I'm using the default Startup.cs, which sets a single instance per request:
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
I'm able to get the ApplicationDbContext instance, which I believe is getting injected by Owin (Is that true?):
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private ApplicationDbContext context;
public GenericRepository(ApplicationDbContext context)
{
this.context = context;
}
}
But I can't do the same with UserManager (It throws the error shown before):
public class AnunciosService : IAnunciosService
{
private IGenericRepository<Anuncio> _repo;
private ApplicationUserManager _userManager;
public AnunciosService(IRepositorioGenerico<Anuncio> repo, ApplicationUserManager userManager)
{
_repo = repo;
_userManager = userManager;
}
}
The controller uses the UserManager like this:
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
I'm using ninject to inject my other classes, but how do I inject the UserManager with it's dependencies and avoid using it like that in my controllers?

I injected It like this
kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>();
kernel.Bind<UserManager<ApplicationUser>>().ToSelf();
And now It's working as it should.

OP's answer didn't work for me, as I was using a custom ApplicationUser class that has long as a key instead of string .
Hence, I created a generic static method the would get the OwinContext from the current HttpContext and return the desired concrete implementation.
private static T GetOwinInjection<T>(IContext context) where T : class
{
var contextBase = new HttpContextWrapper(HttpContext.Current);
return contextBase.GetOwinContext().Get<T>();
}
I then used GetOwinInjection method for injection like this:
kernel.Bind<ApplicationUserManager>().ToMethod(GetOwinInjection<ApplicationUserManager>);
kernel.Bind<ApplicationSignInManager>().ToMethod(GetOwinInjection<ApplicationSignInManager>);
If you are also using IAuthenticationManger, you should inject it like this:
kernel.Bind<IAuthenticationManager>().ToMethod(context =>
{
var contextBase = new HttpContextWrapper(HttpContext.Current);
return contextBase.GetOwinContext().Authentication;
});

Related

Injecting a service into AccountController

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?
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;
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.

Autofac trouble

I'm new to using Autofac and Dependency injection and have been reading a lot on it. I'm getting an error message:"None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Evaluate.DivisionsController' can be invoked with the available services and parameters:
Cannot resolve parameter 'Evaluate.Services.DivisionService service' of constructor 'Void .ctor(Evaluate.Services.DivisionService)'."
I'm sure my issue is in the syntax I'm using for the configuration.
Here is my configuration in global.asax
//Autofac Configuration
var builder = new Autofac.ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
//builder.RegisterModule(new ServiceModule());
builder.RegisterModule(new EFModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
My EFModule:
builder.RegisterType(typeof(ApplicationDbContext)).As(typeof(IApplicationDbContext)).InstancePerRequest();
builder.RegisterType<UserProvider>().As<IUserProvider>().InstancePerRequest();
builder.RegisterType<DivisionService>().As<IDivisionService>().InstancePerRequest();
Controller:
private DivisionService _divisionService;
public DivisionsController(DivisionService service)
{
_divisionService = service;
}
Division Service:
public class DivisionService : BaseService<Division>, IDivisionService
{
//private IApplicationDbContext _context;
public DivisionService(IApplicationDbContext context)
:base(context)
{
}
ApplicationDBContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
private IUserProvider _user;
public ApplicationDbContext(IUserProvider user)
: base("DefaultConnection", throwIfV1Schema: false)
{
_user = user;
}
User Provider class:
public class UserProvider : IUserProvider
{
public string GetApplicationUserName()
{
return HttpContext.Current.User.ToString();
}
}
I have figured it out. The IDivisionService wasn't inheriting from the IBaseService

can't return roles in AspNetRoles

i need to return all role in identity tabel for create a dropdown list .
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(RoleStore<IdentityRole> store)
: base(store)
{
}
public static ApplicationRoleManager Create(IOwinContext context)
{
var Store = new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>());
// Configure validation logic for usernames
return new ApplicationRoleManager(Store);
}
}
how should i do this ?
Edit
/*******************************************************************************************************/
The process to get all roles via setting up ApplicationRoleManager is the following (as per Identity samples provided by Microsoft found here).
Add the code below to your IdentityConfig.cs
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
}
}
Then initialize the single instance per Owin context of your RoleManager in Startup.Auth.cs:
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
In your controller where you want to get all roles, do the following:
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
private set
{
_roleManager = value;
}
}
After that you can simply use RoleManager.Roles in any of your action methods to get all roles.
This answer contains all the steps you need to get this to work but refer to the link to the nuget package above if you're still unclear on the process.

How to conditionally instantiate a named Unity registration type

I have looked around on StackOverflow for a solution to my problem. Though I don't think this is a unique problem, I haven't been able to find a good solution.
In my WPF application, in my viewmodels, I need to call some services to return some data. These services get injected with UnitOfWork which in turn gets injected with the DbContext. This dbcontext that get injected into the UnitOfWork should differ based on some criteria.
I am having trouble doing the IoC container registrations the right way and injecting the right DbContext at runtime. So, if someone can please fill in the blanks (in the unity registrations as well as it's usage). I have some inline comments in the following code where I am in trouble and need help. Thanks.
If someone can replace my Registration code the right way and also educate me how to use it in my WPF ViewModel class, that would be truly great! Thanks.
One final note: If you find coding errors in this code, please don't start wondering how does this even compile? The code here is not my real code. To simplify things, I just wrote them up. But it does resemble very closely to my real app code.
public interface IDBContext{}
public interface IUnitOfWork{}
public interface ISomeEntityService{}
public interface IRepository<T> where T : class
{ T GetSingle( Expression<Func<T, bool>> predicate ); }
public class DBContext1 : IDBContext
{
public DBContext1(connString) : base(connString){}
}
public class DBContext2 : IDBContext
{
public DBContext2(connString) : base(connString){}
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDBContext context;
private readonly IDbSet<T> dbSet;
public Repository(IDBContext ctx)
{
context = ctx;
dbSet = ((DbContext)context).Set<T>();
}
public T GetSingle( Expression<Func<T, bool>> predicate )
{
return ((DbContext)context).Set<T>().SingleOrDefault(predicate);
}
}
public class UnitOfWork : IUnitOfWork
{
IDBContext ctx;
private Dictionary<string, dynamic> repositories;
public UnitOfWork(IDBContext context)
{
ctx = context;
}
public IRepository<T> Repository<T>() where T : class
{
if (repositories == null)
repositories = new Dictionary<string, dynamic>();
var type = nameof(T);
if (repositories.ContainsKey(type))
return (IRepository<T>)repositories[type];
var repositoryType = typeof(Repository<>);
repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), ctx));
return repositories[type];
}
public int SaveChanges()
{
return ctx.SaveChanges();
}
}
public class MyUnityBootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
Container.RegisterType<IDBContext, DBContext1>("Context1");
Container.RegisterType<IDBContext, DBContext2>("Context2");
Container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
Container.RegisterType<IUnitOfWork, UnitOfWork>();
}
}
public class SomeEntityService : ISomeEntityService
{
private IUnitOfWork uow;
public ConsumerService( IUnitOfWork _uow )
{ uow = _uow; }
public SomeEntity GetSomeData( int id )
{
return uow.Repository<SomeEntity>().GetSingle( x => x.Id == id);
}
}
public class SomeViewModel : BindableBase
{
private readonly ISomeEntityService someService;
public SomeViewModel( ISomeEntityService _someService)
{
// when I call someService, I want to make sure it is using either
// DBContext1 or DBContext2 based on some condition I can set here.
// This is where I am totally stuck.
someService = _someService;
}
// get the repository instance with an id of 1000
someService.GetSomeData( 1000 );
}
/*
I could do something like this. But I am afraid, I am violating
two of the best practices recommendations.
1. I am creating a dependency to my IoC Container here.
2. I am using the container as a Service Locator
*/
public class SomeViewModel : BindableBase
{
private readonly ISomeEntityService someService;
public SomeViewModel()
{
var container = SomeHowGetTheContainer();
/*
1. Call Container.Resolve<IDBContext>(with the required context);
2. Use the retrieved context to inject into the UnitOfWork
3. Use the retrieved UnitOfWork to inject into the service
But that would be like throwing everything about best practices to the wind!
*/
someService = container.Resolve<ISomeEntityService>( /*do some magic here to get the right context*/)
}
// get the repository instance with an id of 1000
someService.GetSomeData( 1000 );
}
Add a factory like this that resolves your ISomeEntityService:
public MySomeEntityServiceFactory
{
public MySomeEntityServiceFactory( IUnityContainer container )
{
_container = container;
}
public ISomeEntityService CreateSomeEntityService( bool condition )
{
return _container.Resolve<ISomeEntityService>( condition ? "VariantA" : "VariantB" );
}
private readonly IUnityContainer _container;
}
and add two named bindings like:
_container.RegisterType<ISomeEntityService, SomeEntityService>( "VariantA", new InjectionConstructor( new ResolvedParameter<IDBContext>( "VariantA" ) ) );
_container.RegisterType<ISomeEntityService, SomeEntityService>( "VariantB", new InjectionConstructor( new ResolvedParameter<IDBContext>( "VariantB" ) ) );
For IUnitOfWork, you can add a similar factory that resolves the unit of work, and call it in SomeEntityService's constructor passing in the IDBContext...
Those factories are additional dependencies themselves, btw...

Accessing UserManager outside AccountController

I am trying to set the value of a column in aspnetuser table from a different controller (not accountcontroller). I have been trying to access UserManager but I can't figure our how to do it.
So far I have tried the following in the controller I want to use it in:
ApplicationUser u = UserManager.FindById(User.Identity.GetUserId());
u.IsRegComplete = true;
UserManager.Update(u);
This would not compile (I think because UserManager has not been instantiated the controller)
I also tried to create a public method in the AccountController to accept the value I want to change the value to and do it there but I can't figure out how to call it.
public void setIsRegComplete(Boolean setValue)
{
ApplicationUser u = UserManager.FindById(User.Identity.GetUserId());
u.IsRegComplete = setValue;
UserManager.Update(u);
return;
}
How do you access and edit user data outside of the Account Controller?
UPDATE:
I tried to instantiate the UserManager in the other controller like so:
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
ApplicationUser u = userManager.FindById(User.Identity.GetUserId());
I the project complied (got a little excited) but when I ran the code I get the following error:
Additional information: The entity type ApplicationUser is not part of the model for the current context.
UPDATE 2:
I have moved the function to the IdentityModel (don't ask I am clutching at straws here) like so:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public Boolean IsRegComplete { get; set; }
public void SetIsRegComplete(string userId, Boolean valueToSet)
{
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>());
ApplicationUser u = new ApplicationUser();
u = userManager.FindById(userId);
u.IsRegComplete = valueToSet;
return;
}
}
However I am still getting the following:
The entity type ApplicationUser is not part of the model for the current context.
There is also the following class in IdentitiesModels.cs:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
What am I doing wrong here? It feels like I am completely barking up the wrong tree. All I am trying to do is update a column in aspnetuser table from the action of a different controller (i.e not the AccountsController).
If you're using the default project template, the UserManager gets created the following way:
In the Startup.Auth.cs file, there's a line like this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
that makes OWIN pipeline instantiate an instance of ApplicationUserManager each time a request arrives at the server. You can get that instance from OWIN pipeline using the following code inside a controller:
Request.GetOwinContext().GetUserManager<ApplicationUserManager>()
If you look carefully at your AccountController class, you'll see the following pieces of code that makes access to the ApplicationUserManager possible:
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Please note, that in case you need to instantiate the ApplicationUserManager class, you need to use the ApplicationUserManager.Create static method so that you have the appropriate settings and configuration applied to it.
If you have to get UserManager's instance in another Controller just add its parameter in Controller's constructor like this
public class MyController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public MyController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;;
}
}
But I have to get UserManager in a class that is not controller !
Any help would be appreciated.
UPDATE
I am considering you are using asp.net core
I ran into this same problem and modified my code to pass a reference to the UserManager class from the Controller to the Model:
//snippet from Controller
public async Task<JsonResult> UpdateUser(ApplicationUser applicationUser)
{
return Json(await UserIdentityDataAccess.UpdateUser(UserManager, applicationUser));
}
//snippet from Data Model
public static async Task<IdentityResult> UpdateUser(ApplicationUserManager userManager, ApplicationUser applicationUser)
{
applicationUser.UserName = applicationUser.Email;
var result = await userManager.UpdateAsync(applicationUser);
return result;
}
FOR MVC 5
The steps to access usermanger or createUser outside Account controller is easy. Follow the below steps
Create a controller, consider SuperAdminController
Decorate the SuperAdminController same as the AccountController as below,
private readonly IAdminOrganizationService _organizationService;
private readonly ICommonService _commonService;
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
public SuperAdminController()
{
}
public SuperAdminController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
{
UserManager = userManager;
SignInManager = signInManager;
}
public SuperAdminController(IAdminOrganizationService organizationService, ICommonService commonService)
{
if (organizationService == null)
throw new ArgumentNullException("organizationService");
if (commonService == null)
throw new ArgumentNullException("commonService");
_organizationService = organizationService;
_commonService = commonService;
}
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;
}
}
Create User in Action method
[HttpPost]
public async Task<ActionResult> AddNewOrganizationAdminUser(UserViewModel userViewModel)
{
if (!ModelState.IsValid)
{
return View(userViewModel);
}
var user = new ApplicationUser { UserName = userViewModel.Email, Email = userViewModel.Email };
var result = await UserManager.CreateAsync(user, userViewModel.Password);
if (result.Succeeded)
{
var model = Mapper.Map<UserViewModel, tblUser>(userViewModel);
var success = _organizationService.AddNewOrganizationAdminUser(model);
return RedirectToAction("OrganizationAdminUsers", "SuperAdmin");
}
AddErrors(result);
return View(userViewModel);
}
If you need access to the UserManager outside of a controller you can use the following:
var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
var applicationManager = new ApplicationUserManager(userStore);

Resources