ChatGPT解决这个技术问题 Extra ChatGPT

ASP.NET MVC 5 - Identity. How to get current ApplicationUser

I have an Article entity in my project which has the ApplicationUser property named Author. How can I get the full object of currently logged ApplicationUser? While creating a new article, I have to set the Author property in Article to the current ApplicationUser.

In the old Membership mechanism it was simple, but in the new Identity approach I don't know how to do this.

I tried to do it this way:

Add using statement for Identity extensions: using Microsoft.AspNet.Identity;

Then I try to get the current user: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

But I get the following exception:

LINQ to Entities does not recognize the method 'System.String GetUserId(System.Security.Principal.IIdentity)' method, and this method cannot be translated into a store expression. Source=EntityFramework


G
Gone Coding

You should not need to query the database directly for the current ApplicationUser.

That introduces a new dependency of having an extra context for starters, but going forward the user database tables change (3 times in the past 2 years) but the API is consistent. For example the users table is now called AspNetUsers in Identity Framework, and the names of several primary key fields kept changing, so the code in several answers will no longer work as-is.

Another problem is that the underlying OWIN access to the database will use a separate context, so changes from separate SQL access can produce invalid results (e.g. not seeing changes made to the database). Again the solution is to work with the supplied API and not try to work-around it.

The correct way to access the current user object in ASP.Net identity (as at this date) is:

var user = UserManager.FindById(User.Identity.GetUserId());

or, if you have an async action, something like:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

FindById requires you have the following using statement so that the non-async UserManager methods are available (they are extension methods for UserManager, so if you do not include this you will only see FindByIdAsync):

using Microsoft.AspNet.Identity;

If you are not in a controller at all (e.g. you are using IOC injection), then the user id is retrieved in full from:

System.Web.HttpContext.Current.User.Identity.GetUserId();

If you are not in the standard Account controller you will need to add the following (as an example) to your controller:

1. Add these two properties:

    /// <summary>
    /// Application DB context
    /// </summary>
    protected ApplicationDbContext ApplicationDbContext { get; set; }

    /// <summary>
    /// User manager - attached to application DB context
    /// </summary>
    protected UserManager<ApplicationUser> UserManager { get; set; }

2. Add this in the Controller's constructor:

    this.ApplicationDbContext = new ApplicationDbContext();
    this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.ApplicationDbContext));

Update March 2015

Note: The most recent update to Identity framework changes one of the underlying classes used for authentication. You can now access it from the Owin Context of the current HttpContent.

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

Addendum:

When using EF and Identity Framework with Azure, over a remote database connection (e.g. local host testing to Azure database), you can randomly hit the dreaded “error: 19 - Physical connection is not usable”. As the cause is buried away inside Identity Framework, where you cannot add retries (or what appears to be a missing .Include(x->someTable)), you need to implement a custom SqlAzureExecutionStrategy in your project.


@TBA - thanks, I realized later it's an extension method. Need to add Microsoft.AspNet.Identity using . thanks again
Type or namesapce UserStore could not be found.I added using Microsft.AspNet.Indentity
@Zapnologica: That sounds like a new question (suggest you post it). You can extend the ApplicationUser class (application specific) and the AspNetUsers table in parallel and they will provide any new fields. Again: Do not hit the database directly! :)
@LifeH2O: The ApplicationUser returned by FindById is your class, complete with your extra properties. Please try it.
Waiting For your new Workaround :P
R
Rikin Patel

My mistake, I shouldn't have used a method inside a LINQ query.

Correct code:

using Microsoft.AspNet.Identity;


string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);

User.Identiy.GetUserId does not exist for me. is that i custom method? I only get up to User.Identity
Nevermind... you need the "using Microsoft.AspNet.Identity;" for that method to be there.
Just a note, the User object is visible only in Controllers.
Surely you should be using UserManager methods and not hitting the database directly?
@Josh Bjelovuk: Never hit a database directly when an API is available. That introduces a new dependency of having an extra context for starters, but going forward the user database tables change (3 times in the past 2 years) but the API is consistent.
r
rtpHarry

Its in the comments of the answers but nobody has posted this as the actual solution.

You just need to add a using statement at the top:

using Microsoft.AspNet.Identity;

I came here with that exception, I solved it with that using. Seeing as 15k people have visited the question I figured it was a helpful answer :)
@TrueBlueAussie, despite not being a direct answer to the OPs question, I feel that mentioning the using is a very useful addition.
For clarity, it's because .GetUserId() is an extension method
D
Diego Borges

The code of Ellbar works! You need only add using.

1 - using Microsoft.AspNet.Identity;

And... the code of Ellbar:

2 - string currentUserId = User.Identity.GetUserId(); ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);

With this code (in currentUser), you work the general data of the connected user, if you want extra data... see this link


It may "work", but it is certainly not recommended to bypass the supplied API and hit the database directly If you did use the API you would not need extra work to get the extra data as it would already be in the ApplicationUser object
I agree! However, resorted to this way because I had already have a system in place today, with a run in the database and I need a simple solution to solve this issue! Certainly, in an early system, I would put objects in their proper classes and identities.
S
Seth IK

As of ASP.NET Identity 3.0.0, This has been refactored into

//returns the userid claim value if present, otherwise returns null
User.GetUserId();

M
Majid joghataey
ApplicationDbContext context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
ApplicationUser currentUser = UserManager.FindById(User.Identity.GetUserId());

string ID = currentUser.Id;
string Email = currentUser.Email;
string Username = currentUser.UserName;

P
Paceman

For MVC 5 just look inside the EnableTwoFactorAuthentication method of ManageController in WebApplication template scaffold, its being done there:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> EnableTwoFactorAuthentication()
        {
            await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
            var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
            if (user != null)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            }
            return RedirectToAction("Index", "Manage");
        }

The answer is right there as suggested by Microsoft itself:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

It will have all the additional properties you defined in ApplicationUser class.


Already covered. Please check that an identical answer is not already posted (or add a comment to an existing answer) :)
L
Liam

Right now the asp.mvc project template creates an account controller that gets the usermanager this way:

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

The following works for me:

ApplicationUser user = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId());

J
Jamshaid K.

In case someone is working with Identity users in web forms, I got it working by doing so:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());

h
harili

There is a simple way :

User.Identity.Name

It provides the Id of the current user.


A
Abdul Hannan

I was successfully available to get Application User By Following Piece of Code

var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());
            ApplicationUser EmpUser = user;