Saya harus mengatakan saya cukup terkejut bahwa HttpContext adalah null di dalam konstruktor. Saya yakin itu untuk alasan kinerja. Telah mengkonfirmasikan bahwa menggunakan IPrincipal
seperti yang dijelaskan di bawah ini berhasil memasukkannya ke dalam konstruktor. Ini pada dasarnya melakukan hal yang sama seperti jawaban yang diterima, tetapi dengan cara yang lebih antarmuka.
Bagi siapa pun yang menemukan pertanyaan ini mencari jawaban untuk pertanyaan umum "Bagaimana cara mendapatkan pengguna saat ini?" Anda dapat User
langsung mengaksesnya dari Controller.User
. Tetapi Anda hanya dapat melakukan ini di dalam metode tindakan (saya berasumsi karena pengontrol tidak hanya berjalan dengan HttpContexts dan untuk alasan kinerja).
Namun - jika Anda membutuhkannya di konstruktor (seperti yang dilakukan OP) atau perlu membuat objek injeksi lain yang membutuhkan pengguna saat ini, maka di bawah ini adalah pendekatan yang lebih baik:
Masukkan IPrincipal untuk mendapatkan pengguna
Pertama bertemu IPrincipal
danIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipal
dan IIdentity
mewakili pengguna dan nama pengguna. Wikipedia akan menghibur Anda jika 'Kepala Sekolah' terdengar aneh .
Penting untuk disadari bahwa baik Anda mendapatkannya dari IHttpContextAccessor.HttpContext.User
, ControllerBase.User
atau ControllerBase.HttpContext.User
Anda mendapatkan suatu objek yang dijamin menjadi ClaimsPrincipal
objek yang diimplementasikanIPrincipal
.
Tidak ada jenis Pengguna lain yang digunakan ASP.NET untuk User
saat ini, (tetapi itu tidak berarti hal lain tidak dapat diterapkan IPrincipal
).
Jadi jika Anda memiliki sesuatu yang memiliki ketergantungan 'nama pengguna saat ini' yang ingin Anda suntikkan, Anda harus menyuntikkan IPrincipal
dan tentu saja tidak IHttpContextAccessor
.
Penting: Jangan buang waktu untuk menyuntikkan IPrincipal
langsung ke pengontrol Anda, atau metode tindakan - tidak ada gunanya karena User
sudah tersedia untuk Anda di sana.
Masuk startup.cs
:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Kemudian di objek DI Anda yang membutuhkan pengguna, Anda baru saja menyuntikkan IPrincipal
untuk mendapatkan pengguna saat ini.
Hal yang paling penting di sini adalah jika Anda melakukan pengujian unit, Anda tidak perlu mengirimkannya HttpContext
, tetapi hanya perlu mengejek sesuatu yang mewakili IPrincipal
yang sebenarnya bisa jadi ClaimsPrincipal
.
Satu hal ekstra penting yang saya tidak 100% yakin. Jika Anda perlu untuk mengakses klaim yang sebenarnya dari ClaimsPrincipal
yang Anda butuhkan untuk cor IPrincipal
untuk ClaimsPrincipal
. Ini baik-baik saja karena kita tahu 100% bahwa pada waktu proses itu dari jenis itu (karena itulah HttpContext.User
). Saya sebenarnya suka melakukan ini di konstruktor karena saya sudah tahu pasti ada yang IPrincipal
akan menjadi ClaimsPrincipal
.
Jika Anda sedang mengejek, buatClaimsPrincipal
saja langsung dan berikan ke apa pun IPrincipal
.
Persisnya mengapa tidak ada antarmuka untuk IClaimsPrincipal
Saya tidak yakin. Saya berasumsi MS memutuskan ClaimsPrincipal
itu hanya 'koleksi' khusus yang tidak memerlukan antarmuka.