Skip to content
This repository has been archived by the owner on Dec 2, 2023. It is now read-only.

Commit

Permalink
For review
Browse files Browse the repository at this point in the history
Complete redesign:
-Changed how developer configures the error response container
-Changed how developer creates new custom details
-Added Swagger example documentation models
-Simplified/cleaned up how developer sets up ExceptionAll in Program.cs
  • Loading branch information
1eyewonder committed Jan 18, 2022
1 parent e83d092 commit c31ca9c
Show file tree
Hide file tree
Showing 68 changed files with 1,279 additions and 909 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ PublishScripts/
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
**/nuget.config

# Microsoft Azure Build Output
csx/
Expand Down
137 changes: 77 additions & 60 deletions ExceptionAll.APIExample/Controllers/WeatherForecastController.cs
Original file line number Diff line number Diff line change
@@ -1,83 +1,100 @@
using ExceptionAll.Details;
using ExceptionAll.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using ExceptionAll.Models;
using Microsoft.AspNetCore.Authorization;

namespace ExceptionAll.APIExample.Controllers
namespace ExceptionAll.APIExample.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
private static readonly string[] Summaries = new[]
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger<WeatherForecastController> _logger;
private readonly IActionResultService _actionResultService;
private readonly ILogger<WeatherForecastController> _logger;
private readonly IActionResultService _actionResultService;

public WeatherForecastController(ILogger<WeatherForecastController> logger,
IActionResultService actionResultService)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_actionResultService = actionResultService ?? throw new ArgumentNullException(nameof(actionResultService));
}
public WeatherForecastController(ILogger<WeatherForecastController> logger,
IActionResultService actionResultService)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_actionResultService = actionResultService ?? throw new ArgumentNullException(nameof(actionResultService));
}

[HttpGet]
public async Task<IActionResult> GetAll()
[HttpGet]
[ProducesResponseType(typeof(ApiErrorDetails), (int)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> GetAll()
{
await Task.Delay(0);
var rng = new Random();
var result = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
await Task.Delay(0);
var rng = new Random();
var result = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
throw new Exception("This is simulating an uncaught exception");
}
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
throw new Exception("This is simulating an uncaught exception");
}

[HttpGet]
[Route("api/GetNullRefError")]
public async Task<IActionResult> GetNullRefError(string param)
[HttpGet]
[Route("api/GetNullRefError")]
public async Task<IActionResult> GetNullRefError(string param, string otherParam)
{
param = null;
await Task.Delay(0);
throw new ArgumentNullException(nameof(param));
}

// If the developer doesn't want to use the template in all instances,
// wrapping the code in try catch will let you use your own logic
[HttpGet]
[Route("api/GetWithoutExceptionAllError")]
public async Task<IActionResult> GetWithoutExceptionAllError()
{
await Task.Delay(0);
try
{
param = null;
await Task.Delay(0);
throw new ArgumentNullException(nameof(param));
throw new Exception("Some exception");
}

// If the developer doesn't want to use the template in all instances,
// wrapping the code in try catch will let you use your own logic
[HttpGet]
[Route("api/GetWithoutExceptionAllError")]
public async Task<IActionResult> GetWithoutExceptionAllError()
catch (Exception e)
{
await Task.Delay(0);
try
{
throw new Exception("Some exception");
}
catch (Exception e)
{
Console.WriteLine(e);
return BadRequest(e.Message);
}
Console.WriteLine(e);
return BadRequest(e.Message);
}
}

// If the developer needs to manually error handle, they can call
// the 'GetResponse' manually
[HttpGet]
[Route("api/GetSomething")]
public async Task<IActionResult> GetSomethingWithQuery([FromQuery]string test)
// If the developer needs to manually error handle, they can call
// the 'GetResponse' manually
[HttpGet]
[Route("api/GetSomething")]
[ProducesResponseType(typeof(BadRequestDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(NotFoundDetails), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(InternalServerErrorDetails), StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetSomethingWithQuery([FromQuery] string test)
{
await Task.Delay(0);

var errors = new List<ErrorDetail>
{
await Task.Delay(0);
return _actionResultService.GetResponse<NotFoundDetails>(ControllerContext,
$"No item exists with name of {test}");
}
new("Error #1", "Something wrong happened here"),
new("Error #2", "Something wrong happened there")
};

return _actionResultService.GetResponse<NotFoundDetails>(
ControllerContext,
$"No item exists with name of {test}",
errors);
}
}
9 changes: 6 additions & 3 deletions ExceptionAll.APIExample/ExceptionAll.APIExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentValidation" Version="10.3.0" />
<PackageReference Include="FluentValidation.AspNetCore" Version="10.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.5" />
<PackageReference Include="FluentValidation" Version="10.3.6" />
<PackageReference Include="FluentValidation.AspNetCore" Version="10.3.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down
51 changes: 27 additions & 24 deletions ExceptionAll.APIExample/ExceptionAllConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
using ExceptionAll.Details;
using ExceptionAll.Dtos;
using ExceptionAll.Interfaces;
using ExceptionAll.Interfaces;
using ExceptionAll.Models;
using FluentValidation;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;

namespace ExceptionAll.APIExample
namespace ExceptionAll.APIExample;

public class ExceptionAllConfiguration : IExceptionAllConfiguration
{
public static class ExceptionAllConfiguration
public List<IErrorResponse> ErrorResponses => new()
{
public static List<IErrorResponse> GetErrorResponses()
{
return new List<IErrorResponse>()
{
ErrorResponse
.CreateErrorResponse()
.WithTitle("Bad Request - Fluent Validation")
.ForException<ValidationException>()
.WithReturnType<BadRequestDetails>()
.WithLogAction((x, e) => x.LogError(e, "Something bad happened")),
ErrorResponse
.CreateErrorResponse()
.WithTitle("Argument Null Exception")
.WithStatusCode(500)
.WithMessage("The developer goofed")
.ForException<ArgumentNullException>()
.WithLogAction((x, e) => x.LogDebug(e, "Oops I did it again"))
};

ErrorResponse
.CreateErrorResponse()
.WithTitle("Bad Request")
.ForException<ArgumentNullException>()
.WithReturnType<BadRequestDetails>()
.WithLogAction((x, e) => x.LogError(e, "Something bad happened"))
};
public Dictionary<string, Func<HttpContext, object>>? ContextConfiguration => new()
{
{ "Path", x => x?.Request.Path.Value ?? string.Empty },
{ "Query", x => x.Request.QueryString.Value ?? string.Empty },
{ "TraceIdentifier", x => x?.TraceIdentifier ?? string.Empty },
{ "LocalIpAddress", x => x?.Connection.LocalIpAddress?.ToString() ?? string.Empty },
{
"CorrelationId",
x => x.Request.Headers["x-correlation-id"]
.ToString()
}
}
}
};
}
73 changes: 51 additions & 22 deletions ExceptionAll.APIExample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,55 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ExceptionAll.APIExample
{
public class Program
using ExceptionAll.APIExample;
using ExceptionAll.Helpers;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
using System.IO;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddExceptionAll<ExceptionAllConfiguration>()
.WithExceptionAllSwaggerExamples();

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen(
c =>
{
public static void Main(string[] args)
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ExceptionAll.APIExample", Version = "v1" });
c.EnableAnnotations();
c.ExampleFilters();

if (File.Exists("/ExceptionAll-swagger.xml"))
{
CreateHostBuilder(args).Build().Run();
c.IncludeXmlComments("/ExceptionAll-swagger.xml");
}
});

var app = builder.Build();

app.Services.AddExceptionAll();

// Configure the HTTP request pipeline.

app.UseSwagger();

app.UseSwaggerUI(
c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "ExceptionAll.APIExample v1");
c.DisplayRequestDuration();
c.EnableTryItOutByDefault();
});

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
app.Run();
61 changes: 0 additions & 61 deletions ExceptionAll.APIExample/Startup.cs

This file was deleted.

Loading

0 comments on commit c31ca9c

Please sign in to comment.