Search code examples
asp.net-coreserviceinterfaceentity-framework-coreasp.net-identity

How to get the currently logged in user name through an interface to insert in updated by column in asp.net core mvc?


I want to create a column updated by so whenever a user modifies a data, the updated by column is filled with currently logged in user name. I want to use an interface that gets the name of currently logged in user and then in AppDbContext in savechanges method the username is inserted whenever the data is updated. Please someone help me out how to do it as I'm new to ASP.NET core mvc and I got an assignment from University. I will be really thankful to all the experienced programmers here.


Solution

  • I hope I understood your question well. Here it goes:

    If you want to retrieve some information about the user that sent a request to your server and you use default identity behavior, then it should be easy. I do not know what version of ASP.NET do you use, I will presume its ASP.NET Core 3 (from you tags and such).

    With each request, there is a HttpContext object that remembers information about the HTTP request, the HTTP response, etc. If you inherit your controllers from the Controller/ControllerBase, you can directly access that context. The context contains a property called "User" that contains various information, including your user name.

    [AllowAnonymous]
    [HttpGet("me")]
    public string WhoAmI()
    {
         //Try this
         var userName = HttpContext.User?.Identity?.Name;
    
         //Or even
         var userName = User?.Identity?.Name;
    
         return userName;
    }
    

    Now, how can you get this name for your AppDbContext context? First of all, the best approach would be to create a service that provides you this name. Let's call it UserRepository. The user repository will accept IHttpContextAccessor that provides you with the HttpContext (and this username). The IHttpContextAccessor will be injected if you use dependency injection (used "automatically" within ASP.NET).

    public class UserRepository : IUserRepository
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
    
        public UserRepository(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }
    
        public void GetCurrentUserName()
        {
            var username = _httpContextAccessor.HttpContext.User.Identity.Name;
            return username;
        }
    }
    

    You can add this service to your services and you can inject it in various places. I should be even injectable to your DB context.

    Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
         services.AddControllersWithViews(); //You probably have this one
         services.AddHttpContextAccessor(); //Add the context accessor
         services.AddTransient<IUserRepository, UserRepository>(); //This is our user repository
    }
    

    And you should be able to use it as:

    public class AppDb : DbContext
    {
        readonly IUserRepository userRepo;
    
        public AppDb(DbContextOptions<AppDb> options,
            IUserRepository userRepo) 
            : base(options)
        {
            this.userRepo = userRepo;
    
            userRepo.GetCurrentUserName();
        }
    }
    

    The IUserRepository will "automatically" get injected with each request.

    Or, you can just inject the IUserRepository wherever you need. For example in the constructor of a Controller, similarly as shown in the AppDb object. Not sure what you really need.