Search code examples
asp.net-core.net-coreasp.net-core-identity.net-core-3.1

ASP.NET Core 3.1 "'User' does not contain a definition for 'FindFirstValue'"


While trying to implement the answer from here > How to get the current logged in user Id in ASP.NET Core and the user redirected me to here > https://github.com/dotnet/aspnetcore/issues/18348

var UserId = User.FindFirstValue(ClaimTypes.Name);

^ This is not working, and prints the following error 'User' does not contain a definition for 'FindFirstValue'

Edit: Adding controller snippet

The full snippet of my controller...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ProjectName.Processing;
using ProjectName.Repository;
using Newtonsoft.Json;

namespace ProjectName.Controllers
{
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class ClassNameController : ControllerBase
    {
        private readonly ILogger<ClassNameController> _logger;
        private OtherClassNameProcessing proc = new OtherClassNameProcessing();

        public ClassNameController(ILogger<ClassNameController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        [ProducesResponseType(typeof(List<2ndOtherClassNameRepository>), StatusCodes.Status200OK)]
        public IActionResult GetUserName()
        {
            var data = proc.GetUserName();
            return Ok(data.Result);
        }
    }
}

The full snippet my controller is calling...

using Microsoft.EntityFrameworkCore;
using ProjectName.Data;
using ProjectName.Repo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Web;
using System.Threading.Tasks;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using System.Web.Providers.Entities;

namespace ProjectName.Processing
{
    public class OtherClassNameProcessing
    {
        private readonly ProjName_DevelContext _context = new ProjName_DevelContext();
        private async Task<List<2ndOtherClassNameRepository>> GetNameFromRepo()
        {
            List<2ndOtherClassNameRepository> repoList = new List<2ndOtherClassNameRepository>();
            var Temp = await _context.tablename.ToListAsync();
            /* Working Test
            2ndOtherClassNameRepository repo = new 2ndOtherClassNameRepository();
            repo.UserName = "JohnDoe";
            repoList.Add(repo);
            return repoList;
            */
            2ndOtherClassNameRepository repo = new 2ndOtherClassNameRepository();
            // repo.UserName = "JohnDoe";
            var userId = User.FindFirstValue(ClaimTypes.Name);
            repo.UserName = userId;
            repoList.Add(repo);
            return repoList;
        }
        internal async Task<List<2ndOtherClassNameRepository>> GetUserName()
        {
            return await GetNameFromRepo();
        }
    }
}

Any idea why I'm getting this error?


Solution

  • Okay! Got the problem. User ClaimPrinciple is only available in the Controller context. I see your ControllerNameProcessing is not a Controller class. So you should do as follows:

    public class ControllerNameProcessing
    {
         private readonly IHttpContextAccessor _httpContextAccessor;
    
         public ControllerNameProcessing(IHttpContextAccessor httpContextAccessor)
         {
             _httpContextAccessor = httpContextAccessor;
         }
    
         private async Task<List<2ndClassNameRepository>> GetNameFromRepo()
         {
             // Omitted your other codes for brevity
    
             var userName = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.Name);
    
            // Omitted your other codes for brevity
         }
    }
    

    Then you should register IHttpContextAccessor in the Startup class as follows:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }
    

    Now in your controller:

    [ApiController]
    [Route("api/[controller]/[action]")]
    public class ClassNameController : ControllerBase
    {
        private readonly ILogger<ClassNameController> _logger;
        private OtherClassNameProcessing _otherClassNameProcessing;
    
        public ClassNameController(ILogger<ClassNameController> logger, OtherClassNameProcessing otherClassNameProcessing)
        {
            _logger = logger;
            _otherClassNameProcessing = otherClassNameProcessing;
        }
    
        [HttpGet]
        [ProducesResponseType(typeof(List<2ndOtherClassNameRepository>), StatusCodes.Status200OK)]
        public IActionResult GetUserName()
        {
            var data = proc.GetUserName();
            return Ok(data.Result);
        }
    }
    

    Then you should register OtherClassNameProcessing in the Startup class as follows:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
        services.AddScoped<OtherClassNameProcessing>();
    }