ASP.NET Core web API'lerindeki hataları işleme

Bu makalede, ASP.NET Core web API'leriyle hataların nasıl işleneceğini ve hata işlemenin nasıl özelleştirileceği açıklanır.

Geliştirici Özel Durum Sayfası

Geliştirici Özel Durum Sayfası, sunucu hataları için ayrıntılı yığın izlemelerini gösterir. HTTP işlem hattından zaman uyumlu ve zaman uyumsuz özel durumları yakalamak ve hata yanıtları oluşturmak için kullanır DeveloperExceptionPageMiddleware . Örneğin, özel durum oluşturan aşağıdaki denetleyici eylemini göz önünde bulundurun:

[HttpGet("Throw")]
public IActionResult Throw() =>
    throw new Exception("Sample exception.");

Geliştirici Özel Durum Sayfası işlenmeyen bir özel durum algıladığında, aşağıdaki örneğe benzer bir varsayılan düz metin yanıtı oluşturur:

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

...

İstemci HTML biçimli bir yanıt isterse, Geliştirici Özel Durum Sayfası aşağıdaki örneğe benzer bir yanıt oluşturur:

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;
}

...

HTML biçimli yanıt istemek için HTTP isteği üst bilgisini olarak text/htmlayarlayınAccept.

Uyarı

Uygulama Geliştirme ortamında çalışmadığı sürece Geliştirici Özel Durum Sayfası'nı etkinleştirmeyin. Uygulama üretimde çalışırken ayrıntılı özel durum bilgilerini herkese açık olarak paylaşmayın. Ortamları yapılandırma hakkında daha fazla bilgi için bkz . ASP.NET Core'da birden çok ortam kullanma.

Özel durum işleyicisi

Geliştirme dışı ortamlarda hata yükü oluşturmak için Özel Durum İşleme Ara Yazılımını kullanın:

  1. içinde Program.cs, Özel Durum İşleme Ara Yazılımını eklemek için öğesini çağırın UseExceptionHandler :

    var app = builder.Build();
    
    app.UseHttpsRedirection();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error");
    }
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    
  2. Bir denetleyici eylemini yola yanıt verecek şekilde /error yapılandırın:

    [Route("/error")]
    public IActionResult HandleError() =>
        Problem();
    

Yukarıdaki HandleError eylem, istemciye RFC 7807 uyumlu bir yük gönderir.

Uyarı

Hata işleyicisi eylem yöntemini gibi HttpGetHTTP yöntemi öznitelikleriyle işaretlemeyin. Açık fiiller bazı isteklerin eylem yöntemine ulaşmasını engeller.

Swagger / OpenAPI kullanan web API'leri için hata işleyici eylemini [ApiExplorer Ayarlar] özniteliğiyle işaretleyin ve özelliğini olarak trueayarlayınIgnoreApi. Bu öznitelik yapılandırması, hata işleyici eylemini uygulamanın OpenAPI belirtiminin dışında tutar:

[ApiExplorerSettings(IgnoreApi = true)]

Kimliği doğrulanmamış kullanıcıların hatayı görmesi gerekiyorsa yönteme anonim erişime izin verin.

Özel Durum İşleme Ara Yazılımı, tüm ortamlarda tutarlı bir yük biçimi oluşturmak için Geliştirme ortamında da kullanılabilir:

  1. içinde Program.cs, ortama özgü Özel Durum İşleme Ara Yazılım örneklerini kaydedin:

    if (app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error-development");
    }
    else
    {
        app.UseExceptionHandler("/error");
    }
    

    Yukarıdaki kodda ara yazılım şu şekilde kaydedilir:

    • Geliştirme ortamındaki bir yolu /error-development .
    • Geliştirme dışı ortamlardaki bir yolu /error .

  2. Hem Geliştirme hem de Geliştirme dışı yollar için denetleyici eylemleri ekleyin:

    [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();
    

Yanıtı değiştirmek için özel durumları kullanma

Yanıtın içeriği özel bir özel durum ve eylem filtresi kullanılarak denetleyici dışından değiştirilebilir:

  1. adlı HttpResponseExceptioniyi bilinen bir özel durum türü oluşturun:

    public class HttpResponseException : Exception
    {
        public HttpResponseException(int statusCode, object? value = null) =>
            (StatusCode, Value) = (statusCode, value);
    
        public int StatusCode { get; }
    
        public object? Value { get; }
    }
    
  2. adlı HttpResponseExceptionFilterbir eylem filtresi oluşturun:

    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;
            }
        }
    }
    

    Yukarıdaki filtre, en büyük tamsayı değeri eksi 10 değerini belirtir Order . Bu Order , diğer filtrelerin işlem hattının sonunda çalışmasını sağlar.

  3. içinde Program.cs, eylem filtresini filtreler koleksiyonuna ekleyin:

    builder.Services.AddControllers(options =>
    {
        options.Filters.Add<HttpResponseExceptionFilter>();
    });
    

Doğrulama hatası hatası yanıtı

Web API denetleyicileri için MVC, model doğrulaması başarısız olduğunda yanıt ValidationProblemDetails türüyle yanıt verir. MVC, doğrulama hatası için hata yanıtını oluşturmak için 'in InvalidModelStateResponseFactory sonuçlarını kullanır. Aşağıdaki örnek, içindeki varsayılan fabrikayı, yanıtları XML Program.csolarak biçimlendirmeyi de destekleyen bir uygulamayla değiştirir:

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
            new BadRequestObjectResult(context.ModelState)
            {
                ContentTypes =
                {
                    // using static System.Net.Mime.MediaTypeNames;
                    Application.Json,
                    Application.Xml
                }
            };
    })
    .AddXmlSerializerFormatters();

İstemci hatası yanıtı

Hata sonucu , 400 veya üzeri bir HTTP durum koduyla sonuç olarak tanımlanır. Web API denetleyicileri için, MVC bir hata sonucunu dönüştürerek bir ProblemDetailsoluşturur.

Hata durum kodları için otomatik oluşturma ProblemDetails varsayılan olarak etkindir, ancak hata yanıtları aşağıdaki yollardan biriyle yapılandırılabilir:

  1. Sorun ayrıntıları hizmetini kullanma
  2. ProblemDetailsFactory Uygulama
  3. ApiBehaviorOptions.ClientErrorMapping kullanma

Varsayılan sorun ayrıntıları yanıtı

Aşağıdaki Program.cs dosya, API denetleyicileri için web uygulaması şablonları tarafından oluşturulmuştur:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Giriş geçersiz olduğunda döndüren BadRequest aşağıdaki denetleyiciyi göz önünde bulundurun:

[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));
    }
}

Aşağıdaki koşullardan herhangi biri geçerli olduğunda önceki kodla bir sorun ayrıntıları yanıtı oluşturulur:

  • /api/values2/divide nokta sıfır payda ile çağrılır.
  • /api/values2/squareroot nokta, sıfırdan küçük bir radik ve ile çağrılır.

Varsayılan sorun ayrıntıları yanıt gövdesinde aşağıdaki type, titleve status değerleri bulunur:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Bad Request",
  "status": 400,
  "traceId": "00-84c1fd4063c38d9f3900d06e56542d48-85d1d4-00"
}

Sorun ayrıntıları hizmeti

ASP.NET Core, kullanarak IProblemDetailsServiceHTTP API'leri için Sorun Ayrıntıları oluşturmayı destekler. Daha fazla bilgi için Sorun ayrıntıları hizmetine bakın.

Aşağıdaki kod, uygulamayı henüz gövde içeriği olmayan tüm HTTP istemcisi ve sunucu hata yanıtları için bir sorun ayrıntıları yanıtı oluşturacak şekilde yapılandırır:

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();

Önceki bölümde yer alan ve giriş geçersiz olduğunda döndüren BadRequest API denetleyicisini göz önünde bulundurun:

[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));
    }
}

Aşağıdaki koşullardan herhangi biri geçerli olduğunda önceki kodla bir sorun ayrıntıları yanıtı oluşturulur:

  • Geçersiz bir giriş sağlandı.
  • URI'nin eşleşen uç noktası yok.
  • İşlenmeyen bir özel durum oluşur.

SuppressMapClientErrors özelliği true olarak ayarlandığında hata durum kodları için otomatik bir ProblemDetails oluşturma devre dışı bırakılır:

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();

Önceki kodu kullanarak, bir API denetleyicisi döndürdüğünde BadRequestyanıt gövdesi olmayan bir HTTP 400 yanıt durumu döndürülür. SuppressMapClientErrorsProblemDetails API Denetleyicisi uç noktası çağrılsa WriteAsync bile yanıtın oluşturulmasını engeller. WriteAsync bu makalenin devamında açıklanmıştır.

Sonraki bölümde, daha yararlı bir yanıt döndürmek için kullanarak CustomizeProblemDetailssorunun ayrıntılarının yanıt gövdesinin nasıl özelleştirileceği gösterilmektedir. Daha fazla özelleştirme seçeneği için bkz . Sorun ayrıntılarını özelleştirme.

Ile sorun ayrıntılarını özelleştirme CustomizeProblemDetails

Ayarlamak için CustomizeProblemDetailsaşağıdaki kod kullanılırProblemDetailsOptions:

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();

Güncelleştirilmiş API denetleyicisi:

[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));
    }

}

Aşağıdaki kod, önceki örnekle birlikte kullanılan ve MathErrorTypekodunu içerirMathErrorFeature:

// Custom Http Request Feature
class MathErrorFeature
{
    public MathErrorType MathError { get; set; }
}

// Custom math errors
enum MathErrorType
{
    DivisionByZeroError,
    NegativeRadicandError
}

Aşağıdaki koşullardan herhangi biri geçerli olduğunda önceki kodla bir sorun ayrıntıları yanıtı oluşturulur:

  • /divide nokta sıfır payda ile çağrılır.
  • /squareroot nokta, sıfırdan küçük bir radik ve ile çağrılır.
  • URI'nin eşleşen uç noktası yok.

Sorun ayrıntıları yanıt gövdesi, uç noktalardan biri squareroot radik ve sıfırdan küçük olarak çağrıldığında aşağıdakileri içerir:

{
  "type": "https://en.wikipedia.org/wiki/Square_root",
  "title": "Bad Input",
  "status": 400,
  "detail": "Negative or complex numbers are not allowed."
}

Örnek kodu görüntüleme veya indirme

Uygulamak ProblemDetailsFactory

MVC, ve ValidationProblemDetails'nin ProblemDetails tüm örneklerini üretmek için kullanırMicrosoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory. Bu fabrika aşağıdakiler için kullanılır:

Sorun ayrıntıları yanıtını özelleştirmek için içindeki özel uygulamasını ProblemDetailsFactoryProgram.cskaydedin:

builder.Services.AddControllers();
builder.Services.AddTransient<ProblemDetailsFactory, SampleProblemDetailsFactory>();

ApiBehaviorOptions.ClientErrorMapping komutunu kullanma

yanıtın ClientErrorMapping içeriğini ProblemDetails yapılandırmak için özelliğini kullanın. Örneğin, aşağıdaki kod Program.cs 404 yanıtları için özelliğini güncelleştirir Link :

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

Ek kaynaklar

Bu makalede, ASP.NET Core web API'leriyle hataların nasıl işleneceğini ve hata işlemenin nasıl özelleştirileceği açıklanır.

Geliştirici Özel Durum Sayfası

Geliştirici Özel Durum Sayfası, sunucu hataları için ayrıntılı yığın izlemelerini gösterir. HTTP işlem hattından zaman uyumlu ve zaman uyumsuz özel durumları yakalamak ve hata yanıtları oluşturmak için kullanır DeveloperExceptionPageMiddleware . Örneğin, özel durum oluşturan aşağıdaki denetleyici eylemini göz önünde bulundurun:

[HttpGet("Throw")]
public IActionResult Throw() =>
    throw new Exception("Sample exception.");

Geliştirici Özel Durum Sayfası işlenmeyen bir özel durum algıladığında, aşağıdaki örneğe benzer bir varsayılan düz metin yanıtı oluşturur:

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

...

İstemci HTML biçimli bir yanıt isterse, Geliştirici Özel Durum Sayfası aşağıdaki örneğe benzer bir yanıt oluşturur:

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;
}

...

HTML biçimli yanıt istemek için HTTP isteği üst bilgisini olarak text/htmlayarlayınAccept.

Uyarı

Uygulama Geliştirme ortamında çalışmadığı sürece Geliştirici Özel Durum Sayfası'nı etkinleştirmeyin. Uygulama üretimde çalışırken ayrıntılı özel durum bilgilerini herkese açık olarak paylaşmayın. Ortamları yapılandırma hakkında daha fazla bilgi için bkz . ASP.NET Core'da birden çok ortam kullanma.

Özel durum işleyicisi

Geliştirme dışı ortamlarda hata yükü oluşturmak için Özel Durum İşleme Ara Yazılımını kullanın:

  1. içinde Program.cs, Özel Durum İşleme Ara Yazılımını eklemek için öğesini çağırın UseExceptionHandler :

    var app = builder.Build();
    
    app.UseHttpsRedirection();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error");
    }
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    
  2. Bir denetleyici eylemini yola yanıt verecek şekilde /error yapılandırın:

    [Route("/error")]
    public IActionResult HandleError() =>
        Problem();
    

Yukarıdaki HandleError eylem, istemciye RFC 7807 uyumlu bir yük gönderir.

Uyarı

Hata işleyicisi eylem yöntemini gibi HttpGetHTTP yöntemi öznitelikleriyle işaretlemeyin. Açık fiiller bazı isteklerin eylem yöntemine ulaşmasını engeller.

Swagger / OpenAPI kullanan web API'leri için hata işleyici eylemini [ApiExplorer Ayarlar] özniteliğiyle işaretleyin ve özelliğini olarak trueayarlayınIgnoreApi. Bu öznitelik yapılandırması, hata işleyici eylemini uygulamanın OpenAPI belirtiminin dışında tutar:

[ApiExplorerSettings(IgnoreApi = true)]

Kimliği doğrulanmamış kullanıcıların hatayı görmesi gerekiyorsa yönteme anonim erişime izin verin.

Özel Durum İşleme Ara Yazılımı, tüm ortamlarda tutarlı bir yük biçimi oluşturmak için Geliştirme ortamında da kullanılabilir:

  1. içinde Program.cs, ortama özgü Özel Durum İşleme Ara Yazılım örneklerini kaydedin:

    if (app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error-development");
    }
    else
    {
        app.UseExceptionHandler("/error");
    }
    

    Yukarıdaki kodda ara yazılım şu şekilde kaydedilir:

    • Geliştirme ortamındaki bir yolu /error-development .
    • Geliştirme dışı ortamlardaki bir yolu /error .

  2. Hem Geliştirme hem de Geliştirme dışı yollar için denetleyici eylemleri ekleyin:

    [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();
    

Yanıtı değiştirmek için özel durumları kullanma

Yanıtın içeriği özel bir özel durum ve eylem filtresi kullanılarak denetleyici dışından değiştirilebilir:

  1. adlı HttpResponseExceptioniyi bilinen bir özel durum türü oluşturun:

    public class HttpResponseException : Exception
    {
        public HttpResponseException(int statusCode, object? value = null) =>
            (StatusCode, Value) = (statusCode, value);
    
        public int StatusCode { get; }
    
        public object? Value { get; }
    }
    
  2. adlı HttpResponseExceptionFilterbir eylem filtresi oluşturun:

    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;
            }
        }
    }
    

    Yukarıdaki filtre, en büyük tamsayı değeri eksi 10 değerini belirtir Order . Bu Order , diğer filtrelerin işlem hattının sonunda çalışmasını sağlar.

  3. içinde Program.cs, eylem filtresini filtreler koleksiyonuna ekleyin:

    builder.Services.AddControllers(options =>
    {
        options.Filters.Add<HttpResponseExceptionFilter>();
    });
    

Doğrulama hatası hatası yanıtı

Web API denetleyicileri için MVC, model doğrulaması başarısız olduğunda yanıt ValidationProblemDetails türüyle yanıt verir. MVC, doğrulama hatası için hata yanıtını oluşturmak için 'in InvalidModelStateResponseFactory sonuçlarını kullanır. Aşağıdaki örnek, içindeki varsayılan fabrikayı, yanıtları XML Program.csolarak biçimlendirmeyi de destekleyen bir uygulamayla değiştirir:

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
            new BadRequestObjectResult(context.ModelState)
            {
                ContentTypes =
                {
                    // using static System.Net.Mime.MediaTypeNames;
                    Application.Json,
                    Application.Xml
                }
            };
    })
    .AddXmlSerializerFormatters();

İstemci hatası yanıtı

Hata sonucu , 400 veya üzeri bir HTTP durum koduyla sonuç olarak tanımlanır. Web API denetleyicileri için, MVC bir hata sonucunu dönüştürerek bir ProblemDetailsoluşturur.

Hata yanıtı aşağıdaki yollardan biriyle yapılandırılabilir:

  1. ProblemDetailsFactory Uygulama
  2. ApiBehaviorOptions.ClientErrorMapping kullanma

Uygulamak ProblemDetailsFactory

MVC, ve ValidationProblemDetails'nin ProblemDetails tüm örneklerini üretmek için kullanırMicrosoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory. Bu fabrika aşağıdakiler için kullanılır:

Sorun ayrıntıları yanıtını özelleştirmek için içindeki özel uygulamasını ProblemDetailsFactoryProgram.cskaydedin:

builder.Services.AddControllers();
builder.Services.AddTransient<ProblemDetailsFactory, SampleProblemDetailsFactory>();

ApiBehaviorOptions.ClientErrorMapping komutunu kullanma

yanıtın ClientErrorMapping içeriğini ProblemDetails yapılandırmak için özelliğini kullanın. Örneğin, aşağıdaki kod Program.cs 404 yanıtları için özelliğini güncelleştirir Link :

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

Özel durumları işlemek için özel Ara Yazılım

Özel durum işleme ara yazılımındaki varsayılanlar çoğu uygulama için iyi çalışır. Özel özel durum işleme gerektiren uygulamalar için özel durum işleme ara yazılımını özelleştirmeyi göz önünde bulundurun.

Özel durumlar için ProblemDetails yükü oluşturma

ASP.NET Core, işlenmeyen bir özel durum oluştuğunda standartlaştırılmış bir hata yükü üretmez. İstemciye standartlaştırılmış bir ProblemDetails yanıtının döndürülmesi istenen senaryolarda, ProblemDetails ara yazılımı özel durumları ve 404 yanıtı bir ProblemDetails yüküyle eşlemek için kullanılabilir. Özel durum işleme ara yazılımı, işlenmeyen özel durumlar için yük ProblemDetails döndürmek için de kullanılabilir.

Ek kaynaklar

Bu makalede, ASP.NET Core web API'leriyle hata işlemenin nasıl işlenip özelleştirileceği açıklanır.

Örnek kodu görüntüleme veya indirme (İndirme)

Geliştirici Özel Durum Sayfası

Geliştirici Özel Durum Sayfası, sunucu hataları için ayrıntılı yığın izlemeleri almak için kullanışlı bir araçtır. HTTP işlem hattından zaman uyumlu ve zaman uyumsuz özel durumları yakalamak ve hata yanıtları oluşturmak için kullanır DeveloperExceptionPageMiddleware . Bunu göstermek için aşağıdaki denetleyici eylemini göz önünde bulundurun:

[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();
}

Önceki eylemi test etmek için aşağıdaki curl komutu çalıştırın:

curl -i https://localhost:5001/weatherforecast/chicago

İstemci HTML biçimli çıkış istemezse Geliştirici Özel Durum Sayfası düz metin yanıtı görüntüler. Aşağıdaki çıkış görüntülenir:

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

Bunun yerine HTML biçimli bir yanıt görüntülemek için HTTP isteği üst bilgisini medya türüne text/html ayarlayınAccept. Örneğin:

curl -i -H "Accept: text/html" https://localhost:5001/weatherforecast/chicago

HTTP yanıtından aşağıdaki alıntıyı göz önünde bulundurun:

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;
}

HTML biçimli yanıt, Postman gibi araçlar aracılığıyla test ederken kullanışlı hale gelir. Aşağıdaki ekran görüntüsünde Postman'deki hem düz metin hem de HTML biçimli yanıtlar gösterilmektedir:

Test the Developer Exception Page in Postman.

Uyarı

Geliştirici Özel Durum Sayfası'nı yalnızca uygulama Geliştirme ortamında çalışırken etkinleştirin. Uygulama üretimde çalışırken ayrıntılı özel durum bilgilerini herkese açık olarak paylaşmayın. Ortamları yapılandırma hakkında daha fazla bilgi için bkz . ASP.NET Core'da birden çok ortam kullanma.

Hata işleyicisi eylem yöntemini gibi HttpGetHTTP yöntemi öznitelikleriyle işaretlemeyin. Açık fiiller bazı isteklerin eylem yöntemine ulaşmasını engeller. Kimliği doğrulanmamış kullanıcıların hatayı görmesi gerekiyorsa yönteme anonim erişime izin verin.

Özel durum işleyicisi

Geliştirme dışı ortamlarda, hata yükü oluşturmak için Özel Durum İşleme Ara Yazılımı kullanılabilir:

  1. içinde Startup.Configureara yazılımı kullanmak için komutunu çağırın UseExceptionHandler :

    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();
        });
    }
    
  2. Bir denetleyici eylemini yola yanıt verecek şekilde /error yapılandırın:

    [ApiController]
    public class ErrorController : ControllerBase
    {
        [Route("/error")]
        public IActionResult Error() => Problem();
    }
    

Yukarıdaki Error eylem, istemciye RFC 7807 uyumlu bir yük gönderir.

Özel Durum İşleme Ara Yazılımı, yerel geliştirme ortamında daha ayrıntılı içerik anlaşması çıktısı da sağlayabilir. Geliştirme ve üretim ortamlarında tutarlı bir yük biçimi oluşturmak için aşağıdaki adımları kullanın:

  1. içinde Startup.Configure, ortama özgü Özel Durum İşleme Ara Yazılım örneklerini kaydedin:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseExceptionHandler("/error-local-development");
        }
        else
        {
            app.UseExceptionHandler("/error");
        }
    }
    

    Yukarıdaki kodda ara yazılım şu şekilde kaydedilir:

    • Geliştirme ortamındaki bir yolu /error-local-development .
    • Geliştirme olmayan ortamlardaki bir yolu /error .

  2. Denetleyici eylemlerine öznitelik yönlendirmesi uygulama:

    [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();
    }
    

    Yukarıdaki kod, yanıt ProblemDetails oluşturmak için ControllerBase.Problem öğesini çağırır.

Yanıtı değiştirmek için özel durumları kullanma

Yanıtın içeriği denetleyici dışından değiştirilebilir. ASP.NET 4.x Web API'sinde bunu gerçekleştirmenin bir yolu türünü kullanmaktı HttpResponseException . ASP.NET Core eşdeğer bir tür içermez. desteği HttpResponseException aşağıdaki adımlarla eklenebilir:

  1. adlı HttpResponseExceptioniyi bilinen bir özel durum türü oluşturun:

    public class HttpResponseException : Exception
    {
        public int Status { get; set; } = 500;
    
        public object Value { get; set; }
    }
    
  2. adlı HttpResponseExceptionFilterbir eylem filtresi oluşturun:

    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;
            }
        }
    }
    

    Yukarıdaki filtre, en büyük tamsayı değeri eksi 10 değerini belirtir Order . Bu Order , diğer filtrelerin işlem hattının sonunda çalışmasını sağlar.

  3. içinde Startup.ConfigureServices, eylem filtresini filtreler koleksiyonuna ekleyin:

    services.AddControllers(options =>
        options.Filters.Add(new HttpResponseExceptionFilter()));
    

Doğrulama hatası hatası yanıtı

Web API denetleyicileri için MVC, model doğrulaması başarısız olduğunda yanıt ValidationProblemDetails türüyle yanıt verir. MVC, doğrulama hatası için hata yanıtını oluşturmak için 'in InvalidModelStateResponseFactory sonuçlarını kullanır. Aşağıdaki örnek, içinde varsayılan yanıt türünü olarak değiştirmek için SerializableErrorStartup.ConfigureServicesfabrikayı kullanır:

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;
        };
    });

İstemci hatası yanıtı

Hata sonucu , 400 veya üzeri bir HTTP durum koduyla sonuç olarak tanımlanır. Web API denetleyicileri için MVC, hata sonucunu ile ProblemDetailsbir sonucta dönüştürür.

Hata yanıtı aşağıdaki yollardan biriyle yapılandırılabilir:

  1. ProblemDetailsFactory Uygulama
  2. ApiBehaviorOptions.ClientErrorMapping kullanma

Uygulamak ProblemDetailsFactory

MVC, ve ValidationProblemDetails'nin ProblemDetails tüm örneklerini üretmek için kullanırMicrosoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory. Bu fabrika aşağıdakiler için kullanılır:

Sorun ayrıntıları yanıtını özelleştirmek için içindeki özel uygulamasını ProblemDetailsFactoryStartup.ConfigureServiceskaydedin:

public void ConfigureServices(IServiceCollection serviceCollection)
{
    services.AddControllers();
    services.AddTransient<ProblemDetailsFactory, CustomProblemDetailsFactory>();
}

ApiBehaviorOptions.ClientErrorMapping kullanma

yanıtın ClientErrorMapping içeriğini ProblemDetails yapılandırmak için özelliğini kullanın. Örneğin, aşağıdaki kod Startup.ConfigureServices 404 yanıtları için özelliğini güncelleştirir type :

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;
    });

Özel durumları işlemek için özel Ara Yazılım

Özel durum işleme ara yazılımındaki varsayılanlar çoğu uygulama için iyi çalışır. Özel özel durum işleme gerektiren uygulamalar için özel durum işleme ara yazılımını özelleştirmeyi göz önünde bulundurun.

Özel durumlar için ProblemDetails yükü oluşturma

ASP.NET Core, işlenmeyen bir özel durum oluştuğunda standartlaştırılmış bir hata yükü üretmez. İstemciye standartlaştırılmış bir ProblemDetails yanıtının döndürülmesi istenen senaryolarda, ProblemDetails ara yazılımı özel durumları ve 404 yanıtı bir ProblemDetails yüküyle eşlemek için kullanılabilir. Özel durum işleme ara yazılımı, işlenmeyen özel durumlar için yük ProblemDetails döndürmek için de kullanılabilir.