2

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?

Fiddle Freak
  • 1,923
  • 5
  • 43
  • 83

4 Answers4

7

The issue you are likely having is that you lack the right package.

Install this: Microsoft.Extensions.Identity.Core

Then it should start working once the using statement is included.

Joao Ricardo
  • 311
  • 3
  • 6
4

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>();
}
TanvirArjel
  • 30,049
  • 14
  • 78
  • 114
  • I've added both snippets and I'm getting the following error during the build: "Error CS7036 There is no argument given that corresponds to the required formal parameter 'httpContextAccessor' of 'ControllerNameProcessing.ControllerNameProcessing(IHttpContextAccessor)'". Any idea why this is happening? – Fiddle Freak Apr 06 '20 at 16:19
  • This another error! You are creating an instance of class without passing the constructor required parameter. Better pass your class as Dependency Injection. – TanvirArjel Apr 06 '20 at 16:22
  • ah yes, the squiggly line found in the controller (edited code in question). Now I need to pass that as an object through the constructor, as I get an error saying "A field initializer cannot reference the non-static field, method, or property 'ClassNameController._httpContextAccessor'".(not currently shown in the question code, but only adding live). I guess I need to learn how to do dependency injection with this thing(`_httpContextAccessor`). – Fiddle Freak Apr 06 '20 at 16:47
  • I noticed you removed the line `private OtherClassNameProcessing proc = new OtherClassNameProcessing();`. Not sure if I should be referencing this within the function itself in order to use it on the 4th-to-last-line in your controller solution. So I changed `var data = proc.GetUserName();` to `var data = _otherClassNameProcessing.GetUserName();`. No build errors, but it is returning a null – Fiddle Freak Apr 06 '20 at 17:11
  • This is done here! Close issue here. Now submit anothet for getting null. – TanvirArjel Apr 06 '20 at 17:13
  • 1
    Okay, I agree this is another type of issue and will close this one here. Thank you for your patience. Also if you could please change `var data = proc.GetUserName();` to `var data = _otherClassNameProcessing.GetUserName();` so others don't have to debug the solution they copy and paste... it would be much appreciated. – Fiddle Freak Apr 06 '20 at 17:16
1

Try to get user id as follow (for User of type ClaimsPrincipal)

 var userId = User.Claims.Where(c => c.Type == "sub").FirstOrDefault().Value;

And For User of type System.Web.Providers.Entities.User use

User.UserId

https://learn.microsoft.com/en-us/previous-versions/aspnet/dn253175(v=vs.108)

MohammadAmin Mohammadi
  • 1,183
  • 3
  • 14
  • 23
  • Getting relevant error: 'User' does not contain a definition for 'Claims' – Fiddle Freak Apr 06 '20 at 15:25
  • Whats the type of User? Normally it should be ClaimsPrincipal – MohammadAmin Mohammadi Apr 06 '20 at 15:28
  • System.Web.Providers.Entities.User – Fiddle Freak Apr 06 '20 at 15:30
  • So you can use User.UserId property as 'https://learn.microsoft.com/en-us/previous-versions/aspnet/dn253175%28v%3dvs.108%29'. But i think you should use IdentityUser. – MohammadAmin Mohammadi Apr 06 '20 at 15:34
  • So when I try that, it says it cannot be used as a static context. So I added `User user = new User();` and now the issue I am having is returning `null`. My co-worker is saying something about it has to reach the oicd servers. I'm not sure what all that entails, but we were able to get this to work with .net mvc and .net framework. But having issues with .net core (going with CRUD backend). – Fiddle Freak Apr 06 '20 at 16:08
  • getting the relevant error "the name 'Context' does not exist in the current context" – Fiddle Freak Apr 06 '20 at 16:50
  • use the below refactored version var userId = User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value; – vCillusion Nov 23 '20 at 07:43
0

This was my solution:

result = _httpContextAccessor.HttpContext.User.Claims.First(x => x.Type == ClaimTypes.Name).Value;

Eric Milliot-Martinez
  • 4,076
  • 3
  • 23
  • 28