Created global filters for web apis
Fix bug BadRequest response after creating order
This commit is contained in:
parent
45499808b9
commit
3a7a14bdb7
@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.Infrastructure.ActionResults
|
||||
{
|
||||
public class InternalServerErrorObjectResult : ObjectResult
|
||||
{
|
||||
public InternalServerErrorObjectResult(object error)
|
||||
: base(error)
|
||||
{
|
||||
StatusCode = StatusCodes.Status500InternalServerError;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.Infrastructure.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception type for app exceptions
|
||||
/// </summary>
|
||||
public class BasketDomainException : Exception
|
||||
{
|
||||
public BasketDomainException()
|
||||
{ }
|
||||
|
||||
public BasketDomainException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public BasketDomainException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
using Basket.API.Infrastructure.ActionResults;
|
||||
using Basket.API.Infrastructure.Exceptions;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.Infrastructure.Filters
|
||||
{
|
||||
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||
{
|
||||
private readonly IHostingEnvironment env;
|
||||
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||
|
||||
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
||||
{
|
||||
this.env = env;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void OnException(ExceptionContext context)
|
||||
{
|
||||
logger.LogError(new EventId(context.Exception.HResult),
|
||||
context.Exception,
|
||||
context.Exception.Message);
|
||||
|
||||
if (context.Exception.GetType() == typeof(BasketDomainException))
|
||||
{
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
Messages = new[] { context.Exception.Message }
|
||||
};
|
||||
|
||||
context.Result = new BadRequestObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
Messages = new[] { "An error ocurr.Try it again." }
|
||||
};
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
json.DeveloperMeesage = context.Exception;
|
||||
}
|
||||
|
||||
context.Result = new InternalServerErrorObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
|
||||
private class JsonErrorResponse
|
||||
{
|
||||
public string[] Messages { get; set; }
|
||||
|
||||
public object DeveloperMeesage { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events;
|
||||
using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling;
|
||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
||||
using System;
|
||||
using Basket.API.Infrastructure.Filters;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
@ -35,7 +36,11 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add framework services.
|
||||
services.AddMvc();
|
||||
services.AddMvc(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||
}).AddControllersAsServices();
|
||||
|
||||
services.Configure<BasketSettings>(Configuration);
|
||||
|
||||
//By connecting here we are making sure that our service
|
||||
|
@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Catalog.API.Infrastructure.ActionResults
|
||||
{
|
||||
public class InternalServerErrorObjectResult : ObjectResult
|
||||
{
|
||||
public InternalServerErrorObjectResult(object error)
|
||||
: base(error)
|
||||
{
|
||||
StatusCode = StatusCodes.Status500InternalServerError;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Catalog.API.Infrastructure.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception type for app exceptions
|
||||
/// </summary>
|
||||
public class CatalogDomainException : Exception
|
||||
{
|
||||
public CatalogDomainException()
|
||||
{ }
|
||||
|
||||
public CatalogDomainException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public CatalogDomainException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
using Catalog.API.Infrastructure.ActionResults;
|
||||
using Catalog.API.Infrastructure.Exceptions;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net;
|
||||
|
||||
namespace Catalog.API.Infrastructure.Filters
|
||||
{
|
||||
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||
{
|
||||
private readonly IHostingEnvironment env;
|
||||
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||
|
||||
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
||||
{
|
||||
this.env = env;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void OnException(ExceptionContext context)
|
||||
{
|
||||
logger.LogError(new EventId(context.Exception.HResult),
|
||||
context.Exception,
|
||||
context.Exception.Message);
|
||||
|
||||
if (context.Exception.GetType() == typeof(CatalogDomainException))
|
||||
{
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
Messages = new[] { context.Exception.Message }
|
||||
};
|
||||
|
||||
context.Result = new BadRequestObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
Messages = new[] { "An error ocurr.Try it again." }
|
||||
};
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
json.DeveloperMeesage = context.Exception;
|
||||
}
|
||||
|
||||
context.Result = new InternalServerErrorObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
|
||||
private class JsonErrorResponse
|
||||
{
|
||||
public string[] Messages { get; set; }
|
||||
|
||||
public object DeveloperMeesage { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||
{
|
||||
using global::Catalog.API.Infrastructure.Filters;
|
||||
using global::Catalog.API.IntegrationEvents;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
@ -41,6 +42,12 @@
|
||||
{
|
||||
var sqlConnection = new SqlConnection(Configuration["ConnectionString"]);
|
||||
|
||||
// Add framework services.
|
||||
services.AddMvc(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||
}).AddControllersAsServices();
|
||||
|
||||
services.AddDbContext<CatalogContext>(c =>
|
||||
{
|
||||
c.UseSqlServer(sqlConnection);
|
||||
@ -86,19 +93,12 @@
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var configuration = serviceProvider.GetRequiredService<IOptionsSnapshot<Settings>>().Value;
|
||||
services.AddSingleton<IEventBus>(new EventBusRabbitMQ(configuration.EventBusConnection));
|
||||
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IntegrationEventLogContext integrationEventLogContext)
|
||||
{
|
||||
//Configure logs
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
|
||||
|
@ -51,11 +51,8 @@
|
||||
|
||||
_orderRepository.Add(order);
|
||||
|
||||
var result = await _orderRepository.UnitOfWork
|
||||
return await _orderRepository.UnitOfWork
|
||||
.SaveEntitiesAsync();
|
||||
|
||||
return result > 0;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
||||
}
|
||||
else
|
||||
{
|
||||
await _requestManager.CreateRequestForCommandAsync<T>(message.Id);
|
||||
var result = await _mediator.SendAsync(message.Command);
|
||||
await _requestManager.CreateRequestForCommandAsync<T>(message.Id);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Filters
|
||||
{
|
||||
using AspNetCore.Mvc;
|
||||
using global::Ordering.Domain.Exceptions;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||
{
|
||||
@ -24,7 +25,7 @@
|
||||
context.Exception,
|
||||
context.Exception.Message);
|
||||
|
||||
if (context.Exception.GetType() == typeof(ArgumentException)) //TODO:Select a common exception for application like EshopException
|
||||
if (context.Exception.GetType() == typeof(OrderingDomainException))
|
||||
{
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
@ -32,6 +33,7 @@
|
||||
};
|
||||
|
||||
context.Result = new BadRequestObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -46,8 +48,9 @@
|
||||
}
|
||||
|
||||
context.Result = new InternalServerErrorObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
|
||||
private class JsonErrorResponse
|
||||
|
@ -103,11 +103,6 @@
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseCors("CorsPolicy");
|
||||
|
||||
app.UseFailingMiddleware();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
||||
using Ordering.Domain.Exceptions;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate
|
||||
@ -22,13 +23,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
|
||||
public PaymentMethod(int cardTypeId, string alias, string cardNumber, string securityNumber, string cardHolderName, DateTime expiration)
|
||||
{
|
||||
|
||||
_cardNumber = !string.IsNullOrWhiteSpace(cardNumber) ? cardNumber : throw new ArgumentException(nameof(cardNumber));
|
||||
_securityNumber = !string.IsNullOrWhiteSpace(securityNumber) ? securityNumber : throw new ArgumentException(nameof(securityNumber));
|
||||
_cardHolderName = !string.IsNullOrWhiteSpace(cardHolderName) ? cardHolderName : throw new ArgumentException(nameof(cardHolderName));
|
||||
_cardNumber = !string.IsNullOrWhiteSpace(cardNumber) ? cardNumber : throw new OrderingDomainException(nameof(cardNumber));
|
||||
_securityNumber = !string.IsNullOrWhiteSpace(securityNumber) ? securityNumber : throw new OrderingDomainException(nameof(securityNumber));
|
||||
_cardHolderName = !string.IsNullOrWhiteSpace(cardHolderName) ? cardHolderName : throw new OrderingDomainException(nameof(cardHolderName));
|
||||
|
||||
if (expiration < DateTime.UtcNow)
|
||||
{
|
||||
throw new ArgumentException(nameof(expiration));
|
||||
throw new OrderingDomainException(nameof(expiration));
|
||||
}
|
||||
|
||||
_alias = alias;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
||||
using Ordering.Domain.Exceptions;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate
|
||||
@ -24,12 +25,12 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
||||
{
|
||||
if (units <= 0)
|
||||
{
|
||||
throw new ArgumentNullException("Invalid number of units");
|
||||
throw new OrderingDomainException("Invalid number of units");
|
||||
}
|
||||
|
||||
if ((unitPrice * units) < discount)
|
||||
{
|
||||
throw new ArgumentException("The total of order item is lower than applied discount");
|
||||
throw new OrderingDomainException("The total of order item is lower than applied discount");
|
||||
}
|
||||
|
||||
ProductId = productId;
|
||||
@ -58,7 +59,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
||||
{
|
||||
if (discount < 0)
|
||||
{
|
||||
throw new ArgumentException("Discount is not valid");
|
||||
throw new OrderingDomainException("Discount is not valid");
|
||||
}
|
||||
|
||||
_discount = discount;
|
||||
@ -68,7 +69,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
||||
{
|
||||
if (units < 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid units");
|
||||
throw new OrderingDomainException("Invalid units");
|
||||
}
|
||||
|
||||
_units += units;
|
||||
|
@ -1,5 +1,6 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate
|
||||
{
|
||||
using global::Ordering.Domain.Exceptions;
|
||||
using Seedwork;
|
||||
using SeedWork;
|
||||
using System;
|
||||
@ -34,7 +35,7 @@
|
||||
|
||||
if (state == null)
|
||||
{
|
||||
throw new ArgumentException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
||||
throw new OrderingDomainException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
||||
}
|
||||
|
||||
return state;
|
||||
@ -46,7 +47,7 @@
|
||||
|
||||
if (state == null)
|
||||
{
|
||||
throw new ArgumentException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
||||
throw new OrderingDomainException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
||||
}
|
||||
|
||||
return state;
|
||||
|
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ordering.Domain.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception type for domain exceptions
|
||||
/// </summary>
|
||||
public class OrderingDomainException : Exception
|
||||
{
|
||||
public OrderingDomainException()
|
||||
{ }
|
||||
|
||||
public OrderingDomainException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public OrderingDomainException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
}
|
||||
}
|
@ -7,6 +7,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork
|
||||
public interface IUnitOfWork : IDisposable
|
||||
{
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
||||
Task<int> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
||||
Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
||||
.IsRequired();
|
||||
}
|
||||
|
||||
public async Task<int> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// Dispatch Domain Events collection.
|
||||
// Choices:
|
||||
@ -249,7 +249,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
||||
// After executing this line all the changes performed thought the DbContext will be commited
|
||||
var result = await base.SaveChangesAsync();
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||
using Ordering.Domain.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
@ -26,7 +27,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor
|
||||
|
||||
var exists = await ExistAsync(id);
|
||||
var request = exists ?
|
||||
throw new Exception($"Request with {id} already exists") :
|
||||
throw new OrderingDomainException($"Request with {id} already exists") :
|
||||
new ClientRequest()
|
||||
{
|
||||
Id = id,
|
||||
|
@ -56,6 +56,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
|
||||
var response = await _apiClient.PostAsync(basketUrl, basket);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return basket;
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
||||
throw new Exception("Error creating order, try later");
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public void OverrideUserInfoIntoOrder(Order original, Order destination)
|
||||
|
@ -1,8 +1,10 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Polly;
|
||||
using Polly.Wrap;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -78,9 +80,13 @@ namespace WebMVC.Services.Utilities
|
||||
HttpInvoker(() =>
|
||||
{
|
||||
var response = _client.PostAsync(uri, new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"));
|
||||
// raise exception if not success response
|
||||
// raise exception if HttpResponseCode 500
|
||||
// needed for circuit breaker to track fails
|
||||
response.Result.EnsureSuccessStatusCode();
|
||||
if (response.Result.StatusCode == HttpStatusCode.InternalServerError)
|
||||
{
|
||||
throw new HttpRequestException();
|
||||
}
|
||||
|
||||
return response;
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user