Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
1 contributor

Users who have contributed to this file

157 lines (130 sloc) 5.22 KB
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Hellang.Middleware.ProblemDetails.Sample
{
public class Startup
{
public Startup(IWebHostEnvironment environment)
{
Environment = environment;
}
private IWebHostEnvironment Environment { get; }
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseEnvironment(Environments.Development)
//.UseEnvironment(Environments.Production) // Uncomment to remove exception details from responses.
.ConfigureWebHostDefaults(web =>
{
web.UseStartup<Startup>();
});
}
public void ConfigureServices(IServiceCollection services)
{
services.AddProblemDetails(ConfigureProblemDetails)
.AddControllers()
.AddJsonOptions(x => x.JsonSerializerOptions.IgnoreNullValues = true);
}
public void Configure(IApplicationBuilder app)
{
app.UseProblemDetails();
app.Use(CustomMiddleware);
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
private void ConfigureProblemDetails(ProblemDetailsOptions options)
{
// This is the default behavior; only include exception details in a development environment.
options.IncludeExceptionDetails = (ctx, ex) => Environment.IsDevelopment();
// This will map NotImplementedException to the 501 Not Implemented status code.
options.MapToStatusCode<NotImplementedException>(StatusCodes.Status501NotImplemented);
// This will map HttpRequestException to the 503 Service Unavailable status code.
options.MapToStatusCode<HttpRequestException>(StatusCodes.Status503ServiceUnavailable);
// Because exceptions are handled polymorphically, this will act as a "catch all" mapping, which is why it's added last.
// If an exception other than NotImplementedException and HttpRequestException is thrown, this will handle it.
options.MapToStatusCode<Exception>(StatusCodes.Status500InternalServerError);
}
private Task CustomMiddleware(HttpContext context, Func<Task> next)
{
if (context.Request.Path.StartsWithSegments("/middleware", out _, out var remaining))
{
if (remaining.StartsWithSegments("/error"))
{
throw new Exception("This is an exception thrown from middleware.");
}
if (remaining.StartsWithSegments("/status", out _, out remaining))
{
var statusCodeString = remaining.Value.Trim('/');
if (int.TryParse(statusCodeString, out var statusCode))
{
context.Response.StatusCode = statusCode;
return Task.CompletedTask;
}
}
}
return next();
}
}
[Route("mvc")]
public class MvcController : ControllerBase
{
[HttpGet("status/{statusCode}")]
public IActionResult Status([FromRoute] int statusCode)
{
return StatusCode(statusCode);
}
[HttpGet("error")]
public IActionResult Error()
{
throw new NotImplementedException("This is an exception thrown from an MVC controller.");
}
[HttpGet("error/details")]
public IActionResult ErrorDetails()
{
ModelState.AddModelError("someProperty", "This property failed validation.");
var validation = new ValidationProblemDetails(ModelState)
{
Status = StatusCodes.Status422UnprocessableEntity
};
throw new ProblemDetailsException(validation);
}
[HttpGet("result")]
public IActionResult Result()
{
var problem = new OutOfCreditProblemDetails
{
Type = "https://example.com/probs/out-of-credit",
Title = "You do not have enough credit.",
Detail = "Your current balance is 30, but that costs 50.",
Instance = "/account/12345/msgs/abc",
Balance = 30.0m,
Accounts = { "/account/12345","/account/67890" }
};
return BadRequest(problem);
}
}
public class OutOfCreditProblemDetails : Microsoft.AspNetCore.Mvc.ProblemDetails
{
public OutOfCreditProblemDetails()
{
Accounts = new List<string>();
}
public decimal Balance { get; set; }
public ICollection<string> Accounts { get; }
}
}
You can’t perform that action at this time.