jasontaylordev / CleanArchitecture

Clean Architecture Solution Template for ASP.NET Core
MIT License
16.15k stars 3.46k forks source link

Injecting IIdentityService (IdentityService) into IUser or Interceptors #998

Open jhuerta opened 9 months ago

jhuerta commented 9 months ago

Discussed in https://github.com/jasontaylordev/CleanArchitecture/discussions/993

Originally posted by **jhuerta** September 20, 2023 Hi, I am trying to get some user information while doing some operations in the AuditableEntityInterceptor.cs I notice that if I inject "IIdentityService identityService" in the constructor of AuditableEntityInterceptor, then the following code will freeze in DependencyInjection.cs: options.AddInterceptors(sp.GetServices()); For what I observe, if I comment out this line in DependencyInjection.cs, then the code runs fine: services.AddScoped(); So my understanding is that something goes wrong when it tries to build the IdentityService for the IIdentityService interface in the AuditableEntityInterceptor.cs constructor. Probably is something that I don't understand, maybe some circular dependency? I had the same issue when I tried to inject IIdentityService in the constructor of CurrentUser.cs. In this case I was not able to generate and run migrations, it hangs at some point. Any idea why I cannot use IIdentityService in AuditableEntityInterceptor or CurrentUser.cs? https://github.com/jasontaylordev/CleanArchitecture/discussions/412 seems to be related but ICurrentUservice is now IUser. Here it mentions "Update: If you need the current user in any other command/query you can simply ask for an ICurrentUserService and for an IIdentityService using dependency injection and can access the user info with this." This is similar of what I want to do, but not in a command/query, but in the AuditableEntityInterceptor or in the IUser itself. Thanks, Juan
JohannesMogashoa commented 9 months ago

@jhuerta I encountered a similar issue with wanting to inject user infomation into the db interceptor and could not do it with the IdentityService but my way around this was having the ICurrentUserService still in the Application layer but I placed the implementation in the Web API project and grabbed the current logged in user claims from the HTTP context. The below implementation allowed me to inject ICurrentUserService in the inceptor without any problems.

public interface ICurrentUserService
{
    string? UserId { get; }
    string? UserName { get; }
}
public class CurrentUserService : ICurrentUserService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CurrentUserService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public string? UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
    public string? UserName => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name);
}