在AccountController之外访问UserManager

31

我想在不同的控制器(非accountcontroller)中设置aspnetuser表格的一列值。我一直在尝试访问UserManager,但我无法弄清楚如何做到这一点。

到目前为止,在我想要使用它的控制器中,我尝试了以下操作:

    ApplicationUser u = UserManager.FindById(User.Identity.GetUserId());
    u.IsRegComplete = true;
    UserManager.Update(u);

我认为这段代码无法编译通过(可能是因为控制器中的UserManager未被实例化)。

我还尝试在AccountController中创建一个公共方法,接受想要更改的值并在那里进行更改,但我无法弄清如何调用它。

public void setIsRegComplete(Boolean setValue)
{
    ApplicationUser u = UserManager.FindById(User.Identity.GetUserId());
    u.IsRegComplete = setValue;
    UserManager.Update(u);

    return;
}
你如何在“账户控制器”之外访问和编辑用户数据?
更新:
我尝试在另一个控制器中实例化UserManager,像这样:
    var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
    ApplicationUser u = userManager.FindById(User.Identity.GetUserId());

我编译(有点兴奋)了这个项目,但当我运行代码时,出现了以下错误:

Additional information: The entity type ApplicationUser is not part of the model for the current context.

更新2:

我已将该函数移至IdentityModel中(不要问我为什么,我在试探可能性):

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

然而我仍然得到以下内容:

The entity type ApplicationUser is not part of the model for the current context.

IdentitiesModels.cs 中还有以下类:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

在这里我做错了什么?感觉我完全在错误的方向上努力。我所要做的只是从不同控制器的操作(即不是AccountsController)中更新aspnetuser表中的一列。


从错误信息来看,似乎您传递给存储的“db”不是包含身份表的同一DbContext。 - Iravanchi
你的 db 上下文类中是否有 public class ApplicationDbContext : IdentityDbContext<ApplicationUser>{} - Mike Debela
请参见上面更新过的帖子,谢谢。 - Spionred
5
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(ApplicationDbContext.Create()));翻译:创建一个新的UserManager<ApplicationUser>对象,并传入UserStore<ApplicationUser>(ApplicationDbContext.Create())作为参数。 - Mike Debela
是的,那很有效。谢谢! - Spionred
我还没有足够的声望来发表评论,所以我正在创建一个新的答案帖子。只是添加到@Iravanchi的答案中,GetOwinContext()的扩展方法已经移动到Microsoft.AspNet.Identity.Owin中; https://dev59.com/YmAg5IYBdhLWcg3wfbB6 - salli
5个回答

35
如果您正在使用默认项目模板,则UserManager会以以下方式创建:
在Startup.Auth.cs文件中,有一行类似于此的代码:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

这会使 OWIN 管道在每次请求到达服务器时实例化 ApplicationUserManager 的一个实例。您可以在控制器内使用以下代码从 OWIN 管道获取该实例:

Request.GetOwinContext().GetUserManager<ApplicationUserManager>()

如果您仔细查看AccountController类,您会发现以下代码片段使得访问ApplicationUserManager成为可能:

    private ApplicationUserManager _userManager;

    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }
请注意,如果您需要实例化ApplicationUserManager类,则需要使用ApplicationUserManager.Create静态方法,以便对其应用适当的设置和配置。

感谢您的贡献。上面评论中的建议起了作用。我将代码保留在IdentityModels.cs文件中,因为我需要在多个地方访问它。 - Spionred
2
我建议您从OWIN上下文中检索UserManager而不是创建一个新实例,因为它在每个请求中都会被创建,创建新实例是多余的开销。 - Iravanchi

5

如果您需要在另一个控制器中获取UserManager的实例,只需在控制器的构造函数中添加其参数,如下所示

public class MyController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;

    public MyController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;;
    }
}

但我需要在不是控制器的类中获取UserManager!

任何帮助将不胜感激。

更新

我考虑您正在使用asp.net core。


但是你如何首先将它传递给控制器呢?在我的整个项目中,我没有对我的控制器的引用,因此我不知道如何将它传递给userManager的引用?它实际上是在哪里实例化的? - rollsch
不是这样的。UserManager<ApplicationUser> 将从您的 startup.cs 类向应用程序控制器注入。在 ASP.NET Core 中创建一个 ASP.NET Identity 项目并查看 startup.cs 类。 以下代码将 UserManager<Application> 实例注入到您的控制器中services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); - Abubakar Ikram
@JonathanWood 尝试创建另一个空参数的构造函数,然后进行检查。 - Abubakar Ikram
1
@ДвυΒдкдя:当然可以。但是这样我就没有一个UserManager<ApplicationUser>实例了。 - Jonathan Wood
@JonathanWood 创建一个新的 ASP.NET Core 应用程序,并进行用户身份验证,查看 AccountController。 - Abubakar Ikram
显示剩余2条评论

0

针对MVC 5

在Account控制器之外访问usermanger或createUser的步骤很简单。请按照以下步骤进行操作:

  1. 创建一个控制器,考虑使用SuperAdminController
  2. 像下面的AccountController一样装饰SuperAdminController,

    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;
        }
    }
    
  3. 在Action方法中创建用户

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

0
我遇到了同样的问题,并修改了我的代码,从控制器向模型传递了一个UserManager类的引用:
//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;
}

0
如果您需要在控制器之外访问UserManager,可以使用以下方法:
var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
var applicationManager = new ApplicationUserManager(userStore);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接