Browse Source

Code re-factorings and formatting for Basket.API project

pull/762/head
Rafsanul Hasan 6 years ago
parent
commit
d44c12e718
No known key found for this signature in database GPG Key ID: FC57FD2D87BE60DD
36 changed files with 9862 additions and 9882 deletions
  1. +23
    -23
      src/Services/Basket/Basket.API/Auth/Client/enable-token-client.js
  2. +8843
    -8868
      src/Services/Basket/Basket.API/Auth/Client/oidc-token-manager.js
  3. +6
    -6
      src/Services/Basket/Basket.API/Auth/Client/popup.html
  4. +24
    -22
      src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs
  5. +14
    -14
      src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs
  6. +5
    -5
      src/Services/Basket/Basket.API/BasketSettings.cs
  7. +82
    -82
      src/Services/Basket/Basket.API/Controllers/BasketController.cs
  8. +6
    -8
      src/Services/Basket/Basket.API/Controllers/HomeController.cs
  9. +6
    -8
      src/Services/Basket/Basket.API/Infrastructure/ActionResults/InternalServerErrorObjectResult.cs
  10. +14
    -14
      src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs
  11. +12
    -14
      src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs
  12. +19
    -19
      src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
  13. +39
    -39
      src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs
  14. +5
    -5
      src/Services/Basket/Basket.API/Infrastructure/Filters/JsonErrorResponse.cs
  15. +20
    -20
      src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs
  16. +60
    -61
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/ByPassAuthMiddleware.cs
  17. +67
    -67
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs
  18. +5
    -5
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs
  19. +16
    -16
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs
  20. +11
    -11
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs
  21. +12
    -12
      src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs
  22. +41
    -41
      src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs
  23. +9
    -9
      src/Services/Basket/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs
  24. +15
    -15
      src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs
  25. +40
    -40
      src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
  26. +15
    -15
      src/Services/Basket/Basket.API/Model/BasketCheckout.cs
  27. +19
    -19
      src/Services/Basket/Basket.API/Model/BasketItem.cs
  28. +10
    -10
      src/Services/Basket/Basket.API/Model/CustomerBasket.cs
  29. +7
    -7
      src/Services/Basket/Basket.API/Model/IBasketRepository.cs
  30. +47
    -47
      src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs
  31. +49
    -43
      src/Services/Basket/Basket.API/Program.cs
  32. +4
    -4
      src/Services/Basket/Basket.API/Services/IIdentityService.cs
  33. +12
    -12
      src/Services/Basket/Basket.API/Services/IdentityService.cs
  34. +276
    -272
      src/Services/Basket/Basket.API/Startup.cs
  35. +22
    -22
      src/Services/Basket/Basket.API/appsettings.json
  36. +7
    -7
      src/Services/Basket/Basket.API/web.config

+ 23
- 23
src/Services/Basket/Basket.API/Auth/Client/enable-token-client.js View File

@ -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);

+ 8843
- 8868
src/Services/Basket/Basket.API/Auth/Client/oidc-token-manager.js
File diff suppressed because it is too large
View File


+ 6
- 6
src/Services/Basket/Basket.API/Auth/Client/popup.html View File

@ -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>

+ 24
- 22
src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs View File

@ -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"
});
}
}
}
}

+ 14
- 14
src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs View File

@ -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"
});
}
}
}

+ 5
- 5
src/Services/Basket/Basket.API/BasketSettings.cs View File

@ -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; }
}
}

+ 82
- 82
src/Services/Basket/Basket.API/Controllers/BasketController.cs View File

@ -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;
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) { });
}
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);
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();
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
guid : basketCheckout.RequestId;
var basket = await _repository.GetBasketAsync(userId);
if (basket == null)
{
return BadRequest();
}
var userName = User.FindFirst(x => x.Type == "unique_name").Value;
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);
// 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);
return Accepted();
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(string id)
{
_repository.DeleteBasketAsync(id);
}
}
[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;
}
// 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);
}
// 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);
}
[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);
if (basket == null)
{
return BadRequest();
}
var userName = User.FindFirst(x => x.Type == "unique_name").Value;
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);
// 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);
return Accepted();
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(string id)
{
_repository.DeleteBasketAsync(id);
}
}
}

+ 6
- 8
src/Services/Basket/Basket.API/Controllers/HomeController.cs View File

@ -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");
}
}

+ 6
- 8
src/Services/Basket/Basket.API/Infrastructure/ActionResults/InternalServerErrorObjectResult.cs View File

@ -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;
}
}

+ 14
- 14
src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs View File

@ -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)
{ }
}
}

+ 12
- 14
src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs View File

@ -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;
}
}
}

+ 19
- 19
src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs View File

@ -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" } }
});
}
}
}
}

+ 39
- 39
src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs View File

@ -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;
}
}
}

+ 5
- 5
src/Services/Basket/Basket.API/Infrastructure/Filters/JsonErrorResponse.cs View File

@ -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; }
}
}

+ 20
- 20
src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs View File

@ -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);
}
}
}

+ 60
- 61
src/Services/Basket/Basket.API/Infrastructure/Middlewares/ByPassAuthMiddleware.cs View File

@ -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);
}
}
}
}

+ 67
- 67
src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs View File

@ -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);
}
}
}

+ 5
- 5
src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs View File

@ -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>();
}
}

+ 16
- 16
src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs View File

@ -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);
};
}
}
}

+ 11
- 11
src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs View File

@ -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;
}
}
}

+ 12
- 12
src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs View File

@ -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());
}
}
}


+ 41
- 41
src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs View File

@ -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 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);
await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, 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);
}
}
}
public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>
{
private readonly IBasketRepository _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);
await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, 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);
}
}
}
}

+ 9
- 9
src/Services/Basket/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs View File

@ -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;
}
}

+ 15
- 15
src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs View File

@ -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;
}
}
}

+ 40
- 40
src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs View File

@ -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;
}
}
}
}

+ 15
- 15
src/Services/Basket/Basket.API/Model/BasketCheckout.cs View File

@ -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; }
}
}

+ 19
- 19
src/Services/Basket/Basket.API/Model/BasketItem.cs View File

@ -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;
}
}
}

+ 10
- 10
src/Services/Basket/Basket.API/Model/CustomerBasket.cs View File

@ -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>();
}
}
}

+ 7
- 7
src/Services/Basket/Basket.API/Model/IBasketRepository.cs View File

@ -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);
}
}

+ 47
- 47
src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs View File

@ -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());
}
}
}

+ 49
- 43
src/Services/Basket/Basket.API/Program.cs View File

@ -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();
}
}

+ 4
- 4
src/Services/Basket/Basket.API/Services/IIdentityService.cs View File

@ -1,7 +1,7 @@
namespace Microsoft.eShopOnContainers.Services.Basket.API.Services
{
public interface IIdentityService
{
string GetUserIdentity();
}
public interface IIdentityService
{
string GetUserIdentity();
}
}

+ 12
- 12
src/Services/Basket/Basket.API/Services/IdentityService.cs View File

@ -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;
}
}
}

+ 276
- 272
src/Services/Basket/Basket.API/Startup.cs View File

@ -34,281 +34,285 @@ using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Basket.API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
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);
// Add framework services.
services.AddMvc(options =>
{
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
options.Filters.Add(typeof(ValidateModelStateFilter));
}).AddControllersAsServices();
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.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);
configuration.ResolveDns = true;
return ConnectionMultiplexer.Connect(configuration);
});
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
{
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
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>>();
var factory = new ConnectionFactory()
{
HostName = Configuration["EventBusConnection"]
};
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
{
factory.UserName = Configuration["EventBusUserName"];
}
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
{
factory.Password = Configuration["EventBusPassword"];
}
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
});
}
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"
});
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>();
});
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();
var container = new ContainerBuilder();
container.Populate(services);
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);
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
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);
// Add framework services.
services
.AddMvc(options =>
{
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
options.Filters.Add(typeof(ValidateModelStateFilter));
})
.AddControllersAsServices();
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.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(sp =>
{
var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true);
configuration.ResolveDns = true;
return ConnectionMultiplexer.Connect(configuration);
});
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
{
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
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>>();
var factory = new ConnectionFactory()
{
HostName = Configuration["EventBusConnection"]
};
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
{
factory.UserName = Configuration["EventBusUserName"];
}
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
{
factory.Password = Configuration["EventBusPassword"];
}
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
});
}
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"
});
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>();
});
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();
var container = new ContainerBuilder();
container.Populate(services);
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);
}
#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");
ConfigureAuth(app);
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");
});
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 ConfigureAuthService(IServiceCollection services)
{
// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.Audience = "basket";
});
}
protected virtual void ConfigureAuth(IApplicationBuilder app)
{
if (Configuration.GetValue<bool>("UseLoadTest"))
{
app.UseMiddleware<ByPassAuthMiddleware>();
}
app.UseAuthentication();
}
private void RegisterEventBus(IServiceCollection services)
{
var subscriptionClientName = Configuration["SubscriptionClientName"];
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 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>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
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>();
}
}
app.UseStaticFiles();
app.UseCors("CorsPolicy");
ConfigureAuth(app);
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");
});
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 ConfigureAuthService(IServiceCollection services)
{
// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.Audience = "basket";
});
}
protected virtual void ConfigureAuth(IApplicationBuilder app)
{
if (Configuration.GetValue<bool>("UseLoadTest"))
{
app.UseMiddleware<ByPassAuthMiddleware>();
}
app.UseAuthentication();
}
private void RegisterEventBus(IServiceCollection services)
{
var subscriptionClientName = Configuration["SubscriptionClientName"];
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 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>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
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>();
}
}
}

+ 22
- 22
src/Services/Basket/Basket.API/appsettings.json View File

@ -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"
}
}

+ 7
- 7
src/Services/Basket/Basket.API/web.config View File

@ -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…
Cancel
Save