Code re-factorings and formatting for Basket.API project
This commit is contained in:
parent
386c118616
commit
d44c12e718
@ -1,28 +1,28 @@
|
||||
(function ($, swaggerUi) {
|
||||
$(function () {
|
||||
var settings = {
|
||||
authority: 'https://localhost:5105',
|
||||
client_id: 'js',
|
||||
popup_redirect_uri: window.location.protocol
|
||||
+ '//'
|
||||
+ window.location.host
|
||||
+ '/tokenclient/popup.html',
|
||||
$(function () {
|
||||
var settings = {
|
||||
authority: 'https://localhost:5105',
|
||||
client_id: 'js',
|
||||
popup_redirect_uri: window.location.protocol
|
||||
+ '//'
|
||||
+ window.location.host
|
||||
+ '/tokenclient/popup.html',
|
||||
|
||||
response_type: 'id_token token',
|
||||
scope: 'openid profile basket',
|
||||
response_type: 'id_token token',
|
||||
scope: 'openid profile basket',
|
||||
|
||||
filter_protocol_claims: true
|
||||
},
|
||||
manager = new OidcTokenManager(settings),
|
||||
$inputApiKey = $('#input_apiKey');
|
||||
filter_protocol_claims: true
|
||||
},
|
||||
manager = new OidcTokenManager(settings),
|
||||
$inputApiKey = $('#input_apiKey');
|
||||
|
||||
$inputApiKey.on('dblclick', function () {
|
||||
manager.openPopupForTokenAsync()
|
||||
.then(function () {
|
||||
$inputApiKey.val(manager.access_token).change();
|
||||
}, function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
$inputApiKey.on('dblclick', function () {
|
||||
manager.openPopupForTokenAsync()
|
||||
.then(function () {
|
||||
$inputApiKey.val(manager.access_token).change();
|
||||
}, function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
})(jQuery, window.swaggerUi);
|
File diff suppressed because one or more lines are too long
@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="oidc-token-manager.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
new OidcTokenManager().processTokenPopup();
|
||||
</script>
|
||||
<script type="text/javascript" src="oidc-token-manager.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
new OidcTokenManager().processTokenPopup();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -6,28 +6,30 @@ using System.Linq;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server
|
||||
{
|
||||
public class AuthorizationHeaderParameterOperationFilter : IOperationFilter
|
||||
{
|
||||
public void Apply(Operation operation, OperationFilterContext context)
|
||||
{
|
||||
var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors;
|
||||
var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
|
||||
var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);
|
||||
public class AuthorizationHeaderParameterOperationFilter : IOperationFilter
|
||||
{
|
||||
public void Apply(Operation operation, OperationFilterContext context)
|
||||
{
|
||||
var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors;
|
||||
var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
|
||||
var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);
|
||||
|
||||
if (isAuthorized && !allowAnonymous)
|
||||
{
|
||||
if (operation.Parameters == null)
|
||||
operation.Parameters = new List<IParameter>();
|
||||
if (isAuthorized && !allowAnonymous)
|
||||
{
|
||||
if (operation.Parameters == null)
|
||||
{
|
||||
operation.Parameters = new List<IParameter>();
|
||||
}
|
||||
|
||||
operation.Parameters.Add(new NonBodyParameter
|
||||
{
|
||||
Name = "Authorization",
|
||||
In = "header",
|
||||
Description = "access token",
|
||||
Required = true,
|
||||
Type = "string"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
operation.Parameters.Add(new NonBodyParameter
|
||||
{
|
||||
Name = "Authorization",
|
||||
In = "header",
|
||||
Description = "access token",
|
||||
Required = true,
|
||||
Type = "string"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,18 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server
|
||||
{
|
||||
public class IdentitySecurityScheme:SecurityScheme
|
||||
{
|
||||
public IdentitySecurityScheme()
|
||||
{
|
||||
Type = "IdentitySecurityScheme";
|
||||
Description = "Security definition that provides to the user of Swagger a mechanism to obtain a token from the identity service that secures the api";
|
||||
Extensions.Add("authorizationUrl", "http://localhost:5103/Auth/Client/popup.html");
|
||||
Extensions.Add("flow", "implicit");
|
||||
Extensions.Add("scopes", new List<string>
|
||||
{
|
||||
"basket"
|
||||
});
|
||||
}
|
||||
}
|
||||
public class IdentitySecurityScheme : SecurityScheme
|
||||
{
|
||||
public IdentitySecurityScheme()
|
||||
{
|
||||
Type = "IdentitySecurityScheme";
|
||||
Description = "Security definition that provides to the user of Swagger a mechanism to obtain a token from the identity service that secures the api";
|
||||
Extensions.Add("authorizationUrl", "http://localhost:5103/Auth/Client/popup.html");
|
||||
Extensions.Add("flow", "implicit");
|
||||
Extensions.Add("scopes", new List<string>
|
||||
{
|
||||
"basket"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
public class BasketSettings
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
public class BasketSettings
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
|
||||
public string EventBusConnection { get; set; }
|
||||
}
|
||||
public string EventBusConnection { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -11,86 +11,86 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
||||
{
|
||||
[Route("api/v1/[controller]")]
|
||||
[Authorize]
|
||||
public class BasketController : Controller
|
||||
{
|
||||
private readonly IBasketRepository _repository;
|
||||
private readonly IIdentityService _identitySvc;
|
||||
private readonly IEventBus _eventBus;
|
||||
[Route("api/v1/[controller]")]
|
||||
[Authorize]
|
||||
public class BasketController : Controller
|
||||
{
|
||||
private readonly IBasketRepository _repository;
|
||||
private readonly IIdentityService _identitySvc;
|
||||
private readonly IEventBus _eventBus;
|
||||
|
||||
public BasketController(IBasketRepository repository,
|
||||
IIdentityService identityService,
|
||||
IEventBus eventBus)
|
||||
{
|
||||
_repository = repository;
|
||||
_identitySvc = identityService;
|
||||
_eventBus = eventBus;
|
||||
}
|
||||
public BasketController(IBasketRepository repository,
|
||||
IIdentityService identityService,
|
||||
IEventBus eventBus)
|
||||
{
|
||||
_repository = repository;
|
||||
_identitySvc = identityService;
|
||||
_eventBus = eventBus;
|
||||
}
|
||||
|
||||
// GET /id
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> Get(string id)
|
||||
{
|
||||
var basket = await _repository.GetBasketAsync(id);
|
||||
if (basket == null)
|
||||
{
|
||||
return Ok(new CustomerBasket(id) { });
|
||||
}
|
||||
// GET /id
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> Get(string id)
|
||||
{
|
||||
var basket = await _repository.GetBasketAsync(id);
|
||||
if (basket == null)
|
||||
{
|
||||
return Ok(new CustomerBasket(id) { });
|
||||
}
|
||||
|
||||
return Ok(basket);
|
||||
}
|
||||
return Ok(basket);
|
||||
}
|
||||
|
||||
// POST /value
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> Post([FromBody]CustomerBasket value)
|
||||
{
|
||||
var basket = await _repository.UpdateBasketAsync(value);
|
||||
// POST /value
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> Post([FromBody]CustomerBasket value)
|
||||
{
|
||||
var basket = await _repository.UpdateBasketAsync(value);
|
||||
|
||||
return Ok(basket);
|
||||
}
|
||||
return Ok(basket);
|
||||
}
|
||||
|
||||
[Route("checkout")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType((int)HttpStatusCode.Accepted)]
|
||||
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
|
||||
{
|
||||
var userId = _identitySvc.GetUserIdentity();
|
||||
|
||||
[Route("checkout")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType((int)HttpStatusCode.Accepted)]
|
||||
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
|
||||
{
|
||||
var userId = _identitySvc.GetUserIdentity();
|
||||
|
||||
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
|
||||
guid : basketCheckout.RequestId;
|
||||
|
||||
var basket = await _repository.GetBasketAsync(userId);
|
||||
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
|
||||
guid : basketCheckout.RequestId;
|
||||
|
||||
if (basket == null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
var basket = await _repository.GetBasketAsync(userId);
|
||||
|
||||
var userName = User.FindFirst(x => x.Type == "unique_name").Value;
|
||||
if (basket == null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street,
|
||||
basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName,
|
||||
basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket);
|
||||
var userName = User.FindFirst(x => x.Type == "unique_name").Value;
|
||||
|
||||
// Once basket is checkout, sends an integration event to
|
||||
// ordering.api to convert basket to order and proceeds with
|
||||
// order creation process
|
||||
_eventBus.Publish(eventMessage);
|
||||
var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street,
|
||||
basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName,
|
||||
basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket);
|
||||
|
||||
return Accepted();
|
||||
}
|
||||
// Once basket is checkout, sends an integration event to
|
||||
// ordering.api to convert basket to order and proceeds with
|
||||
// order creation process
|
||||
_eventBus.Publish(eventMessage);
|
||||
|
||||
// DELETE api/values/5
|
||||
[HttpDelete("{id}")]
|
||||
public void Delete(string id)
|
||||
{
|
||||
_repository.DeleteBasketAsync(id);
|
||||
}
|
||||
return Accepted();
|
||||
}
|
||||
|
||||
}
|
||||
// DELETE api/values/5
|
||||
[HttpDelete("{id}")]
|
||||
public void Delete(string id)
|
||||
{
|
||||
_repository.DeleteBasketAsync(id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,10 @@
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
// GET: /<controller>/
|
||||
public IActionResult Index()
|
||||
{
|
||||
return new RedirectResult("~/swagger");
|
||||
}
|
||||
}
|
||||
public class HomeController : Controller
|
||||
{
|
||||
// GET: /<controller>/
|
||||
public IActionResult Index()
|
||||
=> new RedirectResult("~/swagger");
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,10 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Basket.API.Infrastructure.ActionResults
|
||||
{
|
||||
public class InternalServerErrorObjectResult : ObjectResult
|
||||
{
|
||||
public InternalServerErrorObjectResult(object error)
|
||||
: base(error)
|
||||
{
|
||||
StatusCode = StatusCodes.Status500InternalServerError;
|
||||
}
|
||||
}
|
||||
public class InternalServerErrorObjectResult : ObjectResult
|
||||
{
|
||||
public InternalServerErrorObjectResult(object error)
|
||||
: base(error)
|
||||
=> StatusCode = StatusCodes.Status500InternalServerError;
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,20 @@
|
||||
|
||||
namespace Basket.API.Infrastructure.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception type for app exceptions
|
||||
/// </summary>
|
||||
public class BasketDomainException : Exception
|
||||
{
|
||||
public BasketDomainException()
|
||||
{ }
|
||||
/// <summary>
|
||||
/// Exception type for app exceptions
|
||||
/// </summary>
|
||||
public class BasketDomainException : Exception
|
||||
{
|
||||
public BasketDomainException()
|
||||
{ }
|
||||
|
||||
public BasketDomainException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
public BasketDomainException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public BasketDomainException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
}
|
||||
public BasketDomainException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,16 @@ using System;
|
||||
|
||||
namespace Basket.API.Infrastructure.Middlewares
|
||||
{
|
||||
public static class FailingMiddlewareAppBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder)
|
||||
{
|
||||
return UseFailingMiddleware(builder, null);
|
||||
}
|
||||
public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder, Action<FailingOptions> action)
|
||||
{
|
||||
var options = new FailingOptions();
|
||||
action?.Invoke(options);
|
||||
builder.UseMiddleware<FailingMiddleware>(options);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
public static class FailingMiddlewareAppBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder)
|
||||
=> UseFailingMiddleware(builder, null);
|
||||
public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder, Action<FailingOptions> action)
|
||||
{
|
||||
var options = new FailingOptions();
|
||||
action?.Invoke(options);
|
||||
builder.UseMiddleware<FailingMiddleware>(options);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,25 +6,25 @@ using System.Linq;
|
||||
|
||||
namespace Basket.API.Infrastructure.Filters
|
||||
{
|
||||
public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||
{
|
||||
public void Apply(Operation operation, OperationFilterContext context)
|
||||
{
|
||||
// Check for authorize attribute
|
||||
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
|
||||
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
|
||||
public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||
{
|
||||
public void Apply(Operation operation, OperationFilterContext context)
|
||||
{
|
||||
// Check for authorize attribute
|
||||
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
|
||||
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
|
||||
|
||||
if (hasAuthorize)
|
||||
{
|
||||
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
|
||||
operation.Responses.Add("403", new Response { Description = "Forbidden" });
|
||||
if (hasAuthorize)
|
||||
{
|
||||
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
|
||||
operation.Responses.Add("403", new Response { Description = "Forbidden" });
|
||||
|
||||
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
|
||||
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
|
||||
{
|
||||
{ "oauth2", new [] { "basketapi" } }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
|
||||
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
|
||||
{
|
||||
{ "oauth2", new [] { "basketapi" } }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,49 +8,49 @@ using System.Net;
|
||||
|
||||
namespace Basket.API.Infrastructure.Filters
|
||||
{
|
||||
public partial class HttpGlobalExceptionFilter : IExceptionFilter
|
||||
{
|
||||
private readonly IHostingEnvironment env;
|
||||
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||
public partial 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 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);
|
||||
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 }
|
||||
};
|
||||
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 occurred. Try it again." }
|
||||
};
|
||||
context.Result = new BadRequestObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
Messages = new[] { "An error occurred. Try it again." }
|
||||
};
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
json.DeveloperMessage = context.Exception;
|
||||
}
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
json.DeveloperMessage = context.Exception;
|
||||
}
|
||||
|
||||
context.Result = new InternalServerErrorObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
}
|
||||
context.Result = new InternalServerErrorObjectResult(json);
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
namespace Basket.API.Infrastructure.Filters
|
||||
{
|
||||
public class JsonErrorResponse
|
||||
{
|
||||
public string[] Messages { get; set; }
|
||||
public class JsonErrorResponse
|
||||
{
|
||||
public string[] Messages { get; set; }
|
||||
|
||||
public object DeveloperMessage { get; set; }
|
||||
}
|
||||
public object DeveloperMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -4,27 +4,27 @@ using System.Linq;
|
||||
|
||||
namespace Basket.API.Infrastructure.Filters
|
||||
{
|
||||
public class ValidateModelStateFilter : ActionFilterAttribute
|
||||
{
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
if (context.ModelState.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public class ValidateModelStateFilter : ActionFilterAttribute
|
||||
{
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
if (context.ModelState.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var validationErrors = context.ModelState
|
||||
.Keys
|
||||
.SelectMany(k => context.ModelState[k].Errors)
|
||||
.Select(e => e.ErrorMessage)
|
||||
.ToArray();
|
||||
var validationErrors = context.ModelState
|
||||
.Keys
|
||||
.SelectMany(k => context.ModelState[k].Errors)
|
||||
.Select(e => e.ErrorMessage)
|
||||
.ToArray();
|
||||
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
Messages = validationErrors
|
||||
};
|
||||
var json = new JsonErrorResponse
|
||||
{
|
||||
Messages = validationErrors
|
||||
};
|
||||
|
||||
context.Result = new BadRequestObjectResult(json);
|
||||
}
|
||||
}
|
||||
context.Result = new BadRequestObjectResult(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,79 +1,78 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.Infrastructure.Middlewares
|
||||
{
|
||||
class ByPassAuthMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private string _currentUserId;
|
||||
public ByPassAuthMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
_currentUserId = null;
|
||||
}
|
||||
class ByPassAuthMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private string _currentUserId;
|
||||
public ByPassAuthMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
_currentUserId = null;
|
||||
}
|
||||
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var path = context.Request.Path;
|
||||
if (path == "/noauth")
|
||||
{
|
||||
var userid = context.Request.Query["userid"];
|
||||
if (!string.IsNullOrEmpty(userid))
|
||||
{
|
||||
_currentUserId = userid;
|
||||
}
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentType = "text/string";
|
||||
await context.Response.WriteAsync($"User set to {_currentUserId}");
|
||||
}
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var path = context.Request.Path;
|
||||
if (path == "/noauth")
|
||||
{
|
||||
var userid = context.Request.Query["userid"];
|
||||
if (!string.IsNullOrEmpty(userid))
|
||||
{
|
||||
_currentUserId = userid;
|
||||
}
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentType = "text/string";
|
||||
await context.Response.WriteAsync($"User set to {_currentUserId}");
|
||||
}
|
||||
|
||||
else if (path == "/noauth/reset")
|
||||
{
|
||||
_currentUserId = null;
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentType = "text/string";
|
||||
await context.Response.WriteAsync($"User set to none. Token required for protected endpoints.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentUserId = _currentUserId;
|
||||
else if (path == "/noauth/reset")
|
||||
{
|
||||
_currentUserId = null;
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentType = "text/string";
|
||||
await context.Response.WriteAsync($"User set to none. Token required for protected endpoints.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentUserId = _currentUserId;
|
||||
|
||||
var authHeader = context.Request.Headers["Authorization"];
|
||||
if (authHeader != StringValues.Empty)
|
||||
{
|
||||
var header = authHeader.FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(header) && header.StartsWith("Email ") && header.Length > "Email ".Length)
|
||||
{
|
||||
currentUserId = header.Substring("Email ".Length);
|
||||
}
|
||||
}
|
||||
var authHeader = context.Request.Headers["Authorization"];
|
||||
if (authHeader != StringValues.Empty)
|
||||
{
|
||||
var header = authHeader.FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(header) && header.StartsWith("Email ") && header.Length > "Email ".Length)
|
||||
{
|
||||
currentUserId = header.Substring("Email ".Length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(currentUserId))
|
||||
{
|
||||
var user = new ClaimsIdentity(new[] {
|
||||
new Claim("emails", currentUserId),
|
||||
new Claim("name", "Test user"),
|
||||
new Claim("nonce", Guid.NewGuid().ToString()),
|
||||
new Claim("ttp://schemas.microsoft.com/identity/claims/identityprovider", "ByPassAuthMiddleware"),
|
||||
new Claim("nonce", Guid.NewGuid().ToString()),
|
||||
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname","User"),
|
||||
new Claim("sub", "1234"),
|
||||
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","Microsoft")}
|
||||
, "ByPassAuth");
|
||||
if (!string.IsNullOrEmpty(currentUserId))
|
||||
{
|
||||
var user = new ClaimsIdentity(new[] {
|
||||
new Claim("emails", currentUserId),
|
||||
new Claim("name", "Test user"),
|
||||
new Claim("nonce", Guid.NewGuid().ToString()),
|
||||
new Claim("ttp://schemas.microsoft.com/identity/claims/identityprovider", "ByPassAuthMiddleware"),
|
||||
new Claim("nonce", Guid.NewGuid().ToString()),
|
||||
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname","User"),
|
||||
new Claim("sub", "1234"),
|
||||
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","Microsoft")}
|
||||
, "ByPassAuth");
|
||||
|
||||
context.User = new ClaimsPrincipal(user);
|
||||
}
|
||||
context.User = new ClaimsPrincipal(user);
|
||||
}
|
||||
|
||||
await _next.Invoke(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
await _next.Invoke(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,78 +5,78 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.Infrastructure.Middlewares
|
||||
{
|
||||
public class FailingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private bool _mustFail;
|
||||
private readonly FailingOptions _options;
|
||||
public FailingMiddleware(RequestDelegate next, FailingOptions options)
|
||||
{
|
||||
_next = next;
|
||||
_options = options;
|
||||
_mustFail = false;
|
||||
}
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var path = context.Request.Path;
|
||||
if (path.Equals(_options.ConfigPath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await ProcessConfigRequest(context);
|
||||
return;
|
||||
}
|
||||
public class FailingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private bool _mustFail;
|
||||
private readonly FailingOptions _options;
|
||||
public FailingMiddleware(RequestDelegate next, FailingOptions options)
|
||||
{
|
||||
_next = next;
|
||||
_options = options;
|
||||
_mustFail = false;
|
||||
}
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var path = context.Request.Path;
|
||||
if (path.Equals(_options.ConfigPath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await ProcessConfigRequest(context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MustFail(context))
|
||||
{
|
||||
context.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Failed due to FailingMiddleware enabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await _next.Invoke(context);
|
||||
}
|
||||
}
|
||||
if (MustFail(context))
|
||||
{
|
||||
context.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Failed due to FailingMiddleware enabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await _next.Invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessConfigRequest(HttpContext context)
|
||||
{
|
||||
var enable = context.Request.Query.Keys.Any(k => k == "enable");
|
||||
var disable = context.Request.Query.Keys.Any(k => k == "disable");
|
||||
private async Task ProcessConfigRequest(HttpContext context)
|
||||
{
|
||||
var enable = context.Request.Query.Keys.Any(k => k == "enable");
|
||||
var disable = context.Request.Query.Keys.Any(k => k == "disable");
|
||||
|
||||
if (enable && disable)
|
||||
{
|
||||
throw new ArgumentException("Must use enable or disable querystring values, but not both");
|
||||
}
|
||||
if (enable && disable)
|
||||
{
|
||||
throw new ArgumentException("Must use enable or disable querystring values, but not both");
|
||||
}
|
||||
|
||||
if (disable)
|
||||
{
|
||||
_mustFail = false;
|
||||
await SendOkResponse(context, "FailingMiddleware disabled. Further requests will be processed.");
|
||||
return;
|
||||
}
|
||||
if (enable)
|
||||
{
|
||||
_mustFail = true;
|
||||
await SendOkResponse(context, "FailingMiddleware enabled. Further requests will return HTTP 500");
|
||||
return;
|
||||
}
|
||||
if (disable)
|
||||
{
|
||||
_mustFail = false;
|
||||
await SendOkResponse(context, "FailingMiddleware disabled. Further requests will be processed.");
|
||||
return;
|
||||
}
|
||||
if (enable)
|
||||
{
|
||||
_mustFail = true;
|
||||
await SendOkResponse(context, "FailingMiddleware enabled. Further requests will return HTTP 500");
|
||||
return;
|
||||
}
|
||||
|
||||
// If reach here, that means that no valid parameter has been passed. Just output status
|
||||
await SendOkResponse(context, string.Format("FailingMiddleware is {0}", _mustFail ? "enabled" : "disabled"));
|
||||
return;
|
||||
}
|
||||
// If reach here, that means that no valid parameter has been passed. Just output status
|
||||
await SendOkResponse(context, string.Format("FailingMiddleware is {0}", _mustFail ? "enabled" : "disabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
private async Task SendOkResponse(HttpContext context, string message)
|
||||
{
|
||||
context.Response.StatusCode = (int)System.Net.HttpStatusCode.OK;
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync(message);
|
||||
}
|
||||
private async Task SendOkResponse(HttpContext context, string message)
|
||||
{
|
||||
context.Response.StatusCode = (int)System.Net.HttpStatusCode.OK;
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync(message);
|
||||
}
|
||||
|
||||
private bool MustFail(HttpContext context)
|
||||
{
|
||||
return _mustFail &&
|
||||
(_options.EndpointPaths.Any(x => x == context.Request.Path.Value)
|
||||
|| _options.EndpointPaths.Count == 0);
|
||||
}
|
||||
}
|
||||
private bool MustFail(HttpContext context)
|
||||
{
|
||||
return _mustFail &&
|
||||
(_options.EndpointPaths.Any(x => x == context.Request.Path.Value)
|
||||
|| _options.EndpointPaths.Count == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace Basket.API.Infrastructure.Middlewares
|
||||
{
|
||||
public class FailingOptions
|
||||
{
|
||||
public string ConfigPath = "/Failing";
|
||||
public List<string> EndpointPaths { get; set; } = new List<string>();
|
||||
}
|
||||
public class FailingOptions
|
||||
{
|
||||
public string ConfigPath = "/Failing";
|
||||
public List<string> EndpointPaths { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
||||
|
@ -4,21 +4,21 @@ using System;
|
||||
|
||||
namespace Basket.API.Infrastructure.Middlewares
|
||||
{
|
||||
public class FailingStartupFilter : IStartupFilter
|
||||
{
|
||||
private readonly Action<FailingOptions> _options;
|
||||
public FailingStartupFilter(Action<FailingOptions> optionsAction)
|
||||
{
|
||||
_options = optionsAction;
|
||||
}
|
||||
public class FailingStartupFilter : IStartupFilter
|
||||
{
|
||||
private readonly Action<FailingOptions> _options;
|
||||
public FailingStartupFilter(Action<FailingOptions> optionsAction)
|
||||
{
|
||||
_options = optionsAction;
|
||||
}
|
||||
|
||||
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
||||
{
|
||||
return app =>
|
||||
{
|
||||
app.UseFailingMiddleware(_options);
|
||||
next(app);
|
||||
};
|
||||
}
|
||||
}
|
||||
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
||||
{
|
||||
return app =>
|
||||
{
|
||||
app.UseFailingMiddleware(_options);
|
||||
next(app);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,15 @@ using System;
|
||||
|
||||
namespace Basket.API.Infrastructure.Middlewares
|
||||
{
|
||||
public static class WebHostBuildertExtensions
|
||||
{
|
||||
public static IWebHostBuilder UseFailing(this IWebHostBuilder builder, Action<FailingOptions> options)
|
||||
{
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
services.AddSingleton<IStartupFilter>(new FailingStartupFilter(options));
|
||||
});
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
public static class WebHostBuildertExtensions
|
||||
{
|
||||
public static IWebHostBuilder UseFailing(this IWebHostBuilder builder, Action<FailingOptions> options)
|
||||
{
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
services.AddSingleton<IStartupFilter>(new FailingStartupFilter(options));
|
||||
});
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,20 +6,20 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Basket.API.IntegrationEvents.EventHandling
|
||||
{
|
||||
public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler<OrderStartedIntegrationEvent>
|
||||
{
|
||||
private readonly IBasketRepository _repository;
|
||||
public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler<OrderStartedIntegrationEvent>
|
||||
{
|
||||
private readonly IBasketRepository _repository;
|
||||
|
||||
public OrderStartedIntegrationEventHandler(IBasketRepository repository)
|
||||
{
|
||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
}
|
||||
public OrderStartedIntegrationEventHandler(IBasketRepository repository)
|
||||
{
|
||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
}
|
||||
|
||||
public async Task Handle(OrderStartedIntegrationEvent @event)
|
||||
{
|
||||
await _repository.DeleteBasketAsync(@event.UserId.ToString());
|
||||
}
|
||||
}
|
||||
public async Task Handle(OrderStartedIntegrationEvent @event)
|
||||
{
|
||||
await _repository.DeleteBasketAsync(@event.UserId.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,46 +7,46 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling
|
||||
{
|
||||
public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>
|
||||
{
|
||||
private readonly IBasketRepository _repository;
|
||||
public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>
|
||||
{
|
||||
private readonly IBasketRepository _repository;
|
||||
|
||||
public ProductPriceChangedIntegrationEventHandler(IBasketRepository repository)
|
||||
{
|
||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
}
|
||||
public ProductPriceChangedIntegrationEventHandler(IBasketRepository repository)
|
||||
{
|
||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
}
|
||||
|
||||
public async Task Handle(ProductPriceChangedIntegrationEvent @event)
|
||||
{
|
||||
var userIds = _repository.GetUsers();
|
||||
|
||||
foreach (var id in userIds)
|
||||
{
|
||||
var basket = await _repository.GetBasketAsync(id);
|
||||
public async Task Handle(ProductPriceChangedIntegrationEvent @event)
|
||||
{
|
||||
var userIds = _repository.GetUsers();
|
||||
|
||||
await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
|
||||
}
|
||||
}
|
||||
foreach (var id in userIds)
|
||||
{
|
||||
var basket = await _repository.GetBasketAsync(id);
|
||||
|
||||
private async Task UpdatePriceInBasketItems(int productId, decimal newPrice, decimal oldPrice, CustomerBasket basket)
|
||||
{
|
||||
string match = productId.ToString();
|
||||
var itemsToUpdate = basket?.Items?.Where(x => x.ProductId == match).ToList();
|
||||
await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemsToUpdate != null)
|
||||
{
|
||||
foreach (var item in itemsToUpdate)
|
||||
{
|
||||
if(item.UnitPrice == oldPrice)
|
||||
{
|
||||
var originalPrice = item.UnitPrice;
|
||||
item.UnitPrice = newPrice;
|
||||
item.OldUnitPrice = originalPrice;
|
||||
}
|
||||
}
|
||||
await _repository.UpdateBasketAsync(basket);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task UpdatePriceInBasketItems(int productId, decimal newPrice, decimal oldPrice, CustomerBasket basket)
|
||||
{
|
||||
string match = productId.ToString();
|
||||
var itemsToUpdate = basket?.Items?.Where(x => x.ProductId == match).ToList();
|
||||
|
||||
if (itemsToUpdate != null)
|
||||
{
|
||||
foreach (var item in itemsToUpdate)
|
||||
{
|
||||
if (item.UnitPrice == oldPrice)
|
||||
{
|
||||
var originalPrice = item.UnitPrice;
|
||||
item.UnitPrice = newPrice;
|
||||
item.OldUnitPrice = originalPrice;
|
||||
}
|
||||
}
|
||||
await _repository.UpdateBasketAsync(basket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,14 @@
|
||||
|
||||
namespace Basket.API.IntegrationEvents.Events
|
||||
{
|
||||
// Integration Events notes:
|
||||
// An Event is “something that has happened in the past”, therefore its name has to be
|
||||
// An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems.
|
||||
public class OrderStartedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
// Integration Events notes:
|
||||
// An Event is “something that has happened in the past”, therefore its name has to be
|
||||
// An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems.
|
||||
public class OrderStartedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
|
||||
public OrderStartedIntegrationEvent(string userId)
|
||||
=> UserId = userId;
|
||||
}
|
||||
public OrderStartedIntegrationEvent(string userId)
|
||||
=> UserId = userId;
|
||||
}
|
||||
}
|
||||
|
@ -2,22 +2,22 @@
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events
|
||||
{
|
||||
// Integration Events notes:
|
||||
// An Event is “something that has happened in the past”, therefore its name has to be
|
||||
// An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems.
|
||||
public class ProductPriceChangedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public int ProductId { get; private set; }
|
||||
// Integration Events notes:
|
||||
// An Event is “something that has happened in the past”, therefore its name has to be
|
||||
// An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems.
|
||||
public class ProductPriceChangedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public int ProductId { get; private set; }
|
||||
|
||||
public decimal NewPrice { get; private set; }
|
||||
public decimal NewPrice { get; private set; }
|
||||
|
||||
public decimal OldPrice { get; private set; }
|
||||
public decimal OldPrice { get; private set; }
|
||||
|
||||
public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice)
|
||||
{
|
||||
ProductId = productId;
|
||||
NewPrice = newPrice;
|
||||
OldPrice = oldPrice;
|
||||
}
|
||||
}
|
||||
public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice)
|
||||
{
|
||||
ProductId = productId;
|
||||
NewPrice = newPrice;
|
||||
OldPrice = oldPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,61 +4,61 @@ using System;
|
||||
|
||||
namespace Basket.API.IntegrationEvents.Events
|
||||
{
|
||||
public class UserCheckoutAcceptedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public string UserId { get; }
|
||||
public class UserCheckoutAcceptedIntegrationEvent : IntegrationEvent
|
||||
{
|
||||
public string UserId { get; }
|
||||
|
||||
public string UserName { get; }
|
||||
public string UserName { get; }
|
||||
|
||||
public int OrderNumber { get; set; }
|
||||
public int OrderNumber { get; set; }
|
||||
|
||||
public string City { get; set; }
|
||||
public string City { get; set; }
|
||||
|
||||
public string Street { get; set; }
|
||||
public string Street { get; set; }
|
||||
|
||||
public string State { get; set; }
|
||||
public string State { get; set; }
|
||||
|
||||
public string Country { get; set; }
|
||||
public string Country { get; set; }
|
||||
|
||||
public string ZipCode { get; set; }
|
||||
public string ZipCode { get; set; }
|
||||
|
||||
public string CardNumber { get; set; }
|
||||
public string CardNumber { get; set; }
|
||||
|
||||
public string CardHolderName { get; set; }
|
||||
public string CardHolderName { get; set; }
|
||||
|
||||
public DateTime CardExpiration { get; set; }
|
||||
public DateTime CardExpiration { get; set; }
|
||||
|
||||
public string CardSecurityNumber { get; set; }
|
||||
public string CardSecurityNumber { get; set; }
|
||||
|
||||
public int CardTypeId { get; set; }
|
||||
public int CardTypeId { get; set; }
|
||||
|
||||
public string Buyer { get; set; }
|
||||
public string Buyer { get; set; }
|
||||
|
||||
public Guid RequestId { get; set; }
|
||||
public Guid RequestId { get; set; }
|
||||
|
||||
public CustomerBasket Basket { get; }
|
||||
public CustomerBasket Basket { get; }
|
||||
|
||||
public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street,
|
||||
string state, string country, string zipCode, string cardNumber, string cardHolderName,
|
||||
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
|
||||
CustomerBasket basket)
|
||||
{
|
||||
UserId = userId;
|
||||
UserName = userName;
|
||||
City = city;
|
||||
Street = street;
|
||||
State = state;
|
||||
Country = country;
|
||||
ZipCode = zipCode;
|
||||
CardNumber = cardNumber;
|
||||
CardHolderName = cardHolderName;
|
||||
CardExpiration = cardExpiration;
|
||||
CardSecurityNumber = cardSecurityNumber;
|
||||
CardTypeId = cardTypeId;
|
||||
Buyer = buyer;
|
||||
Basket = basket;
|
||||
RequestId = requestId;
|
||||
}
|
||||
public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street,
|
||||
string state, string country, string zipCode, string cardNumber, string cardHolderName,
|
||||
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
|
||||
CustomerBasket basket)
|
||||
{
|
||||
UserId = userId;
|
||||
UserName = userName;
|
||||
City = city;
|
||||
Street = street;
|
||||
State = state;
|
||||
Country = country;
|
||||
ZipCode = zipCode;
|
||||
CardNumber = cardNumber;
|
||||
CardHolderName = cardHolderName;
|
||||
CardExpiration = cardExpiration;
|
||||
CardSecurityNumber = cardSecurityNumber;
|
||||
CardTypeId = cardTypeId;
|
||||
Buyer = buyer;
|
||||
Basket = basket;
|
||||
RequestId = requestId;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,31 +2,31 @@
|
||||
|
||||
namespace Basket.API.Model
|
||||
{
|
||||
public class BasketCheckout
|
||||
{
|
||||
public string City { get; set; }
|
||||
public class BasketCheckout
|
||||
{
|
||||
public string City { get; set; }
|
||||
|
||||
public string Street { get; set; }
|
||||
public string Street { get; set; }
|
||||
|
||||
public string State { get; set; }
|
||||
public string State { get; set; }
|
||||
|
||||
public string Country { get; set; }
|
||||
public string Country { get; set; }
|
||||
|
||||
public string ZipCode { get; set; }
|
||||
public string ZipCode { get; set; }
|
||||
|
||||
public string CardNumber { get; set; }
|
||||
public string CardNumber { get; set; }
|
||||
|
||||
public string CardHolderName { get; set; }
|
||||
public string CardHolderName { get; set; }
|
||||
|
||||
public DateTime CardExpiration { get; set; }
|
||||
public DateTime CardExpiration { get; set; }
|
||||
|
||||
public string CardSecurityNumber { get; set; }
|
||||
public string CardSecurityNumber { get; set; }
|
||||
|
||||
public int CardTypeId { get; set; }
|
||||
public int CardTypeId { get; set; }
|
||||
|
||||
public string Buyer { get; set; }
|
||||
public string Buyer { get; set; }
|
||||
|
||||
public Guid RequestId { get; set; }
|
||||
}
|
||||
public Guid RequestId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,25 +3,25 @@ using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public class BasketItem : IValidatableObject
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string ProductId { get; set; }
|
||||
public string ProductName { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
public decimal OldUnitPrice { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public string PictureUrl { get; set; }
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
var results = new List<ValidationResult>();
|
||||
public class BasketItem : IValidatableObject
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string ProductId { get; set; }
|
||||
public string ProductName { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
public decimal OldUnitPrice { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public string PictureUrl { get; set; }
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
var results = new List<ValidationResult>();
|
||||
|
||||
if (Quantity < 1)
|
||||
{
|
||||
results.Add(new ValidationResult("Invalid number of units", new []{ "Quantity" }));
|
||||
}
|
||||
if (Quantity < 1)
|
||||
{
|
||||
results.Add(new ValidationResult("Invalid number of units", new[] { "Quantity" }));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,15 @@
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public class CustomerBasket
|
||||
{
|
||||
public string BuyerId { get; set; }
|
||||
public List<BasketItem> Items { get; set; }
|
||||
public class CustomerBasket
|
||||
{
|
||||
public string BuyerId { get; set; }
|
||||
public List<BasketItem> Items { get; set; }
|
||||
|
||||
public CustomerBasket(string customerId)
|
||||
{
|
||||
BuyerId = customerId;
|
||||
Items = new List<BasketItem>();
|
||||
}
|
||||
}
|
||||
public CustomerBasket(string customerId)
|
||||
{
|
||||
BuyerId = customerId;
|
||||
Items = new List<BasketItem>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public interface IBasketRepository
|
||||
{
|
||||
Task<CustomerBasket> GetBasketAsync(string customerId);
|
||||
IEnumerable<string> GetUsers();
|
||||
Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket);
|
||||
Task<bool> DeleteBasketAsync(string id);
|
||||
}
|
||||
public interface IBasketRepository
|
||||
{
|
||||
Task<CustomerBasket> GetBasketAsync(string customerId);
|
||||
IEnumerable<string> GetUsers();
|
||||
Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket);
|
||||
Task<bool> DeleteBasketAsync(string id);
|
||||
}
|
||||
}
|
||||
|
@ -7,61 +7,61 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public class RedisBasketRepository : IBasketRepository
|
||||
{
|
||||
private readonly ILogger<RedisBasketRepository> _logger;
|
||||
public class RedisBasketRepository : IBasketRepository
|
||||
{
|
||||
private readonly ILogger<RedisBasketRepository> _logger;
|
||||
|
||||
private readonly ConnectionMultiplexer _redis;
|
||||
private readonly IDatabase _database;
|
||||
private readonly ConnectionMultiplexer _redis;
|
||||
private readonly IDatabase _database;
|
||||
|
||||
public RedisBasketRepository(ILoggerFactory loggerFactory, ConnectionMultiplexer redis)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<RedisBasketRepository>();
|
||||
_redis = redis;
|
||||
_database = redis.GetDatabase();
|
||||
}
|
||||
public RedisBasketRepository(ILoggerFactory loggerFactory, ConnectionMultiplexer redis)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<RedisBasketRepository>();
|
||||
_redis = redis;
|
||||
_database = redis.GetDatabase();
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteBasketAsync(string id)
|
||||
{
|
||||
return await _database.KeyDeleteAsync(id);
|
||||
}
|
||||
public async Task<bool> DeleteBasketAsync(string id)
|
||||
{
|
||||
return await _database.KeyDeleteAsync(id);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetUsers()
|
||||
{
|
||||
var server = GetServer();
|
||||
var data = server.Keys();
|
||||
return data?.Select(k => k.ToString());
|
||||
}
|
||||
public IEnumerable<string> GetUsers()
|
||||
{
|
||||
var server = GetServer();
|
||||
var data = server.Keys();
|
||||
return data?.Select(k => k.ToString());
|
||||
}
|
||||
|
||||
public async Task<CustomerBasket> GetBasketAsync(string customerId)
|
||||
{
|
||||
var data = await _database.StringGetAsync(customerId);
|
||||
if (data.IsNullOrEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public async Task<CustomerBasket> GetBasketAsync(string customerId)
|
||||
{
|
||||
var data = await _database.StringGetAsync(customerId);
|
||||
if (data.IsNullOrEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<CustomerBasket>(data);
|
||||
}
|
||||
return JsonConvert.DeserializeObject<CustomerBasket>(data);
|
||||
}
|
||||
|
||||
public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket)
|
||||
{
|
||||
var created = await _database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket));
|
||||
if (!created)
|
||||
{
|
||||
_logger.LogInformation("Problem occur persisting the item.");
|
||||
return null;
|
||||
}
|
||||
public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket)
|
||||
{
|
||||
var created = await _database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket));
|
||||
if (!created)
|
||||
{
|
||||
_logger.LogInformation("Problem occur persisting the item.");
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Basket item persisted succesfully.");
|
||||
_logger.LogInformation("Basket item persisted succesfully.");
|
||||
|
||||
return await GetBasketAsync(basket.BuyerId);
|
||||
}
|
||||
return await GetBasketAsync(basket.BuyerId);
|
||||
}
|
||||
|
||||
private IServer GetServer()
|
||||
{
|
||||
var endpoint = _redis.GetEndPoints();
|
||||
return _redis.GetServer(endpoint.First());
|
||||
}
|
||||
}
|
||||
private IServer GetServer()
|
||||
{
|
||||
var endpoint = _redis.GetEndPoints();
|
||||
return _redis.GetServer(endpoint.First());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +1,61 @@
|
||||
using Basket.API.Infrastructure.Middlewares;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using static Microsoft.AspNetCore.Hosting.ApplicationInsightsWebHostBuilderExtensions;
|
||||
using static Microsoft.AspNetCore.Hosting.HealthCheckWebHostBuilderExtension;
|
||||
using static Microsoft.AspNetCore.Hosting.HostingAbstractionsWebHostBuilderExtensions;
|
||||
using static Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions;
|
||||
using static Microsoft.AspNetCore.Hosting.WebHostExtensions;
|
||||
using static Microsoft.Extensions.Configuration.AzureKeyVaultConfigurationExtensions;
|
||||
using static Microsoft.Extensions.Configuration.ChainedBuilderExtensions;
|
||||
using static Microsoft.Extensions.Configuration.EnvironmentVariablesExtensions;
|
||||
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
|
||||
using Convert = System.Convert;
|
||||
using Directory = System.IO.Directory;
|
||||
using IWebHost = Microsoft.AspNetCore.Hosting.IWebHost;
|
||||
using WebHost = Microsoft.AspNetCore.WebHost;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
BuildWebHost(args).Run();
|
||||
}
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
=> BuildWebHost(args).Run();
|
||||
|
||||
public static IWebHost BuildWebHost(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseFailing(options =>
|
||||
{
|
||||
options.ConfigPath = "/Failing";
|
||||
})
|
||||
.UseHealthChecks("/hc")
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseStartup<Startup>()
|
||||
.ConfigureAppConfiguration((builderContext, config) =>
|
||||
{
|
||||
var builtConfig = config.Build();
|
||||
public static IWebHost BuildWebHost(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseFailing(options =>
|
||||
{
|
||||
options.ConfigPath = "/Failing";
|
||||
})
|
||||
.UseHealthChecks("/hc")
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseStartup<Startup>()
|
||||
.ConfigureAppConfiguration((builderContext, config) =>
|
||||
{
|
||||
var builtConfig = config.Build();
|
||||
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
|
||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
||||
{
|
||||
configurationBuilder.AddAzureKeyVault(
|
||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
||||
builtConfig["Vault:ClientId"],
|
||||
builtConfig["Vault:ClientSecret"]);
|
||||
}
|
||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
||||
{
|
||||
configurationBuilder.AddAzureKeyVault(
|
||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
||||
builtConfig["Vault:ClientId"],
|
||||
builtConfig["Vault:ClientSecret"]);
|
||||
}
|
||||
|
||||
configurationBuilder.AddEnvironmentVariables();
|
||||
configurationBuilder.AddEnvironmentVariables();
|
||||
|
||||
config.AddConfiguration(configurationBuilder.Build());
|
||||
})
|
||||
.ConfigureLogging((hostingContext, builder) =>
|
||||
{
|
||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
builder.AddConsole();
|
||||
builder.AddDebug();
|
||||
})
|
||||
.UseApplicationInsights()
|
||||
.Build();
|
||||
}
|
||||
config.AddConfiguration(configurationBuilder.Build());
|
||||
})
|
||||
.ConfigureLogging((hostingContext, builder) =>
|
||||
{
|
||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
builder.AddConsole();
|
||||
builder.AddDebug();
|
||||
})
|
||||
.UseApplicationInsights()
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Services
|
||||
{
|
||||
public interface IIdentityService
|
||||
{
|
||||
string GetUserIdentity();
|
||||
}
|
||||
public interface IIdentityService
|
||||
{
|
||||
string GetUserIdentity();
|
||||
}
|
||||
}
|
||||
|
@ -4,18 +4,18 @@ using System;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Services
|
||||
{
|
||||
public class IdentityService : IIdentityService
|
||||
{
|
||||
private IHttpContextAccessor _context;
|
||||
public class IdentityService : IIdentityService
|
||||
{
|
||||
private IHttpContextAccessor _context;
|
||||
|
||||
public IdentityService(IHttpContextAccessor context)
|
||||
{
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
public IdentityService(IHttpContextAccessor context)
|
||||
{
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
public string GetUserIdentity()
|
||||
{
|
||||
return _context.HttpContext.User.FindFirst("sub").Value;
|
||||
}
|
||||
}
|
||||
public string GetUserIdentity()
|
||||
{
|
||||
return _context.HttpContext.User.FindFirst("sub").Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,281 +34,285 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
RegisterAppInsights(services);
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
RegisterAppInsights(services);
|
||||
|
||||
// Add framework services.
|
||||
services.AddMvc(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||
options.Filters.Add(typeof(ValidateModelStateFilter));
|
||||
// Add framework services.
|
||||
services
|
||||
.AddMvc(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||
options.Filters.Add(typeof(ValidateModelStateFilter));
|
||||
|
||||
}).AddControllersAsServices();
|
||||
})
|
||||
.AddControllersAsServices();
|
||||
|
||||
ConfigureAuthService(services);
|
||||
ConfigureAuthService(services);
|
||||
|
||||
services.AddHealthChecks(checks =>
|
||||
{
|
||||
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")),
|
||||
TimeSpan.Zero //No cache for this HealthCheck, better just for demos
|
||||
);
|
||||
});
|
||||
services.AddHealthChecks(checks =>
|
||||
{
|
||||
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")),
|
||||
TimeSpan.Zero //No cache for this HealthCheck, better just for demos
|
||||
);
|
||||
});
|
||||
|
||||
services.Configure<BasketSettings>(Configuration);
|
||||
services.Configure<BasketSettings>(Configuration);
|
||||
|
||||
//By connecting here we are making sure that our service
|
||||
//cannot start until redis is ready. This might slow down startup,
|
||||
//but given that there is a delay on resolving the ip address
|
||||
//and then creating the connection it seems reasonable to move
|
||||
//that cost to startup instead of having the first request pay the
|
||||
//penalty.
|
||||
services.AddSingleton<ConnectionMultiplexer>(sp =>
|
||||
{
|
||||
var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
|
||||
var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true);
|
||||
//By connecting here we are making sure that our service
|
||||
//cannot start until redis is ready. This might slow down startup,
|
||||
//but given that there is a delay on resolving the ip address
|
||||
//and then creating the connection it seems reasonable to move
|
||||
//that cost to startup instead of having the first request pay the
|
||||
//penalty.
|
||||
services.AddSingleton(sp =>
|
||||
{
|
||||
var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
|
||||
var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true);
|
||||
|
||||
configuration.ResolveDns = true;
|
||||
configuration.ResolveDns = true;
|
||||
|
||||
return ConnectionMultiplexer.Connect(configuration);
|
||||
});
|
||||
return ConnectionMultiplexer.Connect(configuration);
|
||||
});
|
||||
|
||||
|
||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||
{
|
||||
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||
{
|
||||
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||
{
|
||||
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||
{
|
||||
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
||||
|
||||
var serviceBusConnectionString = Configuration["EventBusConnection"];
|
||||
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
||||
var serviceBusConnectionString = Configuration["EventBusConnection"];
|
||||
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
||||
|
||||
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
||||
{
|
||||
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
||||
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
||||
{
|
||||
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
||||
|
||||
var factory = new ConnectionFactory()
|
||||
{
|
||||
HostName = Configuration["EventBusConnection"]
|
||||
};
|
||||
var factory = new ConnectionFactory()
|
||||
{
|
||||
HostName = Configuration["EventBusConnection"]
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
|
||||
{
|
||||
factory.UserName = Configuration["EventBusUserName"];
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
|
||||
{
|
||||
factory.UserName = Configuration["EventBusUserName"];
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
|
||||
{
|
||||
factory.Password = Configuration["EventBusPassword"];
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
|
||||
{
|
||||
factory.Password = Configuration["EventBusPassword"];
|
||||
}
|
||||
|
||||
var retryCount = 5;
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||
{
|
||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||
}
|
||||
var retryCount = 5;
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||
{
|
||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||
}
|
||||
|
||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
||||
});
|
||||
}
|
||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
||||
});
|
||||
}
|
||||
|
||||
RegisterEventBus(services);
|
||||
RegisterEventBus(services);
|
||||
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.DescribeAllEnumsAsStrings();
|
||||
options.SwaggerDoc("v1", new Info
|
||||
{
|
||||
Title = "Basket HTTP API",
|
||||
Version = "v1",
|
||||
Description = "The Basket Service HTTP API",
|
||||
TermsOfService = "Terms Of Service"
|
||||
});
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.DescribeAllEnumsAsStrings();
|
||||
options.SwaggerDoc("v1", new Info
|
||||
{
|
||||
Title = "Basket HTTP API",
|
||||
Version = "v1",
|
||||
Description = "The Basket Service HTTP API",
|
||||
TermsOfService = "Terms Of Service"
|
||||
});
|
||||
|
||||
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
||||
{
|
||||
Type = "oauth2",
|
||||
Flow = "implicit",
|
||||
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
||||
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
||||
Scopes = new Dictionary<string, string>()
|
||||
{
|
||||
{ "basket", "Basket API" }
|
||||
}
|
||||
});
|
||||
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
||||
{
|
||||
Type = "oauth2",
|
||||
Flow = "implicit",
|
||||
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
||||
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
||||
Scopes = new Dictionary<string, string>()
|
||||
{
|
||||
{ "basket", "Basket API" }
|
||||
}
|
||||
});
|
||||
|
||||
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||
});
|
||||
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||
});
|
||||
|
||||
services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("CorsPolicy",
|
||||
builder => builder.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials());
|
||||
});
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
||||
services.AddTransient<IIdentityService, IdentityService>();
|
||||
services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("CorsPolicy",
|
||||
builder => builder.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials());
|
||||
});
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
||||
services.AddTransient<IIdentityService, IdentityService>();
|
||||
|
||||
services.AddOptions();
|
||||
services.AddOptions();
|
||||
|
||||
var container = new ContainerBuilder();
|
||||
container.Populate(services);
|
||||
var container = new ContainerBuilder();
|
||||
container.Populate(services);
|
||||
|
||||
return new AutofacServiceProvider(container.Build());
|
||||
}
|
||||
|
||||
return new AutofacServiceProvider(container.Build());
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||
{
|
||||
loggerFactory.AddAzureWebAppDiagnostics();
|
||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||
|
||||
var pathBase = Configuration["PATH_BASE"];
|
||||
if (!string.IsNullOrEmpty(pathBase))
|
||||
{
|
||||
app.UsePathBase(pathBase);
|
||||
}
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||
{
|
||||
loggerFactory.AddAzureWebAppDiagnostics();
|
||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||
|
||||
var pathBase = Configuration["PATH_BASE"];
|
||||
if (!string.IsNullOrEmpty(pathBase))
|
||||
{
|
||||
app.UsePathBase(pathBase);
|
||||
}
|
||||
|
||||
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
||||
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseCors("CorsPolicy");
|
||||
app.UseStaticFiles();
|
||||
app.UseCors("CorsPolicy");
|
||||
|
||||
ConfigureAuth(app);
|
||||
ConfigureAuth(app);
|
||||
|
||||
app.UseMvcWithDefaultRoute();
|
||||
app.UseMvcWithDefaultRoute();
|
||||
|
||||
app.UseSwagger()
|
||||
.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
|
||||
c.OAuthClientId ("basketswaggerui");
|
||||
c.OAuthAppName("Basket Swagger UI");
|
||||
});
|
||||
app.UseSwagger()
|
||||
.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
|
||||
c.OAuthClientId("basketswaggerui");
|
||||
c.OAuthAppName("Basket Swagger UI");
|
||||
});
|
||||
|
||||
ConfigureEventBus(app);
|
||||
ConfigureEventBus(app);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterAppInsights(IServiceCollection services)
|
||||
{
|
||||
services.AddApplicationInsightsTelemetry(Configuration);
|
||||
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
||||
|
||||
if (orchestratorType?.ToUpper() == "K8S")
|
||||
{
|
||||
// Enable K8s telemetry initializer
|
||||
services.EnableKubernetes();
|
||||
}
|
||||
if (orchestratorType?.ToUpper() == "SF")
|
||||
{
|
||||
// Enable SF telemetry initializer
|
||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||
new FabricTelemetryInitializer());
|
||||
}
|
||||
}
|
||||
private void RegisterAppInsights(IServiceCollection services)
|
||||
{
|
||||
services.AddApplicationInsightsTelemetry(Configuration);
|
||||
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
||||
|
||||
private void ConfigureAuthService(IServiceCollection services)
|
||||
{
|
||||
// prevent from mapping "sub" claim to nameidentifier.
|
||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||
if (orchestratorType?.ToUpper() == "K8S")
|
||||
{
|
||||
// Enable K8s telemetry initializer
|
||||
services.EnableKubernetes();
|
||||
}
|
||||
if (orchestratorType?.ToUpper() == "SF")
|
||||
{
|
||||
// Enable SF telemetry initializer
|
||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||
new FabricTelemetryInitializer());
|
||||
}
|
||||
}
|
||||
|
||||
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
||||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
private void ConfigureAuthService(IServiceCollection services)
|
||||
{
|
||||
// prevent from mapping "sub" claim to nameidentifier.
|
||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||
|
||||
}).AddJwtBearer(options =>
|
||||
{
|
||||
options.Authority = identityUrl;
|
||||
options.RequireHttpsMetadata = false;
|
||||
options.Audience = "basket";
|
||||
});
|
||||
}
|
||||
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
||||
|
||||
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||
{
|
||||
if (Configuration.GetValue<bool>("UseLoadTest"))
|
||||
{
|
||||
app.UseMiddleware<ByPassAuthMiddleware>();
|
||||
}
|
||||
services
|
||||
.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
|
||||
app.UseAuthentication();
|
||||
}
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.Authority = identityUrl;
|
||||
options.RequireHttpsMetadata = false;
|
||||
options.Audience = "basket";
|
||||
});
|
||||
}
|
||||
|
||||
private void RegisterEventBus(IServiceCollection services)
|
||||
{
|
||||
var subscriptionClientName = Configuration["SubscriptionClientName"];
|
||||
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||
{
|
||||
if (Configuration.GetValue<bool>("UseLoadTest"))
|
||||
{
|
||||
app.UseMiddleware<ByPassAuthMiddleware>();
|
||||
}
|
||||
|
||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||
{
|
||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||
{
|
||||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||
app.UseAuthentication();
|
||||
}
|
||||
|
||||
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
||||
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
|
||||
{
|
||||
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
|
||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
|
||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||
private void RegisterEventBus(IServiceCollection services)
|
||||
{
|
||||
var subscriptionClientName = Configuration["SubscriptionClientName"];
|
||||
|
||||
var retryCount = 5;
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||
{
|
||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||
}
|
||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||
{
|
||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||
{
|
||||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||
|
||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||
});
|
||||
}
|
||||
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
||||
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
|
||||
{
|
||||
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
|
||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
|
||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||
|
||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||
var retryCount = 5;
|
||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||
{
|
||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||
}
|
||||
|
||||
services.AddTransient<ProductPriceChangedIntegrationEventHandler>();
|
||||
services.AddTransient<OrderStartedIntegrationEventHandler>();
|
||||
}
|
||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||
});
|
||||
}
|
||||
|
||||
private void ConfigureEventBus(IApplicationBuilder app)
|
||||
{
|
||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||
|
||||
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>();
|
||||
eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>();
|
||||
}
|
||||
}
|
||||
services.AddTransient<ProductPriceChangedIntegrationEventHandler>();
|
||||
services.AddTransient<OrderStartedIntegrationEventHandler>();
|
||||
}
|
||||
|
||||
private void ConfigureEventBus(IApplicationBuilder app)
|
||||
{
|
||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
||||
|
||||
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>();
|
||||
eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
{
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
"IdentityUrl": "http://localhost:5105",
|
||||
"ConnectionString": "127.0.0.1",
|
||||
"AzureServiceBusEnabled": false,
|
||||
"SubscriptionClientName": "Basket",
|
||||
"ApplicationInsights": {
|
||||
"InstrumentationKey": ""
|
||||
},
|
||||
"EventBusRetryCount": 5,
|
||||
"UseVault": false,
|
||||
"Vault": {
|
||||
"Name": "eshop",
|
||||
"ClientId": "your-clien-id",
|
||||
"ClientSecret": "your-client-secret"
|
||||
}
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
"IdentityUrl": "http://localhost:5105",
|
||||
"ConnectionString": "127.0.0.1",
|
||||
"AzureServiceBusEnabled": false,
|
||||
"SubscriptionClientName": "Basket",
|
||||
"ApplicationInsights": {
|
||||
"InstrumentationKey": ""
|
||||
},
|
||||
"EventBusRetryCount": 5,
|
||||
"UseVault": false,
|
||||
"Vault": {
|
||||
"Name": "eshop",
|
||||
"ClientId": "your-clien-id",
|
||||
"ClientSecret": "your-client-secret"
|
||||
}
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
|
||||
-->
|
||||
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
||||
</system.webServer>
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
|
Loading…
x
Reference in New Issue
Block a user