Menangani kesalahan di API web berbasis pengontrol inti ASP.NET
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.
Artikel ini menjelaskan cara menangani kesalahan dan menyesuaikan penanganan kesalahan di API web ASP.NET Core berbasis pengontrol. Untuk informasi tentang penanganan kesalahan dalam API minimal, lihat Menangani kesalahan di ASP.NET Core dan Menangani kesalahan dalam API minimal.
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
Untuk melihat Halaman Pengecualian Pengembang:
Tambahkan tindakan pengontrol berikut ke API berbasis pengontrol. Tindakan melemparkan pengecualian saat titik akhir diminta.
[HttpGet("Throw")] public IActionResult Throw() => throw new Exception("Sample exception.");
Jalankan aplikasi di lingkungan pengembangan.
Buka titik akhir yang ditentukan oleh tindakan pengontrol.
Handler pengecualian
Di lingkungan non-pengembangan, gunakan Middleware Penanganan Pengecualian untuk menghasilkan payload kesalahan:
Di
Program.cs
, panggil UseExceptionHandler untuk menambahkan Middleware Penanganan Pengecualian:var app = builder.Build(); app.UseHttpsRedirection(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/error"); } app.UseAuthorization(); app.MapControllers(); app.Run();
Konfigurasikan tindakan pengontrol untuk merespons
/error
rute:[Route("/error")] public IActionResult HandleError() => Problem();
Tindakan sebelumnya HandleError
mengirimkan payload yang mematuhi RFC 7807 ke klien.
Peringatan
Jangan tandai metode tindakan penangan kesalahan dengan atribut metode HTTP, seperti HttpGet
. Kata kerja eksplisit mencegah beberapa permintaan mencapai metode tindakan.
Untuk API web yang menggunakan Swagger / OpenAPI, tandai tindakan handler kesalahan dengan atribut [ApiExplorerSettings] dan atur propertinya IgnoreApi ke true
. Konfigurasi atribut ini mengecualikan tindakan penanganan kesalahan dari spesifikasi OpenAPI aplikasi:
[ApiExplorerSettings(IgnoreApi = true)]
Izinkan akses anonim ke metode jika pengguna yang tidak diaturentikasi akan melihat kesalahan.
Middleware Penanganan Pengecualian juga dapat digunakan di lingkungan Pengembangan untuk menghasilkan format payload yang konsisten di semua lingkungan:
Dalam
Program.cs
, daftarkan instans Middleware Penanganan Pengecualian khusus lingkungan:if (app.Environment.IsDevelopment()) { app.UseExceptionHandler("/error-development"); } else { app.UseExceptionHandler("/error"); }
Dalam kode sebelumnya, middleware terdaftar dengan:
- Rute
/error-development
di lingkungan Pengembangan. - Rute
/error
di lingkungan non-Pengembangan.
- Rute
Tambahkan tindakan pengontrol untuk rute Pengembangan dan non-Pengembangan:
[Route("/error-development")] public IActionResult HandleErrorDevelopment( [FromServices] IHostEnvironment hostEnvironment) { if (!hostEnvironment.IsDevelopment()) { return NotFound(); } var exceptionHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>()!; return Problem( detail: exceptionHandlerFeature.Error.StackTrace, title: exceptionHandlerFeature.Error.Message); } [Route("/error")] public IActionResult HandleError() => Problem();
Gunakan pengecualian untuk mengubah respons
Konten respons dapat dimodifikasi dari luar pengontrol menggunakan pengecualian kustom dan filter tindakan:
Buat jenis pengecualian terkenal bernama
HttpResponseException
:public class HttpResponseException : Exception { public HttpResponseException(int statusCode, object? value = null) => (StatusCode, Value) = (statusCode, value); public int StatusCode { get; } public object? Value { get; } }
Buat filter tindakan bernama
HttpResponseExceptionFilter
:public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter { public int Order => int.MaxValue - 10; public void OnActionExecuting(ActionExecutingContext context) { } public void OnActionExecuted(ActionExecutedContext context) { if (context.Exception is HttpResponseException httpResponseException) { context.Result = new ObjectResult(httpResponseException.Value) { StatusCode = httpResponseException.StatusCode }; context.ExceptionHandled = true; } } }
Filter sebelumnya menentukan
Order
nilai bilangan bulat maksimum dikurangi 10. IniOrder
memungkinkan filter lain berjalan di akhir alur.Di
Program.cs
, tambahkan filter tindakan ke kumpulan filter:builder.Services.AddControllers(options => { options.Filters.Add<HttpResponseExceptionFilter>(); });
Respons kesalahan kegagalan validasi
Untuk pengontrol API web, MVC merespons dengan ValidationProblemDetails jenis respons saat validasi model gagal. MVC menggunakan hasil InvalidModelStateResponseFactory untuk membangun respons kesalahan untuk kegagalan validasi. Contoh berikut mengganti pabrik default dengan implementasi yang juga mendukung respons pemformatan sebagai XML, di Program.cs
:
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
new BadRequestObjectResult(context.ModelState)
{
ContentTypes =
{
// using static System.Net.Mime.MediaTypeNames;
Application.Json,
Application.Xml
}
};
})
.AddXmlSerializerFormatters();
Respons kesalahan klien
Hasil kesalahan didefinisikan sebagai hasilnya dengan kode status HTTP 400 atau lebih tinggi. Untuk pengontrol API web, MVC mengubah hasil kesalahan untuk menghasilkan ProblemDetails.
Pembuatan ProblemDetails
otomatis untuk kode status kesalahan diaktifkan secara default, tetapi respons kesalahan dapat dikonfigurasi dengan salah satu cara berikut:
- Menggunakan layanan detail masalah
- Menerapkan ProblemDetailsFactory
- Menggunakan ApiBehaviorOptions.ClientErrorMapping
Respons detail masalah default
File berikut Program.cs
dihasilkan oleh templat aplikasi web untuk pengontrol API:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Pertimbangkan pengontrol berikut, yang mengembalikan BadRequest ketika input tidak valid:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values2Controller : ControllerBase
{
// /api/values2/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values2 /squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Respons detail masalah dihasilkan dengan kode sebelumnya ketika salah satu kondisi berikut berlaku:
- Titik
/api/values2/divide
akhir dipanggil dengan penyebut nol. - Titik
/api/values2/squareroot
akhir dipanggil dengan radicand kurang dari nol.
Isi respons detail masalah default memiliki nilai , , title
dan status
berikuttype
:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"traceId": "00-84c1fd4063c38d9f3900d06e56542d48-85d1d4-00"
}
Layanan detail masalah
ASP.NET Core mendukung pembuatan Detail Masalah untuk API HTTP menggunakan IProblemDetailsService. Untuk informasi selengkapnya, lihat layanan Detail masalah.
Kode berikut mengonfigurasi aplikasi untuk menghasilkan respons detail masalah untuk semua respons kesalahan klien HTTP dan server yang belum memiliki konten isi:
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();
Pertimbangkan pengontrol API dari bagian sebelumnya, yang mengembalikan BadRequest ketika input tidak valid:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values2Controller : ControllerBase
{
// /api/values2/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values2 /squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Respons detail masalah dihasilkan dengan kode sebelumnya ketika salah satu kondisi berikut berlaku:
- Input yang tidak valid disediakan.
- URI tidak memiliki titik akhir yang cocok.
- Terjadi pengecualian yang tidak tertangani.
Pembuatan ProblemDetails
otomatis untuk kode status kesalahan dinonaktifkan saat properti SuppressMapClientErrors diatur ke true
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressMapClientErrors = true;
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Menggunakan kode sebelumnya, ketika pengontrol API mengembalikan BadRequest
, status respons HTTP 400 dikembalikan tanpa isi respons. SuppressMapClientErrors
ProblemDetails
mencegah respons dibuat, bahkan saat memanggil WriteAsync
titik akhir PENGONTROL API. WriteAsync
dijelaskan kemudian dalam artikel ini.
Bagian berikutnya menunjukkan cara menyesuaikan isi respons detail masalah, menggunakan CustomizeProblemDetails, untuk mengembalikan respons yang lebih membantu. Untuk opsi penyesuaian lainnya, lihat Menyesuaikan detail masalah.
Menyesuaikan detail masalah dengan CustomizeProblemDetails
Kode berikut menggunakan ProblemDetailsOptions untuk mengatur CustomizeProblemDetails:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = (context) =>
{
var mathErrorFeature = context.HttpContext.Features
.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError =>
("Divison by zero is not defined.",
"https://wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://wikipedia.org/wiki/Square_root")
};
context.ProblemDetails.Type = details.Type;
context.ProblemDetails.Title = "Bad Input";
context.ProblemDetails.Detail = details.Detail;
}
}
);
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
app.UseAuthorization();
app.MapControllers();
app.Run();
Pengontrol API yang diperbarui:
[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));
}
}
Kode berikut berisi MathErrorFeature
dan MathErrorType
, yang digunakan dengan sampel sebelumnya:
// Custom Http Request Feature
class MathErrorFeature
{
public MathErrorType MathError { get; set; }
}
// Custom math errors
enum MathErrorType
{
DivisionByZeroError,
NegativeRadicandError
}
Respons detail masalah dihasilkan dengan kode sebelumnya ketika salah satu kondisi berikut berlaku:
- Titik
/divide
akhir dipanggil dengan penyebut nol. - Titik
/squareroot
akhir dipanggil dengan radicand kurang dari nol. - URI tidak memiliki titik akhir yang cocok.
Isi respons detail masalah berisi hal berikut ketika salah satu squareroot
titik akhir dipanggil dengan radicand kurang dari nol:
{
"type": "https://en.wikipedia.org/wiki/Square_root",
"title": "Bad Input",
"status": 400,
"detail": "Negative or complex numbers are not allowed."
}
Menampilkan atau mengunduh kode sampel
Alat ProblemDetailsFactory
MVC menggunakan Microsoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory untuk menghasilkan semua instans ProblemDetails dan ValidationProblemDetails. Pabrik ini digunakan untuk:
- Respons kesalahan klien
- Respons kesalahan kegagalan validasi
- ControllerBase.Problem dan ControllerBase.ValidationProblem
Untuk menyesuaikan respons detail masalah, daftarkan implementasi ProblemDetailsFactory kustom di Program.cs
:
builder.Services.AddControllers();
builder.Services.AddTransient<ProblemDetailsFactory, SampleProblemDetailsFactory>();
Menggunakan ApiBehaviorOptions.ClientErrorMapping
ClientErrorMapping Gunakan properti untuk mengonfigurasi konten ProblemDetails
respons. Misalnya, kode berikut dalam Program.cs
memperbarui Link properti untuk 404 respons:
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
"https://httpstatuses.com/404";
});
Sumber Daya Tambahan:
Artikel ini menjelaskan cara menangani kesalahan dan menyesuaikan penanganan kesalahan dengan API web ASP.NET Core.
Halaman Pengecualian Pengembang
Halaman Pengecualian Pengembang memperlihatkan jejak tumpukan terperinci untuk kesalahan server. Ini menggunakan DeveloperExceptionPageMiddleware untuk menangkap pengecualian sinkron dan asinkron dari alur HTTP dan untuk menghasilkan respons kesalahan. Misalnya, pertimbangkan tindakan pengontrol berikut, yang melemparkan pengecualian:
[HttpGet("Throw")]
public IActionResult Throw() =>
throw new Exception("Sample exception.");
Saat Halaman Pengecualian Pengembang mendeteksi pengecualian yang tidak tertangani, Halaman tersebut menghasilkan respons teks biasa default yang mirip dengan contoh berikut:
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
System.Exception: Sample exception.
at HandleErrorsSample.Controllers.ErrorsController.Get() in ...
at lambda_method1(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
...
Jika klien meminta respons berformat HTML, Halaman Pengecualian Pengembang menghasilkan respons yang mirip dengan contoh berikut:
HTTP/1.1 500 Internal Server Error
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Internal Server Error</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;
font-size: .813em;
color: #222;
background-color: #fff;
}
h1 {
color: #44525e;
margin: 15px 0 15px 0;
}
...
Untuk meminta respons berformat HTML, atur Accept
header permintaan HTTP ke text/html
.
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.
Handler pengecualian
Di lingkungan non-pengembangan, gunakan Middleware Penanganan Pengecualian untuk menghasilkan payload kesalahan:
Di
Program.cs
, panggil UseExceptionHandler untuk menambahkan Middleware Penanganan Pengecualian:var app = builder.Build(); app.UseHttpsRedirection(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/error"); } app.UseAuthorization(); app.MapControllers(); app.Run();
Konfigurasikan tindakan pengontrol untuk merespons
/error
rute:[Route("/error")] public IActionResult HandleError() => Problem();
Tindakan sebelumnya HandleError
mengirimkan payload yang mematuhi RFC 7807 ke klien.
Peringatan
Jangan tandai metode tindakan penangan kesalahan dengan atribut metode HTTP, seperti HttpGet
. Kata kerja eksplisit mencegah beberapa permintaan mencapai metode tindakan.
Untuk API web yang menggunakan Swagger / OpenAPI, tandai tindakan handler kesalahan dengan atribut [ApiExplorerSettings] dan atur propertinya IgnoreApi ke true
. Konfigurasi atribut ini mengecualikan tindakan penanganan kesalahan dari spesifikasi OpenAPI aplikasi:
[ApiExplorerSettings(IgnoreApi = true)]
Izinkan akses anonim ke metode jika pengguna yang tidak diaturentikasi akan melihat kesalahan.
Middleware Penanganan Pengecualian juga dapat digunakan di lingkungan Pengembangan untuk menghasilkan format payload yang konsisten di semua lingkungan:
Dalam
Program.cs
, daftarkan instans Middleware Penanganan Pengecualian khusus lingkungan:if (app.Environment.IsDevelopment()) { app.UseExceptionHandler("/error-development"); } else { app.UseExceptionHandler("/error"); }
Dalam kode sebelumnya, middleware terdaftar dengan:
- Rute
/error-development
di lingkungan Pengembangan. - Rute
/error
di lingkungan non-Pengembangan.
- Rute
Tambahkan tindakan pengontrol untuk rute Pengembangan dan non-Pengembangan:
[Route("/error-development")] public IActionResult HandleErrorDevelopment( [FromServices] IHostEnvironment hostEnvironment) { if (!hostEnvironment.IsDevelopment()) { return NotFound(); } var exceptionHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>()!; return Problem( detail: exceptionHandlerFeature.Error.StackTrace, title: exceptionHandlerFeature.Error.Message); } [Route("/error")] public IActionResult HandleError() => Problem();
Gunakan pengecualian untuk mengubah respons
Konten respons dapat dimodifikasi dari luar pengontrol menggunakan pengecualian kustom dan filter tindakan:
Buat jenis pengecualian terkenal bernama
HttpResponseException
:public class HttpResponseException : Exception { public HttpResponseException(int statusCode, object? value = null) => (StatusCode, Value) = (statusCode, value); public int StatusCode { get; } public object? Value { get; } }
Buat filter tindakan bernama
HttpResponseExceptionFilter
:public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter { public int Order => int.MaxValue - 10; public void OnActionExecuting(ActionExecutingContext context) { } public void OnActionExecuted(ActionExecutedContext context) { if (context.Exception is HttpResponseException httpResponseException) { context.Result = new ObjectResult(httpResponseException.Value) { StatusCode = httpResponseException.StatusCode }; context.ExceptionHandled = true; } } }
Filter sebelumnya menentukan
Order
nilai bilangan bulat maksimum dikurangi 10. IniOrder
memungkinkan filter lain berjalan di akhir alur.Di
Program.cs
, tambahkan filter tindakan ke kumpulan filter:builder.Services.AddControllers(options => { options.Filters.Add<HttpResponseExceptionFilter>(); });
Respons kesalahan kegagalan validasi
Untuk pengontrol API web, MVC merespons dengan ValidationProblemDetails jenis respons saat validasi model gagal. MVC menggunakan hasil InvalidModelStateResponseFactory untuk membangun respons kesalahan untuk kegagalan validasi. Contoh berikut mengganti pabrik default dengan implementasi yang juga mendukung respons pemformatan sebagai XML, di Program.cs
:
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
new BadRequestObjectResult(context.ModelState)
{
ContentTypes =
{
// using static System.Net.Mime.MediaTypeNames;
Application.Json,
Application.Xml
}
};
})
.AddXmlSerializerFormatters();
Respons kesalahan klien
Hasil kesalahan didefinisikan sebagai hasilnya dengan kode status HTTP 400 atau lebih tinggi. Untuk pengontrol API web, MVC mengubah hasil kesalahan untuk menghasilkan ProblemDetails.
Respons kesalahan dapat dikonfigurasi dengan salah satu cara berikut:
Alat ProblemDetailsFactory
MVC menggunakan Microsoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory untuk menghasilkan semua instans ProblemDetails dan ValidationProblemDetails. Pabrik ini digunakan untuk:
- Respons kesalahan klien
- Respons kesalahan kegagalan validasi
- ControllerBase.Problem dan ControllerBase.ValidationProblem
Untuk menyesuaikan respons detail masalah, daftarkan implementasi ProblemDetailsFactory kustom di Program.cs
:
builder.Services.AddControllers();
builder.Services.AddTransient<ProblemDetailsFactory, SampleProblemDetailsFactory>();
Menggunakan ApiBehaviorOptions.ClientErrorMapping
ClientErrorMapping Gunakan properti untuk mengonfigurasi konten ProblemDetails
respons. Misalnya, kode berikut dalam Program.cs
memperbarui Link properti untuk 404 respons:
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
"https://httpstatuses.com/404";
});
Middleware Kustom untuk menangani pengecualian
Default dalam penanganan pengecualian middleware berfungsi dengan baik untuk sebagian besar aplikasi. Untuk aplikasi yang memerlukan penanganan pengecualian khusus, pertimbangkan untuk menyesuaikan middleware penanganan pengecualian.
Menghasilkan payload ProblemDetails untuk pengecualian
ASP.NET Core tidak menghasilkan payload kesalahan standar saat terjadi pengecualian yang tidak tertangani. Untuk skenario di mana diinginkan untuk mengembalikan respons ProblemDetails standar kepada klien, middleware ProblemDetails dapat digunakan untuk memetakan pengecualian dan 404 respons terhadap payload ProblemDetails. Middleware penanganan pengecualian juga dapat digunakan untuk mengembalikan ProblemDetails payload untuk pengecualian yang tidak tertangani.
Sumber Daya Tambahan:
Artikel ini menjelaskan cara menangani dan menyesuaikan penanganan kesalahan dengan API web ASP.NET Core.
Melihat atau mengunduh kode sampel (Cara mengunduh)
Halaman Pengecualian Pengembang
Halaman Pengecualian Pengembang adalah alat yang berguna untuk mendapatkan jejak tumpukan terperinci untuk kesalahan server. Ini menggunakan DeveloperExceptionPageMiddleware untuk menangkap pengecualian sinkron dan asinkron dari alur HTTP dan untuk menghasilkan respons kesalahan. Untuk mengilustrasikan, pertimbangkan tindakan pengontrol berikut:
[HttpGet("{city}")]
public WeatherForecast Get(string city)
{
if (!string.Equals(city?.TrimEnd(), "Redmond", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException(
$"We don't offer a weather forecast for {city}.", nameof(city));
}
return GetWeather().First();
}
Jalankan perintah berikut curl
untuk menguji tindakan sebelumnya:
curl -i https://localhost:5001/weatherforecast/chicago
Halaman Pengecualian Pengembang menampilkan respons teks biasa jika klien tidak meminta output berformat HTML. Output berikut muncul:
HTTP/1.1 500 Internal Server Error
Transfer-Encoding: chunked
Content-Type: text/plain
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2019 16:13:16 GMT
System.ArgumentException: We don't offer a weather forecast for chicago. (Parameter 'city')
at WebApiSample.Controllers.WeatherForecastController.Get(String city) in C:\working_folder\aspnet\AspNetCore.Docs\aspnetcore\web-api\handle-errors\samples\3.x\Controllers\WeatherForecastController.cs:line 34
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Host: localhost:44312
User-Agent: curl/7.55.1
Untuk menampilkan respons berformat HTML, atur Accept
header permintaan HTTP ke text/html
jenis media. Contohnya:
curl -i -H "Accept: text/html" https://localhost:5001/weatherforecast/chicago
Pertimbangkan kutipan berikut dari respons HTTP:
HTTP/1.1 500 Internal Server Error
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2019 16:55:37 GMT
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Internal Server Error</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;
font-size: .813em;
color: #222;
background-color: #fff;
}
Respons berformat HTML menjadi berguna saat menguji melalui alat seperti curl.
Peringatan
Aktifkan Halaman Pengecualian Pengembang hanya saat 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.
Jangan tandai metode tindakan penangan kesalahan dengan atribut metode HTTP, seperti HttpGet
. Kata kerja eksplisit mencegah beberapa permintaan mencapai metode tindakan. Izinkan akses anonim ke metode jika pengguna yang tidak diaturentikasi akan melihat kesalahan.
Handler pengecualian
Di lingkungan non-pengembangan, Middleware Penanganan Pengecualian dapat digunakan untuk menghasilkan payload kesalahan:
Di
Startup.Configure
, panggil UseExceptionHandler untuk menggunakan middleware:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/error"); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
Konfigurasikan tindakan pengontrol untuk merespons
/error
rute:[ApiController] public class ErrorController : ControllerBase { [Route("/error")] public IActionResult Error() => Problem(); }
Tindakan sebelumnya Error
mengirimkan payload yang mematuhi RFC 7807 ke klien.
Middleware Penanganan Pengecualian juga dapat memberikan output yang dinegosiasikan konten yang lebih rinci di lingkungan pengembangan lokal. Gunakan langkah-langkah berikut untuk menghasilkan format payload yang konsisten di seluruh lingkungan pengembangan dan produksi:
Dalam
Startup.Configure
, daftarkan instans Middleware Penanganan Pengecualian khusus lingkungan:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseExceptionHandler("/error-local-development"); } else { app.UseExceptionHandler("/error"); } }
Dalam kode sebelumnya, middleware terdaftar dengan:
- Rute
/error-local-development
di lingkungan Pengembangan. - Rute
/error
di lingkungan yang bukan Pengembangan.
- Rute
Terapkan perutean atribut ke tindakan pengontrol:
[ApiController] public class ErrorController : ControllerBase { [Route("/error-local-development")] public IActionResult ErrorLocalDevelopment( [FromServices] IWebHostEnvironment webHostEnvironment) { if (webHostEnvironment.EnvironmentName != "Development") { throw new InvalidOperationException( "This shouldn't be invoked in non-development environments."); } var context = HttpContext.Features.Get<IExceptionHandlerFeature>(); return Problem( detail: context.Error.StackTrace, title: context.Error.Message); } [Route("/error")] public IActionResult Error() => Problem(); }
Kode sebelumnya memanggil ControllerBase.Problem untuk membuat ProblemDetails respons.
Gunakan pengecualian untuk mengubah respons
Konten respons dapat dimodifikasi dari luar pengontrol. Dalam ASP.NET 4.x Web API, salah satu cara untuk melakukan ini adalah menggunakan jenis .HttpResponseException ASP.NET Core tidak menyertakan jenis yang setara. Dukungan untuk HttpResponseException
dapat ditambahkan dengan langkah-langkah berikut:
Buat jenis pengecualian terkenal bernama
HttpResponseException
:public class HttpResponseException : Exception { public int Status { get; set; } = 500; public object Value { get; set; } }
Buat filter tindakan bernama
HttpResponseExceptionFilter
:public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter { public int Order { get; } = int.MaxValue - 10; public void OnActionExecuting(ActionExecutingContext context) { } public void OnActionExecuted(ActionExecutedContext context) { if (context.Exception is HttpResponseException exception) { context.Result = new ObjectResult(exception.Value) { StatusCode = exception.Status, }; context.ExceptionHandled = true; } } }
Filter sebelumnya menentukan
Order
nilai bilangan bulat maksimum dikurangi 10. IniOrder
memungkinkan filter lain berjalan di akhir alur.Di
Startup.ConfigureServices
, tambahkan filter tindakan ke kumpulan filter:services.AddControllers(options => options.Filters.Add(new HttpResponseExceptionFilter()));
Respons kesalahan kegagalan validasi
Untuk pengontrol API web, MVC merespons dengan ValidationProblemDetails jenis respons saat validasi model gagal. MVC menggunakan hasil InvalidModelStateResponseFactory untuk membangun respons kesalahan untuk kegagalan validasi. Contoh berikut menggunakan pabrik untuk mengubah jenis respons default menjadi SerializableError di Startup.ConfigureServices
:
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var result = new BadRequestObjectResult(context.ModelState);
// TODO: add `using System.Net.Mime;` to resolve MediaTypeNames
result.ContentTypes.Add(MediaTypeNames.Application.Json);
result.ContentTypes.Add(MediaTypeNames.Application.Xml);
return result;
};
});
Respons kesalahan klien
Hasil kesalahan didefinisikan sebagai hasilnya dengan kode status HTTP 400 atau lebih tinggi. Untuk pengontrol API web, MVC mengubah hasil kesalahan menjadi hasil dengan ProblemDetails.
Respons kesalahan dapat dikonfigurasi dengan salah satu cara berikut:
Alat ProblemDetailsFactory
MVC menggunakan Microsoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory untuk menghasilkan semua instans ProblemDetails dan ValidationProblemDetails. Pabrik ini digunakan untuk:
- Respons kesalahan klien
- Respons kesalahan kegagalan validasi
- ControllerBase.Problem dan ControllerBase.ValidationProblem
Untuk menyesuaikan respons detail masalah, daftarkan implementasi ProblemDetailsFactory kustom di Startup.ConfigureServices
:
public void ConfigureServices(IServiceCollection serviceCollection)
{
services.AddControllers();
services.AddTransient<ProblemDetailsFactory, CustomProblemDetailsFactory>();
}
Menggunakan ApiBehaviorOptions.ClientErrorMapping
ClientErrorMapping Gunakan properti untuk mengonfigurasi konten ProblemDetails
respons. Misalnya, kode berikut dalam Startup.ConfigureServices
memperbarui type
properti untuk 404 respons:
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
"https://httpstatuses.com/404";
options.DisableImplicitFromServicesParameters = true;
});
Middleware Kustom untuk menangani pengecualian
Default dalam penanganan pengecualian middleware berfungsi dengan baik untuk sebagian besar aplikasi. Untuk aplikasi yang memerlukan penanganan pengecualian khusus, pertimbangkan untuk menyesuaikan middleware penanganan pengecualian.
Menghasilkan payload ProblemDetails untuk pengecualian
ASP.NET Core tidak menghasilkan payload kesalahan standar saat terjadi pengecualian yang tidak tertangani. Untuk skenario di mana diinginkan untuk mengembalikan respons ProblemDetails standar kepada klien, middleware ProblemDetails dapat digunakan untuk memetakan pengecualian dan 404 respons terhadap payload ProblemDetails. Middleware penanganan pengecualian juga dapat digunakan untuk mengembalikan ProblemDetails payload untuk pengecualian yang tidak tertangani.
ASP.NET Core