Accessing UserManager outside AccountController - asp.net-mvc

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);

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.

How UserManager is linked with DbContext?

I have the following code:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("AssetContext", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
ApplicationDbContext dbContext = context.Get<ApplicationDbContext>();
return Create(options, dbContext);
}
.....
}
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
then I have the controller method:
public async Task<ActionResult> EditUser(UserEditViewModel model)
{
var user = mapper.Map<UserEditViewModel, AspNetUser>(model, _db.AspNetUsers.Where(p => p.UserName == model.UserName).FirstOrDefault());
user.CompanyId = null;
user.LockoutEnabled = false;
user.LockoutEndDateUtc = null;
_db.SaveChanges();
var roles = UserManager.GetRoles(user.Id);
UserManager.AddToRole(user.Id, model.RoleName);
UserManager.RemoveFromRoles(user.Id, roles.ToArray());
return RedirectToAction("UserList");
}
(please, don't say me about DI, I'm not an owner of code :) )
Problem is that all changes in user :
user.CompanyId = null;
user.LockoutEnabled = false;
user.LockoutEndDateUtc = null;
is rewritten when I call
UserManager.AddToRole(user.Id, model.RoleName);
why it happens?
UserManager directly depends on UserStore and that directly depends on IdentityDbContext. Every operation in UserManager that involves access to db will be using DbContext. Especially the write operations in UserManager will be calling dbContext.SaveChangesAsync().
If you have the same instance of DbContext used, you will get SaveChangesAsync() called on every identity-related write and that will commit all other uncommited changes related to this context.
So what you describe is a consequence of having the same instance of DbContext and calling to save changes (though deep inside of Identity framework).
UPD I think I've misread your question. Seems like you have 2 instances of DbContext that play a tug-of-war. You have your own instance and another instance that is part of Identity. When you call _db.SaveChanges() you are saving changes in your context and it is flushed to a DB. At the same time you have another instance of DbContext that does not know anything about modifications that you have done already. And it tracks instance of that user (somewhere else) and keeps internal information about that user, but it does not query for an updated state of the related record in DB. And when you call UserManager.AddToRole that state is flushed back to DB again, but with the old values.
So your issue is really having 2 DbContexts.

Using Ninject in asp.net mvc GenerateUserIdentityAsync to add custom claim

I need to add custom claims when a user signs in (external sign in from Google) by performing a read to the database and adding the values returned. I am using Ninject for dependency injection to inject controllers with interfaces to my business layer services.
So I have located the identityModels.cs method to add claims:
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
string userId = userIdentity.GetUserId();
//var _iUserBLL = (IUserBLL)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IUserBLL));
//UserBO objUser = _iUserBLL.GetById(userId);
//userIdentity.AddClaim(new Claim("Value1", objUser.Value1));
//userIdentity.AddClaim(new Claim("Value2", objUser.Value2));
return userIdentity;
}
Here the System.Web.Mvc.DependencyResolver.Current.GetService line fails and causes it to crash. This works elsewhere and I've also tried the same approach I use to inject controllers like:
public class MyController : Controller
{
private readonly IUserBLL _iUserBLL;
public MyController (IUserBLL iUserBLL)
{
_iUserBLL = iUserBLL;
}
}
And even:
[Inject]
public IUserBLL _iUserBLL { get; set; }
But when used in the GenerateUserIdentityAsync method the _iUserBLL is null. Any ideas how I can inject my IUserBLL to make a custom database call here?
A bit more info - if you aren't familiar with this method, it's part of the Identity code generated in a visual studio project with individual user accounts.
The full class is like so:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
...
}
}
So I tried the constructor in here, which doesn't work:
public class ApplicationUser : IdentityUser
{
private readonly IUserBLL _iUserBLL;
public ApplicationUser (IUserBLL iUserBLL)
{
_iUserBLL = iUserBLL;
}
...
}
The IdentityUser is declared in the inner workings of the pre supplied identity.entityframework class and is called from within that which I can't edit, so I'm confused how to approach this?
Thanks for your reply Sam, it put me onto a solution. Here is the code I ended up with. I had trouble with the static 'Create' method so I used the [Inject] attribute instead. Is there a way to alter the static 'Create' method to use IUserBLL in the constructor? Here is the code that I have working:
In App_Start/IdentityConfig.cs
// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
[Inject]
public IUserBLL _iUserBLL { get; set; }
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
var userIdentity = user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
UserBO objUser = _iUserBLL.GetById(user.Id);
userIdentity.Result.AddClaim(new Claim("Claim1", objUser.Value1));
userIdentity.Result.AddClaim(new Claim("Claim2", objUser.Value2));
return userIdentity;
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
In my NinjectWebCommon.cs I also include these lines, extra to all my bindings:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<System.Security.Principal.IPrincipal>().ToMethod(context => HttpContext.Current.User).InRequestScope();
kernel.Bind<ApplicationUserManager>().ToMethod(context => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()).InRequestScope();
kernel.Bind<ApplicationSignInManager>().ToMethod((context) =>
{
var cbase = new HttpContextWrapper(HttpContext.Current);
return cbase.GetOwinContext().Get<ApplicationSignInManager>();
});
...
}
ApplicationUser is an entity object and this kind of objects are responsible to holding data not doing logic. It will be much better if you add your custom claim in UserManager rather than ApplicationUser. Consider this:
public class ApplicationUserManager: UserManager<ApplicationUser>
{
private readonly IUserBLL _iUserBLL;
public ApplicationSignInManager(IUserStore<ApplicationUser> store,
IUserBLL iUserBLL)
: base(store)
{
// if you already fully integrated Identity with ninject,
// ninject could automatically resolve this for you.
_iUserBLL=iUserBLL;
// other configurations here
}
public override async Task<ClaimsIdentity> CreateIdentityAsync(
ApplicationUser user,
string authenticationType)
{
var userIdentity=await base.CreateIdentityAsync(user, authenticationType);
UserBO objUser = _iUserBLL.GetById(userId);
userIdentity.AddClaim(new Claim("Value1", objUser.Value1));
userIdentity.AddClaim(new Claim("Value2", objUser.Value2));
return userIdentity;
}
}

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 do I inject Identity classes with Ninject?

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;
});

Resources