Added Error Handling
11
API/Controllers/BaseApiController.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace API.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class BaseApiController : ControllerBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
47
API/Controllers/BuggyController.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using API.Errors;
|
||||
using Infrastructure.Data;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace API.Controllers
|
||||
{
|
||||
public class BuggyController : BaseApiController
|
||||
{
|
||||
private readonly StoreContext _context;
|
||||
public BuggyController(StoreContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
[HttpGet("notfound")]
|
||||
public ActionResult GetNotFoundRequest()
|
||||
{
|
||||
var thing = _context.Products.Find(42);
|
||||
if (thing == null)
|
||||
{
|
||||
return NotFound(new ApiResponse(404));
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet("servererror")]
|
||||
public ActionResult GetServerError()
|
||||
{
|
||||
var thing = _context.Products.Find(42);
|
||||
var thingToReturn = thing.ToString();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet("badrequest")]
|
||||
public ActionResult GetBadRequest()
|
||||
{
|
||||
return BadRequest(new ApiResponse(400));
|
||||
}
|
||||
|
||||
[HttpGet("badrequest/{id}")]
|
||||
public ActionResult GetNotFoundRequest(int id)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
14
API/Controllers/ErrorController.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using API.Errors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace API.Controllers
|
||||
{
|
||||
[Route("errors/{code}")]
|
||||
public class ErrorController : BaseApiController
|
||||
{
|
||||
public IActionResult Error(int code)
|
||||
{
|
||||
return new ObjectResult(new ApiResponse(code));
|
||||
}
|
||||
}
|
||||
}
|
@ -7,9 +7,7 @@ using AutoMapper;
|
||||
|
||||
namespace API.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ProductsController : ControllerBase
|
||||
public class ProductsController : BaseApiController
|
||||
{
|
||||
private readonly IGenericRepository<Product> _productsRepo;
|
||||
private readonly IGenericRepository<ProductBrand> _productBrandRepo;
|
||||
|
12
API/Errors/ApiException.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace API.Errors
|
||||
{
|
||||
public class ApiException : ApiResponse
|
||||
{
|
||||
public ApiException(int statusCode, string message = null, string details = null) : base(statusCode, message)
|
||||
{
|
||||
Details = details;
|
||||
}
|
||||
|
||||
public string Details { get; set; }
|
||||
}
|
||||
}
|
31
API/Errors/ApiResponse.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace API.Errors
|
||||
{
|
||||
public class ApiResponse
|
||||
{
|
||||
public ApiResponse(int statusCode, string message = null)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Message = message ?? GetDefaultMessageForStatusCode(statusCode);
|
||||
}
|
||||
|
||||
public int StatusCode { get; set; }
|
||||
public string Message { get; set; }
|
||||
|
||||
private string GetDefaultMessageForStatusCode(int statusCode)
|
||||
{
|
||||
return statusCode switch
|
||||
{
|
||||
400 => "A bad request, you have made",
|
||||
401 => "Authorized, you are not",
|
||||
404 => "Resource found, it was not",
|
||||
500 => "Errors are the path to the dark side. Errors lead to anger. Anger leads to hate. Hate leads to career change",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
39
API/Middleware/ExceptionMiddleware.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using API.Errors;
|
||||
|
||||
namespace API.Middleware
|
||||
{
|
||||
public class ExceptionMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<ExceptionMiddleware> _logger;
|
||||
private readonly IHostEnvironment _env;
|
||||
public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger, IHostEnvironment env)
|
||||
{
|
||||
_env = env;
|
||||
_logger = logger;
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, ex.Message);
|
||||
context.Response.ContentType = "application/json";
|
||||
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
var response = _env.IsDevelopment()
|
||||
? new ApiException((int)HttpStatusCode.InternalServerError, ex.Message, ex.StackTrace.ToString())
|
||||
: new ApiException((int)HttpStatusCode.InternalServerError);
|
||||
var options = new JsonSerializerOptions{PropertyNamingPolicy = JsonNamingPolicy.CamelCase};
|
||||
var json = JsonSerializer.Serialize(response, options);
|
||||
await context.Response.WriteAsync(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using API.Helpers;
|
||||
using API.Middleware;
|
||||
using Core.Interfaces;
|
||||
using Infrastructure.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -33,16 +34,20 @@ namespace API
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
app.UseMiddleware<ExceptionMiddleware>();
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPIv5 v1"));
|
||||
}
|
||||
|
||||
app.UseStatusCodePagesWithReExecute("/errors/{0}");
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseRouting();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
|
BIN
API/wwwroot/images/products/boot-ang1.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
API/wwwroot/images/products/boot-ang2.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
API/wwwroot/images/products/boot-core1.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
API/wwwroot/images/products/boot-core2.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
API/wwwroot/images/products/boot-redis1.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
API/wwwroot/images/products/glove-code1.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
API/wwwroot/images/products/glove-code2.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
API/wwwroot/images/products/glove-react1.png
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
API/wwwroot/images/products/glove-react2.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
API/wwwroot/images/products/hat-core1.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
API/wwwroot/images/products/hat-react1.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
API/wwwroot/images/products/hat-react2.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
API/wwwroot/images/products/sb-ang1.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
API/wwwroot/images/products/sb-ang2.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
API/wwwroot/images/products/sb-core1.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
API/wwwroot/images/products/sb-core2.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
API/wwwroot/images/products/sb-react1.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
API/wwwroot/images/products/sb-ts1.png
Normal file
After Width: | Height: | Size: 50 KiB |