Bagikan melalui


Cara menangani kesalahan di aplikasi API Minimal

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.

Dengan kontribusi oleh David Acker

Artikel ini menjelaskan cara menangani kesalahan di aplikasi API Minimal. Untuk informasi tentang penanganan kesalahan di API berbasis pengontrol, lihat Menangani kesalahan di kesalahan ASP.NET Core dan Menangani kesalahan di API web berbasis pengontrol Inti ASP.NET.

Pengecualian

Dalam aplikasi API Minimal, ada dua mekanisme terpusat bawaan yang berbeda untuk menangani pengecualian yang tidak tertangani:

Bagian ini mengacu pada aplikasi sampel berikut untuk menunjukkan cara menangani pengecualian dalam API Minimal. Ini melemparkan pengecualian ketika titik /exception akhir diminta:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

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:

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
  • Cookies, 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:

Halaman pengecualian pengembang dianimasikan untuk menampilkan setiap tab yang dipilih.

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:

  • Jalankan aplikasi sampel di lingkungan Pengembangan.
  • /exception Buka titik akhir.

Handler pengecualian

Di lingkungan non-pengembangan, gunakan Middleware Handler Pengecualian untuk menghasilkan payload kesalahan. Untuk mengonfigurasi Exception Handler Middleware, panggil UseExceptionHandler.

Misalnya, kode berikut mengubah aplikasi untuk merespons dengan payload yang mematuhi RFC 7807 ke klien. Untuk informasi selengkapnya, lihat bagian Detail Masalah nanti di artikel ini.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Respons kesalahan Klien dan Server

Pertimbangkan aplikasi API Minimal berikut.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Titik /users akhir menghasilkan 200 OK dengan json representasi User kapan id lebih besar dari 0, jika tidak 400 BAD REQUEST , kode status tanpa isi respons. Untuk informasi selengkapnya tentang membuat respons, lihat Membuat respons di aplikasi API Minimal.

Status Code Pages middleware dapat dikonfigurasi untuk menghasilkan konten isi umum, ketika kosong, untuk semua respons klien HTTP (499-400) atau server ().500 -599 Middleware dikonfigurasi dengan memanggil metode ekstensi UseStatusCodePages .

Misalnya, contoh berikut mengubah aplikasi untuk merespons dengan payload yang mematuhi RFC 7807 ke klien untuk semua respons klien dan server, termasuk kesalahan perutean (misalnya, 404 NOT FOUND). Untuk informasi selengkapnya, lihat bagian Detail Masalah.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    => await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

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):

Aplikasi API minimal dapat dikonfigurasi untuk menghasilkan respons detail masalah untuk semua respons kesalahan klien HTTP dan server yang belum memiliki konten isi dengan menggunakan AddProblemDetails metode ekstensi.

Kode berikut mengonfigurasi aplikasi untuk menghasilkan detail masalah:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Untuk informasi selengkapnya tentang menggunakan AddProblemDetails, lihat Detail Masalah

Fallback IProblemDetailsService

Dalam kode berikut, httpContext.Response.WriteAsync("Fallback: An error occurred.") mengembalikan kesalahan jika IProblemDetailsService implementasi tidak dapat menghasilkan ProblemDetails:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Kode sebelumnya:

  • Menulis pesan kesalahan dengan kode fallback jika problemDetailsService tidak dapat menulis ProblemDetails. Misalnya, titik akhir di mana header Permintaan terima menentukan jenis media yang DefaulProblemDetailsWriter tidak didukung.
  • Menggunakan Middleware Handler Pengecualian.

Sampel berikut mirip dengan sebelumnya kecuali bahwa ia memanggil Status Code Pages middleware.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseStatusCodePages(statusCodeHandlerApp =>
{
    statusCodeHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/users/{id:int}", (int id) =>
{
    return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id));
});

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Artikel ini menjelaskan cara menangani kesalahan di aplikasi API Minimal.

Pengecualian

Dalam aplikasi API Minimal, ada dua mekanisme terpusat bawaan yang berbeda untuk menangani pengecualian yang tidak tertangani:

Bagian ini mengacu pada aplikasi API Minimal berikut untuk menunjukkan cara menangani pengecualian. Ini melemparkan pengecualian ketika titik /exception akhir diminta:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

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.

aplikasi ASP.NET Core mengaktifkan halaman pengecualian pengembang secara default saat keduanya:

Untuk informasi selengkapnya tentang mengonfigurasi middleware, lihat Middleware di aplikasi API Minimal.

Menggunakan aplikasi API Minimal sebelumnya, ketika Developer Exception Page mendeteksi pengecualian yang tidak tertangani, aplikasi menghasilkan respons teks biasa default yang mirip dengan contoh berikut:

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Thu, 27 Oct 2022 18:00:59 GMT
Server: Kestrel
Transfer-Encoding: chunked

    System.InvalidOperationException: Sample Exception
    at Program.<>c.<<Main>$>b__0_1() in ....:line 17
    at lambda_method2(Closure, Object, HttpContext)
    at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
    --- End of stack trace from previous location ---
    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:5239
Accept-Encoding: gzip, deflate, br

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 Handler Pengecualian untuk menghasilkan payload kesalahan. Untuk mengonfigurasi Exception Handler Middleware, panggil UseExceptionHandler.

Misalnya, kode berikut mengubah aplikasi untuk merespons dengan payload yang mematuhi RFC 7807 ke klien. Untuk informasi selengkapnya, lihat bagian Detail Masalah.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Respons kesalahan Klien dan Server

Pertimbangkan aplikasi API Minimal berikut.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Run();

public record User(int Id);

Titik /users akhir menghasilkan 200 OK dengan json representasi User kapan id lebih besar dari 0, jika tidak 400 BAD REQUEST , kode status tanpa isi respons. Untuk informasi selengkapnya tentang membuat respons, lihat Membuat respons di aplikasi API Minimal.

Status Code Pages middleware dapat dikonfigurasi untuk menghasilkan konten isi umum, ketika kosong, untuk semua respons klien HTTP (499-400) atau server ().500 -599 Middleware dikonfigurasi dengan memanggil metode ekstensi UseStatusCodePages .

Misalnya, contoh berikut mengubah aplikasi untuk merespons dengan payload yang mematuhi RFC 7807 ke klien untuk semua respons klien dan server, termasuk kesalahan perutean (misalnya, 404 NOT FOUND). Untuk informasi selengkapnya, lihat bagian Detail Masalah.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    =>  await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Run();

public record User(int Id);

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):

Aplikasi API minimal dapat dikonfigurasi untuk menghasilkan respons detail masalah untuk semua respons kesalahan klien HTTP dan server yang belum memiliki konten isi dengan menggunakan AddProblemDetails metode ekstensi.

Kode berikut mengonfigurasi aplikasi untuk menghasilkan detail masalah:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Untuk informasi selengkapnya tentang menggunakan AddProblemDetails, lihat Detail Masalah