Tengo que decir que me sorprendió bastante que HttpContext sea nulo dentro del constructor. Estoy seguro de que es por razones de rendimiento. Han confirmado que el uso IPrincipalcomo se describe a continuación lo inyecta en el constructor. Básicamente está haciendo lo mismo que la respuesta aceptada, pero de una manera más interactiva.
Para cualquiera que encuentre esta pregunta y busque una respuesta al genérico "¿Cómo obtener un usuario actual?" puedes acceder Userdirectamente desde Controller.User. Pero solo puede hacer esto dentro de los métodos de acción (supongo que los controladores no solo se ejecutan con HttpContexts y por razones de rendimiento).
Sin embargo, si lo necesita en el constructor (como lo hizo OP) o necesita crear otros objetos inyectables que necesitan el usuario actual, entonces el siguiente es un mejor enfoque:
Inyecte IPrincipal para obtener el usuario
Primer encuentro IPrincipalyIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipaly IIdentityrepresenta al usuario y nombre de usuario. Wikipedia te consolará si 'Principal' suena extraño .
Es importante darse cuenta de que si la recibe de IHttpContextAccessor.HttpContext.User, ControllerBase.Usero ControllerBase.HttpContext.Userque está recibiendo un objeto que se garantiza que sea un ClaimsPrincipalobjeto que implementaIPrincipal .
No hay otro tipo de usuario que ASP.NET use en Usereste momento (pero eso no quiere decir que otra cosa no pueda implementar IPrincipal).
Entonces, si tiene algo que depende del 'nombre de usuario actual' que desea inyectar, debería inyectar IPrincipaly definitivamente no IHttpContextAccessor.
Importante: No pierda el tiempo inyectando IPrincipaldirectamente en su controlador o método de acción, no tiene sentido ya Userque ya está disponible para usted.
En startup.cs:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Luego, en su objeto DI que necesita el usuario que acaba de inyectar IPrincipalpara obtener el usuario actual.
Lo más importante aquí es que si está haciendo pruebas unitarias, no necesita enviar una HttpContext, pero solo necesita burlarse de algo que representa lo IPrincipal que puede ser ClaimsPrincipal .
Una cosa extra importante de la que no estoy 100% seguro. Si necesita acceder a los reclamos reales ClaimsPrincipal, debe enviarlos IPrincipala ClaimsPrincipal. Esto está bien ya que sabemos al 100% que en tiempo de ejecución es de ese tipo (ya que eso HttpContext.Useres lo que es). De hecho, me gusta hacer esto en el constructor, ya que sé con certeza que cualquiera IPrincipal será a ClaimsPrincipal.
Si te estás burlando, solo crea uno ClaimsPrincipaldirectamente y pásalo a lo que sea necesario IPrincipal.
Exactamente por qué no hay interfaz porque IClaimsPrincipalno estoy seguro. Supongo que MS decidió que ClaimsPrincipalera solo una 'colección' especializada que no garantizaba una interfaz.