Треба сказати, що я був дуже здивований, що HttpContext є нульовим усередині конструктора. Я впевнений, що це з міркувань продуктивності. Підтвердили, що, IPrincipalяк описано нижче, вводять його в конструктор. По суті, це робиться так само, як прийнята відповідь, але більш інтерфейсно.
Кожен, хто знайде це питання, шукає відповідь на загальне "Як отримати поточного користувача?" Ви можете просто отримати доступ Userбезпосередньо з Controller.User. Але ви можете це робити лише у внутрішніх методах дій (я припускаю, що контролери не працюють лише з HttpContexts і з міркувань продуктивності).
Однак - якщо вам це потрібно в конструкторі (як це робилося в ОП) або потрібно створити інші об'єкти, які можна вводити, які потребують поточного користувача, то нижче - кращий підхід:
Введіть IPrincipal, щоб отримати користувача
Перша зустріч IPrincipalіIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipalі IIdentityпредставляє користувача та ім'я користувача. Вікіпедія потішить вас, якщо "Основний" звучить дивно .
Важливо усвідомити, чи отримуєте ви це IHttpContextAccessor.HttpContext.User, ControllerBase.Userчи ControllerBase.HttpContext.Userотримуєте ви об'єкт, який гарантовано є ClaimsPrincipalоб'єктом, який реалізуєтьсяIPrincipal .
Немає іншого типу Користувачів, яким ASP.NET зараз користується User(але це не означає, що інші, які ще щось не вдалося реалізувати IPrincipal).
Тож якщо у вас є щось, що має залежність від "поточного імені користувача", яке ви хочете зробити ін'єкційним, вам слід вводити ін'єкцію, IPrincipalа точно - ні IHttpContextAccessor.
Важливо: не витрачайте час на введення ін'єкцій IPrincipalбезпосередньо своєму контролеру чи метод дій - з тих пір це безглуздоUser він уже доступний для вас.
В startup.cs:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Потім у ваш об’єкт DI, який потребує користувача, якого ви просто введете, IPrincipalщоб отримати поточного користувача.
Найголовніше тут, якщо ви робите одиничні тести, вам не потрібно надсилати HttpContext, а потрібно лише знущатися над тим, що представляє, IPrincipal що може бути ClaimsPrincipal .
Ще одна важлива річ, в якій я не впевнений на 100%. Якщо вам потрібно отримати доступ до фактичних претензій, до ClaimsPrincipalяких потрібно IPrincipalзвернутись ClaimsPrincipal. Це добре, оскільки ми знаємо на 100%, що під час виконання це саме такий тип (оскільки це HttpContext.Userє). Насправді мені подобається просто робити це в конструкторі, оскільки я вже точно знаю, що хтось IPrincipal будеClaimsPrincipal .
Якщо ви знущаєтесь, просто створіть ClaimsPrincipalбезпосередньо та передайте їх усім, що потрібно IPrincipal.
Точно чому немає інтерфейсу, IClaimsPrincipalя не впевнений. Я припускаю, що MS вирішила, що ClaimsPrincipalце просто спеціалізована «колекція», яка не гарантує інтерфейс.