Menangani kesalahan di ASP.NET Core
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Oleh Tom Dykstra
Artikel ini membahas pendekatan umum untuk menangani kesalahan di aplikasi web ASP.NET Core. Lihat juga Menangani kesalahan di API web berbasis pengontrol inti ASP.NET dan Menangani kesalahan dalam API minimal.
Untuk Blazor panduan penanganan kesalahan, yang menambahkan atau menggantikan panduan dalam artikel ini, lihat Menangani kesalahan di aplikasi ASP.NET CoreBlazor.
Halaman pengecualian pengembang
Halaman Pengecualian Pengembang menampilkan informasi terperinci tentang pengecualian permintaan yang tidak tertangani. Ini menggunakan DeveloperExceptionPageMiddleware untuk menangkap pengecualian sinkron dan asinkron dari alur HTTP dan untuk menghasilkan respons kesalahan. Halaman pengecualian pengembang berjalan lebih awal di alur middleware, sehingga dapat menangkap pengecualian yang tidak tertangani yang dilemparkan dalam middleware yang mengikuti.
aplikasi ASP.NET Core mengaktifkan halaman pengecualian pengembang secara default saat keduanya:
- Berjalan di lingkungan Pengembangan.
- Aplikasi ini dibuat dengan templat saat ini, yaitu dengan menggunakan WebApplication.CreateBuilder.
Aplikasi yang dibuat menggunakan templat sebelumnya, yaitu, dengan menggunakan WebHost.CreateDefaultBuilder, dapat mengaktifkan halaman pengecualian pengembang dengan memanggil app.UseDeveloperExceptionPage
.
Peringatan
Jangan aktifkan Halaman Pengecualian Pengembang kecuali aplikasi berjalan di lingkungan Pengembangan. Jangan bagikan informasi pengecualian terperinci secara publik saat aplikasi berjalan dalam produksi. Untuk informasi selengkapnya tentang mengonfigurasi lingkungan, lihat Menggunakan beberapa lingkungan di ASP.NET Core.
Halaman Pengecualian Pengembang dapat menyertakan informasi berikut tentang pengecualian dan permintaan:
- Pelacakan tumpukan
- Parameter string kueri, jika ada
- Cookie, jika ada
- Header
- Metadata titik akhir, jika ada
Halaman Pengecualian Pengembang tidak dijamin untuk memberikan informasi apa pun. Gunakan Pengelogan untuk informasi kesalahan lengkap.
Gambar berikut menunjukkan contoh halaman pengecualian pengembang dengan animasi untuk memperlihatkan tab dan informasi yang ditampilkan:
Menanggapi permintaan dengan Accept: text/plain
header, Halaman Pengecualian Pengembang mengembalikan teks biasa alih-alih HTML. Contohnya:
Status: 500 Internal Server Error
Time: 9.39 msSize: 480 bytes
FormattedRawHeadersRequest
Body
text/plain; charset=utf-8, 480 bytes
System.InvalidOperationException: Sample Exception
at WebApplicationMinimal.Program.<>c.<Main>b__0_0() in C:\Source\WebApplicationMinimal\Program.cs:line 12
at lambda_method1(Closure, Object, HttpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: text/plain
Host: localhost:7267
traceparent: 00-0eab195ea19d07b90a46cd7d6bf2f
Halaman handler pengecualian
Untuk mengonfigurasi halaman penanganan kesalahan kustom untuk lingkungan Produksi, panggil UseExceptionHandler. Middleware penanganan pengecualian ini:
- Menangkap dan mencatat pengecualian yang tidak tertangani.
- Menjalankan kembali permintaan dalam alur alternatif menggunakan jalur yang ditunjukkan. Permintaan tidak dijalankan kembali jika respons telah dimulai. Kode yang dihasilkan templat menjalankan kembali permintaan menggunakan
/Error
jalur .
Peringatan
Jika alur alternatif melemparkan pengecualian sendiri, Exception Handling Middleware akan memunculkan kembali pengecualian asli.
Karena middleware ini dapat menjalankan kembali alur permintaan:
- Middleware perlu menangani reentrancy dengan permintaan yang sama. Ini biasanya berarti membersihkan status mereka setelah memanggil
_next
atau menyimpan cache pemrosesan mereka untukHttpContext
menghindari mengulanginya. Saat berhadapan dengan isi permintaan, ini berarti buffering atau penembolokan hasil seperti pembaca Formulir. - UseExceptionHandler(IApplicationBuilder, String) Untuk kelebihan beban yang digunakan dalam templat, hanya jalur permintaan yang dimodifikasi, dan data rute dibersihkan. Data permintaan seperti header, metode, dan item semuanya digunakan kembali apa adanya.
- Layanan terlingkup tetap sama.
Dalam contoh berikut, UseExceptionHandler menambahkan middleware penanganan pengecualian di lingkungan non-Pengembangan:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Razor Templat aplikasi Halaman menyediakan halaman Kesalahan (.cshtml
) dan PageModel kelas (ErrorModel
) di folder Halaman. Untuk aplikasi MVC, templat proyek menyertakan Error
metode tindakan dan tampilan Kesalahan untuk Home pengontrol.
Middleware penanganan pengecualian menjalankan kembali permintaan menggunakan metode HTTP asli . Jika titik akhir handler kesalahan dibatasi untuk sekumpulan metode HTTP tertentu, titik akhir hanya berjalan untuk metode HTTP tersebut. Misalnya, tindakan pengontrol MVC yang menggunakan [HttpGet]
atribut hanya berjalan untuk permintaan GET. Untuk memastikan bahwa semua permintaan mencapai halaman penanganan kesalahan kustom, jangan batasi ke sekumpulan metode HTTP tertentu.
Untuk menangani pengecualian secara berbeda berdasarkan metode HTTP asli:
- Untuk Razor Pages, buat beberapa metode handler. Misalnya, gunakan
OnGet
untuk menangani pengecualian GET dan gunakanOnPost
untuk menangani pengecualian POST. - Untuk MVC, terapkan atribut kata kerja HTTP ke beberapa tindakan. Misalnya, gunakan
[HttpGet]
untuk menangani pengecualian GET dan gunakan[HttpPost]
untuk menangani pengecualian POST.
Untuk mengizinkan pengguna yang tidak diaturentikasi untuk melihat halaman penanganan kesalahan kustom, pastikan pengguna tersebut mendukung akses anonim.
Mengakses pengecualian
Gunakan IExceptionHandlerPathFeature untuk mengakses pengecualian dan jalur permintaan asli dalam penangan kesalahan. Contoh berikut menggunakan IExceptionHandlerPathFeature
untuk mendapatkan informasi selengkapnya tentang pengecualian yang dilemparkan:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Penangan pengecualian lambda
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan sebelum mengembalikan respons.
Kode berikut menggunakan lambda untuk penanganan pengecualian:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Cara lain untuk menggunakan lambda adalah dengan mengatur kode status berdasarkan jenis pengecualian, seperti dalam contoh berikut:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseExceptionHandler(new ExceptionHandlerOptions
{
StatusCodeSelector = ex => ex is TimeoutException
? StatusCodes.Status503ServiceUnavailable
: StatusCodes.Status500InternalServerError
});
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
IExceptionHandler
IExceptionHandler adalah antarmuka yang memberi pengembang panggilan balik untuk menangani pengecualian yang diketahui di lokasi pusat.
IExceptionHandler
implementasi didaftarkan dengan memanggil IServiceCollection.AddExceptionHandler<T>
. Masa pakai IExceptionHandler
instans adalah singleton. Beberapa implementasi dapat ditambahkan, dan dipanggil dalam urutan terdaftar.
Jika handler pengecualian menangani permintaan, handler tersebut dapat kembali true
berhenti memproses. Jika pengecualian tidak ditangani oleh handler pengecualian apa pun, kontrol akan kembali ke perilaku dan opsi default dari middleware. Metrik dan log yang berbeda dipancarkan untuk pengecualian yang ditangani versus pengecualian yang tidak tertangani.
Contoh berikut menunjukkan IExceptionHandler
implementasi:
using Microsoft.AspNetCore.Diagnostics;
namespace ErrorHandlingSample
{
public class CustomExceptionHandler : IExceptionHandler
{
private readonly ILogger<CustomExceptionHandler> logger;
public CustomExceptionHandler(ILogger<CustomExceptionHandler> logger)
{
this.logger = logger;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
var exceptionMessage = exception.Message;
logger.LogError(
"Error Message: {exceptionMessage}, Time of occurrence {time}",
exceptionMessage, DateTime.UtcNow);
// Return false to continue with the default behavior
// - or - return true to signal that this exception is handled
return ValueTask.FromResult(false);
}
}
}
Contoh berikut menunjukkan cara mendaftarkan IExceptionHandler
implementasi untuk injeksi dependensi:
using ErrorHandlingSample;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// Remaining Program.cs code omitted for brevity
Saat kode sebelumnya berjalan di lingkungan Pengembangan:
- dipanggil
CustomExceptionHandler
terlebih dahulu untuk menangani pengecualian. - Setelah mencatat pengecualian,
TryHandleAsync
metode mengembalikanfalse
, sehingga halaman pengecualian pengembang ditampilkan.
Di lingkungan lain:
- dipanggil
CustomExceptionHandler
terlebih dahulu untuk menangani pengecualian. - Setelah mencatat pengecualian,
TryHandleAsync
metode mengembalikanfalse
, sehingga/Error
halaman ditampilkan.
GunakanStatusCodePages
Secara default, aplikasi ASP.NET Core tidak menyediakan halaman kode status untuk kode status kesalahan HTTP, seperti 404 - Tidak Ditemukan. Saat aplikasi menetapkan kode status kesalahan HTTP 400-599 yang tidak memiliki isi, aplikasi mengembalikan kode status dan isi respons kosong. Untuk mengaktifkan penangan teks-saja default untuk kode status kesalahan umum, panggil UseStatusCodePages di Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Panggil UseStatusCodePages
sebelum meminta penanganan middleware. Misalnya, panggil UseStatusCodePages
sebelum Middleware File Statis dan Middleware Titik Akhir.
Saat UseStatusCodePages
tidak digunakan, menavigasi ke URL tanpa titik akhir mengembalikan pesan kesalahan yang bergantung pada browser yang menunjukkan titik akhir tidak dapat ditemukan. Ketika UseStatusCodePages
dipanggil, browser mengembalikan respons berikut:
Status Code: 404; Not Found
UseStatusCodePages
biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
Catatan
Halaman kode status middleware tidak menangkap pengecualian. Untuk menyediakan halaman penanganan kesalahan kustom, gunakan halaman handler pengecualian.
GunakanStatusCodePages dengan string format
Untuk mengkustomisasi tipe konten respons dan teks, gunakan kelebihan beban UseStatusCodePages yang mengambil tipe konten dan format string:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Dalam kode sebelumnya, {0}
adalah tempat penampung untuk kode kesalahan.
UseStatusCodePages
dengan string format biasanya tidak digunakan dalam produksi karena menampilkan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePages dengan lambda
Untuk menentukan penanganan kesalahan kustom dan kode penulisan respons, gunakan kelebihan beban UseStatusCodePages yang mengambil ekspresi lambda:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
dengan lambda biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePagesWithRedirects
Metode UseStatusCodePagesWithRedirects ekstensi:
- Mengirim kode status 302 - Ditemukan ke klien.
- Mengalihkan klien ke titik akhir penanganan kesalahan yang disediakan dalam templat URL. Titik akhir penanganan kesalahan biasanya menampilkan informasi kesalahan dan mengembalikan HTTP 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Templat URL dapat menyertakan {0}
tempat penampung untuk kode status, seperti yang ditunjukkan dalam kode sebelumnya. Jika templat URL dimulai dengan ~
(tilde), ~
digantikan oleh aplikasi PathBase
. Saat menentukan titik akhir di aplikasi, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan saat aplikasi:
- Harus mengalihkan klien ke titik akhir yang berbeda, biasanya dalam kasus di mana aplikasi yang berbeda memproses kesalahan. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang dialihkan.
- Tidak boleh mempertahankan dan mengembalikan kode status asli dengan respons pengalihan awal.
GunakanStatusCodePagesWithReExecute
Metode UseStatusCodePagesWithReExecute ekstensi:
- Menghasilkan isi respons dengan mengeksekusi ulang alur permintaan menggunakan jalur alternatif.
- Tidak mengubah kode status sebelum atau sesudah mengeksekusi ulang alur.
Eksekusi alur baru dapat mengubah kode status respons, karena alur baru memiliki kontrol penuh atas kode status. Jika alur baru tidak mengubah kode status, kode status asli akan dikirim ke klien.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Jika titik akhir dalam aplikasi ditentukan, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan ketika aplikasi harus:
- Proses permintaan tanpa mengalihkan ke titik akhir yang berbeda. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang awalnya diminta.
- Pertahankan dan kembalikan kode status asli dengan respons.
Templat URL harus dimulai dengan /
dan dapat menyertakan tempat penampung {0}
untuk kode status. Untuk meneruskan kode status sebagai parameter string kueri, teruskan argumen kedua ke dalam UseStatusCodePagesWithReExecute
. Contohnya:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Titik akhir yang memproses kesalahan bisa mendapatkan URL asli yang menghasilkan kesalahan, seperti yang ditunjukkan dalam contoh berikut:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = $"{statusCodeReExecuteFeature.OriginalPathBase}"
+ $"{statusCodeReExecuteFeature.OriginalPath}"
+ $"{statusCodeReExecuteFeature.OriginalQueryString}";
}
}
}
Karena middleware ini dapat menjalankan kembali alur permintaan:
- Middleware perlu menangani reentrancy dengan permintaan yang sama. Ini biasanya berarti membersihkan status mereka setelah memanggil
_next
atau menyimpan cache pemrosesan mereka untukHttpContext
menghindari mengulanginya. Saat berhadapan dengan isi permintaan, ini berarti buffering atau penembolokan hasil seperti pembaca Formulir. - Layanan terlingkup tetap sama.
Menonaktifkan halaman kode status
Untuk menonaktifkan halaman kode status untuk pengontrol MVC atau metode tindakan, gunakan atribut [SkipStatusCodePages ].
Untuk menonaktifkan halaman kode status untuk permintaan tertentu dalam Razor metode handler Pages atau di pengontrol MVC, gunakan IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kode penanganan pengecualian
Kode dalam halaman penanganan pengecualian juga dapat melemparkan pengecualian. Halaman kesalahan produksi harus diuji secara menyeluruh dan berhati-hatilah untuk menghindari melempar pengecualian sendiri.
Header respons
Setelah header untuk respons dikirim:
- Aplikasi tidak dapat mengubah kode status respons.
- Halaman pengecualian atau handler apa pun tidak dapat dijalankan. Respons harus diselesaikan atau koneksi dibatalkan.
Penanganan pengecualian server
Selain logika penanganan pengecualian dalam aplikasi, implementasi server HTTP dapat menangani beberapa pengecualian. Jika server menangkap pengecualian sebelum header respons dikirim, server mengirim 500 - Internal Server Error
respons tanpa isi respons. Jika server menangkap pengecualian setelah header respons dikirim, server menutup koneksi. Permintaan yang tidak ditangani oleh aplikasi ditangani oleh server. Pengecualian apa pun yang terjadi ketika server menangani permintaan ditangani oleh penanganan pengecualian server. Halaman kesalahan kustom aplikasi, middleware penanganan pengecualian, dan filter tidak memengaruhi perilaku ini.
Penanganan pengecualian startup
Hanya lapisan hosting yang dapat menangani pengecualian yang terjadi selama startup aplikasi. Host dapat dikonfigurasi untuk menangkap kesalahan startup dan menangkap kesalahan terperinci.
Lapisan hosting dapat menampilkan halaman kesalahan untuk kesalahan startup yang diambil hanya jika kesalahan terjadi setelah alamat host/pengikatan port. Jika pengikatan gagal:
- Lapisan hosting mencatat pengecualian penting.
- Proses dotnet mengalami crash.
- Tidak ada halaman kesalahan yang ditampilkan ketika server HTTP adalah Kestrel.
Saat berjalan di IIS (atau Azure App Service) atau IIS Express, 502.5 - Kegagalan Proses dikembalikan oleh Modul Inti ASP.NET jika proses tidak dapat dimulai. Untuk informasi selengkapnya, lihat Memecahkan masalah ASP.NET Core di Azure App Service dan IIS.
Halaman kesalahan database
Filter AddDatabaseDeveloperPageExceptionFilter pengecualian halaman pengembang Database menangkap pengecualian terkait database yang dapat diselesaikan dengan menggunakan migrasi Entity Framework Core. Ketika pengecualian ini terjadi, respons HTML dihasilkan dengan detail kemungkinan tindakan untuk menyelesaikan masalah. Halaman ini hanya diaktifkan di lingkungan Pengembangan. Kode berikut menambahkan filter pengecualian halaman pengembang Database:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filter pengecualian
Di aplikasi MVC, filter pengecualian dapat dikonfigurasi secara global atau berdasarkan per pengontrol atau per tindakan. Di Razor aplikasi Pages, aplikasi tersebut dapat dikonfigurasi secara global atau per model halaman. Filter ini menangani pengecualian yang tidak tertangani yang terjadi selama eksekusi tindakan pengontrol atau filter lain. Untuk informasi selengkapnya, lihat Filter di ASP.NET Core.
Filter pengecualian berguna untuk menjebak pengecualian yang terjadi dalam tindakan MVC, tetapi tidak fleksibel seperti middleware penanganan pengecualian bawaan, UseExceptionHandler. Sebaiknya gunakan UseExceptionHandler
, kecuali Anda perlu melakukan penanganan kesalahan secara berbeda berdasarkan tindakan MVC mana yang dipilih.
Kesalahan status model
Untuk informasi tentang cara menangani kesalahan status model, lihat Pengikatan model dan Validasi model.
Detail masalah
Detail Masalah bukan satu-satunya format respons untuk menjelaskan kesalahan API HTTP, namun, biasanya digunakan untuk melaporkan kesalahan untuk API HTTP.
Layanan detail masalah mengimplementasikan IProblemDetailsService antarmuka, yang mendukung pembuatan detail masalah di ASP.NET Core. Metode AddProblemDetails(IServiceCollection) ekstensi pada IServiceCollection mendaftarkan implementasi default IProblemDetailsService
.
Di aplikasi ASP.NET Core, middleware berikut menghasilkan respons HTTP detail masalah saat AddProblemDetails
dipanggil, kecuali ketika Accept
header HTTP permintaan tidak menyertakan salah satu jenis konten yang didukung oleh yang terdaftar IProblemDetailsWriter (default: application/json
):
- ExceptionHandlerMiddleware: Menghasilkan respons detail masalah saat handler kustom tidak ditentukan.
- StatusCodePagesMiddleware: Menghasilkan respons detail masalah secara default.
- DeveloperExceptionPageMiddleware: Menghasilkan respons detail masalah dalam pengembangan ketika
Accept
header HTTP permintaan tidak menyertakantext/html
.
Kode berikut mengonfigurasi aplikasi untuk menghasilkan respons detail masalah untuk semua respons kesalahan klien HTTP dan server yang belum memiliki konten isi:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Bagian berikutnya memperlihatkan cara menyesuaikan isi respons detail masalah.
Menyesuaikan detail masalah
Pembuatan ProblemDetails
otomatis dapat dikustomisasi menggunakan salah satu opsi berikut:
- Menggunakan
ProblemDetailsOptions.CustomizeProblemDetails
- Menggunakan kustom
IProblemDetailsWriter
IProblemDetailsService
Memanggil di middleware
CustomizeProblemDetails
operasi
Detail masalah yang dihasilkan dapat disesuaikan menggunakan CustomizeProblemDetails, dan kustomisasi diterapkan ke semua detail masalah yang dihasilkan secara otomatis.
Kode berikut menggunakan ProblemDetailsOptions untuk mengatur CustomizeProblemDetails:
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Misalnya, HTTP Status 400 Bad Request
hasil titik akhir menghasilkan isi respons detail masalah berikut:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Adat IProblemDetailsWriter
Implementasi IProblemDetailsWriter dapat dibuat untuk kustomisasi tingkat lanjut.
public class SampleProblemDetailsWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// are handled by this writer. All others are
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public ValueTask WriteAsync(ProblemDetailsContext context)
{
// Additional customizations.
// Write to the response.
var response = context.HttpContext.Response;
return new ValueTask(response.WriteAsJsonAsync(context.ProblemDetails));
}
}
Catatan: Saat menggunakan kustom IProblemDetailsWriter
, kustom IProblemDetailsWriter
harus didaftarkan sebelum memanggil AddRazorPages, , AddControllers, AddControllersWithViewsatau AddMvc:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<IProblemDetailsWriter, SampleProblemDetailsWriter>();
var app = builder.Build();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsWriter>() is
{ } problemDetailsService)
{
if (problemDetailsService.CanWrite(new ProblemDetailsContext() { HttpContext = context }))
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.Run();
Detail masalah dari Middleware
Pendekatan alternatif untuk digunakan ProblemDetailsOptions adalah mengatur CustomizeProblemDetails ProblemDetails middleware. Respons detail masalah dapat ditulis dengan memanggil IProblemDetailsService.WriteAsync
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.DivisionByZeroError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.NegativeRadicandError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.MapControllers();
app.Run();
Dalam kode sebelumnya, titik /divide
akhir API minimal dan /squareroot
mengembalikan respons masalah kustom yang diharapkan pada input kesalahan.
Titik akhir pengontrol API mengembalikan respons masalah default pada input kesalahan, bukan respons masalah kustom. Respons masalah default dikembalikan karena pengontrol API telah menulis ke aliran respons, Detail masalah untuk kode status kesalahan, sebelum IProblemDetailsService.WriteAsync
dipanggil dan respons tidak ditulis lagi.
Berikut ini ValuesController
mengembalikan BadRequestResult, yang menulis ke aliran respons dan oleh karena itu mencegah respons masalah kustom dikembalikan.
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// /api/values/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Berikut ini Values3Controller
mengembalikan ControllerBase.Problem
sehingga hasil masalah kustom yang diharapkan dikembalikan:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values3Controller : ControllerBase
{
// /api/values3/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Divison by zero is not defined.",
type: "https://en.wikipedia.org/wiki/Division_by_zero",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Numerator / Denominator);
}
// /api/values3/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Negative or complex numbers are not valid input.",
type: "https://en.wikipedia.org/wiki/Square_root",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Math.Sqrt(radicand));
}
}
Menghasilkan payload ProblemDetails untuk pengecualian
Pertimbangkan aplikasi berikut:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
Di lingkungan non-pengembangan, ketika pengecualian terjadi, berikut ini adalah respons ProblemDetails standar yang dikembalikan ke klien:
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}
Untuk sebagian besar aplikasi, kode sebelumnya adalah semua yang diperlukan untuk pengecualian. Namun, bagian berikut menunjukkan cara mendapatkan respons masalah yang lebih rinci.
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan dan menulis respons detail masalah dengan IProblemDetailsService.WriteAsync
:
using Microsoft.AspNetCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = Text.Plain;
var title = "Bad Input";
var detail = "Invalid input";
var type = "https://errors.example.com/badInput";
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
var exceptionHandlerFeature =
context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType != null &&
exceptionType.Message.Contains("infinity"))
{
title = "Argument exception";
detail = "Invalid input";
type = "https://errors.example.com/argumentException";
}
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = title,
Detail = detail,
Type = type
}
});
}
});
});
}
app.MapControllers();
app.Run();
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Pendekatan alternatif untuk menghasilkan detail masalah adalah menggunakan paket NuGet pihak ketiga Hellang.Middleware.ProblemDetails yang dapat digunakan untuk memetakan pengecualian dan kesalahan klien ke detail masalah.
Sumber Daya Tambahan:
- Melihat atau mengunduh kode sampel (cara mengunduh)
- Memecahkan masalah ASP.NET Core pada Azure App Service dan IIS
- Pemecahan masalah kesalahan umum untuk Azure App Service dan IIS dengan ASP.NET Core
- Menangani kesalahan di API web berbasis pengontrol inti ASP.NET
- Menangani kesalahan dalam API minimal.
Oleh Tom Dykstra
Artikel ini membahas pendekatan umum untuk menangani kesalahan di aplikasi web ASP.NET Core. Lihat juga Menangani kesalahan di API web berbasis pengontrol inti ASP.NET dan Menangani kesalahan dalam API minimal.
Halaman pengecualian pengembang
Halaman Pengecualian Pengembang menampilkan informasi terperinci tentang pengecualian permintaan yang tidak tertangani. aplikasi ASP.NET Core mengaktifkan halaman pengecualian pengembang secara default saat keduanya:
- Berjalan di lingkungan Pengembangan.
- Aplikasi yang dibuat dengan templat saat ini, yaitu, menggunakan WebApplication.CreateBuilder. Aplikasi yang
WebHost.CreateDefaultBuilder
dibuat menggunakan halaman harus mengaktifkan pengecualian pengembang dengan memanggilapp.UseDeveloperExceptionPage
diConfigure
.
Halaman pengecualian pengembang berjalan lebih awal di alur middleware, sehingga dapat menangkap pengecualian yang tidak tertangani yang dilemparkan dalam middleware yang mengikuti.
Informasi pengecualian terperinci tidak boleh ditampilkan secara publik saat aplikasi berjalan di lingkungan Produksi. Untuk informasi selengkapnya tentang mengonfigurasi lingkungan, lihat Menggunakan beberapa lingkungan di ASP.NET Core.
Halaman Pengecualian Pengembang dapat menyertakan informasi berikut tentang pengecualian dan permintaan:
- Pelacakan tumpukan
- Parameter string kueri, jika ada
- Cookie, jika ada
- Header
Halaman Pengecualian Pengembang tidak dijamin untuk memberikan informasi apa pun. Gunakan Pengelogan untuk informasi kesalahan lengkap.
Halaman handler pengecualian
Untuk mengonfigurasi halaman penanganan kesalahan kustom untuk lingkungan Produksi, panggil UseExceptionHandler. Middleware penanganan pengecualian ini:
- Menangkap dan mencatat pengecualian yang tidak tertangani.
- Menjalankan kembali permintaan dalam alur alternatif menggunakan jalur yang ditunjukkan. Permintaan tidak dijalankan kembali jika respons telah dimulai. Kode yang dihasilkan templat menjalankan kembali permintaan menggunakan
/Error
jalur .
Peringatan
Jika alur alternatif melemparkan pengecualian sendiri, Exception Handling Middleware akan memunculkan kembali pengecualian asli.
Karena middleware ini dapat menjalankan kembali alur permintaan:
- Middleware perlu menangani reentrancy dengan permintaan yang sama. Ini biasanya berarti membersihkan status mereka setelah memanggil
_next
atau menyimpan cache pemrosesan mereka untukHttpContext
menghindari mengulanginya. Saat berhadapan dengan isi permintaan, ini berarti buffering atau penembolokan hasil seperti pembaca Formulir. - UseExceptionHandler(IApplicationBuilder, String) Untuk kelebihan beban yang digunakan dalam templat, hanya jalur permintaan yang dimodifikasi, dan data rute dibersihkan. Data permintaan seperti header, metode, dan item semuanya digunakan kembali apa adanya.
- Layanan terlingkup tetap sama.
Dalam contoh berikut, UseExceptionHandler menambahkan middleware penanganan pengecualian di lingkungan non-Pengembangan:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Razor Templat aplikasi Halaman menyediakan halaman Kesalahan (.cshtml
) dan PageModel kelas (ErrorModel
) di folder Halaman. Untuk aplikasi MVC, templat proyek menyertakan Error
metode tindakan dan tampilan Kesalahan untuk Home pengontrol.
Middleware penanganan pengecualian menjalankan kembali permintaan menggunakan metode HTTP asli . Jika titik akhir handler kesalahan dibatasi untuk sekumpulan metode HTTP tertentu, titik akhir hanya berjalan untuk metode HTTP tersebut. Misalnya, tindakan pengontrol MVC yang menggunakan [HttpGet]
atribut hanya berjalan untuk permintaan GET. Untuk memastikan bahwa semua permintaan mencapai halaman penanganan kesalahan kustom, jangan batasi ke sekumpulan metode HTTP tertentu.
Untuk menangani pengecualian secara berbeda berdasarkan metode HTTP asli:
- Untuk Razor Pages, buat beberapa metode handler. Misalnya, gunakan
OnGet
untuk menangani pengecualian GET dan gunakanOnPost
untuk menangani pengecualian POST. - Untuk MVC, terapkan atribut kata kerja HTTP ke beberapa tindakan. Misalnya, gunakan
[HttpGet]
untuk menangani pengecualian GET dan gunakan[HttpPost]
untuk menangani pengecualian POST.
Untuk mengizinkan pengguna yang tidak diaturentikasi untuk melihat halaman penanganan kesalahan kustom, pastikan pengguna tersebut mendukung akses anonim.
Mengakses pengecualian
Gunakan IExceptionHandlerPathFeature untuk mengakses pengecualian dan jalur permintaan asli dalam penangan kesalahan. Contoh berikut menggunakan IExceptionHandlerPathFeature
untuk mendapatkan informasi selengkapnya tentang pengecualian yang dilemparkan:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Penangan pengecualian lambda
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan sebelum mengembalikan respons.
Kode berikut menggunakan lambda untuk penanganan pengecualian:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
IExceptionHandler
IExceptionHandler adalah antarmuka yang memberi pengembang panggilan balik untuk menangani pengecualian yang diketahui di lokasi pusat.
IExceptionHandler
implementasi didaftarkan dengan memanggil IServiceCollection.AddExceptionHandler<T>
. Masa pakai IExceptionHandler
instans adalah singleton. Beberapa implementasi dapat ditambahkan, dan dipanggil dalam urutan terdaftar.
Jika handler pengecualian menangani permintaan, handler tersebut dapat kembali true
berhenti memproses. Jika pengecualian tidak ditangani oleh handler pengecualian apa pun, kontrol akan kembali ke perilaku dan opsi default dari middleware. Metrik dan log yang berbeda dipancarkan untuk pengecualian yang ditangani versus pengecualian yang tidak tertangani.
Contoh berikut menunjukkan IExceptionHandler
implementasi:
using Microsoft.AspNetCore.Diagnostics;
namespace ErrorHandlingSample
{
public class CustomExceptionHandler : IExceptionHandler
{
private readonly ILogger<CustomExceptionHandler> logger;
public CustomExceptionHandler(ILogger<CustomExceptionHandler> logger)
{
this.logger = logger;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
var exceptionMessage = exception.Message;
logger.LogError(
"Error Message: {exceptionMessage}, Time of occurrence {time}",
exceptionMessage, DateTime.UtcNow);
// Return false to continue with the default behavior
// - or - return true to signal that this exception is handled
return ValueTask.FromResult(false);
}
}
}
Contoh berikut menunjukkan cara mendaftarkan IExceptionHandler
implementasi untuk injeksi dependensi:
using ErrorHandlingSample;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// Remaining Program.cs code omitted for brevity
Saat kode sebelumnya berjalan di lingkungan Pengembangan:
- dipanggil
CustomExceptionHandler
terlebih dahulu untuk menangani pengecualian. - Setelah mencatat pengecualian,
TryHandleException
metode mengembalikanfalse
, sehingga halaman pengecualian pengembang ditampilkan.
Di lingkungan lain:
- dipanggil
CustomExceptionHandler
terlebih dahulu untuk menangani pengecualian. - Setelah mencatat pengecualian,
TryHandleException
metode mengembalikanfalse
, sehingga/Error
halaman ditampilkan.
GunakanStatusCodePages
Secara default, aplikasi ASP.NET Core tidak menyediakan halaman kode status untuk kode status kesalahan HTTP, seperti 404 - Tidak Ditemukan. Saat aplikasi menetapkan kode status kesalahan HTTP 400-599 yang tidak memiliki isi, aplikasi mengembalikan kode status dan isi respons kosong. Untuk mengaktifkan penangan teks-saja default untuk kode status kesalahan umum, panggil UseStatusCodePages di Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Panggil UseStatusCodePages
sebelum meminta penanganan middleware. Misalnya, panggil UseStatusCodePages
sebelum Middleware File Statis dan Middleware Titik Akhir.
Saat UseStatusCodePages
tidak digunakan, menavigasi ke URL tanpa titik akhir mengembalikan pesan kesalahan yang bergantung pada browser yang menunjukkan titik akhir tidak dapat ditemukan. Ketika UseStatusCodePages
dipanggil, browser mengembalikan respons berikut:
Status Code: 404; Not Found
UseStatusCodePages
biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
Catatan
Halaman kode status middleware tidak menangkap pengecualian. Untuk menyediakan halaman penanganan kesalahan kustom, gunakan halaman handler pengecualian.
GunakanStatusCodePages dengan string format
Untuk mengkustomisasi tipe konten respons dan teks, gunakan kelebihan beban UseStatusCodePages yang mengambil tipe konten dan format string:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Dalam kode sebelumnya, {0}
adalah tempat penampung untuk kode kesalahan.
UseStatusCodePages
dengan string format biasanya tidak digunakan dalam produksi karena menampilkan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePages dengan lambda
Untuk menentukan penanganan kesalahan kustom dan kode penulisan respons, gunakan kelebihan beban UseStatusCodePages yang mengambil ekspresi lambda:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
dengan lambda biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePagesWithRedirects
Metode UseStatusCodePagesWithRedirects ekstensi:
- Mengirim kode status 302 - Ditemukan ke klien.
- Mengalihkan klien ke titik akhir penanganan kesalahan yang disediakan dalam templat URL. Titik akhir penanganan kesalahan biasanya menampilkan informasi kesalahan dan mengembalikan HTTP 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Templat URL dapat menyertakan {0}
tempat penampung untuk kode status, seperti yang ditunjukkan dalam kode sebelumnya. Jika templat URL dimulai dengan ~
(tilde), ~
digantikan oleh aplikasi PathBase
. Saat menentukan titik akhir di aplikasi, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan saat aplikasi:
- Harus mengalihkan klien ke titik akhir yang berbeda, biasanya dalam kasus di mana aplikasi yang berbeda memproses kesalahan. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang dialihkan.
- Tidak boleh mempertahankan dan mengembalikan kode status asli dengan respons pengalihan awal.
GunakanStatusCodePagesWithReExecute
Metode UseStatusCodePagesWithReExecute ekstensi:
- Menghasilkan isi respons dengan mengeksekusi ulang alur permintaan menggunakan jalur alternatif.
- Tidak mengubah kode status sebelum atau sesudah mengeksekusi ulang alur.
Eksekusi alur baru dapat mengubah kode status respons, karena alur baru memiliki kontrol penuh atas kode status. Jika alur baru tidak mengubah kode status, kode status asli akan dikirim ke klien.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Jika titik akhir dalam aplikasi ditentukan, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan ketika aplikasi harus:
- Proses permintaan tanpa mengalihkan ke titik akhir yang berbeda. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang awalnya diminta.
- Pertahankan dan kembalikan kode status asli dengan respons.
Templat URL harus dimulai dengan /
dan dapat menyertakan tempat penampung {0}
untuk kode status. Untuk meneruskan kode status sebagai parameter string kueri, teruskan argumen kedua ke dalam UseStatusCodePagesWithReExecute
. Contohnya:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Titik akhir yang memproses kesalahan bisa mendapatkan URL asli yang menghasilkan kesalahan, seperti yang ditunjukkan dalam contoh berikut:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = $"{statusCodeReExecuteFeature.OriginalPathBase}"
+ $"{statusCodeReExecuteFeature.OriginalPath}"
+ $"{statusCodeReExecuteFeature.OriginalQueryString}";
}
}
}
Karena middleware ini dapat menjalankan kembali alur permintaan:
- Middleware perlu menangani reentrancy dengan permintaan yang sama. Ini biasanya berarti membersihkan status mereka setelah memanggil
_next
atau menyimpan cache pemrosesan mereka untukHttpContext
menghindari mengulanginya. Saat berhadapan dengan isi permintaan, ini berarti buffering atau penembolokan hasil seperti pembaca Formulir. - Layanan terlingkup tetap sama.
Menonaktifkan halaman kode status
Untuk menonaktifkan halaman kode status untuk pengontrol MVC atau metode tindakan, gunakan atribut [SkipStatusCodePages ].
Untuk menonaktifkan halaman kode status untuk permintaan tertentu dalam Razor metode handler Pages atau di pengontrol MVC, gunakan IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kode penanganan pengecualian
Kode dalam halaman penanganan pengecualian juga dapat melemparkan pengecualian. Halaman kesalahan produksi harus diuji secara menyeluruh dan berhati-hatilah untuk menghindari melempar pengecualian sendiri.
Header respons
Setelah header untuk respons dikirim:
- Aplikasi tidak dapat mengubah kode status respons.
- Halaman pengecualian atau handler apa pun tidak dapat dijalankan. Respons harus diselesaikan atau koneksi dibatalkan.
Penanganan pengecualian server
Selain logika penanganan pengecualian dalam aplikasi, implementasi server HTTP dapat menangani beberapa pengecualian. Jika server menangkap pengecualian sebelum header respons dikirim, server mengirim 500 - Internal Server Error
respons tanpa isi respons. Jika server menangkap pengecualian setelah header respons dikirim, server menutup koneksi. Permintaan yang tidak ditangani oleh aplikasi ditangani oleh server. Pengecualian apa pun yang terjadi ketika server menangani permintaan ditangani oleh penanganan pengecualian server. Halaman kesalahan kustom aplikasi, middleware penanganan pengecualian, dan filter tidak memengaruhi perilaku ini.
Penanganan pengecualian startup
Hanya lapisan hosting yang dapat menangani pengecualian yang terjadi selama startup aplikasi. Host dapat dikonfigurasi untuk menangkap kesalahan startup dan menangkap kesalahan terperinci.
Lapisan hosting dapat menampilkan halaman kesalahan untuk kesalahan startup yang diambil hanya jika kesalahan terjadi setelah alamat host/pengikatan port. Jika pengikatan gagal:
- Lapisan hosting mencatat pengecualian penting.
- Proses dotnet mengalami crash.
- Tidak ada halaman kesalahan yang ditampilkan ketika server HTTP adalah Kestrel.
Saat berjalan di IIS (atau Azure App Service) atau IIS Express, 502.5 - Kegagalan Proses dikembalikan oleh Modul Inti ASP.NET jika proses tidak dapat dimulai. Untuk informasi selengkapnya, lihat Memecahkan masalah ASP.NET Core di Azure App Service dan IIS.
Halaman kesalahan database
Filter AddDatabaseDeveloperPageExceptionFilter pengecualian halaman pengembang Database menangkap pengecualian terkait database yang dapat diselesaikan dengan menggunakan migrasi Entity Framework Core. Ketika pengecualian ini terjadi, respons HTML dihasilkan dengan detail kemungkinan tindakan untuk menyelesaikan masalah. Halaman ini hanya diaktifkan di lingkungan Pengembangan. Kode berikut menambahkan filter pengecualian halaman pengembang Database:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filter pengecualian
Di aplikasi MVC, filter pengecualian dapat dikonfigurasi secara global atau berdasarkan per pengontrol atau per tindakan. Di Razor aplikasi Pages, aplikasi tersebut dapat dikonfigurasi secara global atau per model halaman. Filter ini menangani pengecualian yang tidak tertangani yang terjadi selama eksekusi tindakan pengontrol atau filter lain. Untuk informasi selengkapnya, lihat Filter di ASP.NET Core.
Filter pengecualian berguna untuk menjebak pengecualian yang terjadi dalam tindakan MVC, tetapi tidak fleksibel seperti middleware penanganan pengecualian bawaan, UseExceptionHandler. Sebaiknya gunakan UseExceptionHandler
, kecuali Anda perlu melakukan penanganan kesalahan secara berbeda berdasarkan tindakan MVC mana yang dipilih.
Kesalahan status model
Untuk informasi tentang cara menangani kesalahan status model, lihat Pengikatan model dan Validasi model.
Detail masalah
Detail Masalah bukan satu-satunya format respons untuk menjelaskan kesalahan API HTTP, namun, biasanya digunakan untuk melaporkan kesalahan untuk API HTTP.
Layanan detail masalah mengimplementasikan IProblemDetailsService antarmuka, yang mendukung pembuatan detail masalah di ASP.NET Core. Metode AddProblemDetails(IServiceCollection) ekstensi pada IServiceCollection mendaftarkan implementasi default IProblemDetailsService
.
Di aplikasi ASP.NET Core, middleware berikut menghasilkan respons HTTP detail masalah saat AddProblemDetails
dipanggil, kecuali ketika Accept
header HTTP permintaan tidak menyertakan salah satu jenis konten yang didukung oleh yang terdaftar IProblemDetailsWriter (default: application/json
):
- ExceptionHandlerMiddleware: Menghasilkan respons detail masalah saat handler kustom tidak ditentukan.
- StatusCodePagesMiddleware: Menghasilkan respons detail masalah secara default.
- DeveloperExceptionPageMiddleware: Menghasilkan respons detail masalah dalam pengembangan ketika
Accept
header HTTP permintaan tidak menyertakantext/html
.
Kode berikut mengonfigurasi aplikasi untuk menghasilkan respons detail masalah untuk semua respons kesalahan klien HTTP dan server yang belum memiliki konten isi:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Bagian berikutnya memperlihatkan cara menyesuaikan isi respons detail masalah.
Menyesuaikan detail masalah
Pembuatan ProblemDetails
otomatis dapat dikustomisasi menggunakan salah satu opsi berikut:
- Menggunakan
ProblemDetailsOptions.CustomizeProblemDetails
- Menggunakan kustom
IProblemDetailsWriter
IProblemDetailsService
Memanggil di middleware
CustomizeProblemDetails
operasi
Detail masalah yang dihasilkan dapat disesuaikan menggunakan CustomizeProblemDetails, dan kustomisasi diterapkan ke semua detail masalah yang dihasilkan secara otomatis.
Kode berikut menggunakan ProblemDetailsOptions untuk mengatur CustomizeProblemDetails:
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Misalnya, HTTP Status 400 Bad Request
hasil titik akhir menghasilkan isi respons detail masalah berikut:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Adat IProblemDetailsWriter
Implementasi IProblemDetailsWriter dapat dibuat untuk kustomisasi tingkat lanjut.
public class SampleProblemDetailsWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// are handled by this writer. All others are
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public ValueTask WriteAsync(ProblemDetailsContext context)
{
// Additional customizations.
// Write to the response.
var response = context.HttpContext.Response;
return new ValueTask(response.WriteAsJsonAsync(context.ProblemDetails));
}
}
Catatan: Saat menggunakan kustom IProblemDetailsWriter
, kustom IProblemDetailsWriter
harus didaftarkan sebelum memanggil AddRazorPages, , AddControllers, AddControllersWithViewsatau AddMvc:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<IProblemDetailsWriter, SampleProblemDetailsWriter>();
var app = builder.Build();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsWriter>() is
{ } problemDetailsService)
{
if (problemDetailsService.CanWrite(new ProblemDetailsContext() { HttpContext = context }))
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.Run();
Detail masalah dari Middleware
Pendekatan alternatif untuk digunakan ProblemDetailsOptions adalah mengatur CustomizeProblemDetails ProblemDetails middleware. Respons detail masalah dapat ditulis dengan memanggil IProblemDetailsService.WriteAsync
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.DivisionByZeroError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.NegativeRadicandError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.MapControllers();
app.Run();
Dalam kode sebelumnya, titik /divide
akhir API minimal dan /squareroot
mengembalikan respons masalah kustom yang diharapkan pada input kesalahan.
Titik akhir pengontrol API mengembalikan respons masalah default pada input kesalahan, bukan respons masalah kustom. Respons masalah default dikembalikan karena pengontrol API telah menulis ke aliran respons, Detail masalah untuk kode status kesalahan, sebelum IProblemDetailsService.WriteAsync
dipanggil dan respons tidak ditulis lagi.
Berikut ini ValuesController
mengembalikan BadRequestResult, yang menulis ke aliran respons dan oleh karena itu mencegah respons masalah kustom dikembalikan.
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// /api/values/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Berikut ini Values3Controller
mengembalikan ControllerBase.Problem
sehingga hasil masalah kustom yang diharapkan dikembalikan:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values3Controller : ControllerBase
{
// /api/values3/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Divison by zero is not defined.",
type: "https://en.wikipedia.org/wiki/Division_by_zero",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Numerator / Denominator);
}
// /api/values3/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Negative or complex numbers are not valid input.",
type: "https://en.wikipedia.org/wiki/Square_root",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Math.Sqrt(radicand));
}
}
Menghasilkan payload ProblemDetails untuk pengecualian
Pertimbangkan aplikasi berikut:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
Di lingkungan non-pengembangan, ketika pengecualian terjadi, berikut ini adalah respons ProblemDetails standar yang dikembalikan ke klien:
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}
Untuk sebagian besar aplikasi, kode sebelumnya adalah semua yang diperlukan untuk pengecualian. Namun, bagian berikut menunjukkan cara mendapatkan respons masalah yang lebih rinci.
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan dan menulis respons detail masalah dengan IProblemDetailsService.WriteAsync
:
using Microsoft.AspNetCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = Text.Plain;
var title = "Bad Input";
var detail = "Invalid input";
var type = "https://errors.example.com/badInput";
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
var exceptionHandlerFeature =
context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType != null &&
exceptionType.Message.Contains("infinity"))
{
title = "Argument exception";
detail = "Invalid input";
type = "https://errors.example.com/argumentException";
}
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = title,
Detail = detail,
Type = type
}
});
}
});
});
}
app.MapControllers();
app.Run();
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Pendekatan alternatif untuk menghasilkan detail masalah adalah menggunakan paket NuGet pihak ketiga Hellang.Middleware.ProblemDetails yang dapat digunakan untuk memetakan pengecualian dan kesalahan klien ke detail masalah.
Sumber Daya Tambahan:
- Melihat atau mengunduh kode sampel (cara mengunduh)
- Memecahkan masalah ASP.NET Core pada Azure App Service dan IIS
- Pemecahan masalah kesalahan umum untuk Azure App Service dan IIS dengan ASP.NET Core
- Menangani kesalahan di API web berbasis pengontrol inti ASP.NET
- Menangani kesalahan dalam API minimal.
Oleh Tom Dykstra
Artikel ini membahas pendekatan umum untuk menangani kesalahan di aplikasi web ASP.NET Core. Lihat juga Menangani kesalahan di API web berbasis pengontrol inti ASP.NET dan Menangani kesalahan dalam API minimal.
Halaman pengecualian pengembang
Halaman Pengecualian Pengembang menampilkan informasi terperinci tentang pengecualian permintaan yang tidak tertangani. aplikasi ASP.NET Core mengaktifkan halaman pengecualian pengembang secara default saat keduanya:
- Berjalan di lingkungan Pengembangan.
- Aplikasi yang dibuat dengan templat saat ini, yaitu, menggunakan WebApplication.CreateBuilder. Aplikasi yang
WebHost.CreateDefaultBuilder
dibuat menggunakan halaman harus mengaktifkan pengecualian pengembang dengan memanggilapp.UseDeveloperExceptionPage
diConfigure
.
Halaman pengecualian pengembang berjalan lebih awal di alur middleware, sehingga dapat menangkap pengecualian yang tidak tertangani yang dilemparkan dalam middleware yang mengikuti.
Informasi pengecualian terperinci tidak boleh ditampilkan secara publik saat aplikasi berjalan di lingkungan Produksi. Untuk informasi selengkapnya tentang mengonfigurasi lingkungan, lihat Menggunakan beberapa lingkungan di ASP.NET Core.
Halaman Pengecualian Pengembang dapat menyertakan informasi berikut tentang pengecualian dan permintaan:
- Pelacakan tumpukan
- Parameter string kueri, jika ada
- Cookie, jika ada
- Header
Halaman Pengecualian Pengembang tidak dijamin untuk memberikan informasi apa pun. Gunakan Pengelogan untuk informasi kesalahan lengkap.
Halaman handler pengecualian
Untuk mengonfigurasi halaman penanganan kesalahan kustom untuk lingkungan Produksi, panggil UseExceptionHandler. Middleware penanganan pengecualian ini:
- Menangkap dan mencatat pengecualian yang tidak tertangani.
- Menjalankan kembali permintaan dalam alur alternatif menggunakan jalur yang ditunjukkan. Permintaan tidak dijalankan kembali jika respons telah dimulai. Kode yang dihasilkan templat menjalankan kembali permintaan menggunakan
/Error
jalur .
Peringatan
Jika alur alternatif melemparkan pengecualian sendiri, Exception Handling Middleware akan memunculkan kembali pengecualian asli.
Karena middleware ini dapat menjalankan kembali alur permintaan:
- Middleware perlu menangani reentrancy dengan permintaan yang sama. Ini biasanya berarti membersihkan status mereka setelah memanggil
_next
atau menyimpan cache pemrosesan mereka untukHttpContext
menghindari mengulanginya. Saat berhadapan dengan isi permintaan, ini berarti buffering atau penembolokan hasil seperti pembaca Formulir. - UseExceptionHandler(IApplicationBuilder, String) Untuk kelebihan beban yang digunakan dalam templat, hanya jalur permintaan yang dimodifikasi, dan data rute dibersihkan. Data permintaan seperti header, metode, dan item semuanya digunakan kembali apa adanya.
- Layanan terlingkup tetap sama.
Dalam contoh berikut, UseExceptionHandler menambahkan middleware penanganan pengecualian di lingkungan non-Pengembangan:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Razor Templat aplikasi Halaman menyediakan halaman Kesalahan (.cshtml
) dan PageModel kelas (ErrorModel
) di folder Halaman. Untuk aplikasi MVC, templat proyek menyertakan Error
metode tindakan dan tampilan Kesalahan untuk Home pengontrol.
Middleware penanganan pengecualian menjalankan kembali permintaan menggunakan metode HTTP asli . Jika titik akhir handler kesalahan dibatasi untuk sekumpulan metode HTTP tertentu, titik akhir hanya berjalan untuk metode HTTP tersebut. Misalnya, tindakan pengontrol MVC yang menggunakan [HttpGet]
atribut hanya berjalan untuk permintaan GET. Untuk memastikan bahwa semua permintaan mencapai halaman penanganan kesalahan kustom, jangan batasi ke sekumpulan metode HTTP tertentu.
Untuk menangani pengecualian secara berbeda berdasarkan metode HTTP asli:
- Untuk Razor Pages, buat beberapa metode handler. Misalnya, gunakan
OnGet
untuk menangani pengecualian GET dan gunakanOnPost
untuk menangani pengecualian POST. - Untuk MVC, terapkan atribut kata kerja HTTP ke beberapa tindakan. Misalnya, gunakan
[HttpGet]
untuk menangani pengecualian GET dan gunakan[HttpPost]
untuk menangani pengecualian POST.
Untuk mengizinkan pengguna yang tidak diaturentikasi untuk melihat halaman penanganan kesalahan kustom, pastikan pengguna tersebut mendukung akses anonim.
Mengakses pengecualian
Gunakan IExceptionHandlerPathFeature untuk mengakses pengecualian dan jalur permintaan asli dalam penangan kesalahan. Contoh berikut menggunakan IExceptionHandlerPathFeature
untuk mendapatkan informasi selengkapnya tentang pengecualian yang dilemparkan:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Penangan pengecualian lambda
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan sebelum mengembalikan respons.
Kode berikut menggunakan lambda untuk penanganan pengecualian:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
GunakanStatusCodePages
Secara default, aplikasi ASP.NET Core tidak menyediakan halaman kode status untuk kode status kesalahan HTTP, seperti 404 - Tidak Ditemukan. Saat aplikasi menetapkan kode status kesalahan HTTP 400-599 yang tidak memiliki isi, aplikasi mengembalikan kode status dan isi respons kosong. Untuk mengaktifkan penangan teks-saja default untuk kode status kesalahan umum, panggil UseStatusCodePages di Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Panggil UseStatusCodePages
sebelum meminta penanganan middleware. Misalnya, panggil UseStatusCodePages
sebelum Middleware File Statis dan Middleware Titik Akhir.
Saat UseStatusCodePages
tidak digunakan, menavigasi ke URL tanpa titik akhir mengembalikan pesan kesalahan yang bergantung pada browser yang menunjukkan titik akhir tidak dapat ditemukan. Ketika UseStatusCodePages
dipanggil, browser mengembalikan respons berikut:
Status Code: 404; Not Found
UseStatusCodePages
biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
Catatan
Halaman kode status middleware tidak menangkap pengecualian. Untuk menyediakan halaman penanganan kesalahan kustom, gunakan halaman handler pengecualian.
GunakanStatusCodePages dengan string format
Untuk mengkustomisasi tipe konten respons dan teks, gunakan kelebihan beban UseStatusCodePages yang mengambil tipe konten dan format string:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Dalam kode sebelumnya, {0}
adalah tempat penampung untuk kode kesalahan.
UseStatusCodePages
dengan string format biasanya tidak digunakan dalam produksi karena menampilkan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePages dengan lambda
Untuk menentukan penanganan kesalahan kustom dan kode penulisan respons, gunakan kelebihan beban UseStatusCodePages yang mengambil ekspresi lambda:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
dengan lambda biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePagesWithRedirects
Metode UseStatusCodePagesWithRedirects ekstensi:
- Mengirim kode status 302 - Ditemukan ke klien.
- Mengalihkan klien ke titik akhir penanganan kesalahan yang disediakan dalam templat URL. Titik akhir penanganan kesalahan biasanya menampilkan informasi kesalahan dan mengembalikan HTTP 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Templat URL dapat menyertakan {0}
tempat penampung untuk kode status, seperti yang ditunjukkan dalam kode sebelumnya. Jika templat URL dimulai dengan ~
(tilde), ~
digantikan oleh aplikasi PathBase
. Saat menentukan titik akhir di aplikasi, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan saat aplikasi:
- Harus mengalihkan klien ke titik akhir yang berbeda, biasanya dalam kasus di mana aplikasi yang berbeda memproses kesalahan. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang dialihkan.
- Tidak boleh mempertahankan dan mengembalikan kode status asli dengan respons pengalihan awal.
GunakanStatusCodePagesWithReExecute
Metode UseStatusCodePagesWithReExecute ekstensi:
- Menghasilkan isi respons dengan mengeksekusi ulang alur permintaan menggunakan jalur alternatif.
- Tidak mengubah kode status sebelum atau sesudah mengeksekusi ulang alur.
Eksekusi alur baru dapat mengubah kode status respons, karena alur baru memiliki kontrol penuh atas kode status. Jika alur baru tidak mengubah kode status, kode status asli akan dikirim ke klien.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Jika titik akhir dalam aplikasi ditentukan, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan ketika aplikasi harus:
- Proses permintaan tanpa mengalihkan ke titik akhir yang berbeda. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang awalnya diminta.
- Pertahankan dan kembalikan kode status asli dengan respons.
Templat URL harus dimulai dengan /
dan dapat menyertakan tempat penampung {0}
untuk kode status. Untuk meneruskan kode status sebagai parameter string kueri, teruskan argumen kedua ke dalam UseStatusCodePagesWithReExecute
. Contohnya:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Titik akhir yang memproses kesalahan bisa mendapatkan URL asli yang menghasilkan kesalahan, seperti yang ditunjukkan dalam contoh berikut:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = $"{statusCodeReExecuteFeature.OriginalPathBase}"
+ $"{statusCodeReExecuteFeature.OriginalPath}"
+ $"{statusCodeReExecuteFeature.OriginalQueryString}";
}
}
}
Karena middleware ini dapat menjalankan kembali alur permintaan:
- Middleware perlu menangani reentrancy dengan permintaan yang sama. Ini biasanya berarti membersihkan status mereka setelah memanggil
_next
atau menyimpan cache pemrosesan mereka untukHttpContext
menghindari mengulanginya. Saat berhadapan dengan isi permintaan, ini berarti buffering atau penembolokan hasil seperti pembaca Formulir. - Layanan terlingkup tetap sama.
Menonaktifkan halaman kode status
Untuk menonaktifkan halaman kode status untuk pengontrol MVC atau metode tindakan, gunakan atribut [SkipStatusCodePages ].
Untuk menonaktifkan halaman kode status untuk permintaan tertentu dalam Razor metode handler Pages atau di pengontrol MVC, gunakan IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kode penanganan pengecualian
Kode dalam halaman penanganan pengecualian juga dapat melemparkan pengecualian. Halaman kesalahan produksi harus diuji secara menyeluruh dan berhati-hatilah untuk menghindari melempar pengecualian sendiri.
Header respons
Setelah header untuk respons dikirim:
- Aplikasi tidak dapat mengubah kode status respons.
- Halaman pengecualian atau handler apa pun tidak dapat dijalankan. Respons harus diselesaikan atau koneksi dibatalkan.
Penanganan pengecualian server
Selain logika penanganan pengecualian dalam aplikasi, implementasi server HTTP dapat menangani beberapa pengecualian. Jika server menangkap pengecualian sebelum header respons dikirim, server mengirim 500 - Internal Server Error
respons tanpa isi respons. Jika server menangkap pengecualian setelah header respons dikirim, server menutup koneksi. Permintaan yang tidak ditangani oleh aplikasi ditangani oleh server. Pengecualian apa pun yang terjadi ketika server menangani permintaan ditangani oleh penanganan pengecualian server. Halaman kesalahan kustom aplikasi, middleware penanganan pengecualian, dan filter tidak memengaruhi perilaku ini.
Penanganan pengecualian startup
Hanya lapisan hosting yang dapat menangani pengecualian yang terjadi selama startup aplikasi. Host dapat dikonfigurasi untuk menangkap kesalahan startup dan menangkap kesalahan terperinci.
Lapisan hosting dapat menampilkan halaman kesalahan untuk kesalahan startup yang diambil hanya jika kesalahan terjadi setelah alamat host/pengikatan port. Jika pengikatan gagal:
- Lapisan hosting mencatat pengecualian penting.
- Proses dotnet mengalami crash.
- Tidak ada halaman kesalahan yang ditampilkan ketika server HTTP adalah Kestrel.
Saat berjalan di IIS (atau Azure App Service) atau IIS Express, 502.5 - Kegagalan Proses dikembalikan oleh Modul Inti ASP.NET jika proses tidak dapat dimulai. Untuk informasi selengkapnya, lihat Memecahkan masalah ASP.NET Core di Azure App Service dan IIS.
Halaman kesalahan database
Filter AddDatabaseDeveloperPageExceptionFilter pengecualian halaman pengembang Database menangkap pengecualian terkait database yang dapat diselesaikan dengan menggunakan migrasi Entity Framework Core. Ketika pengecualian ini terjadi, respons HTML dihasilkan dengan detail kemungkinan tindakan untuk menyelesaikan masalah. Halaman ini hanya diaktifkan di lingkungan Pengembangan. Kode berikut menambahkan filter pengecualian halaman pengembang Database:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filter pengecualian
Di aplikasi MVC, filter pengecualian dapat dikonfigurasi secara global atau berdasarkan per pengontrol atau per tindakan. Di Razor aplikasi Pages, aplikasi tersebut dapat dikonfigurasi secara global atau per model halaman. Filter ini menangani pengecualian yang tidak tertangani yang terjadi selama eksekusi tindakan pengontrol atau filter lain. Untuk informasi selengkapnya, lihat Filter di ASP.NET Core.
Filter pengecualian berguna untuk menjebak pengecualian yang terjadi dalam tindakan MVC, tetapi tidak fleksibel seperti middleware penanganan pengecualian bawaan, UseExceptionHandler. Sebaiknya gunakan UseExceptionHandler
, kecuali Anda perlu melakukan penanganan kesalahan secara berbeda berdasarkan tindakan MVC mana yang dipilih.
Kesalahan status model
Untuk informasi tentang cara menangani kesalahan status model, lihat Pengikatan model dan Validasi model.
Detail masalah
Detail Masalah bukan satu-satunya format respons untuk menjelaskan kesalahan API HTTP, namun, biasanya digunakan untuk melaporkan kesalahan untuk API HTTP.
Layanan detail masalah mengimplementasikan IProblemDetailsService antarmuka, yang mendukung pembuatan detail masalah di ASP.NET Core. Metode AddProblemDetails(IServiceCollection) ekstensi pada IServiceCollection mendaftarkan implementasi default IProblemDetailsService
.
Di aplikasi ASP.NET Core, middleware berikut menghasilkan respons HTTP detail masalah saat AddProblemDetails
dipanggil, kecuali ketika Accept
header HTTP permintaan tidak menyertakan salah satu jenis konten yang didukung oleh yang terdaftar IProblemDetailsWriter (default: application/json
):
- ExceptionHandlerMiddleware: Menghasilkan respons detail masalah saat handler kustom tidak ditentukan.
- StatusCodePagesMiddleware: Menghasilkan respons detail masalah secara default.
- DeveloperExceptionPageMiddleware: Menghasilkan respons detail masalah dalam pengembangan ketika
Accept
header HTTP permintaan tidak menyertakantext/html
.
Kode berikut mengonfigurasi aplikasi untuk menghasilkan respons detail masalah untuk semua respons kesalahan klien HTTP dan server yang belum memiliki konten isi:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Bagian berikutnya memperlihatkan cara menyesuaikan isi respons detail masalah.
Menyesuaikan detail masalah
Pembuatan ProblemDetails
otomatis dapat dikustomisasi menggunakan salah satu opsi berikut:
- Menggunakan
ProblemDetailsOptions.CustomizeProblemDetails
- Menggunakan kustom
IProblemDetailsWriter
IProblemDetailsService
Memanggil di middleware
CustomizeProblemDetails
operasi
Detail masalah yang dihasilkan dapat disesuaikan menggunakan CustomizeProblemDetails, dan kustomisasi diterapkan ke semua detail masalah yang dihasilkan secara otomatis.
Kode berikut menggunakan ProblemDetailsOptions untuk mengatur CustomizeProblemDetails:
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Misalnya, HTTP Status 400 Bad Request
hasil titik akhir menghasilkan isi respons detail masalah berikut:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Adat IProblemDetailsWriter
Implementasi IProblemDetailsWriter dapat dibuat untuk kustomisasi tingkat lanjut.
public class SampleProblemDetailsWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// are handled by this writer. All others are
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public ValueTask WriteAsync(ProblemDetailsContext context)
{
// Additional customizations.
// Write to the response.
var response = context.HttpContext.Response;
return new ValueTask(response.WriteAsJsonAsync(context.ProblemDetails));
}
}
Catatan: Saat menggunakan kustom IProblemDetailsWriter
, kustom IProblemDetailsWriter
harus didaftarkan sebelum memanggil AddRazorPages, , AddControllers, AddControllersWithViewsatau AddMvc:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<IProblemDetailsWriter, SampleProblemDetailsWriter>();
var app = builder.Build();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsWriter>() is
{ } problemDetailsService)
{
if (problemDetailsService.CanWrite(new ProblemDetailsContext() { HttpContext = context }))
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.Run();
Detail masalah dari Middleware
Pendekatan alternatif untuk digunakan ProblemDetailsOptions adalah mengatur CustomizeProblemDetails ProblemDetails middleware. Respons detail masalah dapat ditulis dengan memanggil IProblemDetailsService.WriteAsync
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.DivisionByZeroError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.NegativeRadicandError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.MapControllers();
app.Run();
Dalam kode sebelumnya, titik /divide
akhir API minimal dan /squareroot
mengembalikan respons masalah kustom yang diharapkan pada input kesalahan.
Titik akhir pengontrol API mengembalikan respons masalah default pada input kesalahan, bukan respons masalah kustom. Respons masalah default dikembalikan karena pengontrol API telah menulis ke aliran respons, Detail masalah untuk kode status kesalahan, sebelum IProblemDetailsService.WriteAsync
dipanggil dan respons tidak ditulis lagi.
Berikut ini ValuesController
mengembalikan BadRequestResult, yang menulis ke aliran respons dan oleh karena itu mencegah respons masalah kustom dikembalikan.
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// /api/values/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Berikut ini Values3Controller
mengembalikan ControllerBase.Problem
sehingga hasil masalah kustom yang diharapkan dikembalikan:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values3Controller : ControllerBase
{
// /api/values3/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Divison by zero is not defined.",
type: "https://en.wikipedia.org/wiki/Division_by_zero",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Numerator / Denominator);
}
// /api/values3/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Negative or complex numbers are not valid input.",
type: "https://en.wikipedia.org/wiki/Square_root",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Math.Sqrt(radicand));
}
}
Menghasilkan payload ProblemDetails untuk pengecualian
Pertimbangkan aplikasi berikut:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
Di lingkungan non-pengembangan, ketika pengecualian terjadi, berikut ini adalah respons ProblemDetails standar yang dikembalikan ke klien:
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}
Untuk sebagian besar aplikasi, kode sebelumnya adalah semua yang diperlukan untuk pengecualian. Namun, bagian berikut menunjukkan cara mendapatkan respons masalah yang lebih rinci.
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan dan menulis respons detail masalah dengan IProblemDetailsService.WriteAsync
:
using Microsoft.AspNetCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = Text.Plain;
var title = "Bad Input";
var detail = "Invalid input";
var type = "https://errors.example.com/badInput";
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
var exceptionHandlerFeature =
context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType != null &&
exceptionType.Message.Contains("infinity"))
{
title = "Argument exception";
detail = "Invalid input";
type = "https://errors.example.com/argumentException";
}
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = title,
Detail = detail,
Type = type
}
});
}
});
});
}
app.MapControllers();
app.Run();
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Pendekatan alternatif untuk menghasilkan detail masalah adalah menggunakan paket NuGet pihak ketiga Hellang.Middleware.ProblemDetails yang dapat digunakan untuk memetakan pengecualian dan kesalahan klien ke detail masalah.
Sumber Daya Tambahan:
Oleh Tom Dykstra
Artikel ini membahas pendekatan umum untuk menangani kesalahan di aplikasi web ASP.NET Core. Lihat Menangani kesalahan di API web berbasis pengontrol inti ASP.NET untuk API web.
Halaman pengecualian pengembang
Halaman Pengecualian Pengembang menampilkan informasi terperinci tentang pengecualian permintaan yang tidak tertangani. aplikasi ASP.NET Core mengaktifkan halaman pengecualian pengembang secara default saat keduanya:
- Berjalan di lingkungan Pengembangan.
- Aplikasi yang dibuat dengan templat saat ini, yaitu, menggunakan WebApplication.CreateBuilder. Aplikasi yang
WebHost.CreateDefaultBuilder
dibuat menggunakan halaman harus mengaktifkan pengecualian pengembang dengan memanggilapp.UseDeveloperExceptionPage
diConfigure
.
Halaman pengecualian pengembang berjalan lebih awal di alur middleware, sehingga dapat menangkap pengecualian yang tidak tertangani yang dilemparkan dalam middleware yang mengikuti.
Informasi pengecualian terperinci tidak boleh ditampilkan secara publik saat aplikasi berjalan di lingkungan Produksi. Untuk informasi selengkapnya tentang mengonfigurasi lingkungan, lihat Menggunakan beberapa lingkungan di ASP.NET Core.
Halaman Pengecualian Pengembang dapat menyertakan informasi berikut tentang pengecualian dan permintaan:
- Pelacakan tumpukan
- Parameter string kueri, jika ada
- Cookie, jika ada
- Header
Halaman Pengecualian Pengembang tidak dijamin untuk memberikan informasi apa pun. Gunakan Pengelogan untuk informasi kesalahan lengkap.
Halaman handler pengecualian
Untuk mengonfigurasi halaman penanganan kesalahan kustom untuk lingkungan Produksi, panggil UseExceptionHandler. Middleware penanganan pengecualian ini:
- Menangkap dan mencatat pengecualian yang tidak tertangani.
- Menjalankan kembali permintaan dalam alur alternatif menggunakan jalur yang ditunjukkan. Permintaan tidak dijalankan kembali jika respons telah dimulai. Kode yang dihasilkan templat menjalankan kembali permintaan menggunakan
/Error
jalur .
Peringatan
Jika alur alternatif melemparkan pengecualian sendiri, Exception Handling Middleware akan memunculkan kembali pengecualian asli.
Dalam contoh berikut, UseExceptionHandler menambahkan middleware penanganan pengecualian di lingkungan non-Pengembangan:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Razor Templat aplikasi Halaman menyediakan halaman Kesalahan (.cshtml
) dan PageModel kelas (ErrorModel
) di folder Halaman. Untuk aplikasi MVC, templat proyek menyertakan Error
metode tindakan dan tampilan Kesalahan untuk Home pengontrol.
Middleware penanganan pengecualian menjalankan kembali permintaan menggunakan metode HTTP asli . Jika titik akhir handler kesalahan dibatasi untuk sekumpulan metode HTTP tertentu, titik akhir hanya berjalan untuk metode HTTP tersebut. Misalnya, tindakan pengontrol MVC yang menggunakan [HttpGet]
atribut hanya berjalan untuk permintaan GET. Untuk memastikan bahwa semua permintaan mencapai halaman penanganan kesalahan kustom, jangan batasi ke sekumpulan metode HTTP tertentu.
Untuk menangani pengecualian secara berbeda berdasarkan metode HTTP asli:
- Untuk Razor Pages, buat beberapa metode handler. Misalnya, gunakan
OnGet
untuk menangani pengecualian GET dan gunakanOnPost
untuk menangani pengecualian POST. - Untuk MVC, terapkan atribut kata kerja HTTP ke beberapa tindakan. Misalnya, gunakan
[HttpGet]
untuk menangani pengecualian GET dan gunakan[HttpPost]
untuk menangani pengecualian POST.
Untuk mengizinkan pengguna yang tidak diaturentikasi untuk melihat halaman penanganan kesalahan kustom, pastikan pengguna tersebut mendukung akses anonim.
Mengakses pengecualian
Gunakan IExceptionHandlerPathFeature untuk mengakses pengecualian dan jalur permintaan asli dalam penangan kesalahan. Contoh berikut menggunakan IExceptionHandlerPathFeature
untuk mendapatkan informasi selengkapnya tentang pengecualian yang dilemparkan:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Penangan pengecualian lambda
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan sebelum mengembalikan respons.
Kode berikut menggunakan lambda untuk penanganan pengecualian:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
GunakanStatusCodePages
Secara default, aplikasi ASP.NET Core tidak menyediakan halaman kode status untuk kode status kesalahan HTTP, seperti 404 - Tidak Ditemukan. Saat aplikasi menetapkan kode status kesalahan HTTP 400-599 yang tidak memiliki isi, aplikasi mengembalikan kode status dan isi respons kosong. Untuk mengaktifkan penangan teks-saja default untuk kode status kesalahan umum, panggil UseStatusCodePages di Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Panggil UseStatusCodePages
sebelum meminta penanganan middleware. Misalnya, panggil UseStatusCodePages
sebelum Middleware File Statis dan Middleware Titik Akhir.
Saat UseStatusCodePages
tidak digunakan, menavigasi ke URL tanpa titik akhir mengembalikan pesan kesalahan yang bergantung pada browser yang menunjukkan titik akhir tidak dapat ditemukan. Ketika UseStatusCodePages
dipanggil, browser mengembalikan respons berikut:
Status Code: 404; Not Found
UseStatusCodePages
biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
Catatan
Halaman kode status middleware tidak menangkap pengecualian. Untuk menyediakan halaman penanganan kesalahan kustom, gunakan halaman handler pengecualian.
GunakanStatusCodePages dengan string format
Untuk mengkustomisasi tipe konten respons dan teks, gunakan kelebihan beban UseStatusCodePages yang mengambil tipe konten dan format string:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Dalam kode sebelumnya, {0}
adalah tempat penampung untuk kode kesalahan.
UseStatusCodePages
dengan string format biasanya tidak digunakan dalam produksi karena menampilkan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePages dengan lambda
Untuk menentukan penanganan kesalahan kustom dan kode penulisan respons, gunakan kelebihan beban UseStatusCodePages yang mengambil ekspresi lambda:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
dengan lambda biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
GunakanStatusCodePagesWithRedirects
Metode UseStatusCodePagesWithRedirects ekstensi:
- Mengirim kode status 302 - Ditemukan ke klien.
- Mengalihkan klien ke titik akhir penanganan kesalahan yang disediakan dalam templat URL. Titik akhir penanganan kesalahan biasanya menampilkan informasi kesalahan dan mengembalikan HTTP 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Templat URL dapat menyertakan {0}
tempat penampung untuk kode status, seperti yang ditunjukkan dalam kode sebelumnya. Jika templat URL dimulai dengan ~
(tilde), ~
digantikan oleh aplikasi PathBase
. Saat menentukan titik akhir di aplikasi, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan saat aplikasi:
- Harus mengalihkan klien ke titik akhir yang berbeda, biasanya dalam kasus di mana aplikasi yang berbeda memproses kesalahan. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang dialihkan.
- Tidak boleh mempertahankan dan mengembalikan kode status asli dengan respons pengalihan awal.
GunakanStatusCodePagesWithReExecute
Metode UseStatusCodePagesWithReExecute ekstensi:
- Mengembalikan kode status asli ke klien.
- Menghasilkan isi respons dengan mengeksekusi ulang alur permintaan menggunakan jalur alternatif.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Jika titik akhir dalam aplikasi ditentukan, buat tampilan atau Razor halaman MVC untuk titik akhir.
Metode ini umumnya digunakan ketika aplikasi harus:
- Proses permintaan tanpa mengalihkan ke titik akhir yang berbeda. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang awalnya diminta.
- Pertahankan dan kembalikan kode status asli dengan respons.
Templat URL harus dimulai dengan /
dan dapat menyertakan tempat penampung {0}
untuk kode status. Untuk meneruskan kode status sebagai parameter string kueri, teruskan argumen kedua ke dalam UseStatusCodePagesWithReExecute
. Contohnya:
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Titik akhir yang memproses kesalahan bisa mendapatkan URL asli yang menghasilkan kesalahan, seperti yang ditunjukkan dalam contoh berikut:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = string.Join(
statusCodeReExecuteFeature.OriginalPathBase,
statusCodeReExecuteFeature.OriginalPath,
statusCodeReExecuteFeature.OriginalQueryString);
}
}
}
Menonaktifkan halaman kode status
Untuk menonaktifkan halaman kode status untuk pengontrol MVC atau metode tindakan, gunakan atribut [SkipStatusCodePages ].
Untuk menonaktifkan halaman kode status untuk permintaan tertentu dalam Razor metode handler Pages atau di pengontrol MVC, gunakan IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kode penanganan pengecualian
Kode dalam halaman penanganan pengecualian juga dapat melemparkan pengecualian. Halaman kesalahan produksi harus diuji secara menyeluruh dan berhati-hatilah untuk menghindari melempar pengecualian sendiri.
Header respons
Setelah header untuk respons dikirim:
- Aplikasi tidak dapat mengubah kode status respons.
- Halaman pengecualian atau handler apa pun tidak dapat dijalankan. Respons harus diselesaikan atau koneksi dibatalkan.
Penanganan pengecualian server
Selain logika penanganan pengecualian dalam aplikasi, implementasi server HTTP dapat menangani beberapa pengecualian. Jika server menangkap pengecualian sebelum header respons dikirim, server mengirim 500 - Internal Server Error
respons tanpa isi respons. Jika server menangkap pengecualian setelah header respons dikirim, server menutup koneksi. Permintaan yang tidak ditangani oleh aplikasi ditangani oleh server. Pengecualian apa pun yang terjadi ketika server menangani permintaan ditangani oleh penanganan pengecualian server. Halaman kesalahan kustom aplikasi, middleware penanganan pengecualian, dan filter tidak memengaruhi perilaku ini.
Penanganan pengecualian startup
Hanya lapisan hosting yang dapat menangani pengecualian yang terjadi selama startup aplikasi. Host dapat dikonfigurasi untuk menangkap kesalahan startup dan menangkap kesalahan terperinci.
Lapisan hosting dapat menampilkan halaman kesalahan untuk kesalahan startup yang diambil hanya jika kesalahan terjadi setelah alamat host/pengikatan port. Jika pengikatan gagal:
- Lapisan hosting mencatat pengecualian penting.
- Proses dotnet mengalami crash.
- Tidak ada halaman kesalahan yang ditampilkan ketika server HTTP adalah Kestrel.
Saat berjalan di IIS (atau Azure App Service) atau IIS Express, 502.5 - Kegagalan Proses dikembalikan oleh Modul Inti ASP.NET jika proses tidak dapat dimulai. Untuk informasi selengkapnya, lihat Memecahkan masalah ASP.NET Core di Azure App Service dan IIS.
Halaman kesalahan database
Filter AddDatabaseDeveloperPageExceptionFilter pengecualian halaman pengembang Database menangkap pengecualian terkait database yang dapat diselesaikan dengan menggunakan migrasi Entity Framework Core. Ketika pengecualian ini terjadi, respons HTML dihasilkan dengan detail kemungkinan tindakan untuk menyelesaikan masalah. Halaman ini hanya diaktifkan di lingkungan Pengembangan. Kode berikut menambahkan filter pengecualian halaman pengembang Database:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filter pengecualian
Di aplikasi MVC, filter pengecualian dapat dikonfigurasi secara global atau berdasarkan per pengontrol atau per tindakan. Di Razor aplikasi Pages, aplikasi tersebut dapat dikonfigurasi secara global atau per model halaman. Filter ini menangani pengecualian yang tidak tertangani yang terjadi selama eksekusi tindakan pengontrol atau filter lain. Untuk informasi selengkapnya, lihat Filter di ASP.NET Core.
Filter pengecualian berguna untuk menjebak pengecualian yang terjadi dalam tindakan MVC, tetapi tidak fleksibel seperti middleware penanganan pengecualian bawaan, UseExceptionHandler. Sebaiknya gunakan UseExceptionHandler
, kecuali Anda perlu melakukan penanganan kesalahan secara berbeda berdasarkan tindakan MVC mana yang dipilih.
Kesalahan status model
Untuk informasi tentang cara menangani kesalahan status model, lihat Pengikatan model dan Validasi model.
Sumber Daya Tambahan:
Oleh Kirk Larkin, Tom Dykstra, dan Steve Smith
Artikel ini membahas pendekatan umum untuk menangani kesalahan di aplikasi web ASP.NET Core. Lihat Menangani kesalahan di API web berbasis pengontrol inti ASP.NET untuk API web.
Melihat atau mengunduh kode sampel. (Cara mengunduh.) Tab jaringan pada alat pengembang browser F12 berguna saat menguji aplikasi sampel.
Halaman Pengecualian Pengembang
Halaman Pengecualian Pengembang menampilkan informasi terperinci tentang pengecualian permintaan yang tidak tertangani. Templat ASP.NET Core menghasilkan kode berikut:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Kode yang disorot sebelumnya memungkinkan halaman pengecualian pengembang saat aplikasi berjalan di lingkungan Pengembangan.
Templat ditempatkan UseDeveloperExceptionPage di awal alur middleware sehingga dapat menangkap pengecualian yang tidak tertangani yang dilemparkan dalam middleware yang mengikuti.
Kode sebelumnya memungkinkan Halaman Pengecualian Pengembang hanya saat aplikasi berjalan di lingkungan Pengembangan. Informasi pengecualian terperinci tidak boleh ditampilkan secara publik saat aplikasi berjalan di lingkungan Produksi. Untuk informasi selengkapnya tentang mengonfigurasi lingkungan, lihat Menggunakan beberapa lingkungan di ASP.NET Core.
Halaman Pengecualian Pengembang dapat menyertakan informasi berikut tentang pengecualian dan permintaan:
- Pelacakan tumpukan
- Parameter string kueri jika ada
- Cookie jika ada
- Header
Halaman Pengecualian Pengembang tidak dijamin untuk memberikan informasi apa pun. Gunakan Pengelogan untuk informasi kesalahan lengkap.
Halaman handler pengecualian
Untuk mengonfigurasi halaman penanganan kesalahan kustom untuk lingkungan Produksi, panggil UseExceptionHandler. Middleware penanganan pengecualian ini:
- Menangkap dan mencatat pengecualian yang tidak tertangani.
- Menjalankan kembali permintaan dalam alur alternatif menggunakan jalur yang ditunjukkan. Permintaan tidak dijalankan kembali jika respons telah dimulai. Kode yang dihasilkan templat menjalankan kembali permintaan menggunakan
/Error
jalur .
Peringatan
Jika alur alternatif melemparkan pengecualian sendiri, Exception Handling Middleware akan memunculkan kembali pengecualian asli.
Dalam contoh berikut, UseExceptionHandler menambahkan middleware penanganan pengecualian di lingkungan non-Pengembangan:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Razor Templat aplikasi Halaman menyediakan halaman Kesalahan (.cshtml
) dan PageModel kelas (ErrorModel
) di folder Halaman. Untuk aplikasi MVC, templat proyek menyertakan Error
metode tindakan dan tampilan Kesalahan untuk Home pengontrol.
Middleware penanganan pengecualian menjalankan kembali permintaan menggunakan metode HTTP asli . Jika titik akhir handler kesalahan dibatasi untuk sekumpulan metode HTTP tertentu, titik akhir hanya berjalan untuk metode HTTP tersebut. Misalnya, tindakan pengontrol MVC yang menggunakan [HttpGet]
atribut hanya berjalan untuk permintaan GET. Untuk memastikan bahwa semua permintaan mencapai halaman penanganan kesalahan kustom, jangan batasi ke sekumpulan metode HTTP tertentu.
Untuk menangani pengecualian secara berbeda berdasarkan metode HTTP asli:
- Untuk Razor Pages, buat beberapa metode handler. Misalnya, gunakan
OnGet
untuk menangani pengecualian GET dan gunakanOnPost
untuk menangani pengecualian POST. - Untuk MVC, terapkan atribut kata kerja HTTP ke beberapa tindakan. Misalnya, gunakan
[HttpGet]
untuk menangani pengecualian GET dan gunakan[HttpPost]
untuk menangani pengecualian POST.
Untuk mengizinkan pengguna yang tidak diaturentikasi untuk melihat halaman penanganan kesalahan kustom, pastikan pengguna tersebut mendukung akses anonim.
Mengakses pengecualian
Gunakan IExceptionHandlerPathFeature untuk mengakses pengecualian dan jalur permintaan asli dalam penangan kesalahan. Kode berikut menambahkan ExceptionMessage
ke default Pages/Error.cshtml.cs
yang dihasilkan oleh templat ASP.NET Core:
[ResponseCache(Duration=0, Location=ResponseCacheLocation.None, NoStore=true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ExceptionMessage { get; set; }
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "File error thrown";
_logger.LogError(ExceptionMessage);
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
ExceptionMessage += " from home page";
}
}
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Untuk menguji pengecualian di aplikasi sampel:
- Atur lingkungan ke produksi.
- Hapus komentar dari
webBuilder.UseStartup<Startup>();
dalamProgram.cs
. - Pilih Picu pengecualian di home halaman.
Penangan pengecualian lambda
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan sebelum mengembalikan respons.
Kode berikut menggunakan lambda untuk penanganan pengecualian:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
await context.Response.WriteAsync("ERROR!<br><br>\r\n");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(
"File error thrown!<br><br>\r\n");
}
await context.Response.WriteAsync(
"<a href=\"/\">Home</a><br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
await context.Response.WriteAsync(new string(' ', 512));
});
});
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Peringatan
Jangan melayani informasi kesalahan sensitif dari IExceptionHandlerFeature atau IExceptionHandlerPathFeature ke klien. Melayani kesalahan adalah risiko keamanan.
Untuk menguji penanganan pengecualian lambda di aplikasi sampel:
- Atur lingkungan ke produksi.
- Hapus komentar dari
webBuilder.UseStartup<StartupLambda>();
dalamProgram.cs
. - Pilih Picu pengecualian di home halaman.
GunakanStatusCodePages
Secara default, aplikasi ASP.NET Core tidak menyediakan halaman kode status untuk kode status kesalahan HTTP, seperti 404 - Tidak Ditemukan. Saat aplikasi menetapkan kode status kesalahan HTTP 400-599 yang tidak memiliki isi, aplikasi mengembalikan kode status dan isi respons kosong. Untuk menyediakan halaman kode status, gunakan middleware halaman kode status. Untuk mengaktifkan penangan teks-saja default untuk kode status kesalahan umum, panggil UseStatusCodePages dalam Startup.Configure
metode :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Panggil UseStatusCodePages
sebelum meminta penanganan middleware. Misalnya, panggil UseStatusCodePages
sebelum Middleware File Statis dan Middleware Titik Akhir.
Saat UseStatusCodePages
tidak digunakan, menavigasi ke URL tanpa titik akhir mengembalikan pesan kesalahan yang bergantung pada browser yang menunjukkan titik akhir tidak dapat ditemukan. Misalnya, menavigasi ke Home/Privacy2
. Ketika UseStatusCodePages
dipanggil, browser mengembalikan:
Status Code: 404; Not Found
UseStatusCodePages
biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
Untuk menguji UseStatusCodePages
di aplikasi sampel:
- Atur lingkungan ke produksi.
- Hapus komentar dari
webBuilder.UseStartup<StartupUseStatusCodePages>();
dalamProgram.cs
. - Pilih tautan pada home halaman di home halaman.
Catatan
Halaman kode status middleware tidak menangkap pengecualian. Untuk menyediakan halaman penanganan kesalahan kustom, gunakan halaman handler pengecualian.
GunakanStatusCodePages dengan string format
Untuk mengkustomisasi tipe konten respons dan teks, gunakan kelebihan beban UseStatusCodePages yang mengambil tipe konten dan format string:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Dalam kode sebelumnya, {0}
adalah tempat penampung untuk kode kesalahan.
UseStatusCodePages
dengan string format biasanya tidak digunakan dalam produksi karena menampilkan pesan yang tidak berguna bagi pengguna.
Untuk menguji UseStatusCodePages
di aplikasi sampel, hapus komentar dari webBuilder.UseStartup<StartupFormat>();
dalam Program.cs
.
GunakanStatusCodePages dengan lambda
Untuk menentukan penanganan kesalahan kustom dan kode penulisan respons, gunakan kelebihan beban UseStatusCodePages yang mengambil ekspresi lambda:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
UseStatusCodePages
dengan lambda biasanya tidak digunakan dalam produksi karena mengembalikan pesan yang tidak berguna bagi pengguna.
Untuk menguji UseStatusCodePages
di aplikasi sampel, hapus komentar dari webBuilder.UseStartup<StartupStatusLambda>();
dalam Program.cs
.
GunakanStatusCodePagesWithRedirects
Metode UseStatusCodePagesWithRedirects ekstensi:
- Mengirim kode status 302 - Ditemukan ke klien.
- Mengalihkan klien ke titik akhir penanganan kesalahan yang disediakan dalam templat URL. Titik akhir penanganan kesalahan biasanya menampilkan informasi kesalahan dan mengembalikan HTTP 200.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/MyStatusCode?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Templat URL dapat menyertakan {0}
tempat penampung untuk kode status, seperti yang ditunjukkan dalam kode sebelumnya. Jika templat URL dimulai dengan ~
(tilde), ~
digantikan oleh aplikasi PathBase
. Saat menentukan titik akhir di aplikasi, buat tampilan atau Razor halaman MVC untuk titik akhir. Razor Untuk contoh Halaman, lihat Pages/MyStatusCode.cshtml di aplikasi sampel.
Metode ini umumnya digunakan saat aplikasi:
- Harus mengalihkan klien ke titik akhir yang berbeda, biasanya dalam kasus di mana aplikasi yang berbeda memproses kesalahan. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang dialihkan.
- Tidak boleh mempertahankan dan mengembalikan kode status asli dengan respons pengalihan awal.
Untuk menguji UseStatusCodePages
di aplikasi sampel, hapus komentar dari webBuilder.UseStartup<StartupSCredirect>();
dalam Program.cs
.
GunakanStatusCodePagesWithReExecute
Metode UseStatusCodePagesWithReExecute ekstensi:
- Mengembalikan kode status asli ke klien.
- Menghasilkan isi respons dengan mengeksekusi ulang alur permintaan menggunakan jalur alternatif.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/MyStatusCode2", "?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Jika titik akhir dalam aplikasi ditentukan, buat tampilan atau Razor halaman MVC untuk titik akhir. Pastikan UseStatusCodePagesWithReExecute
ditempatkan sebelumnya UseRouting
sehingga permintaan dapat dialihkan ke halaman status. Razor Untuk contoh Halaman, lihat Pages/MyStatusCode2.cshtml di aplikasi sampel.
Metode ini umumnya digunakan ketika aplikasi harus:
- Proses permintaan tanpa mengalihkan ke titik akhir yang berbeda. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang awalnya diminta.
- Pertahankan dan kembalikan kode status asli dengan respons.
URL dan templat string kueri dapat menyertakan tempat penampung {0}
untuk kode status. Templat URL harus dimulai dengan /
.
Titik akhir yang memproses kesalahan bisa mendapatkan URL asli yang menghasilkan kesalahan, seperti yang ditunjukkan dalam contoh berikut:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class MyStatusCode2Model : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ErrorStatusCode { get; set; }
public string OriginalURL { get; set; }
public bool ShowOriginalURL => !string.IsNullOrEmpty(OriginalURL);
public void OnGet(string code)
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
ErrorStatusCode = code;
var statusCodeReExecuteFeature = HttpContext.Features.Get<
IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
}
}
Razor Untuk contoh Halaman, lihat Pages/MyStatusCode2.cshtml di aplikasi sampel.
Untuk menguji UseStatusCodePages
di aplikasi sampel, hapus komentar dari webBuilder.UseStartup<StartupSCreX>();
dalam Program.cs
.
Menonaktifkan halaman kode status
Untuk menonaktifkan halaman kode status untuk pengontrol MVC atau metode tindakan, gunakan atribut [SkipStatusCodePages ].
Untuk menonaktifkan halaman kode status untuk permintaan tertentu dalam Razor metode handler Pages atau di pengontrol MVC, gunakan IStatusCodePagesFeature:
public void OnGet()
{
// using Microsoft.AspNetCore.Diagnostics;
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kode penanganan pengecualian
Kode dalam halaman penanganan pengecualian juga dapat melemparkan pengecualian. Halaman kesalahan produksi harus diuji secara menyeluruh dan berhati-hatilah untuk menghindari melempar pengecualian sendiri.
Header respons
Setelah header untuk respons dikirim:
- Aplikasi tidak dapat mengubah kode status respons.
- Halaman pengecualian atau handler apa pun tidak dapat dijalankan. Respons harus diselesaikan atau koneksi dibatalkan.
Penanganan pengecualian server
Selain logika penanganan pengecualian dalam aplikasi, implementasi server HTTP dapat menangani beberapa pengecualian. Jika server menangkap pengecualian sebelum header respons dikirim, server mengirim 500 - Internal Server Error
respons tanpa isi respons. Jika server menangkap pengecualian setelah header respons dikirim, server menutup koneksi. Permintaan yang tidak ditangani oleh aplikasi ditangani oleh server. Pengecualian apa pun yang terjadi ketika server menangani permintaan ditangani oleh penanganan pengecualian server. Halaman kesalahan kustom aplikasi, middleware penanganan pengecualian, dan filter tidak memengaruhi perilaku ini.
Penanganan pengecualian startup
Hanya lapisan hosting yang dapat menangani pengecualian yang terjadi selama startup aplikasi. Host dapat dikonfigurasi untuk menangkap kesalahan startup dan menangkap kesalahan terperinci.
Lapisan hosting dapat menampilkan halaman kesalahan untuk kesalahan startup yang diambil hanya jika kesalahan terjadi setelah alamat host/pengikatan port. Jika pengikatan gagal:
- Lapisan hosting mencatat pengecualian penting.
- Proses dotnet mengalami crash.
- Tidak ada halaman kesalahan yang ditampilkan ketika server HTTP adalah Kestrel.
Saat berjalan di IIS (atau Azure App Service) atau IIS Express, 502.5 - Kegagalan Proses dikembalikan oleh Modul Inti ASP.NET jika proses tidak dapat dimulai. Untuk informasi selengkapnya, lihat Memecahkan masalah ASP.NET Core di Azure App Service dan IIS.
Halaman kesalahan database
Filter AddDatabaseDeveloperPageExceptionFilter
pengecualian halaman pengembang Database menangkap pengecualian terkait database yang dapat diselesaikan dengan menggunakan migrasi Entity Framework Core. Ketika pengecualian ini terjadi, respons HTML dihasilkan dengan detail kemungkinan tindakan untuk menyelesaikan masalah. Halaman ini hanya diaktifkan di lingkungan Pengembangan. Kode berikut dihasilkan oleh templat ASP.NET Core Razor Pages saat akun pengguna individual ditentukan:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
}
Filter pengecualian
Di aplikasi MVC, filter pengecualian dapat dikonfigurasi secara global atau berdasarkan per pengontrol atau per tindakan. Di Razor aplikasi Pages, aplikasi tersebut dapat dikonfigurasi secara global atau per model halaman. Filter ini menangani pengecualian yang tidak tertangani yang terjadi selama eksekusi tindakan pengontrol atau filter lain. Untuk informasi selengkapnya, lihat Filter di ASP.NET Core.
Filter pengecualian berguna untuk menjebak pengecualian yang terjadi dalam tindakan MVC, tetapi tidak fleksibel seperti middleware penanganan pengecualian bawaan, UseExceptionHandler
. Sebaiknya gunakan UseExceptionHandler
, kecuali Anda perlu melakukan penanganan kesalahan secara berbeda berdasarkan tindakan MVC mana yang dipilih.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Kesalahan status model
Untuk informasi tentang cara menangani kesalahan status model, lihat Pengikatan model dan Validasi model.
Sumber Daya Tambahan:
Oleh Tom Dykstra, dan Steve Smith
Artikel ini membahas pendekatan umum untuk menangani kesalahan di aplikasi web ASP.NET Core. Lihat Menangani kesalahan di API web berbasis pengontrol inti ASP.NET untuk API web.
Melihat atau mengunduh kode sampel. (Cara mengunduh.)
Halaman Pengecualian Pengembang
Halaman Pengecualian Pengembang menampilkan informasi terperinci tentang pengecualian permintaan. Templat ASP.NET Core menghasilkan kode berikut:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Kode sebelumnya memungkinkan halaman pengecualian pengembang saat aplikasi berjalan di lingkungan Pengembangan.
Tempat templat UseDeveloperExceptionPage sebelum middleware apa pun sehingga pengecualian tertangkap dalam middleware yang mengikuti.
Kode sebelumnya memungkinkan Halaman Pengecualian Pengembang hanya saat aplikasi berjalan di lingkungan Pengembangan. Informasi pengecualian terperinci tidak boleh ditampilkan secara publik saat aplikasi berjalan dalam produksi. Untuk informasi selengkapnya tentang mengonfigurasi lingkungan, lihat Menggunakan beberapa lingkungan di ASP.NET Core.
Halaman Pengecualian Pengembang menyertakan informasi berikut tentang pengecualian dan permintaan:
- Pelacakan tumpukan
- Parameter string kueri jika ada
- Cookie jika ada
- Header
Halaman handler pengecualian
Untuk mengonfigurasi halaman penanganan kesalahan kustom untuk lingkungan Produksi, gunakan Middleware Penanganan Pengecualian. Middleware:
- Menangkap dan mencatat pengecualian.
- Menjalankan kembali permintaan dalam alur alternatif untuk halaman atau pengontrol yang ditunjukkan. Permintaan tidak dijalankan kembali jika respons telah dimulai. Kode yang dihasilkan templat menjalankan kembali permintaan ke
/Error
.
Dalam contoh berikut, UseExceptionHandler menambahkan Middleware Penanganan Pengecualian di lingkungan non-Pengembangan:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Razor Templat aplikasi Halaman menyediakan halaman Kesalahan (.cshtml
) dan PageModel kelas (ErrorModel
) di folder Halaman. Untuk aplikasi MVC, templat proyek menyertakan metode tindakan Kesalahan dan tampilan Kesalahan di Home pengontrol.
Jangan tandai metode tindakan penangan kesalahan dengan atribut metode HTTP, seperti HttpGet
. Kata kerja eksplisit mencegah beberapa permintaan mencapai metode . Izinkan akses anonim ke metode jika pengguna yang tidak diaturentikasi akan melihat tampilan kesalahan.
Mengakses pengecualian
Gunakan IExceptionHandlerPathFeature untuk mengakses pengecualian dan jalur permintaan asli di pengontrol atau halaman penangan kesalahan:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "File error thrown";
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
ExceptionMessage += " from home page";
}
}
}
Peringatan
Jangan melayani informasi kesalahan sensitif kepada klien. Melayani kesalahan adalah risiko keamanan.
Untuk memicu halaman penanganan pengecualian sebelumnya, atur lingkungan ke produksi dan paksa pengecualian.
Penangan pengecualian lambda
Alternatif untuk halaman handler pengecualian kustom adalah menyediakan lambda ke UseExceptionHandler. Menggunakan lambda memungkinkan akses ke kesalahan sebelum mengembalikan respons.
Berikut adalah contoh penggunaan lambda untuk penanganan pengecualian:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
await context.Response.WriteAsync("ERROR!<br><br>\r\n");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
}
await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
await context.Response.WriteAsync(new string(' ', 512)); // IE padding
});
});
app.UseHsts();
}
Dalam kode sebelumnya, await context.Response.WriteAsync(new string(' ', 512));
ditambahkan sehingga browser Internet Explorer menampilkan pesan kesalahan daripada pesan kesalahan IE. Untuk informasi lebih lanjut, lihat masalah GitHub ini.
Peringatan
Jangan melayani informasi kesalahan sensitif dari IExceptionHandlerFeature atau IExceptionHandlerPathFeature ke klien. Melayani kesalahan adalah risiko keamanan.
Untuk melihat hasil penanganan pengecualian lambda di aplikasi sampel, gunakan ProdEnvironment
arahan prapemrossor dan ErrorHandlerLambda
, dan pilih Picu pengecualian di home halaman.
GunakanStatusCodePages
Secara default, aplikasi ASP.NET Core tidak menyediakan halaman kode status untuk kode status HTTP, seperti 404 - Tidak Ditemukan. Aplikasi mengembalikan kode status dan isi respons kosong. Untuk menyediakan halaman kode status, gunakan middleware Halaman Kode Status.
Middleware tersedia oleh paket Microsoft.AspNetCore.Diagnostics .
Untuk mengaktifkan penangan teks-saja default untuk kode status kesalahan umum, panggil UseStatusCodePages dalam Startup.Configure
metode :
app.UseStatusCodePages();
Panggil UseStatusCodePages
sebelum meminta penanganan middleware (misalnya, Middleware File Statis dan Middleware MVC).
Saat UseStatusCodePages
tidak digunakan, menavigasi ke URL tanpa titik akhir mengembalikan pesan kesalahan dependen browser yang menunjukkan titik akhir tidak dapat ditemukan. Misalnya, menavigasi ke Home/Privacy2
. Ketika UseStatusCodePages
dipanggil, browser mengembalikan:
Status Code: 404; Not Found
GunakanStatusCodePages dengan string format
Untuk mengkustomisasi tipe konten respons dan teks, gunakan kelebihan beban UseStatusCodePages yang mengambil tipe konten dan format string:
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
GunakanStatusCodePages dengan lambda
Untuk menentukan penanganan kesalahan kustom dan kode penulisan respons, gunakan kelebihan beban UseStatusCodePages yang mengambil ekspresi lambda:
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
GunakanStatusCodePagesWithRedirects
Metode UseStatusCodePagesWithRedirects ekstensi:
- Mengirim kode status 302 - Ditemukan ke klien.
- Mengalihkan klien ke lokasi yang disediakan dalam templat URL.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");
Templat URL dapat menyertakan {0}
tempat penampung untuk kode status, seperti yang ditunjukkan dalam contoh. Jika templat URL dimulai dengan ~
(tilde), ~
digantikan oleh aplikasi PathBase
. Jika Anda mengarahkan ke titik akhir dalam aplikasi, buat tampilan atau Razor halaman MVC untuk titik akhir. Razor Untuk contoh Halaman, lihat Pages/StatusCode.cshtml
di aplikasi sampel.
Metode ini umumnya digunakan saat aplikasi:
- Harus mengalihkan klien ke titik akhir yang berbeda, biasanya dalam kasus di mana aplikasi yang berbeda memproses kesalahan. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang dialihkan.
- Tidak boleh mempertahankan dan mengembalikan kode status asli dengan respons pengalihan awal.
GunakanStatusCodePagesWithReExecute
Metode UseStatusCodePagesWithReExecute ekstensi:
- Mengembalikan kode status asli ke klien.
- Menghasilkan isi respons dengan mengeksekusi ulang alur permintaan menggunakan jalur alternatif.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");
Jika Anda mengarahkan ke titik akhir dalam aplikasi, buat tampilan atau Razor halaman MVC untuk titik akhir. Pastikan UseStatusCodePagesWithReExecute
ditempatkan sebelumnya UseRouting
sehingga permintaan dapat dialihkan ke halaman status. Razor Untuk contoh Halaman, lihat Pages/StatusCode.cshtml
di aplikasi sampel.
Metode ini umumnya digunakan ketika aplikasi harus:
- Proses permintaan tanpa mengalihkan ke titik akhir yang berbeda. Untuk aplikasi web, bilah alamat browser klien mencerminkan titik akhir yang awalnya diminta.
- Pertahankan dan kembalikan kode status asli dengan respons.
URL dan templat string kueri dapat menyertakan tempat penampung ({0}
) untuk kode status. Templat URL harus dimulai dengan garis miring (/
). Saat menggunakan tempat penampung di jalur, konfirmasikan bahwa titik akhir (halaman atau pengontrol) dapat memproses segmen jalur. Misalnya, Razor Halaman untuk kesalahan harus menerima nilai segmen jalur opsional dengan direktif @page
:
@page "{code?}"
Titik akhir yang memproses kesalahan bisa mendapatkan URL asli yang menghasilkan kesalahan, seperti yang ditunjukkan dalam contoh berikut:
var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
Jangan tandai metode tindakan penangan kesalahan dengan atribut metode HTTP, seperti HttpGet
. Kata kerja eksplisit mencegah beberapa permintaan mencapai metode . Izinkan akses anonim ke metode jika pengguna yang tidak diaturentikasi akan melihat tampilan kesalahan.
Menonaktifkan halaman kode status
Untuk menonaktifkan halaman kode status untuk pengontrol MVC atau metode tindakan, gunakan [SkipStatusCodePages]
atribut .
Untuk menonaktifkan halaman kode status untuk permintaan tertentu dalam Razor metode handler Pages atau di pengontrol MVC, gunakan IStatusCodePagesFeature:
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
Kode penanganan pengecualian
Kode dalam halaman penanganan pengecualian dapat melemparkan pengecualian. Sering kali merupakan ide yang baik untuk halaman kesalahan produksi terdiri dari konten statis murni.
Header respons
Setelah header untuk respons dikirim:
- Aplikasi tidak dapat mengubah kode status respons.
- Halaman pengecualian atau handler apa pun tidak dapat dijalankan. Respons harus diselesaikan atau koneksi dibatalkan.
Penanganan pengecualian server
Selain logika penanganan pengecualian di aplikasi Anda, implementasi server HTTP dapat menangani beberapa pengecualian. Jika server menangkap pengecualian sebelum header respons dikirim, server mengirimkan respons 500 - Kesalahan Server Internal tanpa isi respons. Jika server menangkap pengecualian setelah header respons dikirim, server menutup koneksi. Permintaan yang tidak ditangani oleh aplikasi Anda ditangani oleh server. Pengecualian apa pun yang terjadi ketika server menangani permintaan ditangani oleh penanganan pengecualian server. Halaman kesalahan kustom aplikasi, middleware penanganan pengecualian, dan filter tidak memengaruhi perilaku ini.
Penanganan pengecualian startup
Hanya lapisan hosting yang dapat menangani pengecualian yang terjadi selama startup aplikasi. Host dapat dikonfigurasi untuk menangkap kesalahan startup dan menangkap kesalahan terperinci.
Lapisan hosting dapat menampilkan halaman kesalahan untuk kesalahan startup yang diambil hanya jika kesalahan terjadi setelah alamat host/pengikatan port. Jika pengikatan gagal:
- Lapisan hosting mencatat pengecualian penting.
- Proses dotnet mengalami crash.
- Tidak ada halaman kesalahan yang ditampilkan ketika server HTTP adalah Kestrel.
Saat berjalan di IIS (atau Azure App Service) atau IIS Express, 502.5 - Kegagalan Proses dikembalikan oleh Modul Inti ASP.NET jika proses tidak dapat dimulai. Untuk informasi selengkapnya, lihat Memecahkan masalah ASP.NET Core di Azure App Service dan IIS.
Halaman kesalahan database
Middleware Halaman Kesalahan Database menangkap pengecualian terkait database yang dapat diselesaikan dengan menggunakan migrasi Kerangka Kerja Entitas. Ketika pengecualian ini terjadi, respons HTML dengan detail kemungkinan tindakan untuk menyelesaikan masalah dihasilkan. Halaman ini harus diaktifkan hanya di lingkungan Pengembangan. Aktifkan halaman dengan menambahkan kode ke Startup.Configure
:
if (env.IsDevelopment())
{
app.UseDatabaseErrorPage();
}
UseDatabaseErrorPagememerlukan paket NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.
Filter pengecualian
Di aplikasi MVC, filter pengecualian dapat dikonfigurasi secara global atau berdasarkan per pengontrol atau per tindakan. Di Razor aplikasi Pages, aplikasi tersebut dapat dikonfigurasi secara global atau per model halaman. Filter ini menangani pengecualian yang tidak tertangani yang terjadi selama eksekusi tindakan pengontrol atau filter lain. Untuk informasi selengkapnya, lihat Filter di ASP.NET Core.
Tip
Filter pengecualian berguna untuk menjebak pengecualian yang terjadi dalam tindakan MVC, tetapi tidak fleksibel seperti Middleware Penanganan Pengecualian. Sebaiknya gunakan middleware. Gunakan filter hanya di mana Anda perlu melakukan penanganan kesalahan secara berbeda berdasarkan tindakan MVC mana yang dipilih.
Kesalahan status model
Untuk informasi tentang cara menangani kesalahan status model, lihat Pengikatan model dan Validasi model.
Sumber Daya Tambahan:
ASP.NET Core