Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Oleh Kirk Larkin, Rick Anderson, Tom Dykstra, dan Steve Smith
Filter di ASP.NET Core memungkinkan kode dijalankan sebelum atau sesudah tahap tertentu dalam alur pemrosesan permintaan.
Filter bawaan menangani tugas seperti:
- Otorisasi, mencegah akses ke sumber daya yang tidak diotorisasi pengguna.
- Penembolokan respons, memotong jalur permintaan untuk mengembalikan respons yang telah di-cache.
Filter kustom dapat dibuat untuk menangani kekhawatiran lintas fungsi. Contoh concern lintas proses termasuk penanganan kesalahan, penyimpanan sementara, konfigurasi, otorisasi, dan pencatatan. Filter menghindari kode duplikat. Misalnya, filter pengecualian penanganan kesalahan dapat mengonsolidasikan penanganan kesalahan.
Dokumen ini berlaku untuk Razor Halaman, pengontrol API, dan pengontrol dengan tampilan. Filter tidak berfungsi langsung dengan Razor komponen. Filter hanya dapat secara tidak langsung memengaruhi komponen saat:
- Komponen disematkan dalam halaman atau tampilan.
- Halaman, pengontrol, dan tampilan menggunakan filter.
Cara kerja filter
Filter berjalan dalam jalur pemanggilan aksi ASP.NET Core, kadang-kadang disebut juga sebagai jalur filter. Alur filter berjalan setelah ASP.NET Core memilih tindakan yang akan dijalankan:
Jenis filter
Setiap jenis filter dijalankan pada tahap yang berbeda dalam alur filter:
-
- Jalankan terlebih dahulu.
- Tentukan apakah pengguna berwenang untuk permintaan tersebut.
- Hentikan proses jika permintaan tidak terotorisasi.
-
- Jalankan setelah otorisasi.
-
OnResourceExecuting menjalankan kode sebelum alur pemrosesan filter lainnya mulai. Misalnya,
OnResourceExecuting
menjalankan kode sebelum pengikatan model. - OnResourceExecuted menjalankan program setelah tahap lain dari alur selesai.
-
- Jalankan segera sebelum dan sesudah metode tindakan dipanggil.
- Dapat mengubah argumen yang diteruskan ke tindakan.
- Dapat mengubah hasil yang dihasilkan oleh tindakan.
- Tidak didukung di Razor Halaman.
-
- Jalankan segera sebelum dan sesudah metode tindakan dipanggil.
- Dapat mengubah argumen yang diteruskan ke tindakan.
- Dapat mengubah hasil yang dihasilkan oleh tindakan.
- Tidak didukung di Razor Halaman.
- Dapat dipanggil pada tindakan dan titik akhir berbasis handler rute.
-
- Terapkan kebijakan global ke pengecualian yang tidak tertangani yang terjadi sebelum isi respons ditulis.
- Jalankan setelah pengikatan model dan filter tindakan, tetapi sebelum hasil tindakan dijalankan.
- Jalankan hanya jika pengecualian yang tidak tertangani terjadi selama pelaksanaan tindakan atau hasil tindakan.
- Jangan tangani pengecualian yang dilemparkan selama eksekusi middleware, perutean, atau pengikatan model.
-
- Jalankan segera sebelum dan sesudah pelaksanaan hasil tindakan.
- Jalankan hanya ketika metode tindakan berhasil dijalankan.
- Berguna untuk logika yang harus mengitari tampilan atau eksekusi pemformat.
Razor Pages juga mendukung Razor filter halaman, yang berjalan sebelum dan sesudah Razor handler halaman.
implementasi
Filter mendukung implementasi sinkron dan asinkron melalui definisi antarmuka yang berbeda.
Filter sinkron berjalan sebelum dan sesudah tahap alurnya. Misalnya, OnActionExecuting dipanggil sebelum metode tindakan dipanggil. OnActionExecuted dipanggil setelah metode aksi mengembalikan hasil:
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
}
}
Filter asinkron mendefinisikan metode On-Stage-ExecutionAsync
. Misalnya, OnActionExecutionAsync:
public class SampleAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context, ActionExecutionDelegate next)
{
// Do something before the action executes.
await next();
// Do something after the action executes.
}
}
Dalam kode sebelumnya, SampleAsyncActionFilter
memiliki ActionExecutionDelegate, , next
yang menjalankan metode tindakan.
Beberapa tahap filter
Antarmuka untuk beberapa tahap filter dapat diimplementasikan dalam satu kelas. Misalnya, ActionFilterAttribute kelas mengimplementasikan:
- Sinkron: IActionFilter dan IResultFilter
- Asinkron: IAsyncActionFilter dan IAsyncResultFilter
- IOrderedFilter
Terapkan versi sinkron atau asinkron dari antarmuka filter, bukan keduanya. Runtime memeriksa terlebih dahulu untuk melihat apakah filter mengimplementasikan antarmuka asinkron, dan jika demikian, filter memanggilnya. Jika tidak, ini memanggil metode antarmuka sinkron. Jika antarmuka asinkron dan sinkron diimplementasikan dalam satu kelas, hanya metode asinkron yang dipanggil. Saat menggunakan kelas abstrak seperti ActionFilterAttribute, hanya ambil alih metode sinkron atau metode asinkron untuk setiap jenis filter.
Atribut filter bawaan
ASP.NET Core mencakup filter berbasis atribut bawaan yang dapat disubkelas dan disesuaikan. Misalnya, filter hasil berikut menambahkan header ke respons:
public class ResponseHeaderAttribute : ActionFilterAttribute
{
private readonly string _name;
private readonly string _value;
public ResponseHeaderAttribute(string name, string value) =>
(_name, _value) = (name, value);
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(_name, _value);
base.OnResultExecuting(context);
}
}
Atribut memungkinkan filter untuk menerima argumen, seperti yang ditunjukkan dalam contoh sebelumnya. Terapkan ResponseHeaderAttribute
ke pengontrol atau metode tindakan dan tentukan nama serta nilai header HTTP.
[ResponseHeader("Filter-Header", "Filter Value")]
public class ResponseHeaderController : ControllerBase
{
public IActionResult Index() =>
Content("Examine the response headers using the F12 developer tools.");
// ...
Gunakan alat seperti alat pengembang browser untuk memeriksa header. Di bawah Response Headers, filter-header: Filter Value
ditampilkan.
Kode berikut berlaku ResponseHeaderAttribute
untuk pengontrol dan tindakan:
[ResponseHeader("Filter-Header", "Filter Value")]
public class ResponseHeaderController : ControllerBase
{
public IActionResult Index() =>
Content("Examine the response headers using the F12 developer tools.");
// ...
[ResponseHeader("Another-Filter-Header", "Another Filter Value")]
public IActionResult Multiple() =>
Content("Examine the response headers using the F12 developer tools.");
}
Respon dari tindakan Multiple
mencakup tajuk berikut:
filter-header: Filter Value
another-filter-header: Another Filter Value
Beberapa antarmuka filter memiliki atribut yang sesuai yang dapat digunakan sebagai kelas dasar untuk implementasi kustom.
Filter Atribut:
- ActionFilterAttribute
- ExceptionFilterAttribute
- ResultFilterAttribute
- FormatFilterAttribute
- ServiceFilterAttribute
- TypeFilterAttribute
Filter tidak dapat diterapkan ke metode handler halaman Razor. Mereka dapat diterapkan baik secara global maupun ke Model Halaman Razor.
Cakupan penyaringan dan urutan eksekusi
Filter dapat ditambahkan ke alur di salah satu dari tiga cakupan:
- Menggunakan atribut pada pengontrol atau Razor Halaman.
- Menggunakan atribut pada tindakan pengontrol. Atribut filter tidak dapat diterapkan ke Razor metode handler Pages.
- Secara global untuk semua pengontrol, tindakan, dan Razor Halaman seperti yang ditunjukkan dalam kode berikut:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(options => { options.Filters.Add<GlobalSampleActionFilter>(); });
Urutan eksekusi default
Ketika ada beberapa filter untuk tahap tertentu dari alur kerja, cakupan menentukan urutan default dari eksekusi filter. Filter global mengelilingi filter kelas, yang pada gilirannya mengelilingi filter metode.
Akibat dari penyaringan bersarang, kode setelah filter berjalan dalam urutan terbalik dari kode sebelum. Urutan filter:
- Kode filter global sebelumnya.
- Kode sebelum filter pengontrol.
- Kode sebelum filter metode tindakan.
- Kode setelah filter metode tindakan.
- Kode setelah filter pengontrol.
- Kode sebelum filter pengontrol.
- Kode dari filter global setelah.
Contoh berikut mengilustrasikan urutan metode filter yang dijalankan untuk filter tindakan sinkron:
Urutan | Cakupan filter | Metode filter |
---|---|---|
1 | Mendunia | OnActionExecuting |
2 | Pengontrol | OnActionExecuting |
3 | Perbuatan | OnActionExecuting |
4 | Perbuatan | OnActionExecuted |
5 | Pengontrol | OnActionExecuted |
6 | Mendunia | OnActionExecuted |
Filter pada tingkat pengendali
Setiap pengontrol yang mewarisi dari Controller mencakup metode OnActionExecuting, OnActionExecutionAsync, dan OnActionExecuted. Metode ini membungkus filter yang dijalankan untuk tindakan tertentu.
-
OnActionExecuting
berjalan sebelum filter-filter tindakan apa pun. -
OnActionExecuted
berjalan setelah semua filter tindakan. -
OnActionExecutionAsync
berjalan sebelum filter-filter tindakan apa pun. Kode setelah pemanggilan kenext
berjalan setelah filter tindakan.
Kelas berikut ControllerFiltersController
:
- Menerapkan
SampleActionFilterAttribute
([SampleActionFilter]
) ke pengontrol. - Mengambil alih
OnActionExecuting
danOnActionExecuted
.
[SampleActionFilter]
public class ControllerFiltersController : Controller
{
public override void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine(
$"- {nameof(ControllerFiltersController)}.{nameof(OnActionExecuting)}");
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine(
$"- {nameof(ControllerFiltersController)}.{nameof(OnActionExecuted)}");
base.OnActionExecuted(context);
}
public IActionResult Index()
{
Console.WriteLine(
$"- {nameof(ControllerFiltersController)}.{nameof(Index)}");
return Content("Check the Console.");
}
}
Menavigasi ke https://localhost:<port>/ControllerFilters
menjalankan kode berikut:
ControllerFiltersController.OnActionExecuting
GlobalSampleActionFilter.OnActionExecuting
SampleActionFilterAttribute.OnActionExecuting
ControllerFiltersController.Index
SampleActionFilterAttribute.OnActionExecuted
GlobalSampleActionFilter.OnActionExecuted
ControllerFiltersController.OnActionExecuted
Filter tingkat pengontrol mengatur properti Pesanan ke int.MinValue
. Filter tingkat pengontrol tidak dapat diatur untuk dijalankan setelah filter yang diterapkan pada metode. Pesanan dijelaskan di bagian berikutnya.
Untuk Razor Halaman, lihat Razor.
Mengatasi urutan default
Urutan default eksekusi dapat diganti dengan menerapkan IOrderedFilter.
IOrderedFilter
mengekspos properti Order yang lebih diutamakan daripada cakupan untuk menentukan urutan eksekusi. Filter dengan nilai yang lebih rendah Order
:
- Menjalankan kode sebelum yang dimiliki oleh filter dengan nilai yang lebih tinggi dari
Order
. - Menjalankan kode setelah kode dari filter dengan nilai yang lebih tinggi
Order
.
Dalam contoh filter tingkat pengontrol, memiliki cakupan global sehingga berjalan sebelum GlobalSampleActionFilter
, yang memiliki cakupan pengontrol. Untuk menjalankan SampleActionFilterAttribute
terlebih dahulu, atur urutannya ke int.MinValue
:
[SampleActionFilter(Order = int.MinValue)]
public class ControllerFiltersController : Controller
{
// ...
}
Untuk membuat filter GlobalSampleActionFilter
global berjalan terlebih dahulu, atur Order
ke int.MinValue
:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<GlobalSampleActionFilter>(int.MinValue);
});
Pembatalan dan Pemutusan Arus Pendek
Alur filter dapat diputus dengan mengatur properti Result pada parameter yang disediakan oleh ResourceExecutingContext untuk metode filter. Misalnya, filter Sumber Daya berikut mencegah sisa alur dieksekusi:
public class ShortCircuitingResourceFilterAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
context.Result = new ContentResult
{
Content = nameof(ShortCircuitingResourceFilterAttribute)
};
}
public void OnResourceExecuted(ResourceExecutedContext context) { }
}
Dalam kode berikut, baik filter [ShortCircuitingResourceFilter]
maupun [ResponseHeader]
menargetkan metode tindakan Index
. Filter ShortCircuitingResourceFilterAttribute
:
- Berjalan terlebih dahulu, karena ini adalah Filter Sumber Daya dan
ResponseHeaderAttribute
merupakan Filter Tindakan. - Menghentikan sisa proses.
Oleh karena itu, filter ResponseHeaderAttribute
tidak pernah berjalan untuk tindakan Index
. Perilaku ini akan sama jika kedua filter diterapkan pada tingkat metode tindakan, asalkan ShortCircuitingResourceFilterAttribute
dijalankan terlebih dahulu.
ShortCircuitingResourceFilterAttribute
berjalan lebih dahulu karena jenis filternya:
[ResponseHeader("Filter-Header", "Filter Value")]
public class ShortCircuitingController : Controller
{
[ShortCircuitingResourceFilter]
public IActionResult Index() =>
Content($"- {nameof(ShortCircuitingController)}.{nameof(Index)}");
}
Injeksi dependensi
Filter dapat ditambahkan berdasarkan jenis atau berdasarkan instans. Jika instans ditambahkan, instans tersebut digunakan untuk setiap permintaan. Jika sebuah tipe ditambahkan, maka tipe tersebut akan diaktifkan. Filter yang diaktifkan berdasarkan jenis berarti:
- Instans dibuat untuk setiap permintaan.
- Setiap dependensi konstruktor diisi oleh injeksi dependensi (DI).
Filter yang diimplementasikan sebagai atribut dan ditambahkan langsung ke kelas pengontrol atau metode tindakan tidak dapat memiliki dependensi konstruktor yang disediakan oleh injeksi dependensi (DI). Dependensi konstruktor tidak dapat disediakan oleh DI karena atribut harus memiliki parameter konstruktor yang disediakan di mana mereka diterapkan.
Filter berikut mendukung dependensi konstruktor yang disediakan dari DI:
- ServiceFilterAttribute
- TypeFilterAttribute
- IFilterFactory diimplementasikan pada atribut .
Filter sebelumnya dapat diterapkan ke pengontrol atau tindakan.
Perekam tersedia dari DI. Namun, hindari membuat dan menggunakan filter murni untuk tujuan pengelogan. Pencatatan kerangka kerja bawaan biasanya menyediakan apa yang diperlukan untuk pencatatan. Pencatatan ditambahkan ke dalam filter:
- Harus fokus pada isu atau perilaku domain bisnis yang khusus untuk filter.
- Tidak boleh mencatat tindakan atau peristiwa kerangka kerja lainnya. Filter bawaan sudah mencatat tindakan dan peristiwa kerangka kerja.
Atribut Penyaring Layanan
Jenis implementasi filter layanan terdaftar di Program.cs
. Mengambil ServiceFilterAttribute instans filter dari DI.
Kode berikut menunjukkan LoggingResponseHeaderFilterService
kelas , yang menggunakan DI:
public class LoggingResponseHeaderFilterService : IResultFilter
{
private readonly ILogger _logger;
public LoggingResponseHeaderFilterService(
ILogger<LoggingResponseHeaderFilterService> logger) =>
_logger = logger;
public void OnResultExecuting(ResultExecutingContext context)
{
_logger.LogInformation(
$"- {nameof(LoggingResponseHeaderFilterService)}.{nameof(OnResultExecuting)}");
context.HttpContext.Response.Headers.Add(
nameof(OnResultExecuting), nameof(LoggingResponseHeaderFilterService));
}
public void OnResultExecuted(ResultExecutedContext context)
{
_logger.LogInformation(
$"- {nameof(LoggingResponseHeaderFilterService)}.{nameof(OnResultExecuted)}");
}
}
Dalam kode berikut, LoggingResponseHeaderFilterService
ditambahkan ke kontainer DI:
builder.Services.AddScoped<LoggingResponseHeaderFilterService>();
Dalam kode berikut, atribut ServiceFilter
mengambil contoh filter LoggingResponseHeaderFilterService
dari DI.
[ServiceFilter<LoggingResponseHeaderFilterService>]
public IActionResult WithServiceFilter() =>
Content($"- {nameof(FilterDependenciesController)}.{nameof(WithServiceFilter)}");
Saat menggunakan ServiceFilterAttribute
, menyetel ServiceFilterAttribute.IsReusable:
- Memberikan indikasi bahwa instans filter dapat digunakan kembali di luar cakupan permintaan tempat pembuatannya. Runtime ASP.NET Core tidak menjamin:
- Bahwa satu instans filter akan dibuat.
- Filter tidak akan diminta kembali dari kontainer DI di beberapa titik kemudian.
- Tidak boleh digunakan dengan filter yang bergantung pada layanan dengan masa pakai yang berbeda dari singleton.
ServiceFilterAttribute menerapkan IFilterFactory.
IFilterFactory
mengekspos metode CreateInstance untuk membuat instans IFilterMetadata.
CreateInstance
memuat tipe yang ditentukan dari DI.
TypeFilterAttribute
TypeFilterAttribute mirip dengan ServiceFilterAttribute, tetapi tipe TypeFilterAttribute tidak diambil langsung dari kontainer DI. Ini menginstansiasi jenis dengan menggunakan Microsoft.Extensions.DependencyInjection.ObjectFactory.
Karena TypeFilterAttribute
jenis tidak diselesaikan langsung dari kontainer DI:
- Jenis yang direferensikan menggunakan
TypeFilterAttribute
tidak perlu didaftarkan dengan kontainer DI. Mereka memang memiliki dependensi yang dipenuhi oleh kontainer DI. -
TypeFilterAttribute
dapat secara opsional menerima argumen konstruktor untuk jenis tersebut.
Saat menggunakan TypeFilterAttribute
, menyetel TypeFilterAttribute.IsReusable:
Memberikan indikasi bahwa instans filter dapat digunakan kembali di luar cakupan permintaan asal pembuatannya. Runtime ASP.NET Core tidak memberikan jaminan bahwa satu instans filter akan dibuat.
Tidak boleh digunakan dengan filter yang bergantung pada layanan dengan masa pakai selain singleton.
Contoh berikut menunjukkan cara meneruskan argumen ke jenis menggunakan TypeFilterAttribute
:
[TypeFilter(typeof(LoggingResponseHeaderFilter),
Arguments = new object[] { "Filter-Header", "Filter Value" })]
public IActionResult WithTypeFilter() =>
Content($"- {nameof(FilterDependenciesController)}.{nameof(WithTypeFilter)}");
Filter otorisasi
Filter otorisasi:
- Apakah filter pertama dijalankan di alur filter.
- Mengontrol akses ke metode tindakan.
- Memiliki metode 'before', tetapi tidak memiliki metode 'after'.
Filter otorisasi kustom memerlukan kerangka kerja otorisasi kustom. Lebih suka mengonfigurasi kebijakan otorisasi atau menulis kebijakan otorisasi kustom daripada menulis filter kustom. Filter otorisasi bawaan:
- Memanggil sistem otorisasi.
- Tidak mengotorisasi permintaan.
Jangan melempar pengecualian dalam filter otorisasi.
- Pengecualian tidak akan ditangani.
- Filter pengecualian tidak akan menangani pengecualian.
Pertimbangkan untuk mengeluarkan tantangan saat pengecualian terjadi di filter otorisasi.
Pelajari selengkapnya tentang Otorisasi.
Filter sumber daya
Filter sumber daya:
- Terapkan IResourceFilter antarmuka atau IAsyncResourceFilter .
- Proses mencakup sebagian besar alur pipa filter.
- Hanya Filter Otorisasi yang berjalan sebelum filter sumber daya.
Pemfilteran sumber daya berguna untuk memotong sebagian besar alur. Misalnya, filter penyimpanan sementara dapat menghindari sisa proses saat terjadi hit cache.
Contoh filter sumber daya:
Filter sumber daya pendek sirkuit yang ditunjukkan sebelumnya.
DisableFormValueModelBindingAttribute:
- Mencegah pengikatan pada model untuk mengakses data formulir.
- Digunakan untuk unggahan file besar untuk mencegah data formulir dibaca ke dalam memori.
Penyaring Tindakan
Filter tindakan tidak berlaku untuk Razor Halaman. Razor Pages mendukung IPageFilter dan IAsyncPageFilter. Untuk informasi selengkapnya, lihat Metode filter untuk Razor Halaman.
Filter tindakan:
- Terapkan IActionFilter antarmuka atau IAsyncActionFilter .
- Pelaksanaan mereka berhubungan dengan eksekusi metode aksi.
Kode berikut menunjukkan filter tindakan sampel:
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
}
}
ActionExecutingContext menyediakan properti berikut:
- ActionArguments - memungkinkan untuk membaca masukan ke dalam metode tindakan.
- Controller - memungkinkan memanipulasi instans pengontrol.
-
Result - mengatur
Result
eksekusi sirkuit pendek dari metode tindakan dan filter tindakan berikutnya.
Melemparkan pengecualian dalam metode tindakan:
- Mencegah penerapan filter berikutnya.
- Tidak seperti pengaturan
Result
, ini diperlakukan sebagai kegagalan, bukan hasil sukses.
menyediakan ActionExecutedContextController
dan Result
ditambah properti berikut:
- Canceled - Bernilai benar jika eksekusi tindakan dihentikan oleh filter lain.
-
Exception - Non-null jika tindakan atau filter tindakan yang dijalankan sebelumnya menghasilkan pengecualian. Mengatur properti ini ke null:
- Menangani pengecualian secara efektif.
-
Result
dijalankan seolah-olah dikembalikan dari metode tindakan.
Untuk IAsyncActionFilter
, panggilan ke ActionExecutionDelegate:
- Menjalankan filter tindakan berikutnya dan metode tindakan.
- Menampilkan
ActionExecutedContext
.
Untuk memutus rangkaian, tetapkan Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.Result ke instance hasil dan jangan panggil next
(ActionExecutionDelegate
).
Kerangka kerja menyediakan abstrak ActionFilterAttribute yang dapat disubkelas.
OnActionExecuting
Filter tindakan dapat digunakan untuk:
- Validasi status model.
- Mengembalikan kesalahan jika status tidak valid.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
}
Catatan
Pengontrol yang dianotasi dengan [ApiController]
atribut secara otomatis memvalidasi status model dan mengembalikan respons 400. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.
Metode OnActionExecuted
dijalankan setelah metode aksi:
- Dan dapat melihat dan memanipulasi hasil tindakan melalui Result properti .
- Canceled diatur ke true jika eksekusi tindakan dibatalkan oleh filter lain.
-
Exception diatur ke nilai non-null jika tindakan atau filter tindakan berikutnya melemparkan pengecualian. Pengaturan
Exception
ke null:- Menangani pengecualian secara efektif.
-
ActionExecutedContext.Result
dijalankan seolah-olah hasilnya dikembalikan secara normal dari metode tersebut.
Filter pengecualian
Filter pengecualian:
- Terapkan IExceptionFilter atau IAsyncExceptionFilter.
- Dapat digunakan untuk menerapkan kebijakan penanganan kesalahan umum.
Filter pengecualian sampel berikut menampilkan detail tentang pengecualian yang terjadi saat aplikasi sedang dalam pengembangan:
public class SampleExceptionFilter : IExceptionFilter
{
private readonly IHostEnvironment _hostEnvironment;
public SampleExceptionFilter(IHostEnvironment hostEnvironment) =>
_hostEnvironment = hostEnvironment;
public void OnException(ExceptionContext context)
{
if (!_hostEnvironment.IsDevelopment())
{
// Don't display exception details unless running in Development.
return;
}
context.Result = new ContentResult
{
Content = context.Exception.ToString()
};
}
}
Kode berikut menguji filter pengecualian:
[TypeFilter<SampleExceptionFilter>]
public class ExceptionController : Controller
{
public IActionResult Index() =>
Content($"- {nameof(ExceptionController)}.{nameof(Index)}");
}
Filter pengecualian:
- Tidak memiliki peristiwa sebelum dan sesudah.
- Terapkan OnException atau OnExceptionAsync.
- Tangani pengecualian tidak tertangani yang terjadi saat pembuatan Razor halaman atau pengontrol, pengikatan model, filter tindakan, atau metode tindakan.
- Jangan menangkap pengecualian yang terjadi pada filter sumber daya, filter hasil, atau eksekusi hasil MVC.
Untuk menangani pengecualian, atur properti ExceptionHandled ke true
atau tetapkan nilai properti Result. Ini menghentikan penyebaran pengecualian. Filter pengecualian tidak dapat mengubah pengecualian menjadi "sukses". Hanya filter tindakan yang dapat melakukannya.
Filter pengecualian:
- Baik untuk menangkap pengecualian yang terjadi dalam aksi.
- Tidak fleksibel seperti middleware penanganan kesalahan.
Lebih suka middleware untuk penanganan pengecualian. Gunakan filter pengecualian hanya di mana penanganan kesalahan berbeda berdasarkan metode tindakan mana yang dipanggil. Misalnya, aplikasi mungkin memiliki metode tindakan untuk titik akhir API dan untuk tampilan/HTML. Titik akhir API dapat mengembalikan informasi kesalahan sebagai JSON, sementara tindakan berbasis tampilan dapat mengembalikan halaman kesalahan sebagai HTML.
Filter hasil
Filter hasil:
- Menerapkan antarmuka:
- Pelaksanaan mereka berkaitan dengan hasil dari tindakan tersebut.
IResultFilter dan IAsyncResultFilter
Kode berikut menunjukkan contoh filter hasil:
public class SampleResultFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
// Do something before the result executes.
}
public void OnResultExecuted(ResultExecutedContext context)
{
// Do something after the result executes.
}
}
Hasil yang dihasilkan tergantung pada jenis tindakan. Tindakan yang mengembalikan tampilan mencakup semua pemrosesan pisau cukur sebagai bagian dari ViewResult yang dijalankan. Metode API mungkin melakukan beberapa serialisasi sebagai bagian dari eksekusi hasilnya. Pelajari selengkapnya tentang hasil tindakan.
Filter hasil tindakan hanya dijalankan ketika tindakan atau filter tindakan menghasilkan hasil tindakan. Filter hasil tidak dijalankan ketika:
- Filter otorisasi atau filter sumber daya memotong alur proses.
- Filter pengecualian menangani pengecualian dengan menghasilkan hasil tindakan.
Metode Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuting dapat menghentikan eksekusi lebih awal dari hasil tindakan dan filter hasil berikutnya dengan mengatur Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext.Cancel ke true
. Tulis ke objek respons saat sirkuit pendek untuk menghindari menghasilkan respons kosong. Melemparkan pengecualian di IResultFilter.OnResultExecuting
:
- Mencegah eksekusi hasil tindakan dan filter berikutnya.
- Diperlakukan sebagai kegagalan alih-alih hasil yang berhasil.
Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuted Ketika metode berjalan, respons mungkin sudah dikirim ke klien. Jika respons telah dikirim ke klien, respons tidak dapat diubah.
ResultExecutedContext.Canceled
diatur menjadi true
jika eksekusi hasil aksi dihentikan oleh filter lain.
ResultExecutedContext.Exception
disetel ke dalam nilai non-null jika hasil tindakan atau filter hasil berikutnya memunculkan pengecualian. Pengaturan Exception
ke null secara efektif menangani pengecualian dan mencegah pengecualian dilemparkan lagi nanti di alur. Tidak ada cara yang dapat diandalkan untuk menulis data ke respons saat menangani pengecualian dalam filter hasil. Jika header sudah dikirim ke klien ketika hasil tindakan menghasilkan pengecualian, tidak ada mekanisme yang dapat diandalkan untuk mengirimkan kode kegagalan.
Untuk IAsyncResultFilter, pemanggilan await next
pada ResultExecutionDelegate menjalankan penyaring hasil berikutnya dan hasil tindakan. Untuk sirkuit pendek, atur ResultExecutingContext.Cancel ke true
dan jangan panggil ResultExecutionDelegate
:
public class SampleAsyncResultFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(
ResultExecutingContext context, ResultExecutionDelegate next)
{
if (context.Result is not EmptyResult)
{
await next();
}
else
{
context.Cancel = true;
}
}
}
Kerangka kerja menyediakan abstrak ResultFilterAttribute
yang dapat disubkelas. Kelas ResponseHeaderAttribute yang ditampilkan sebelumnya adalah contoh atribut filter hasil.
IAlwaysRunResultFilter dan IAsyncAlwaysRunResultFilter
Antarmuka IAlwaysRunResultFilter dan IAsyncAlwaysRunResultFilter mendeklarasikan IResultFilter implementasi yang berjalan untuk semua hasil tindakan. Ini termasuk hasil tindakan yang dihasilkan oleh:
- Filter otorisasi dan filter sumber daya yang menghentikan proses di tengah jalan.
- Filter pengecualian.
Misalnya, filter berikut selalu menjalankan dan menetapkan hasil tindakan (ObjectResult) dengan kode status Entitas Tidak Dapat Diproses 422 saat negosiasi konten gagal:
public class UnprocessableResultFilter : IAlwaysRunResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is StatusCodeResult statusCodeResult
&& statusCodeResult.StatusCode == StatusCodes.Status415UnsupportedMediaType)
{
context.Result = new ObjectResult("Unprocessable")
{
StatusCode = StatusCodes.Status422UnprocessableEntity
};
}
}
public void OnResultExecuted(ResultExecutedContext context) { }
}
IFilterFactory
IFilterFactory menerapkan IFilterMetadata. Oleh karena itu, IFilterFactory
instans dapat digunakan sebagai IFilterMetadata
instans di mana saja dalam alur filter. Ketika runtime bersiap untuk memanggil filter, runtime berusaha mengonversinya ke IFilterFactory
. Jika transmisi tersebut berhasil, CreateInstance metode dipanggil untuk membuat IFilterMetadata
instans yang dipanggil. Ini menyediakan desain yang fleksibel, karena alur filter yang tepat tidak perlu diatur secara eksplisit saat aplikasi dimulai.
IFilterFactory.IsReusable
:
- Adalah petunjuk dari fabrik bahwa instance filter yang dibuat oleh fabrik dapat digunakan kembali di luar lingkup permintaan tempat instance tersebut dibuat.
- Jangan digunakan dengan filter yang bergantung pada layanan dengan masa pakai yang berbeda dari singleton.
ASP.NET Core runtime tidak menjamin:
- Bahwa satu instans filter akan dibuat.
- Filter tidak akan diminta kembali dari kontainer DI di beberapa titik kemudian.
Peringatan
Hanya konfigurasikan IFilterFactory.IsReusable untuk mengembalikan true
jika sumber filter tidak ambigu, filter bersifat stateless, dan filter aman digunakan di berbagai permintaan HTTP. Misalnya, jangan mengembalikan filter dari DI yang terdaftar sebagai tercakup atau sementara jika IFilterFactory.IsReusable
mengembalikan true
.
IFilterFactory
dapat diimplementasikan menggunakan implementasi atribut kustom sebagai pendekatan lain untuk membuat filter:
public class ResponseHeaderFilterFactory : Attribute, IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) =>
new InternalResponseHeaderFilter();
private class InternalResponseHeaderFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context) =>
context.HttpContext.Response.Headers.Add(
nameof(OnActionExecuting), nameof(InternalResponseHeaderFilter));
public void OnActionExecuted(ActionExecutedContext context) { }
}
Filter diterapkan dalam kode berikut:
[ResponseHeaderFilterFactory]
public IActionResult Index() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(Index)}");
IFilterFactory diimplementasikan pada atribut
Filter yang mengimplementasikan IFilterFactory
berguna untuk filter yang:
- Tidak memerlukan parameter passing.
- Memiliki dependensi konstruktor yang perlu diisi oleh DI.
TypeFilterAttribute menerapkan IFilterFactory.
IFilterFactory
mengekspos metode CreateInstance untuk membuat instans IFilterMetadata.
CreateInstance
memuat tipe yang ditentukan dari wadah layanan (DI).
public class SampleActionTypeFilterAttribute : TypeFilterAttribute
{
public SampleActionTypeFilterAttribute()
: base(typeof(InternalSampleActionFilter)) { }
private class InternalSampleActionFilter : IActionFilter
{
private readonly ILogger<InternalSampleActionFilter> _logger;
public InternalSampleActionFilter(ILogger<InternalSampleActionFilter> logger) =>
_logger = logger;
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation(
$"- {nameof(InternalSampleActionFilter)}.{nameof(OnActionExecuting)}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation(
$"- {nameof(InternalSampleActionFilter)}.{nameof(OnActionExecuted)}");
}
}
}
Kode berikut menunjukkan tiga pendekatan untuk menerapkan filter:
[SampleActionTypeFilter]
public IActionResult WithDirectAttribute() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(WithDirectAttribute)}");
[TypeFilter<SampleActionTypeFilterAttribute>]
public IActionResult WithTypeFilterAttribute() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(WithTypeFilterAttribute)}");
[ServiceFilter<SampleActionTypeFilterAttribute>]
public IActionResult WithServiceFilterAttribute() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(WithServiceFilterAttribute)}");
Dalam kode sebelumnya, pendekatan pertama untuk menerapkan filter lebih disukai.
Gunakan middleware dalam alur filter
Filter sumber daya berfungsi seperti middleware karena mereka mengelilingi eksekusi semua yang muncul nanti dalam alur. Tetapi filter berbeda dari middleware karena mereka adalah bagian dari runtime, yang berarti bahwa mereka memiliki akses ke konteks dan konstruksi.
Untuk menggunakan middleware sebagai filter, buat tipe dengan metode Configure
yang menentukan middleware untuk dimasukkan ke dalam rangkaian filter. Contoh berikut menggunakan middleware untuk mengatur header respons:
public class FilterMiddlewarePipeline
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Pipeline", "Middleware");
await next();
});
}
}
MiddlewareFilterAttribute Gunakan untuk menjalankan middleware:
[MiddlewareFilter<FilterMiddlewarePipeline>]
public class FilterMiddlewareController : Controller
{
public IActionResult Index() =>
Content($"- {nameof(FilterMiddlewareController)}.{nameof(Index)}");
}
Filter middleware berjalan pada tahap alur filter yang sama dengan filter Sumber Daya, sebelum pengikatan model dan setelah alur lainnya.
Keamanan Thread
Saat meneruskan instans dari filter ke Add
, bukan ke Type
, filter tersebut menjadi singleton dan tidak aman dalam konteks multi-utas.
Sumber Daya Tambahan:
Oleh Kirk Larkin, Rick Anderson, Tom Dykstra, dan Steve Smith
Filter di ASP.NET Core memungkinkan kode dijalankan sebelum atau sesudah tahap tertentu dalam alur pemrosesan permintaan.
Filter bawaan menangani tugas seperti:
- Otorisasi, mencegah akses ke sumber daya yang tidak diotorisasi pengguna.
- Penembolokan respons, memotong jalur permintaan untuk mengembalikan respons yang telah di-cache.
Filter kustom dapat dibuat untuk menangani kekhawatiran lintas fungsi. Contoh concern lintas proses termasuk penanganan kesalahan, penyimpanan sementara, konfigurasi, otorisasi, dan pencatatan. Filter menghindari kode duplikat. Misalnya, filter pengecualian penanganan kesalahan dapat mengonsolidasikan penanganan kesalahan.
Dokumen ini berlaku untuk Razor Halaman, pengontrol API, dan pengontrol dengan tampilan. Filter tidak berfungsi langsung dengan Razor komponen. Filter hanya dapat secara tidak langsung memengaruhi komponen saat:
- Komponen disematkan dalam halaman atau tampilan.
- Halaman, pengontrol, dan tampilan menggunakan filter.
Cara kerja filter
Filter berjalan dalam jalur pemanggilan aksi ASP.NET Core, kadang-kadang disebut juga sebagai jalur filter. Alur filter berjalan setelah ASP.NET Core memilih tindakan yang akan dijalankan:
Jenis filter
Setiap jenis filter dijalankan pada tahap yang berbeda dalam alur filter:
-
- Jalankan terlebih dahulu.
- Tentukan apakah pengguna berwenang untuk permintaan tersebut.
- Hentikan proses jika permintaan tidak terotorisasi.
-
- Jalankan setelah otorisasi.
-
OnResourceExecuting menjalankan kode sebelum alur pemrosesan filter lainnya mulai. Misalnya,
OnResourceExecuting
menjalankan kode sebelum pengikatan model. - OnResourceExecuted menjalankan program setelah tahap lain dari alur selesai.
-
- Jalankan segera sebelum dan sesudah metode tindakan dipanggil.
- Dapat mengubah argumen yang diteruskan ke tindakan.
- Dapat mengubah hasil yang dihasilkan oleh tindakan.
- Tidak didukung di Razor Halaman.
-
- Jalankan segera sebelum dan sesudah metode tindakan dipanggil.
- Dapat mengubah argumen yang diteruskan ke tindakan.
- Dapat mengubah hasil yang dihasilkan oleh tindakan.
- Tidak didukung di Razor Halaman.
- Dapat dipanggil pada tindakan dan titik akhir berbasis handler rute.
Filter pengecualian menerapkan kebijakan global pada pengecualian yang tidak tertangani yang terjadi sebelum isi tanggapan ditulis.
-
- Jalankan segera sebelum dan sesudah pelaksanaan hasil tindakan.
- Jalankan hanya ketika metode tindakan berhasil dijalankan.
- Berguna untuk logika yang harus mengitari tampilan atau eksekusi pemformat.
Diagram berikut menunjukkan bagaimana jenis filter berinteraksi dalam alur filter:
Razor Pages juga mendukung Razor filter halaman, yang berjalan sebelum dan sesudah Razor handler halaman.
implementasi
Filter mendukung implementasi sinkron dan asinkron melalui definisi antarmuka yang berbeda.
Filter sinkron berjalan sebelum dan sesudah tahap alurnya. Misalnya, OnActionExecuting dipanggil sebelum metode tindakan dipanggil. OnActionExecuted dipanggil setelah metode aksi mengembalikan hasil:
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
}
}
Filter asinkron mendefinisikan metode On-Stage-ExecutionAsync
. Misalnya, OnActionExecutionAsync:
public class SampleAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context, ActionExecutionDelegate next)
{
// Do something before the action executes.
await next();
// Do something after the action executes.
}
}
Dalam kode sebelumnya, SampleAsyncActionFilter
memiliki ActionExecutionDelegate, , next
yang menjalankan metode tindakan.
Beberapa tahap filter
Antarmuka untuk beberapa tahap filter dapat diimplementasikan dalam satu kelas. Misalnya, ActionFilterAttribute kelas mengimplementasikan:
- Sinkron: IActionFilter dan IResultFilter
- Asinkron: IAsyncActionFilter dan IAsyncResultFilter
- IOrderedFilter
Terapkan versi sinkron atau asinkron dari antarmuka filter, bukan keduanya. Runtime memeriksa terlebih dahulu untuk melihat apakah filter mengimplementasikan antarmuka asinkron, dan jika demikian, filter memanggilnya. Jika tidak, ini memanggil metode antarmuka sinkron. Jika antarmuka asinkron dan sinkron diimplementasikan dalam satu kelas, hanya metode asinkron yang dipanggil. Saat menggunakan kelas abstrak seperti ActionFilterAttribute, hanya ambil alih metode sinkron atau metode asinkron untuk setiap jenis filter.
Atribut filter bawaan
ASP.NET Core mencakup filter berbasis atribut bawaan yang dapat disubkelas dan disesuaikan. Misalnya, filter hasil berikut menambahkan header ke respons:
public class ResponseHeaderAttribute : ActionFilterAttribute
{
private readonly string _name;
private readonly string _value;
public ResponseHeaderAttribute(string name, string value) =>
(_name, _value) = (name, value);
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(_name, _value);
base.OnResultExecuting(context);
}
}
Atribut memungkinkan filter untuk menerima argumen, seperti yang ditunjukkan dalam contoh sebelumnya. Terapkan ResponseHeaderAttribute
ke pengontrol atau metode tindakan dan tentukan nama serta nilai header HTTP.
[ResponseHeader("Filter-Header", "Filter Value")]
public class ResponseHeaderController : ControllerBase
{
public IActionResult Index() =>
Content("Examine the response headers using the F12 developer tools.");
// ...
Gunakan alat seperti alat pengembang browser untuk memeriksa header. Di bawah Response Headers, filter-header: Filter Value
ditampilkan.
Kode berikut berlaku ResponseHeaderAttribute
untuk pengontrol dan tindakan:
[ResponseHeader("Filter-Header", "Filter Value")]
public class ResponseHeaderController : ControllerBase
{
public IActionResult Index() =>
Content("Examine the response headers using the F12 developer tools.");
// ...
[ResponseHeader("Another-Filter-Header", "Another Filter Value")]
public IActionResult Multiple() =>
Content("Examine the response headers using the F12 developer tools.");
}
Respon dari tindakan Multiple
mencakup tajuk berikut:
filter-header: Filter Value
another-filter-header: Another Filter Value
Beberapa antarmuka filter memiliki atribut yang sesuai yang dapat digunakan sebagai kelas dasar untuk implementasi kustom.
Filter Atribut:
- ActionFilterAttribute
- ExceptionFilterAttribute
- ResultFilterAttribute
- FormatFilterAttribute
- ServiceFilterAttribute
- TypeFilterAttribute
Filter tidak dapat diterapkan ke metode handler halaman Razor. Mereka dapat diterapkan baik secara global maupun ke Model Halaman Razor.
Cakupan penyaringan dan urutan eksekusi
Filter dapat ditambahkan ke alur di salah satu dari tiga cakupan:
- Menggunakan atribut pada pengontrol atau Razor Halaman.
- Menggunakan atribut pada tindakan pengontrol. Atribut filter tidak dapat diterapkan ke Razor metode handler Pages.
- Secara global untuk semua pengontrol, tindakan, dan Razor Halaman seperti yang ditunjukkan dalam kode berikut:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(options => { options.Filters.Add<GlobalSampleActionFilter>(); });
Urutan eksekusi default
Ketika ada beberapa filter untuk tahap tertentu dari alur kerja, cakupan menentukan urutan default dari eksekusi filter. Filter global mengelilingi filter kelas, yang pada gilirannya mengelilingi filter metode.
Akibat dari penyaringan bersarang, kode setelah filter berjalan dalam urutan terbalik dari kode sebelum. Urutan filter:
- Kode filter global sebelumnya.
- Kode sebelum filter pengontrol.
- Kode sebelum filter metode tindakan.
- Kode setelah filter metode tindakan.
- Kode setelah filter pengontrol.
- Kode sebelum filter pengontrol.
- Kode dari filter global setelah.
Contoh berikut mengilustrasikan urutan metode filter yang dijalankan untuk filter tindakan sinkron:
Urutan | Cakupan filter | Metode filter |
---|---|---|
1 | Mendunia | OnActionExecuting |
2 | Pengontrol | OnActionExecuting |
3 | Perbuatan | OnActionExecuting |
4 | Perbuatan | OnActionExecuted |
5 | Pengontrol | OnActionExecuted |
6 | Mendunia | OnActionExecuted |
Filter pada tingkat pengendali
Setiap pengontrol yang mewarisi dari Controller mencakup metode OnActionExecuting, OnActionExecutionAsync, dan OnActionExecuted. Metode ini membungkus filter yang dijalankan untuk tindakan tertentu.
-
OnActionExecuting
berjalan sebelum filter-filter tindakan apa pun. -
OnActionExecuted
berjalan setelah semua filter tindakan. -
OnActionExecutionAsync
berjalan sebelum filter-filter tindakan apa pun. Kode setelah pemanggilan kenext
berjalan setelah filter tindakan.
Kelas berikut ControllerFiltersController
:
- Menerapkan
SampleActionFilterAttribute
([SampleActionFilter]
) ke pengontrol. - Mengambil alih
OnActionExecuting
danOnActionExecuted
.
[SampleActionFilter]
public class ControllerFiltersController : Controller
{
public override void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine(
$"- {nameof(ControllerFiltersController)}.{nameof(OnActionExecuting)}");
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine(
$"- {nameof(ControllerFiltersController)}.{nameof(OnActionExecuted)}");
base.OnActionExecuted(context);
}
public IActionResult Index()
{
Console.WriteLine(
$"- {nameof(ControllerFiltersController)}.{nameof(Index)}");
return Content("Check the Console.");
}
}
Menavigasi ke https://localhost:<port>/ControllerFilters
menjalankan kode berikut:
ControllerFiltersController.OnActionExecuting
GlobalSampleActionFilter.OnActionExecuting
SampleActionFilterAttribute.OnActionExecuting
ControllerFiltersController.Index
SampleActionFilterAttribute.OnActionExecuted
GlobalSampleActionFilter.OnActionExecuted
ControllerFiltersController.OnActionExecuted
Filter tingkat pengontrol mengatur properti Pesanan ke int.MinValue
. Filter tingkat pengontrol tidak dapat diatur untuk dijalankan setelah filter yang diterapkan pada metode. Pesanan dijelaskan di bagian berikutnya.
Untuk Razor Halaman, lihat Razor.
Mengatasi urutan default
Urutan default eksekusi dapat diganti dengan menerapkan IOrderedFilter.
IOrderedFilter
mengekspos properti Order yang lebih diutamakan daripada cakupan untuk menentukan urutan eksekusi. Filter dengan nilai yang lebih rendah Order
:
- Menjalankan kode sebelum yang dimiliki oleh filter dengan nilai yang lebih tinggi dari
Order
. - Menjalankan kode setelah kode dari filter dengan nilai yang lebih tinggi
Order
.
Dalam contoh filter tingkat pengontrol, memiliki cakupan global sehingga berjalan sebelum GlobalSampleActionFilter
, yang memiliki cakupan pengontrol. Untuk menjalankan SampleActionFilterAttribute
terlebih dahulu, atur urutannya ke int.MinValue
:
[SampleActionFilter(Order = int.MinValue)]
public class ControllerFiltersController : Controller
{
// ...
}
Untuk membuat filter GlobalSampleActionFilter
global berjalan terlebih dahulu, atur Order
ke int.MinValue
:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<GlobalSampleActionFilter>(int.MinValue);
});
Pembatalan dan Pemutusan Arus Pendek
Alur filter dapat diputus dengan mengatur properti Result pada parameter yang disediakan oleh ResourceExecutingContext untuk metode filter. Misalnya, filter Sumber Daya berikut mencegah sisa alur dieksekusi:
public class ShortCircuitingResourceFilterAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
context.Result = new ContentResult
{
Content = nameof(ShortCircuitingResourceFilterAttribute)
};
}
public void OnResourceExecuted(ResourceExecutedContext context) { }
}
Dalam kode berikut, baik filter [ShortCircuitingResourceFilter]
maupun [ResponseHeader]
menargetkan metode tindakan Index
. Filter ShortCircuitingResourceFilterAttribute
:
- Berjalan terlebih dahulu, karena ini adalah Filter Sumber Daya dan
ResponseHeaderAttribute
merupakan Filter Tindakan. - Menghentikan sisa proses.
Oleh karena itu, filter ResponseHeaderAttribute
tidak pernah berjalan untuk tindakan Index
. Perilaku ini akan sama jika kedua filter diterapkan pada tingkat metode tindakan, asalkan ShortCircuitingResourceFilterAttribute
dijalankan terlebih dahulu.
ShortCircuitingResourceFilterAttribute
berjalan lebih dahulu karena jenis filternya:
[ResponseHeader("Filter-Header", "Filter Value")]
public class ShortCircuitingController : Controller
{
[ShortCircuitingResourceFilter]
public IActionResult Index() =>
Content($"- {nameof(ShortCircuitingController)}.{nameof(Index)}");
}
Injeksi dependensi
Filter dapat ditambahkan berdasarkan jenis atau berdasarkan instans. Jika instans ditambahkan, instans tersebut digunakan untuk setiap permintaan. Jika sebuah tipe ditambahkan, maka tipe tersebut akan diaktifkan. Filter yang diaktifkan berdasarkan jenis berarti:
- Instans dibuat untuk setiap permintaan.
- Setiap dependensi konstruktor diisi oleh injeksi dependensi (DI).
Filter yang diimplementasikan sebagai atribut dan ditambahkan langsung ke kelas pengontrol atau metode tindakan tidak dapat memiliki dependensi konstruktor yang disediakan oleh injeksi dependensi (DI). Dependensi konstruktor tidak dapat disediakan oleh DI karena atribut harus memiliki parameter konstruktor yang disediakan di mana mereka diterapkan.
Filter berikut mendukung dependensi konstruktor yang disediakan dari DI:
- ServiceFilterAttribute
- TypeFilterAttribute
- IFilterFactory diimplementasikan pada atribut .
Filter sebelumnya dapat diterapkan ke pengontrol atau tindakan.
Perekam tersedia dari DI. Namun, hindari membuat dan menggunakan filter murni untuk tujuan pengelogan. Pencatatan kerangka kerja bawaan biasanya menyediakan apa yang diperlukan untuk pencatatan. Pencatatan ditambahkan ke dalam filter:
- Harus fokus pada isu atau perilaku domain bisnis yang khusus untuk filter.
- Tidak boleh mencatat tindakan atau peristiwa kerangka kerja lainnya. Filter bawaan sudah mencatat tindakan dan peristiwa kerangka kerja.
Atribut Penyaring Layanan
Jenis implementasi filter layanan terdaftar di Program.cs
. Mengambil ServiceFilterAttribute instans filter dari DI.
Kode berikut menunjukkan LoggingResponseHeaderFilterService
kelas , yang menggunakan DI:
public class LoggingResponseHeaderFilterService : IResultFilter
{
private readonly ILogger _logger;
public LoggingResponseHeaderFilterService(
ILogger<LoggingResponseHeaderFilterService> logger) =>
_logger = logger;
public void OnResultExecuting(ResultExecutingContext context)
{
_logger.LogInformation(
$"- {nameof(LoggingResponseHeaderFilterService)}.{nameof(OnResultExecuting)}");
context.HttpContext.Response.Headers.Add(
nameof(OnResultExecuting), nameof(LoggingResponseHeaderFilterService));
}
public void OnResultExecuted(ResultExecutedContext context)
{
_logger.LogInformation(
$"- {nameof(LoggingResponseHeaderFilterService)}.{nameof(OnResultExecuted)}");
}
}
Dalam kode berikut, LoggingResponseHeaderFilterService
ditambahkan ke kontainer DI:
builder.Services.AddScoped<LoggingResponseHeaderFilterService>();
Dalam kode berikut, atribut ServiceFilter
mengambil contoh filter LoggingResponseHeaderFilterService
dari DI.
[ServiceFilter(typeof(LoggingResponseHeaderFilterService))]
public IActionResult WithServiceFilter() =>
Content($"- {nameof(FilterDependenciesController)}.{nameof(WithServiceFilter)}");
Saat menggunakan ServiceFilterAttribute
, menyetel ServiceFilterAttribute.IsReusable:
- Memberikan indikasi bahwa instans filter dapat digunakan kembali di luar cakupan permintaan tempat pembuatannya. Runtime ASP.NET Core tidak menjamin:
- Bahwa satu instans filter akan dibuat.
- Filter tidak akan diminta kembali dari kontainer DI di beberapa titik kemudian.
- Tidak boleh digunakan dengan filter yang bergantung pada layanan dengan masa pakai yang berbeda dari singleton.
ServiceFilterAttribute menerapkan IFilterFactory.
IFilterFactory
mengekspos metode CreateInstance untuk membuat instans IFilterMetadata.
CreateInstance
memuat tipe yang ditentukan dari DI.
TypeFilterAttribute
TypeFilterAttribute mirip dengan ServiceFilterAttribute, tetapi tipe TypeFilterAttribute tidak diambil langsung dari kontainer DI. Ini menginstansiasi jenis dengan menggunakan Microsoft.Extensions.DependencyInjection.ObjectFactory.
Karena TypeFilterAttribute
jenis tidak diselesaikan langsung dari kontainer DI:
- Jenis yang direferensikan menggunakan
TypeFilterAttribute
tidak perlu didaftarkan dengan kontainer DI. Mereka memang memiliki dependensi yang dipenuhi oleh kontainer DI. -
TypeFilterAttribute
dapat secara opsional menerima argumen konstruktor untuk jenis tersebut.
Saat menggunakan TypeFilterAttribute
, menyetel TypeFilterAttribute.IsReusable:
Memberikan indikasi bahwa instans filter dapat digunakan kembali di luar cakupan permintaan asal pembuatannya. Runtime ASP.NET Core tidak memberikan jaminan bahwa satu instans filter akan dibuat.
Tidak boleh digunakan dengan filter yang bergantung pada layanan dengan masa pakai selain singleton.
Contoh berikut menunjukkan cara meneruskan argumen ke jenis menggunakan TypeFilterAttribute
:
[TypeFilter(typeof(LoggingResponseHeaderFilter),
Arguments = new object[] { "Filter-Header", "Filter Value" })]
public IActionResult WithTypeFilter() =>
Content($"- {nameof(FilterDependenciesController)}.{nameof(WithTypeFilter)}");
Filter otorisasi
Filter otorisasi:
- Apakah filter pertama dijalankan di alur filter.
- Mengontrol akses ke metode tindakan.
- Memiliki metode 'before', tetapi tidak memiliki metode 'after'.
Filter otorisasi kustom memerlukan kerangka kerja otorisasi kustom. Lebih suka mengonfigurasi kebijakan otorisasi atau menulis kebijakan otorisasi kustom daripada menulis filter kustom. Filter otorisasi bawaan:
- Memanggil sistem otorisasi.
- Tidak mengotorisasi permintaan.
Jangan melempar pengecualian dalam filter otorisasi.
- Pengecualian tidak akan ditangani.
- Filter pengecualian tidak akan menangani pengecualian.
Pertimbangkan untuk mengeluarkan tantangan saat pengecualian terjadi di filter otorisasi.
Pelajari selengkapnya tentang Otorisasi.
Filter sumber daya
Filter sumber daya:
- Terapkan IResourceFilter antarmuka atau IAsyncResourceFilter .
- Proses mencakup sebagian besar alur pipa filter.
- Hanya Filter Otorisasi yang berjalan sebelum filter sumber daya.
Pemfilteran sumber daya berguna untuk memotong sebagian besar alur. Misalnya, filter penyimpanan sementara dapat menghindari sisa proses saat terjadi hit cache.
Contoh filter sumber daya:
Filter sumber daya pendek sirkuit yang ditunjukkan sebelumnya.
DisableFormValueModelBindingAttribute:
- Mencegah pengikatan pada model untuk mengakses data formulir.
- Digunakan untuk unggahan file besar untuk mencegah data formulir dibaca ke dalam memori.
Penyaring Tindakan
Filter tindakan tidak berlaku untuk Razor Halaman. Razor Pages mendukung IPageFilter dan IAsyncPageFilter. Untuk informasi selengkapnya, lihat Metode filter untuk Razor Halaman.
Filter tindakan:
- Terapkan IActionFilter antarmuka atau IAsyncActionFilter .
- Pelaksanaan mereka berhubungan dengan eksekusi metode aksi.
Kode berikut menunjukkan filter tindakan sampel:
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
}
}
ActionExecutingContext menyediakan properti berikut:
- ActionArguments - memungkinkan untuk membaca masukan ke dalam metode tindakan.
- Controller - memungkinkan memanipulasi instans pengontrol.
-
Result - mengatur
Result
eksekusi sirkuit pendek dari metode tindakan dan filter tindakan berikutnya.
Melemparkan pengecualian dalam metode tindakan:
- Mencegah penerapan filter berikutnya.
- Tidak seperti pengaturan
Result
, ini diperlakukan sebagai kegagalan, bukan hasil sukses.
menyediakan ActionExecutedContextController
dan Result
ditambah properti berikut:
- Canceled - Bernilai benar jika eksekusi tindakan dihentikan oleh filter lain.
-
Exception - Non-null jika tindakan atau filter tindakan yang dijalankan sebelumnya menghasilkan pengecualian. Mengatur properti ini ke null:
- Menangani pengecualian secara efektif.
-
Result
dijalankan seolah-olah dikembalikan dari metode tindakan.
Untuk IAsyncActionFilter
, panggilan ke ActionExecutionDelegate:
- Menjalankan filter tindakan berikutnya dan metode tindakan.
- Menampilkan
ActionExecutedContext
.
Untuk memutus rangkaian, tetapkan Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.Result ke instance hasil dan jangan panggil next
(ActionExecutionDelegate
).
Kerangka kerja menyediakan abstrak ActionFilterAttribute yang dapat disubkelas.
OnActionExecuting
Filter tindakan dapat digunakan untuk:
- Validasi status model.
- Mengembalikan kesalahan jika status tidak valid.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
}
Catatan
Pengontrol yang dianotasi dengan [ApiController]
atribut secara otomatis memvalidasi status model dan mengembalikan respons 400. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.
Metode OnActionExecuted
dijalankan setelah metode aksi:
- Dan dapat melihat dan memanipulasi hasil tindakan melalui Result properti .
- Canceled diatur ke true jika eksekusi tindakan dibatalkan oleh filter lain.
-
Exception diatur ke nilai non-null jika tindakan atau filter tindakan berikutnya melemparkan pengecualian. Pengaturan
Exception
ke null:- Menangani pengecualian secara efektif.
-
ActionExecutedContext.Result
dijalankan seolah-olah hasilnya dikembalikan secara normal dari metode tersebut.
Filter pengecualian
Filter pengecualian:
- Terapkan IExceptionFilter atau IAsyncExceptionFilter.
- Dapat digunakan untuk menerapkan kebijakan penanganan kesalahan umum.
Filter pengecualian sampel berikut menampilkan detail tentang pengecualian yang terjadi saat aplikasi sedang dalam pengembangan:
public class SampleExceptionFilter : IExceptionFilter
{
private readonly IHostEnvironment _hostEnvironment;
public SampleExceptionFilter(IHostEnvironment hostEnvironment) =>
_hostEnvironment = hostEnvironment;
public void OnException(ExceptionContext context)
{
if (!_hostEnvironment.IsDevelopment())
{
// Don't display exception details unless running in Development.
return;
}
context.Result = new ContentResult
{
Content = context.Exception.ToString()
};
}
}
Kode berikut menguji filter pengecualian:
[TypeFilter(typeof(SampleExceptionFilter))]
public class ExceptionController : Controller
{
public IActionResult Index() =>
Content($"- {nameof(ExceptionController)}.{nameof(Index)}");
}
Filter pengecualian:
- Tidak memiliki peristiwa sebelum dan sesudah.
- Terapkan OnException atau OnExceptionAsync.
- Tangani pengecualian tidak tertangani yang terjadi saat pembuatan Razor halaman atau pengontrol, pengikatan model, filter tindakan, atau metode tindakan.
- Jangan menangkap pengecualian yang terjadi pada filter sumber daya, filter hasil, atau eksekusi hasil MVC.
Untuk menangani pengecualian, atur properti ExceptionHandled ke true
atau tetapkan nilai properti Result. Ini menghentikan penyebaran pengecualian. Filter pengecualian tidak dapat mengubah pengecualian menjadi "sukses". Hanya filter tindakan yang dapat melakukannya.
Filter pengecualian:
- Baik untuk menangkap pengecualian yang terjadi dalam aksi.
- Tidak fleksibel seperti middleware penanganan kesalahan.
Lebih suka middleware untuk penanganan pengecualian. Gunakan filter pengecualian hanya di mana penanganan kesalahan berbeda berdasarkan metode tindakan mana yang dipanggil. Misalnya, aplikasi mungkin memiliki metode tindakan untuk titik akhir API dan untuk tampilan/HTML. Titik akhir API dapat mengembalikan informasi kesalahan sebagai JSON, sementara tindakan berbasis tampilan dapat mengembalikan halaman kesalahan sebagai HTML.
Filter hasil
Filter hasil:
- Menerapkan antarmuka:
- Pelaksanaan mereka berkaitan dengan hasil dari tindakan tersebut.
IResultFilter dan IAsyncResultFilter
Kode berikut menunjukkan contoh filter hasil:
public class SampleResultFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
// Do something before the result executes.
}
public void OnResultExecuted(ResultExecutedContext context)
{
// Do something after the result executes.
}
}
Hasil yang dihasilkan tergantung pada jenis tindakan. Tindakan yang mengembalikan tampilan mencakup semua pemrosesan pisau cukur sebagai bagian dari ViewResult yang dijalankan. Metode API mungkin melakukan beberapa serialisasi sebagai bagian dari eksekusi hasilnya. Pelajari selengkapnya tentang hasil tindakan.
Filter hasil tindakan hanya dijalankan ketika tindakan atau filter tindakan menghasilkan hasil tindakan. Filter hasil tidak dijalankan ketika:
- Filter otorisasi atau filter sumber daya memotong alur proses.
- Filter pengecualian menangani pengecualian dengan menghasilkan hasil tindakan.
Metode Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuting dapat menghentikan eksekusi lebih awal dari hasil tindakan dan filter hasil berikutnya dengan mengatur Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext.Cancel ke true
. Tulis ke objek respons saat sirkuit pendek untuk menghindari menghasilkan respons kosong. Melemparkan pengecualian di IResultFilter.OnResultExecuting
:
- Mencegah eksekusi hasil tindakan dan filter berikutnya.
- Diperlakukan sebagai kegagalan alih-alih hasil yang berhasil.
Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuted Ketika metode berjalan, respons mungkin sudah dikirim ke klien. Jika respons telah dikirim ke klien, respons tidak dapat diubah.
ResultExecutedContext.Canceled
diatur menjadi true
jika eksekusi hasil aksi dihentikan oleh filter lain.
ResultExecutedContext.Exception
disetel ke dalam nilai non-null jika hasil tindakan atau filter hasil berikutnya memunculkan pengecualian. Pengaturan Exception
ke null secara efektif menangani pengecualian dan mencegah pengecualian dilemparkan lagi nanti di alur. Tidak ada cara yang dapat diandalkan untuk menulis data ke respons saat menangani pengecualian dalam filter hasil. Jika header sudah dikirim ke klien ketika hasil tindakan menghasilkan pengecualian, tidak ada mekanisme yang dapat diandalkan untuk mengirimkan kode kegagalan.
Untuk IAsyncResultFilter, pemanggilan await next
pada ResultExecutionDelegate menjalankan penyaring hasil berikutnya dan hasil tindakan. Untuk sirkuit pendek, atur ResultExecutingContext.Cancel ke true
dan jangan panggil ResultExecutionDelegate
:
public class SampleAsyncResultFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(
ResultExecutingContext context, ResultExecutionDelegate next)
{
if (context.Result is not EmptyResult)
{
await next();
}
else
{
context.Cancel = true;
}
}
}
Kerangka kerja menyediakan abstrak ResultFilterAttribute
yang dapat disubkelas. Kelas ResponseHeaderAttribute yang ditampilkan sebelumnya adalah contoh atribut filter hasil.
IAlwaysRunResultFilter dan IAsyncAlwaysRunResultFilter
Antarmuka IAlwaysRunResultFilter dan IAsyncAlwaysRunResultFilter mendeklarasikan IResultFilter implementasi yang berjalan untuk semua hasil tindakan. Ini termasuk hasil tindakan yang dihasilkan oleh:
- Filter otorisasi dan filter sumber daya yang menghentikan proses di tengah jalan.
- Filter pengecualian.
Misalnya, filter berikut selalu menjalankan dan menetapkan hasil tindakan (ObjectResult) dengan kode status Entitas Tidak Dapat Diproses 422 saat negosiasi konten gagal:
public class UnprocessableResultFilter : IAlwaysRunResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is StatusCodeResult statusCodeResult
&& statusCodeResult.StatusCode == StatusCodes.Status415UnsupportedMediaType)
{
context.Result = new ObjectResult("Unprocessable")
{
StatusCode = StatusCodes.Status422UnprocessableEntity
};
}
}
public void OnResultExecuted(ResultExecutedContext context) { }
}
IFilterFactory
IFilterFactory menerapkan IFilterMetadata. Oleh karena itu, IFilterFactory
instans dapat digunakan sebagai IFilterMetadata
instans di mana saja dalam alur filter. Ketika runtime bersiap untuk memanggil filter, runtime berusaha mengonversinya ke IFilterFactory
. Jika transmisi tersebut berhasil, CreateInstance metode dipanggil untuk membuat IFilterMetadata
instans yang dipanggil. Ini menyediakan desain yang fleksibel, karena alur filter yang tepat tidak perlu diatur secara eksplisit saat aplikasi dimulai.
IFilterFactory.IsReusable
:
- Adalah petunjuk dari fabrik bahwa instance filter yang dibuat oleh fabrik dapat digunakan kembali di luar lingkup permintaan tempat instance tersebut dibuat.
- Jangan digunakan dengan filter yang bergantung pada layanan dengan masa pakai yang berbeda dari singleton.
ASP.NET Core runtime tidak menjamin:
- Bahwa satu instans filter akan dibuat.
- Filter tidak akan diminta kembali dari kontainer DI di beberapa titik kemudian.
Peringatan
Hanya konfigurasikan IFilterFactory.IsReusable untuk mengembalikan true
jika sumber filter tidak ambigu, filter bersifat stateless, dan filter aman digunakan di berbagai permintaan HTTP. Misalnya, jangan mengembalikan filter dari DI yang terdaftar sebagai tercakup atau sementara jika IFilterFactory.IsReusable
mengembalikan true
.
IFilterFactory
dapat diimplementasikan menggunakan implementasi atribut kustom sebagai pendekatan lain untuk membuat filter:
public class ResponseHeaderFilterFactory : Attribute, IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) =>
new InternalResponseHeaderFilter();
private class InternalResponseHeaderFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context) =>
context.HttpContext.Response.Headers.Add(
nameof(OnActionExecuting), nameof(InternalResponseHeaderFilter));
public void OnActionExecuted(ActionExecutedContext context) { }
}
Filter diterapkan dalam kode berikut:
[ResponseHeaderFilterFactory]
public IActionResult Index() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(Index)}");
IFilterFactory diimplementasikan pada atribut
Filter yang mengimplementasikan IFilterFactory
berguna untuk filter yang:
- Tidak memerlukan parameter passing.
- Memiliki dependensi konstruktor yang perlu diisi oleh DI.
TypeFilterAttribute menerapkan IFilterFactory.
IFilterFactory
mengekspos metode CreateInstance untuk membuat instans IFilterMetadata.
CreateInstance
memuat tipe yang ditentukan dari wadah layanan (DI).
public class SampleActionTypeFilterAttribute : TypeFilterAttribute
{
public SampleActionTypeFilterAttribute()
: base(typeof(InternalSampleActionFilter)) { }
private class InternalSampleActionFilter : IActionFilter
{
private readonly ILogger<InternalSampleActionFilter> _logger;
public InternalSampleActionFilter(ILogger<InternalSampleActionFilter> logger) =>
_logger = logger;
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation(
$"- {nameof(InternalSampleActionFilter)}.{nameof(OnActionExecuting)}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation(
$"- {nameof(InternalSampleActionFilter)}.{nameof(OnActionExecuted)}");
}
}
}
Kode berikut menunjukkan tiga pendekatan untuk menerapkan filter:
[SampleActionTypeFilter]
public IActionResult WithDirectAttribute() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(WithDirectAttribute)}");
[TypeFilter(typeof(SampleActionTypeFilterAttribute))]
public IActionResult WithTypeFilterAttribute() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(WithTypeFilterAttribute)}");
[ServiceFilter(typeof(SampleActionTypeFilterAttribute))]
public IActionResult WithServiceFilterAttribute() =>
Content($"- {nameof(FilterFactoryController)}.{nameof(WithServiceFilterAttribute)}");
Dalam kode sebelumnya, pendekatan pertama untuk menerapkan filter lebih disukai.
Gunakan middleware dalam alur filter
Filter sumber daya berfungsi seperti middleware karena mereka mengelilingi eksekusi semua yang muncul nanti dalam alur. Tetapi filter berbeda dari middleware karena mereka adalah bagian dari runtime, yang berarti bahwa mereka memiliki akses ke konteks dan konstruksi.
Untuk menggunakan middleware sebagai filter, buat tipe dengan metode Configure
yang menentukan middleware untuk dimasukkan ke dalam rangkaian filter. Contoh berikut menggunakan middleware untuk mengatur header respons:
public class FilterMiddlewarePipeline
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Pipeline", "Middleware");
await next();
});
}
}
MiddlewareFilterAttribute Gunakan untuk menjalankan middleware:
[MiddlewareFilter(typeof(FilterMiddlewarePipeline))]
public class FilterMiddlewareController : Controller
{
public IActionResult Index() =>
Content($"- {nameof(FilterMiddlewareController)}.{nameof(Index)}");
}
Filter middleware berjalan pada tahap alur filter yang sama dengan filter Sumber Daya, sebelum pengikatan model dan setelah alur lainnya.
Keamanan Thread
Saat meneruskan instans dari filter ke Add
, bukan ke Type
, filter tersebut menjadi singleton dan tidak aman dalam konteks multi-utas.
Sumber Daya Tambahan:
Oleh Kirk Larkin, Rick Anderson, Tom Dykstra, dan Steve Smith
Filter di ASP.NET Core memungkinkan kode dijalankan sebelum atau sesudah tahap tertentu dalam alur pemrosesan permintaan.
Filter bawaan menangani tugas seperti:
- Otorisasi, mencegah akses ke sumber daya yang tidak diotorisasi pengguna.
- Penembolokan respons, memotong jalur permintaan untuk mengembalikan respons yang telah di-cache.
Filter kustom dapat dibuat untuk menangani kekhawatiran lintas fungsi. Contoh concern lintas proses termasuk penanganan kesalahan, penyimpanan sementara, konfigurasi, otorisasi, dan pencatatan. Filter menghindari kode duplikat. Misalnya, filter pengecualian penanganan kesalahan dapat mengonsolidasikan penanganan kesalahan.
Dokumen ini berlaku untuk Razor Halaman, pengontrol API, dan pengontrol dengan tampilan. Filter tidak berfungsi langsung dengan Razor komponen. Filter hanya dapat secara tidak langsung memengaruhi komponen saat:
- Komponen disematkan dalam halaman atau tampilan.
- Halaman, pengontrol, dan tampilan menggunakan filter.
Lihat atau unduh sampel (cara mengunduh).
Cara kerja filter
Filter berjalan dalam jalur pemanggilan aksi ASP.NET Core, kadang-kadang disebut juga sebagai jalur filter. Alur filter berjalan setelah ASP.NET Core memilih tindakan yang akan dijalankan.
Jenis filter
Setiap jenis filter dijalankan pada tahap yang berbeda dalam alur filter:
Filter otorisasi berjalan terlebih dahulu dan digunakan untuk menentukan apakah pengguna berwenang untuk permintaan tersebut. Filter otorisasi menghentikan alur proses jika permintaan tidak diizinkan.
-
- Jalankan setelah otorisasi.
-
OnResourceExecuting menjalankan kode sebelum alur pemrosesan filter lainnya mulai. Misalnya,
OnResourceExecuting
menjalankan kode sebelum pengikatan model. - OnResourceExecuted menjalankan program setelah tahap lain dari alur selesai.
-
- Jalankan kode segera sebelum dan sesudah metode tindakan dipanggil.
- Dapat mengubah argumen yang diteruskan ke tindakan.
- Dapat mengubah hasil yang dihasilkan oleh tindakan.
- Tidak didukung di Razor Halaman.
Filter pengecualian menerapkan kebijakan global pada pengecualian yang tidak tertangani yang terjadi sebelum isi tanggapan ditulis.
Filter hasil menjalankan kode segera sebelum dan sesudah eksekusi hasil tindakan. Proses ini hanya dijalankan ketika metode tindakan berhasil dieksekusi. Ini berguna untuk logika yang harus mendukung tampilan atau pemrosesan format.
Diagram berikut menunjukkan bagaimana jenis filter berinteraksi dalam alur filter.
implementasi
Filter mendukung implementasi sinkron dan asinkron melalui definisi antarmuka yang berbeda.
Filter sinkron menjalankan kode sebelum dan sesudah tahap jalur pemrosesan mereka. Misalnya, OnActionExecuting dipanggil sebelum metode tindakan dipanggil. OnActionExecuted dipanggil setelah metode aksi mengembalikan hasil.
public class MySampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
}
Dalam kode sebelumnya, MyDebug adalah fungsi utilitas dalam unduhan sampel.
Filter asinkron mendefinisikan metode On-Stage-ExecutionAsync
. Misalnya, OnActionExecutionAsync:
public class SampleAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
// Do something before the action executes.
// next() calls the action method.
var resultContext = await next();
// resultContext.Result is set.
// Do something after the action executes.
}
}
Dalam kode sebelumnya, SampleAsyncActionFilter
memiliki ActionExecutionDelegate (next
) yang menjalankan metode tindakan.
Beberapa tahap filter
Antarmuka untuk beberapa tahap filter dapat diimplementasikan dalam satu kelas. Misalnya, ActionFilterAttribute kelas mengimplementasikan:
- Sinkron: IActionFilter dan IResultFilter
- Asinkron: IAsyncActionFilter dan IAsyncResultFilter
- IOrderedFilter
Terapkan versi sinkron atau asinkron dari antarmuka filter, bukan keduanya. Runtime memeriksa terlebih dahulu untuk melihat apakah filter mengimplementasikan antarmuka asinkron, dan jika demikian, filter memanggilnya. Jika tidak, ini memanggil metode antarmuka sinkron. Jika antarmuka asinkron dan sinkron diimplementasikan dalam satu kelas, hanya metode asinkron yang dipanggil. Saat menggunakan kelas abstrak seperti ActionFilterAttribute, hanya ambil alih metode sinkron atau metode asinkron untuk setiap jenis filter.
Atribut filter bawaan
ASP.NET Core mencakup filter berbasis atribut bawaan yang dapat disubkelas dan disesuaikan. Misalnya, filter hasil berikut menambahkan header ke respons:
public class AddHeaderAttribute : ResultFilterAttribute
{
private readonly string _name;
private readonly string _value;
public AddHeaderAttribute(string name, string value)
{
_name = name;
_value = value;
}
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add( _name, new string[] { _value });
base.OnResultExecuting(context);
}
}
Atribut memungkinkan filter untuk menerima argumen, seperti yang ditunjukkan dalam contoh sebelumnya. Terapkan AddHeaderAttribute
ke pengontrol atau metode tindakan dan tentukan nama serta nilai header HTTP.
[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
public IActionResult Index()
{
return Content("Examine the headers using the F12 developer tools.");
}
Gunakan alat seperti alat pengembang browser untuk memeriksa header. Di bawah Response Headers, author: Rick Anderson
ditampilkan.
Kode berikut mengimplementasikan ActionFilterAttribute
yang:
- Membaca judul dan nama dari sistem konfigurasi tersebut. Tidak seperti sampel sebelumnya, kode berikut tidak memerlukan parameter filter untuk ditambahkan ke kode.
- Menambahkan judul dan nama ke header respons.
public class MyActionFilterAttribute : ActionFilterAttribute
{
private readonly PositionOptions _settings;
public MyActionFilterAttribute(IOptions<PositionOptions> options)
{
_settings = options.Value;
Order = 1;
}
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(_settings.Title,
new string[] { _settings.Name });
base.OnResultExecuting(context);
}
}
Opsi konfigurasi disediakan dari sistem konfigurasi menggunakan pola pengaturan. Misalnya, dari appsettings.json
file:
{
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
StartUp.ConfigureServices
Dalam :
- Kelas
PositionOptions
ditambahkan ke kontainer layanan dengan"Position"
area konfigurasi. -
MyActionFilterAttribute
telah ditambahkan ke wadah layanan.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(
Configuration.GetSection("Position"));
services.AddScoped<MyActionFilterAttribute>();
services.AddControllersWithViews();
}
Kode berikut menunjukkan kelas PositionOptions
.
public class PositionOptions
{
public string Title { get; set; }
public string Name { get; set; }
}
Kode berikut menerapkan MyActionFilterAttribute
ke metode Index2
:
[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
public IActionResult Index()
{
return Content("Examine the headers using the F12 developer tools.");
}
[ServiceFilter(typeof(MyActionFilterAttribute))]
public IActionResult Index2()
{
return Content("Header values by configuration.");
}
Di bawah Respons Header, author: Rick Anderson
, dan Editor: Joe Smith
akan ditampilkan saat Sample/Index2
titik akhir dipanggil.
Kode berikut menerapkan MyActionFilterAttribute
dan AddHeaderAttribute
ke Halaman Razor.
[AddHeader("Author", "Rick Anderson")]
[ServiceFilter(typeof(MyActionFilterAttribute))]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Filter tidak dapat diterapkan ke metode handler halaman Razor. Mereka dapat diterapkan baik secara global maupun ke Model Halaman Razor.
Beberapa antarmuka filter memiliki atribut yang sesuai yang dapat digunakan sebagai kelas dasar untuk implementasi kustom.
Filter Atribut:
- ActionFilterAttribute
- ExceptionFilterAttribute
- ResultFilterAttribute
- FormatFilterAttribute
- ServiceFilterAttribute
- TypeFilterAttribute
Cakupan penyaringan dan urutan eksekusi
Filter dapat ditambahkan ke alur di salah satu dari tiga cakupan:
- Menggunakan atribut pada tindakan pengontrol. Atribut filter tidak dapat diterapkan ke Razor metode handler Pages.
- Menggunakan atribut pada pengontrol atau Razor Halaman.
- Secara global untuk semua pengontrol, tindakan, dan Razor Halaman seperti yang ditunjukkan dalam kode berikut:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(MySampleActionFilter));
});
}
Urutan eksekusi default
Ketika ada beberapa filter untuk tahap tertentu dari alur kerja, cakupan menentukan urutan default dari eksekusi filter. Filter global mengelilingi filter kelas, yang pada gilirannya mengelilingi filter metode.
Akibat dari penyaringan bersarang, kode setelah filter berjalan dalam urutan terbalik dari kode sebelum. Urutan filter:
- Kode filter global sebelumnya.
- Kode sebelum kontroler dan filter Razor Halaman.
- Kode sebelum filter metode tindakan.
- Kode setelah filter metode tindakan.
- Kode setelah pengontrol dan Razor filter Halaman.
- Kode sebelum kontroler dan filter Razor Halaman.
- Kode dari filter global setelah.
Contoh berikut ini menggambarkan urutan dimana metode filter dijalankan pada filter tindakan sinkron.
Urutan | Cakupan filter | Metode filter |
---|---|---|
1 | Mendunia | OnActionExecuting |
2 | Kontroler atau Razor Halaman | OnActionExecuting |
3 | Metode | OnActionExecuting |
4 | Metode | OnActionExecuted |
5 | Kontroler atau Razor Halaman | OnActionExecuted |
6 | Mendunia | OnActionExecuted |
Filter pada tingkat pengendali
Setiap pengontrol yang mewarisi dari kelas dasar Controller mencakup metode Controller.OnActionExecuting, Controller.OnActionExecutionAsync, dan Controller.OnActionExecutedOnActionExecuted
. Metode ini:
- Bungkus filter yang dijalankan untuk tindakan tertentu.
-
OnActionExecuting
dipanggil sebelum salah satu dari semua filter tindakan. -
OnActionExecuted
dipanggil setelah semua filter tindakan. -
OnActionExecutionAsync
dipanggil sebelum salah satu dari semua filter tindakan. Kode dalam filter setelahnext
berjalan setelah metode tindakan.
Misalnya, dalam sampel unduhan, MySampleActionFilter
diterapkan secara global saat memulai.
TestController
:
- Menerapkan
SampleActionFilterAttribute
([SampleActionFilter]
) pada tindakanFilterTest2
. - Mengambil alih
OnActionExecuting
danOnActionExecuted
.
public class TestController : Controller
{
[SampleActionFilter(Order = int.MinValue)]
public IActionResult FilterTest2()
{
return ControllerContext.MyDisplayRouteInfo();
}
public override void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
base.OnActionExecuted(context);
}
}
MyDisplayRouteInfo disediakan oleh paket Rick.Docs.Samples.RouteInfo NuGet dan menampilkan informasi rute.
Menavigasi ke https://localhost:5001/Test/FilterTest2
menjalankan kode berikut:
TestController.OnActionExecuting
MySampleActionFilter.OnActionExecuting
SampleActionFilterAttribute.OnActionExecuting
TestController.FilterTest2
SampleActionFilterAttribute.OnActionExecuted
MySampleActionFilter.OnActionExecuted
TestController.OnActionExecuted
Filter tingkat pengontrol mengatur properti Pesanan ke int.MinValue
. Filter tingkat pengontrol tidak dapat diatur untuk dijalankan setelah filter yang diterapkan pada metode. Pesanan dijelaskan di bagian berikutnya.
Untuk Razor Halaman, lihat Razor.
Mengesampingkan urutan default
Urutan default eksekusi dapat diganti dengan menerapkan IOrderedFilter.
IOrderedFilter
mengekspos properti Order yang lebih diutamakan daripada cakupan untuk menentukan urutan eksekusi. Filter dengan nilai yang lebih rendah Order
:
- Menjalankan kode sebelum yang dimiliki oleh filter dengan nilai yang lebih tinggi dari
Order
. - Menjalankan kode setelah kode dari filter dengan nilai yang lebih tinggi
Order
.
Properti Order
diatur dengan parameter konstruktor:
[SampleActionFilter(Order = int.MinValue)]
Pertimbangkan dua filter tindakan di pengontrol berikut:
[MyAction2Filter]
public class Test2Controller : Controller
{
public IActionResult FilterTest2()
{
return ControllerContext.MyDisplayRouteInfo();
}
public override void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
base.OnActionExecuted(context);
}
}
Filter global ditambahkan di StartUp.ConfigureServices
:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(MySampleActionFilter));
});
}
3 filter berjalan dalam urutan berikut:
Test2Controller.OnActionExecuting
MySampleActionFilter.OnActionExecuting
MyAction2FilterAttribute.OnActionExecuting
Test2Controller.FilterTest2
MyAction2FilterAttribute.OnResultExecuting
MySampleActionFilter.OnActionExecuted
Test2Controller.OnActionExecuted
Properti Order
mengambil alih cakupan saat menentukan urutan filter berjalan. Filter diurutkan terlebih dahulu menurut urutan, lalu cakupan digunakan untuk memutuskan ikatan. Semua filter bawaan mengimplementasikan IOrderedFilter
dan mengatur nilai default Order
ke 0. Seperti disebutkan sebelumnya, filter tingkat pengontrol menetapkan properti Pesanan ke int.MinValue
Untuk filter bawaan, cakupan yang menentukan pesanan kecuali Order
diatur ke nilai bukan nol.
Dalam kode sebelumnya, MySampleActionFilter
memiliki cakupan global sehingga berjalan sebelum MyAction2FilterAttribute
, yang memiliki cakupan pengontrol. Untuk menjalankan MyAction2FilterAttribute
terlebih dahulu, atur urutannya ke int.MinValue
:
[MyAction2Filter(int.MinValue)]
public class Test2Controller : Controller
{
public IActionResult FilterTest2()
{
return ControllerContext.MyDisplayRouteInfo();
}
public override void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), HttpContext.Request.Path);
base.OnActionExecuted(context);
}
}
Untuk membuat filter MySampleActionFilter
global berjalan terlebih dahulu, atur Order
ke int.MinValue
:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(MySampleActionFilter),
int.MinValue);
});
}
Pembatalan dan Pemutusan Arus Pendek
Alur filter dapat diputus dengan mengatur properti Result pada parameter yang disediakan oleh ResourceExecutingContext untuk metode filter. Misalnya, filter Sumber Daya berikut mencegah sisa alur dieksekusi:
public class ShortCircuitingResourceFilterAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
context.Result = new ContentResult()
{
Content = "Resource unavailable - header not set."
};
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
Dalam kode berikut, baik filter ShortCircuitingResourceFilter
maupun AddHeader
menargetkan metode tindakan SomeResource
.
ShortCircuitingResourceFilter
:
- Berjalan terlebih dahulu, karena ini adalah Filter Sumber Daya dan
AddHeader
merupakan Filter Tindakan. - Menghentikan sisa proses.
Oleh karena itu, filter AddHeader
tidak pernah berjalan untuk tindakan SomeResource
. Perilaku ini akan sama jika kedua filter diterapkan pada tingkat metode tindakan, asalkan ShortCircuitingResourceFilter
dijalankan terlebih dahulu.
ShortCircuitingResourceFilter
berjalan dulu karena jenis filternya, atau dengan penggunaan properti Order
secara eksplisit.
[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
public IActionResult Index()
{
return Content("Examine the headers using the F12 developer tools.");
}
[ServiceFilter(typeof(MyActionFilterAttribute))]
public IActionResult Index2()
{
return Content("Header values by configuration.");
}
[ShortCircuitingResourceFilter]
public IActionResult SomeResource()
{
return Content("Successful access to resource - header is set.");
}
[AddHeaderWithFactory]
public IActionResult HeaderWithFactory()
{
return Content("Examine the headers using the F12 developer tools.");
}
}
Injeksi dependensi
Filter dapat ditambahkan berdasarkan jenis atau berdasarkan instans. Jika instans ditambahkan, instans tersebut digunakan untuk setiap permintaan. Jika sebuah tipe ditambahkan, maka tipe tersebut akan diaktifkan. Filter yang diaktifkan berdasarkan jenis berarti:
- Instans dibuat untuk setiap permintaan.
- Setiap dependensi konstruktor diisi oleh injeksi dependensi (DI).
Filter yang diimplementasikan sebagai atribut dan ditambahkan langsung ke kelas pengontrol atau metode tindakan tidak dapat memiliki dependensi konstruktor yang disediakan oleh injeksi dependensi (DI). Dependensi konstruktor tidak dapat disediakan oleh DI karena:
- Atribut harus memiliki parameter konstruktor yang disediakan tempat parameter tersebut diterapkan.
- Ini adalah batasan cara kerja atribut.
Filter berikut mendukung dependensi konstruktor yang disediakan dari DI:
- ServiceFilterAttribute
- TypeFilterAttribute
- IFilterFactory diimplementasikan pada atribut .
Filter sebelumnya dapat diterapkan ke pengontrol atau metode tindakan:
Perekam tersedia dari DI. Namun, hindari membuat dan menggunakan filter murni untuk tujuan pengelogan. Pencatatan kerangka kerja bawaan biasanya menyediakan apa yang diperlukan untuk pencatatan. Pencatatan ditambahkan ke dalam filter:
- Harus fokus pada isu atau perilaku domain bisnis yang khusus untuk filter.
- Tidak boleh mencatat tindakan atau peristiwa kerangka kerja lainnya. Filter bawaan memfilter tindakan log dan peristiwa kerangka kerja.
Atribut Penyaring Layanan
Jenis implementasi filter layanan terdaftar di ConfigureServices
. Mengambil ServiceFilterAttribute instans filter dari DI.
Kode berikut menunjukkan AddHeaderResultServiceFilter
:
public class AddHeaderResultServiceFilter : IResultFilter
{
private ILogger _logger;
public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
}
public void OnResultExecuting(ResultExecutingContext context)
{
var headerName = "OnResultExecuting";
context.HttpContext.Response.Headers.Add(
headerName, new string[] { "ResultExecutingSuccessfully" });
_logger.LogInformation("Header added: {HeaderName}", headerName);
}
public void OnResultExecuted(ResultExecutedContext context)
{
// Can't add to headers here because response has started.
_logger.LogInformation("AddHeaderResultServiceFilter.OnResultExecuted");
}
}
Dalam kode berikut, AddHeaderResultServiceFilter
ditambahkan ke kontainer DI:
public void ConfigureServices(IServiceCollection services)
{
// Add service filters.
services.AddScoped<AddHeaderResultServiceFilter>();
services.AddScoped<SampleActionFilterAttribute>();
services.AddControllersWithViews(options =>
{
options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader",
"Result filter added to MvcOptions.Filters")); // An instance
options.Filters.Add(typeof(MySampleActionFilter)); // By type
options.Filters.Add(new SampleGlobalActionFilter()); // An instance
});
}
Dalam kode berikut, atribut ServiceFilter
mengambil contoh filter AddHeaderResultServiceFilter
dari DI.
[ServiceFilter(typeof(AddHeaderResultServiceFilter))]
public IActionResult Index()
{
return View();
}
Saat menggunakan ServiceFilterAttribute
, menyetel ServiceFilterAttribute.IsReusable:
Memberikan indikasi bahwa instans filter dapat digunakan kembali di luar cakupan permintaan tempat pembuatannya. ASP.NET Core runtime tidak menjamin:
- Bahwa satu instans filter akan dibuat.
- Filter tidak akan diminta kembali dari kontainer DI di beberapa titik kemudian.
Tidak boleh digunakan dengan filter yang bergantung pada layanan dengan masa pakai selain singleton.
ServiceFilterAttribute menerapkan IFilterFactory.
IFilterFactory
mengekspos metode CreateInstance untuk membuat instans IFilterMetadata.
CreateInstance
memuat tipe yang ditentukan dari DI.
TypeFilterAttribute
TypeFilterAttribute mirip dengan ServiceFilterAttribute, tetapi tipe TypeFilterAttribute tidak diambil langsung dari kontainer DI. Ini menginstansiasi jenis dengan menggunakan Microsoft.Extensions.DependencyInjection.ObjectFactory.
Karena TypeFilterAttribute
jenis tidak diselesaikan langsung dari kontainer DI:
- Jenis yang direferensikan menggunakan
TypeFilterAttribute
tidak perlu didaftarkan dengan kontainer DI. Mereka memang memiliki dependensi yang dipenuhi oleh kontainer DI. -
TypeFilterAttribute
dapat secara opsional menerima argumen konstruktor untuk jenis tersebut.
Saat menggunakan TypeFilterAttribute
, menyetel TypeFilterAttribute.IsReusable:
Memberikan indikasi bahwa instans filter dapat digunakan kembali di luar cakupan permintaan asal pembuatannya. Runtime ASP.NET Core tidak memberikan jaminan bahwa satu instans filter akan dibuat.
Tidak boleh digunakan dengan filter yang bergantung pada layanan dengan masa pakai selain singleton.
Contoh berikut menunjukkan cara meneruskan argumen ke jenis menggunakan TypeFilterAttribute
:
[TypeFilter(typeof(LogConstantFilter),
Arguments = new object[] { "Method 'Hi' called" })]
public IActionResult Hi(string name)
{
return Content($"Hi {name}");
}
Filter otorisasi
Filter otorisasi:
- Apakah filter pertama dijalankan di alur filter.
- Mengontrol akses ke metode tindakan.
- Memiliki metode 'before', tetapi tidak memiliki metode 'after'.
Filter otorisasi kustom memerlukan kerangka kerja otorisasi kustom. Lebih suka mengonfigurasi kebijakan otorisasi atau menulis kebijakan otorisasi kustom daripada menulis filter kustom. Filter otorisasi bawaan:
- Memanggil sistem otorisasi.
- Tidak mengotorisasi permintaan.
Jangan melempar pengecualian dalam filter otorisasi.
- Pengecualian tidak akan ditangani.
- Filter pengecualian tidak akan menangani pengecualian.
Pertimbangkan untuk mengeluarkan tantangan saat pengecualian terjadi di filter otorisasi.
Pelajari selengkapnya tentang Otorisasi.
Filter sumber daya
Filter sumber daya:
- Terapkan IResourceFilter antarmuka atau IAsyncResourceFilter .
- Proses mencakup sebagian besar alur pipa filter.
- Hanya Filter Otorisasi yang berjalan sebelum filter sumber daya.
Pemfilteran sumber daya berguna untuk memotong sebagian besar alur. Misalnya, filter penyimpanan sementara dapat menghindari sisa proses saat terjadi hit cache.
Contoh filter sumber daya:
Filter sumber daya pendek sirkuit yang ditunjukkan sebelumnya.
DisableFormValueModelBindingAttribute:
- Mencegah pengikatan pada model untuk mengakses data formulir.
- Digunakan untuk unggahan file besar untuk mencegah data formulir dibaca ke dalam memori.
Penyaring Tindakan
Filter tindakan tidak berlaku untuk Razor Halaman. Razor Pages mendukung IPageFilter dan IAsyncPageFilter. Untuk informasi selengkapnya, lihat Metode filter untuk Razor Halaman.
Filter tindakan:
- Terapkan IActionFilter antarmuka atau IAsyncActionFilter .
- Pelaksanaan mereka berhubungan dengan eksekusi metode aksi.
Kode berikut menunjukkan filter tindakan sampel:
public class MySampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
}
ActionExecutingContext menyediakan properti berikut:
- ActionArguments - memungkinkan untuk membaca masukan ke dalam metode tindakan.
- Controller - memungkinkan memanipulasi instans pengontrol.
-
Result - mengatur
Result
eksekusi sirkuit pendek dari metode tindakan dan filter tindakan berikutnya.
Melemparkan pengecualian dalam metode tindakan:
- Mencegah penerapan filter berikutnya.
- Tidak seperti pengaturan
Result
, ini diperlakukan sebagai kegagalan, bukan hasil sukses.
menyediakan ActionExecutedContextController
dan Result
ditambah properti berikut:
Canceled - Bernilai benar jika eksekusi tindakan dihentikan oleh filter lain.
Exception - Non-null jika tindakan atau filter tindakan yang dijalankan sebelumnya menghasilkan pengecualian. Mengatur properti ini ke null:
- Menangani pengecualian secara efektif.
-
Result
dijalankan seolah-olah dikembalikan dari metode tindakan.
Untuk IAsyncActionFilter
, panggilan ke ActionExecutionDelegate:
- Menjalankan filter tindakan berikutnya dan metode tindakan.
- Menampilkan
ActionExecutedContext
.
Untuk memutus rangkaian, tetapkan Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.Result ke instance hasil dan jangan panggil next
(ActionExecutionDelegate
).
Kerangka kerja menyediakan abstrak ActionFilterAttribute yang dapat disubkelas.
OnActionExecuting
Filter tindakan dapat digunakan untuk:
- Validasi status model.
- Mengembalikan kesalahan jika status tidak valid.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext
context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(
context.ModelState);
}
}
Catatan
Pengontrol yang dianotasi dengan [ApiController]
atribut secara otomatis memvalidasi status model dan mengembalikan respons 400. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.
Metode OnActionExecuted
dijalankan setelah metode aksi:
Dan dapat melihat dan memanipulasi hasil tindakan melalui Result properti .
Canceled diatur ke true jika eksekusi tindakan dibatalkan oleh filter lain.
Exception diatur ke nilai non-null jika tindakan atau filter tindakan berikutnya melemparkan pengecualian. Pengaturan
Exception
ke null:- Menangani pengecualian secara efektif.
-
ActionExecutedContext.Result
dijalankan seolah-olah hasilnya dikembalikan secara normal dari metode tersebut.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext
context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(
context.ModelState);
}
}
public override void OnActionExecuted(ActionExecutedContext
context)
{
var result = context.Result;
// Do something with Result.
if (context.Canceled == true)
{
// Action execution was short-circuited by another filter.
}
if(context.Exception != null)
{
// Exception thrown by action or action filter.
// Set to null to handle the exception.
context.Exception = null;
}
base.OnActionExecuted(context);
}
}
Filter pengecualian
Filter pengecualian:
- Terapkan IExceptionFilter atau IAsyncExceptionFilter.
- Dapat digunakan untuk menerapkan kebijakan penanganan kesalahan umum.
Filter pengecualian sampel berikut menggunakan tampilan kesalahan kustom untuk menampilkan detail tentang pengecualian yang terjadi saat aplikasi sedang dalam pengembangan:
public class CustomExceptionFilter : IExceptionFilter
{
private readonly IWebHostEnvironment _hostingEnvironment;
private readonly IModelMetadataProvider _modelMetadataProvider;
public CustomExceptionFilter(
IWebHostEnvironment hostingEnvironment,
IModelMetadataProvider modelMetadataProvider)
{
_hostingEnvironment = hostingEnvironment;
_modelMetadataProvider = modelMetadataProvider;
}
public void OnException(ExceptionContext context)
{
if (!_hostingEnvironment.IsDevelopment())
{
return;
}
var result = new ViewResult {ViewName = "CustomError"};
result.ViewData = new ViewDataDictionary(_modelMetadataProvider,
context.ModelState);
result.ViewData.Add("Exception", context.Exception);
// TODO: Pass additional detailed data via ViewData
context.Result = result;
}
}
Kode berikut menguji filter pengecualian:
[TypeFilter(typeof(CustomExceptionFilter))]
public class FailingController : Controller
{
[AddHeader("Failing Controller",
"Won't appear when exception is handled")]
public IActionResult Index()
{
throw new Exception("Testing custom exception filter.");
}
}
Filter pengecualian:
- Tidak memiliki peristiwa sebelum dan sesudah.
- Terapkan OnException atau OnExceptionAsync.
- Tangani pengecualian tidak tertangani yang terjadi saat pembuatan Razor halaman atau pengontrol, pengikatan model, filter tindakan, atau metode tindakan.
- Jangan menangkap pengecualian yang terjadi pada filter sumber daya, filter hasil, atau eksekusi hasil MVC.
Untuk menangani pengecualian, atur properti ExceptionHandled ke true
atau tetapkan nilai properti Result. Ini menghentikan penyebaran pengecualian. Filter pengecualian tidak dapat mengubah pengecualian menjadi "sukses". Hanya filter tindakan yang dapat melakukannya.
Filter pengecualian:
- Baik untuk menangkap pengecualian yang terjadi dalam aksi.
- Tidak fleksibel seperti middleware penanganan kesalahan.
Lebih suka middleware untuk penanganan pengecualian. Gunakan filter pengecualian hanya di mana penanganan kesalahan berbeda berdasarkan metode tindakan mana yang dipanggil. Misalnya, aplikasi mungkin memiliki metode tindakan untuk titik akhir API dan untuk tampilan/HTML. Titik akhir API dapat mengembalikan informasi kesalahan sebagai JSON, sementara tindakan berbasis tampilan dapat mengembalikan halaman kesalahan sebagai HTML.
Filter hasil
Filter hasil:
- Menerapkan antarmuka:
- Pelaksanaan mereka berkaitan dengan hasil dari tindakan tersebut.
IResultFilter dan IAsyncResultFilter
Kode berikut menunjukkan filter hasil yang menambahkan header HTTP:
public class AddHeaderResultServiceFilter : IResultFilter
{
private ILogger _logger;
public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
}
public void OnResultExecuting(ResultExecutingContext context)
{
var headerName = "OnResultExecuting";
context.HttpContext.Response.Headers.Add(
headerName, new string[] { "ResultExecutingSuccessfully" });
_logger.LogInformation("Header added: {HeaderName}", headerName);
}
public void OnResultExecuted(ResultExecutedContext context)
{
// Can't add to headers here because response has started.
_logger.LogInformation("AddHeaderResultServiceFilter.OnResultExecuted");
}
}
Hasil yang dihasilkan tergantung pada jenis tindakan. Tindakan yang mengembalikan tampilan mencakup semua pemrosesan pisau cukur sebagai bagian dari ViewResult yang dijalankan. Metode API mungkin melakukan beberapa serialisasi sebagai bagian dari eksekusi hasilnya. Pelajari selengkapnya tentang hasil tindakan.
Filter hasil tindakan hanya dijalankan ketika tindakan atau filter tindakan menghasilkan hasil tindakan. Filter hasil tidak dijalankan ketika:
- Filter otorisasi atau filter sumber daya memotong alur proses.
- Filter pengecualian menangani pengecualian dengan menghasilkan hasil tindakan.
Metode Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuting dapat menghentikan eksekusi lebih awal dari hasil tindakan dan filter hasil berikutnya dengan mengatur Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext.Cancel ke true
. Tulis ke objek respons saat sirkuit pendek untuk menghindari menghasilkan respons kosong. Melemparkan pengecualian di IResultFilter.OnResultExecuting
:
- Mencegah eksekusi hasil tindakan dan filter berikutnya.
- Diperlakukan sebagai kegagalan alih-alih hasil yang berhasil.
Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuted Ketika metode berjalan, respons mungkin sudah dikirim ke klien. Jika respons telah dikirim ke klien, respons tidak dapat diubah.
ResultExecutedContext.Canceled
diatur menjadi true
jika eksekusi hasil aksi dihentikan oleh filter lain.
ResultExecutedContext.Exception
disetel ke dalam nilai non-null jika hasil tindakan atau filter hasil berikutnya memunculkan pengecualian. Pengaturan Exception
ke null secara efektif menangani pengecualian dan mencegah pengecualian dilemparkan lagi nanti di alur. Tidak ada cara yang dapat diandalkan untuk menulis data ke respons saat menangani pengecualian dalam filter hasil. Jika header sudah dikirim ke klien ketika hasil tindakan menghasilkan pengecualian, tidak ada mekanisme yang dapat diandalkan untuk mengirimkan kode kegagalan.
Untuk IAsyncResultFilter, pemanggilan await next
pada ResultExecutionDelegate menjalankan penyaring hasil berikutnya dan hasil tindakan. Untuk sirkuit pendek, atur ResultExecutingContext.Cancel ke true
dan jangan panggil ResultExecutionDelegate
:
public class MyAsyncResponseFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context,
ResultExecutionDelegate next)
{
if (!(context.Result is EmptyResult))
{
await next();
}
else
{
context.Cancel = true;
}
}
}
Kerangka kerja menyediakan abstrak ResultFilterAttribute
yang dapat disubkelas. Kelas AddHeaderAttribute yang ditampilkan sebelumnya adalah contoh atribut filter hasil.
IAlwaysRunResultFilter dan IAsyncAlwaysRunResultFilter
Antarmuka IAlwaysRunResultFilter dan IAsyncAlwaysRunResultFilter mendeklarasikan IResultFilter implementasi yang berjalan untuk semua hasil tindakan. Ini termasuk hasil tindakan yang dihasilkan oleh:
- Filter otorisasi dan filter sumber daya yang menghentikan proses di tengah jalan.
- Filter pengecualian.
Misalnya, filter berikut selalu menjalankan dan menetapkan hasil tindakan (ObjectResult) dengan kode status Entitas Tidak Dapat Diproses 422 saat negosiasi konten gagal:
public class UnprocessableResultFilter : Attribute, IAlwaysRunResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is StatusCodeResult statusCodeResult &&
statusCodeResult.StatusCode == (int) HttpStatusCode.UnsupportedMediaType)
{
context.Result = new ObjectResult("Can't process this!")
{
StatusCode = (int) HttpStatusCode.UnsupportedMediaType,
};
}
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
IFilterFactory
IFilterFactory menerapkan IFilterMetadata. Oleh karena itu, IFilterFactory
instans dapat digunakan sebagai IFilterMetadata
instans di mana saja dalam alur filter. Ketika runtime bersiap untuk memanggil filter, runtime berusaha mengonversinya ke IFilterFactory
. Jika transmisi tersebut berhasil, CreateInstance metode dipanggil untuk membuat IFilterMetadata
instans yang dipanggil. Ini menyediakan desain yang fleksibel, karena alur filter yang tepat tidak perlu diatur secara eksplisit saat aplikasi dimulai.
IFilterFactory.IsReusable
:
- Adalah petunjuk dari fabrik bahwa instance filter yang dibuat oleh fabrik dapat digunakan kembali di luar lingkup permintaan tempat instance tersebut dibuat.
- Jangan digunakan dengan filter yang bergantung pada layanan dengan masa pakai yang berbeda dari singleton.
ASP.NET Core runtime tidak menjamin:
- Bahwa satu instans filter akan dibuat.
- Filter tidak akan diminta kembali dari kontainer DI di beberapa titik kemudian.
Peringatan
Hanya konfigurasikan IFilterFactory.IsReusable untuk mengembalikan true
jika sumber filter tidak ambigu, filter bersifat stateless, dan filter aman digunakan di berbagai permintaan HTTP. Misalnya, jangan mengembalikan filter dari DI yang terdaftar sebagai tercakup atau sementara jika IFilterFactory.IsReusable
mengembalikan true
.
IFilterFactory
dapat diimplementasikan menggunakan implementasi atribut kustom sebagai pendekatan lain untuk membuat filter:
public class AddHeaderWithFactoryAttribute : Attribute, IFilterFactory
{
// Implement IFilterFactory
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return new InternalAddHeaderFilter();
}
private class InternalAddHeaderFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(
"Internal", new string[] { "My header" });
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Filter diterapkan dalam kode berikut:
[AddHeader("Author", "Rick Anderson")]
public class SampleController : Controller
{
public IActionResult Index()
{
return Content("Examine the headers using the F12 developer tools.");
}
[ServiceFilter(typeof(MyActionFilterAttribute))]
public IActionResult Index2()
{
return Content("Header values by configuration.");
}
[ShortCircuitingResourceFilter]
public IActionResult SomeResource()
{
return Content("Successful access to resource - header is set.");
}
[AddHeaderWithFactory]
public IActionResult HeaderWithFactory()
{
return Content("Examine the headers using the F12 developer tools.");
}
}
Uji kode sebelumnya dengan menjalankan sampel unduhan:
- Panggil alat pengembang F12.
- Akses
https://localhost:5001/Sample/HeaderWithFactory
.
Alat pengembang F12 menampilkan header respons berikut ini yang telah ditambahkan oleh kode sampel:
-
pengarang:
Rick Anderson
-
globaladdheader:
Result filter added to MvcOptions.Filters
-
intern:
My header
Kode sebelumnya membuat header internal:My header
respons.
IFilterFactory diimplementasikan pada atribut
Filter yang mengimplementasikan IFilterFactory
berguna untuk filter yang:
- Tidak memerlukan parameter passing.
- Memiliki dependensi konstruktor yang perlu diisi oleh DI.
TypeFilterAttribute menerapkan IFilterFactory.
IFilterFactory
mengekspos metode CreateInstance untuk membuat instans IFilterMetadata.
CreateInstance
memuat tipe yang ditentukan dari wadah layanan (DI).
public class SampleActionFilterAttribute : TypeFilterAttribute
{
public SampleActionFilterAttribute()
:base(typeof(SampleActionFilterImpl))
{
}
private class SampleActionFilterImpl : IActionFilter
{
private readonly ILogger _logger;
public SampleActionFilterImpl(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation("SampleActionFilterAttribute.OnActionExecuting");
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation("SampleActionFilterAttribute.OnActionExecuted");
}
}
}
Kode berikut menunjukkan tiga pendekatan untuk menerapkan [SampleActionFilter]
:
[SampleActionFilter]
public IActionResult FilterTest()
{
return Content("From FilterTest");
}
[TypeFilter(typeof(SampleActionFilterAttribute))]
public IActionResult TypeFilterTest()
{
return Content("From TypeFilterTest");
}
// ServiceFilter must be registered in ConfigureServices or
// System.InvalidOperationException: No service for type '<filter>'
// has been registered. Is thrown.
[ServiceFilter(typeof(SampleActionFilterAttribute))]
public IActionResult ServiceFilterTest()
{
return Content("From ServiceFilterTest");
}
Dalam kode sebelumnya, mendekorasi metode dengan [SampleActionFilter]
adalah pendekatan yang disukai untuk menerapkan SampleActionFilter
.
Menggunakan middleware pada jalur filter
Filter sumber daya berfungsi seperti middleware karena mereka mengelilingi eksekusi semua yang muncul nanti dalam alur. Tetapi filter berbeda dari middleware karena mereka adalah bagian dari runtime, yang berarti bahwa mereka memiliki akses ke konteks dan konstruksi.
Untuk menggunakan middleware sebagai filter, buat tipe dengan metode Configure
yang menentukan middleware untuk dimasukkan ke dalam rangkaian filter. Contoh berikut menggunakan middleware pelokalan untuk membangun budaya saat ini untuk permintaan:
public class LocalizationPipeline
{
public void Configure(IApplicationBuilder applicationBuilder)
{
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr")
};
var options = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(
culture: "en-US",
uiCulture: "en-US"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
options.RequestCultureProviders = new[]
{ new RouteDataRequestCultureProvider() {
Options = options } };
applicationBuilder.UseRequestLocalization(options);
}
}
MiddlewareFilterAttribute Gunakan untuk menjalankan middleware:
[Route("{culture}/[controller]/[action]")]
[MiddlewareFilter(typeof(LocalizationPipeline))]
public IActionResult CultureFromRouteData()
{
return Content(
$"CurrentCulture:{CultureInfo.CurrentCulture.Name},"
+ $"CurrentUICulture:{CultureInfo.CurrentUICulture.Name}");
}
Filter middleware berjalan pada tahap alur filter yang sama dengan filter Sumber Daya, sebelum pengikatan model dan setelah alur lainnya.
Keamanan Thread
Saat meneruskan instans dari filter ke Add
, bukan ke Type
, filter tersebut menjadi singleton dan tidak aman dalam konteks multi-utas.
Tindakan berikutnya
- Lihat Metode filter untuk Razor Pages.
- Untuk bereksperimen dengan filter, unduh, uji, dan ubah sampel GitHub.
ASP.NET Core