Merge pull request #952 from dotnet-architecture/features/add-seq-sink
Add Seq sink for Serilog and sample traces
This commit is contained in:
commit
23992ed324
2
.gitignore
vendored
2
.gitignore
vendored
@ -26,7 +26,7 @@ bld/
|
|||||||
# Visual Studio 2015 cache/options directory
|
# Visual Studio 2015 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
|
|
||||||
# Files created by bundling and minification on startup
|
# .js files created on build:
|
||||||
src/Web/WebMVC/wwwroot/js/site*
|
src/Web/WebMVC/wwwroot/js/site*
|
||||||
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
@ -7,6 +7,12 @@ version: '3.4'
|
|||||||
# An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance.
|
# An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance.
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
seq:
|
||||||
|
environment:
|
||||||
|
- ACCEPT_EULA=Y
|
||||||
|
ports:
|
||||||
|
- "5340:80"
|
||||||
|
|
||||||
sql.data:
|
sql.data:
|
||||||
environment:
|
environment:
|
||||||
- SA_PASSWORD=Pass@word
|
- SA_PASSWORD=Pass@word
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
version: '3.4'
|
version: '3.4'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
seq:
|
||||||
|
image: datalust/seq:latest
|
||||||
|
|
||||||
sql.data:
|
sql.data:
|
||||||
image: microsoft/mssql-server-linux:2017-latest
|
image: microsoft/mssql-server-linux:2017-latest
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
app.UsePathBase(pathBase);
|
app.UsePathBase(pathBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
|
|||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
app.UsePathBase(pathBase);
|
app.UsePathBase(pathBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
.Or<BrokerUnreachableException>()
|
.Or<BrokerUnreachableException>()
|
||||||
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex.ToString());
|
_logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s ({ExceptionMessage})", $"{time.TotalSeconds:n1}", ex.Message);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
_connection.CallbackException += OnCallbackException;
|
_connection.CallbackException += OnCallbackException;
|
||||||
_connection.ConnectionBlocked += OnConnectionBlocked;
|
_connection.ConnectionBlocked += OnConnectionBlocked;
|
||||||
|
|
||||||
_logger.LogInformation($"RabbitMQ persistent connection acquired a connection {_connection.Endpoint.HostName} and is subscribed to failure events");
|
_logger.LogInformation("RabbitMQ Client acquired a persistent connection to '{HostName}' and is subscribed to failure events", _connection.Endpoint.HostName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
.Or<SocketException>()
|
.Or<SocketException>()
|
||||||
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex.ToString());
|
_logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message);
|
||||||
});
|
});
|
||||||
|
|
||||||
using (var channel = _persistentConnection.CreateModel())
|
using (var channel = _persistentConnection.CreateModel())
|
||||||
|
@ -83,7 +83,7 @@
|
|||||||
}
|
}
|
||||||
catch (ServiceBusException)
|
catch (ServiceBusException)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"The messaging entity {eventName} already exists.");
|
_logger.LogWarning("The messaging entity {eventName} already exists.", eventName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@
|
|||||||
}
|
}
|
||||||
catch (MessagingEntityNotFoundException)
|
catch (MessagingEntityNotFoundException)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"The messaging entity {eventName} Could not be found.");
|
_logger.LogWarning("The messaging entity {eventName} Could not be found.", eventName);
|
||||||
}
|
}
|
||||||
|
|
||||||
_subsManager.RemoveSubscription<T, TH>();
|
_subsManager.RemoveSubscription<T, TH>();
|
||||||
@ -194,7 +194,7 @@
|
|||||||
}
|
}
|
||||||
catch (MessagingEntityNotFoundException)
|
catch (MessagingEntityNotFoundException)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"The messaging entity { RuleDescription.DefaultRuleName } Could not be found.");
|
_logger.LogWarning("The messaging entity {DefaultRuleName} Could not be found.", RuleDescription.DefaultRuleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}");
|
logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name);
|
||||||
|
|
||||||
if (underK8s)
|
if (underK8s)
|
||||||
{
|
{
|
||||||
@ -55,11 +55,11 @@ namespace Microsoft.AspNetCore.Hosting
|
|||||||
retry.Execute(() => InvokeSeeder(seeder, context, services));
|
retry.Execute(() => InvokeSeeder(seeder, context, services));
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}");
|
logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, $"An error occurred while migrating the database used on context {typeof(TContext).Name}");
|
logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name);
|
||||||
if (underK8s)
|
if (underK8s)
|
||||||
{
|
{
|
||||||
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
|
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
|
||||||
|
@ -13,25 +13,28 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="2.2.0" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
|
||||||
<PackageReference Include="StackExchange.Redis.StrongName" Version="1.2.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
|
<PackageReference Include="StackExchange.Redis.StrongName" Version="1.2.6" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.Services;
|
using Microsoft.eShopOnContainers.Services.Basket.API.Services;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -19,9 +21,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
|||||||
private readonly IBasketRepository _repository;
|
private readonly IBasketRepository _repository;
|
||||||
private readonly IIdentityService _identityService;
|
private readonly IIdentityService _identityService;
|
||||||
private readonly IEventBus _eventBus;
|
private readonly IEventBus _eventBus;
|
||||||
|
private readonly ILogger<BasketController> _logger;
|
||||||
|
|
||||||
public BasketController(IBasketRepository repository, IIdentityService identityService, IEventBus eventBus)
|
public BasketController(
|
||||||
|
ILogger<BasketController> logger,
|
||||||
|
IBasketRepository repository,
|
||||||
|
IIdentityService identityService,
|
||||||
|
IEventBus eventBus)
|
||||||
{
|
{
|
||||||
|
_logger = logger;
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_identityService = identityService;
|
_identityService = identityService;
|
||||||
_eventBus = eventBus;
|
_eventBus = eventBus;
|
||||||
@ -50,7 +58,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
|||||||
public async Task<ActionResult> CheckoutAsync([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
|
public async Task<ActionResult> CheckoutAsync([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
|
||||||
{
|
{
|
||||||
var userId = _identityService.GetUserIdentity();
|
var userId = _identityService.GetUserIdentity();
|
||||||
|
|
||||||
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
|
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
|
||||||
guid : basketCheckout.RequestId;
|
guid : basketCheckout.RequestId;
|
||||||
|
|
||||||
@ -70,7 +78,18 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
|||||||
// Once basket is checkout, sends an integration event to
|
// Once basket is checkout, sends an integration event to
|
||||||
// ordering.api to convert basket to order and proceeds with
|
// ordering.api to convert basket to order and proceeds with
|
||||||
// order creation process
|
// order creation process
|
||||||
_eventBus.Publish(eventMessage);
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", eventMessage.Id, Program.AppName, eventMessage);
|
||||||
|
|
||||||
|
_eventBus.Publish(eventMessage);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from {AppName}", eventMessage.Id, Program.AppName);
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
return Accepted();
|
return Accepted();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using Basket.API.IntegrationEvents.Events;
|
using Basket.API.IntegrationEvents.Events;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Basket.API;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -9,15 +12,24 @@ namespace Basket.API.IntegrationEvents.EventHandling
|
|||||||
public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler<OrderStartedIntegrationEvent>
|
public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler<OrderStartedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IBasketRepository _repository;
|
private readonly IBasketRepository _repository;
|
||||||
|
private readonly ILogger<OrderStartedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStartedIntegrationEventHandler(IBasketRepository repository)
|
public OrderStartedIntegrationEventHandler(
|
||||||
|
IBasketRepository repository,
|
||||||
|
ILogger<OrderStartedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderStartedIntegrationEvent @event)
|
public async Task Handle(OrderStartedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
await _repository.DeleteBasketAsync(@event.UserId.ToString());
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
await _repository.DeleteBasketAsync(@event.UserId.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events;
|
using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -9,22 +11,31 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
|
|||||||
{
|
{
|
||||||
public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>
|
public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>
|
||||||
{
|
{
|
||||||
|
private readonly ILogger<ProductPriceChangedIntegrationEventHandler> _logger;
|
||||||
private readonly IBasketRepository _repository;
|
private readonly IBasketRepository _repository;
|
||||||
|
|
||||||
public ProductPriceChangedIntegrationEventHandler(IBasketRepository repository)
|
public ProductPriceChangedIntegrationEventHandler(
|
||||||
|
ILogger<ProductPriceChangedIntegrationEventHandler> logger,
|
||||||
|
IBasketRepository repository)
|
||||||
{
|
{
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(ProductPriceChangedIntegrationEvent @event)
|
public async Task Handle(ProductPriceChangedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var userIds = _repository.GetUsers();
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
|
|
||||||
foreach (var id in userIds)
|
|
||||||
{
|
{
|
||||||
var basket = await _repository.GetBasketAsync(id);
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
|
var userIds = _repository.GetUsers();
|
||||||
|
|
||||||
|
foreach (var id in userIds)
|
||||||
|
{
|
||||||
|
var basket = await _repository.GetBasketAsync(id);
|
||||||
|
|
||||||
|
await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,17 +46,19 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
|
|||||||
|
|
||||||
if (itemsToUpdate != null)
|
if (itemsToUpdate != null)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("----- ProductPriceChangedIntegrationEventHandler - Updating items in basket for user: {BuyerId} ({@Items})", basket.BuyerId, itemsToUpdate);
|
||||||
|
|
||||||
foreach (var item in itemsToUpdate)
|
foreach (var item in itemsToUpdate)
|
||||||
{
|
{
|
||||||
if(item.UnitPrice == oldPrice)
|
if (item.UnitPrice == oldPrice)
|
||||||
{
|
{
|
||||||
var originalPrice = item.UnitPrice;
|
var originalPrice = item.UnitPrice;
|
||||||
item.UnitPrice = newPrice;
|
item.UnitPrice = newPrice;
|
||||||
item.OldUnitPrice = originalPrice;
|
item.OldUnitPrice = originalPrice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await _repository.UpdateBasketAsync(basket);
|
await _repository.UpdateBasketAsync(basket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,52 +12,80 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
|||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args).Run();
|
var configuration = GetConfiguration();
|
||||||
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
|
.CaptureStartupErrors(false)
|
||||||
.UseFailing(options =>
|
.UseFailing(options =>
|
||||||
{
|
options.ConfigPath = "/Failing")
|
||||||
options.ConfigPath = "/Failing";
|
|
||||||
})
|
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
|
||||||
.UseStartup<Startup>()
|
.UseStartup<Startup>()
|
||||||
.ConfigureAppConfiguration((builderContext, config) =>
|
|
||||||
{
|
|
||||||
var builtConfig = config.Build();
|
|
||||||
|
|
||||||
var configurationBuilder = new ConfigurationBuilder();
|
|
||||||
|
|
||||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
|
||||||
{
|
|
||||||
configurationBuilder.AddAzureKeyVault(
|
|
||||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
|
||||||
builtConfig["Vault:ClientId"],
|
|
||||||
builtConfig["Vault:ClientSecret"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
configurationBuilder.AddEnvironmentVariables();
|
|
||||||
|
|
||||||
config.AddConfiguration(configurationBuilder.Build());
|
|
||||||
})
|
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddConsole();
|
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddAzureWebAppDiagnostics();
|
|
||||||
})
|
|
||||||
.UseSerilog((builderContext, config) =>
|
|
||||||
{
|
|
||||||
config
|
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.UseApplicationInsights()
|
.UseApplicationInsights()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseConfiguration(configuration)
|
||||||
|
.UseSerilog()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault(
|
||||||
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
|
config["Vault:ClientId"],
|
||||||
|
config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
|||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
RegisterAppInsights(services);
|
RegisterAppInsights(services);
|
||||||
|
|
||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddMvc(options =>
|
services.AddMvc(options =>
|
||||||
@ -66,7 +66,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
|||||||
|
|
||||||
services.AddCustomHealthCheck(Configuration);
|
services.AddCustomHealthCheck(Configuration);
|
||||||
|
|
||||||
services.Configure<BasketSettings>(Configuration);
|
services.Configure<BasketSettings>(Configuration);
|
||||||
|
|
||||||
//By connecting here we are making sure that our service
|
//By connecting here we are making sure that our service
|
||||||
//cannot start until redis is ready. This might slow down startup,
|
//cannot start until redis is ready. This might slow down startup,
|
||||||
@ -179,9 +179,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
|||||||
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Information",
|
||||||
"System": "Information",
|
"Override": {
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://localhost:5105",
|
||||||
|
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.Controllers;
|
using Microsoft.eShopOnContainers.Services.Basket.API.Controllers;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -20,12 +21,14 @@ namespace UnitTest.Basket.Application
|
|||||||
private readonly Mock<IBasketRepository> _basketRepositoryMock;
|
private readonly Mock<IBasketRepository> _basketRepositoryMock;
|
||||||
private readonly Mock<IBasketIdentityService> _identityServiceMock;
|
private readonly Mock<IBasketIdentityService> _identityServiceMock;
|
||||||
private readonly Mock<IEventBus> _serviceBusMock;
|
private readonly Mock<IEventBus> _serviceBusMock;
|
||||||
|
private readonly Mock<ILogger<BasketController>> _loggerMock;
|
||||||
|
|
||||||
public BasketWebApiTest()
|
public BasketWebApiTest()
|
||||||
{
|
{
|
||||||
_basketRepositoryMock = new Mock<IBasketRepository>();
|
_basketRepositoryMock = new Mock<IBasketRepository>();
|
||||||
_identityServiceMock = new Mock<IBasketIdentityService>();
|
_identityServiceMock = new Mock<IBasketIdentityService>();
|
||||||
_serviceBusMock = new Mock<IEventBus>();
|
_serviceBusMock = new Mock<IEventBus>();
|
||||||
|
_loggerMock = new Mock<ILogger<BasketController>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -43,7 +46,11 @@ namespace UnitTest.Basket.Application
|
|||||||
|
|
||||||
//Act
|
//Act
|
||||||
var basketController = new BasketController(
|
var basketController = new BasketController(
|
||||||
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
|
_loggerMock.Object,
|
||||||
|
_basketRepositoryMock.Object,
|
||||||
|
_identityServiceMock.Object,
|
||||||
|
_serviceBusMock.Object);
|
||||||
|
|
||||||
var actionResult = await basketController.GetBasketByIdAsync(fakeCustomerId);
|
var actionResult = await basketController.GetBasketByIdAsync(fakeCustomerId);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -65,14 +72,17 @@ namespace UnitTest.Basket.Application
|
|||||||
|
|
||||||
//Act
|
//Act
|
||||||
var basketController = new BasketController(
|
var basketController = new BasketController(
|
||||||
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
|
_loggerMock.Object,
|
||||||
|
_basketRepositoryMock.Object,
|
||||||
|
_identityServiceMock.Object,
|
||||||
|
_serviceBusMock.Object);
|
||||||
|
|
||||||
var actionResult = await basketController.UpdateBasketAsync(fakeCustomerBasket);
|
var actionResult = await basketController.UpdateBasketAsync(fakeCustomerBasket);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK);
|
Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK);
|
||||||
Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId);
|
Assert.Equal(((CustomerBasket)actionResult.Value).BuyerId, fakeCustomerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Doing_Checkout_Without_Basket_Should_Return_Bad_Request()
|
public async Task Doing_Checkout_Without_Basket_Should_Return_Bad_Request()
|
||||||
@ -84,7 +94,10 @@ namespace UnitTest.Basket.Application
|
|||||||
|
|
||||||
//Act
|
//Act
|
||||||
var basketController = new BasketController(
|
var basketController = new BasketController(
|
||||||
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
|
_loggerMock.Object,
|
||||||
|
_basketRepositoryMock.Object,
|
||||||
|
_identityServiceMock.Object,
|
||||||
|
_serviceBusMock.Object);
|
||||||
|
|
||||||
var result = await basketController.CheckoutAsync(new BasketCheckout(), Guid.NewGuid().ToString()) as BadRequestResult;
|
var result = await basketController.CheckoutAsync(new BasketCheckout(), Guid.NewGuid().ToString()) as BadRequestResult;
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
@ -102,7 +115,10 @@ namespace UnitTest.Basket.Application
|
|||||||
_identityServiceMock.Setup(x => x.GetUserIdentity()).Returns(fakeCustomerId);
|
_identityServiceMock.Setup(x => x.GetUserIdentity()).Returns(fakeCustomerId);
|
||||||
|
|
||||||
var basketController = new BasketController(
|
var basketController = new BasketController(
|
||||||
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
|
_loggerMock.Object,
|
||||||
|
_basketRepositoryMock.Object,
|
||||||
|
_identityServiceMock.Object,
|
||||||
|
_serviceBusMock.Object);
|
||||||
|
|
||||||
basketController.ControllerContext = new ControllerContext()
|
basketController.ControllerContext = new ControllerContext()
|
||||||
{
|
{
|
||||||
@ -122,7 +138,7 @@ namespace UnitTest.Basket.Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
private CustomerBasket GetCustomerBasketFake(string fakeCustomerId)
|
private CustomerBasket GetCustomerBasketFake(string fakeCustomerId)
|
||||||
{
|
{
|
||||||
return new CustomerBasket(fakeCustomerId)
|
return new CustomerBasket(fakeCustomerId)
|
||||||
{
|
{
|
||||||
Items = new List<BasketItem>()
|
Items = new List<BasketItem>()
|
||||||
|
@ -34,24 +34,25 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -76,14 +76,14 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex.Message);
|
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
return GetPreconfiguredCatalogBrands();
|
return GetPreconfiguredCatalogBrands();
|
||||||
}
|
}
|
||||||
|
|
||||||
return File.ReadAllLines(csvFileCatalogBrands)
|
return File.ReadAllLines(csvFileCatalogBrands)
|
||||||
.Skip(1) // skip header row
|
.Skip(1) // skip header row
|
||||||
.SelectTry(x => CreateCatalogBrand(x))
|
.SelectTry(x => CreateCatalogBrand(x))
|
||||||
.OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
|
.OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
|
||||||
.Where(x => x != null);
|
.Where(x => x != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,14 +131,14 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex.Message);
|
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
return GetPreconfiguredCatalogTypes();
|
return GetPreconfiguredCatalogTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
return File.ReadAllLines(csvFileCatalogTypes)
|
return File.ReadAllLines(csvFileCatalogTypes)
|
||||||
.Skip(1) // skip header row
|
.Skip(1) // skip header row
|
||||||
.SelectTry(x => CreateCatalogType(x))
|
.SelectTry(x => CreateCatalogType(x))
|
||||||
.OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
|
.OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
|
||||||
.Where(x => x != null);
|
.Where(x => x != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +186,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex.Message);
|
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
return GetPreconfiguredItems();
|
return GetPreconfiguredItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +197,7 @@
|
|||||||
.Skip(1) // skip header row
|
.Skip(1) // skip header row
|
||||||
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
|
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
|
||||||
.SelectTry(column => CreateCatalogItem(column, csvheaders, catalogTypeIdLookup, catalogBrandIdLookup))
|
.SelectTry(column => CreateCatalogItem(column, csvheaders, catalogTypeIdLookup, catalogBrandIdLookup))
|
||||||
.OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
|
.OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
|
||||||
.Where(x => x != null);
|
.Where(x => x != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +377,7 @@
|
|||||||
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
|
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
|
||||||
onRetry: (exception, timeSpan, retry, ctx) =>
|
onRetry: (exception, timeSpan, retry, ctx) =>
|
||||||
{
|
{
|
||||||
logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
|
logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", prefix, exception.GetType().Name, exception.Message, retry, retries);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,10 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
|||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Catalog.API;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -17,10 +20,15 @@ namespace Catalog.API.IntegrationEvents
|
|||||||
private readonly IEventBus _eventBus;
|
private readonly IEventBus _eventBus;
|
||||||
private readonly CatalogContext _catalogContext;
|
private readonly CatalogContext _catalogContext;
|
||||||
private readonly IIntegrationEventLogService _eventLogService;
|
private readonly IIntegrationEventLogService _eventLogService;
|
||||||
|
private readonly ILogger<CatalogIntegrationEventService> _logger;
|
||||||
|
|
||||||
public CatalogIntegrationEventService(IEventBus eventBus, CatalogContext catalogContext,
|
public CatalogIntegrationEventService(
|
||||||
Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
|
ILogger<CatalogIntegrationEventService> logger,
|
||||||
|
IEventBus eventBus,
|
||||||
|
CatalogContext catalogContext,
|
||||||
|
Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
|
||||||
{
|
{
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_catalogContext = catalogContext ?? throw new ArgumentNullException(nameof(catalogContext));
|
_catalogContext = catalogContext ?? throw new ArgumentNullException(nameof(catalogContext));
|
||||||
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
|
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
|
||||||
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
@ -31,26 +39,31 @@ namespace Catalog.API.IntegrationEvents
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("----- Publishing integration event: {IntegrationEventId_published} from {AppName} - ({@IntegrationEvent})", evt.Id, Program.AppName, evt);
|
||||||
|
|
||||||
await _eventLogService.MarkEventAsInProgressAsync(evt.Id);
|
await _eventLogService.MarkEventAsInProgressAsync(evt.Id);
|
||||||
_eventBus.Publish(evt);
|
_eventBus.Publish(evt);
|
||||||
await _eventLogService.MarkEventAsPublishedAsync(evt.Id);
|
await _eventLogService.MarkEventAsPublishedAsync(evt.Id);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", evt.Id, Program.AppName, evt);
|
||||||
await _eventLogService.MarkEventAsFailedAsync(evt.Id);
|
await _eventLogService.MarkEventAsFailedAsync(evt.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt)
|
public async Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("----- CatalogIntegrationEventService - Saving changes and integrationEvent: {IntegrationEventId}", evt.Id);
|
||||||
|
|
||||||
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
|
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
|
||||||
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
await ResilientTransaction.New(_catalogContext)
|
await ResilientTransaction.New(_catalogContext).ExecuteAsync(async () =>
|
||||||
.ExecuteAsync(async () => {
|
{
|
||||||
// Achieving atomicity between original catalog database operation and the IntegrationEventLog thanks to a local transaction
|
// Achieving atomicity between original catalog database operation and the IntegrationEventLog thanks to a local transaction
|
||||||
await _catalogContext.SaveChangesAsync();
|
await _catalogContext.SaveChangesAsync();
|
||||||
await _eventLogService.SaveEventAsync(evt, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
|
await _eventLogService.SaveEventAsync(evt, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,39 +8,51 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using global::Catalog.API.IntegrationEvents;
|
using global::Catalog.API.IntegrationEvents;
|
||||||
using IntegrationEvents.Events;
|
using IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler :
|
public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler :
|
||||||
IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent>
|
IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly CatalogContext _catalogContext;
|
private readonly CatalogContext _catalogContext;
|
||||||
private readonly ICatalogIntegrationEventService _catalogIntegrationEventService;
|
private readonly ICatalogIntegrationEventService _catalogIntegrationEventService;
|
||||||
|
private readonly ILogger<OrderStatusChangedToAwaitingValidationIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(CatalogContext catalogContext,
|
public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(
|
||||||
ICatalogIntegrationEventService catalogIntegrationEventService)
|
CatalogContext catalogContext,
|
||||||
|
ICatalogIntegrationEventService catalogIntegrationEventService,
|
||||||
|
ILogger<OrderStatusChangedToAwaitingValidationIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_catalogContext = catalogContext;
|
_catalogContext = catalogContext;
|
||||||
_catalogIntegrationEventService = catalogIntegrationEventService;
|
_catalogIntegrationEventService = catalogIntegrationEventService;
|
||||||
|
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent command)
|
public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var confirmedOrderStockItems = new List<ConfirmedOrderStockItem>();
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
|
|
||||||
foreach (var orderStockItem in command.OrderStockItems)
|
|
||||||
{
|
{
|
||||||
var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
var hasStock = catalogItem.AvailableStock >= orderStockItem.Units;
|
|
||||||
var confirmedOrderStockItem = new ConfirmedOrderStockItem(catalogItem.Id, hasStock);
|
var confirmedOrderStockItems = new List<ConfirmedOrderStockItem>();
|
||||||
|
|
||||||
|
foreach (var orderStockItem in @event.OrderStockItems)
|
||||||
|
{
|
||||||
|
var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
|
||||||
|
var hasStock = catalogItem.AvailableStock >= orderStockItem.Units;
|
||||||
|
var confirmedOrderStockItem = new ConfirmedOrderStockItem(catalogItem.Id, hasStock);
|
||||||
|
|
||||||
|
confirmedOrderStockItems.Add(confirmedOrderStockItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
var confirmedIntegrationEvent = confirmedOrderStockItems.Any(c => !c.HasStock)
|
||||||
|
? (IntegrationEvent)new OrderStockRejectedIntegrationEvent(@event.OrderId, confirmedOrderStockItems)
|
||||||
|
: new OrderStockConfirmedIntegrationEvent(@event.OrderId);
|
||||||
|
|
||||||
|
await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(confirmedIntegrationEvent);
|
||||||
|
await _catalogIntegrationEventService.PublishThroughEventBusAsync(confirmedIntegrationEvent);
|
||||||
|
|
||||||
confirmedOrderStockItems.Add(confirmedOrderStockItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var confirmedIntegrationEvent = confirmedOrderStockItems.Any(c => !c.HasStock)
|
|
||||||
? (IntegrationEvent) new OrderStockRejectedIntegrationEvent(command.OrderId, confirmedOrderStockItems)
|
|
||||||
: new OrderStockConfirmedIntegrationEvent(command.OrderId);
|
|
||||||
|
|
||||||
await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(confirmedIntegrationEvent);
|
|
||||||
await _catalogIntegrationEventService.PublishThroughEventBusAsync(confirmedIntegrationEvent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,28 +4,40 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Infrastructure;
|
using Infrastructure;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
|
|
||||||
public class OrderStatusChangedToPaidIntegrationEventHandler :
|
public class OrderStatusChangedToPaidIntegrationEventHandler :
|
||||||
IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent>
|
IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly CatalogContext _catalogContext;
|
private readonly CatalogContext _catalogContext;
|
||||||
|
private readonly ILogger<OrderStatusChangedToPaidIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToPaidIntegrationEventHandler(CatalogContext catalogContext)
|
public OrderStatusChangedToPaidIntegrationEventHandler(
|
||||||
|
CatalogContext catalogContext,
|
||||||
|
ILogger<OrderStatusChangedToPaidIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_catalogContext = catalogContext;
|
_catalogContext = catalogContext;
|
||||||
|
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToPaidIntegrationEvent command)
|
public async Task Handle(OrderStatusChangedToPaidIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
//we're not blocking stock/inventory
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
foreach (var orderStockItem in command.OrderStockItems)
|
|
||||||
{
|
{
|
||||||
var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
//we're not blocking stock/inventory
|
||||||
|
foreach (var orderStockItem in @event.OrderStockItems)
|
||||||
|
{
|
||||||
|
var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
|
||||||
|
|
||||||
|
catalogItem.RemoveStock(orderStockItem.Units);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _catalogContext.SaveChangesAsync();
|
||||||
|
|
||||||
catalogItem.RemoveStock(orderStockItem.Units);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await _catalogContext.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,66 +9,97 @@ using Microsoft.Extensions.Options;
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args)
|
var configuration = GetConfiguration();
|
||||||
.MigrateDbContext<CatalogContext>((context,services)=>
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
|
||||||
|
host.MigrateDbContext<CatalogContext>((context, services) =>
|
||||||
{
|
{
|
||||||
var env = services.GetService<IHostingEnvironment>();
|
var env = services.GetService<IHostingEnvironment>();
|
||||||
var settings = services.GetService<IOptions<CatalogSettings>>();
|
var settings = services.GetService<IOptions<CatalogSettings>>();
|
||||||
var logger = services.GetService<ILogger<CatalogContextSeed>>();
|
var logger = services.GetService<ILogger<CatalogContextSeed>>();
|
||||||
|
|
||||||
new CatalogContextSeed()
|
new CatalogContextSeed()
|
||||||
.SeedAsync(context,env,settings,logger)
|
.SeedAsync(context, env, settings, logger)
|
||||||
.Wait();
|
.Wait();
|
||||||
|
|
||||||
})
|
})
|
||||||
.MigrateDbContext<IntegrationEventLogContext>((_,__)=> { })
|
.MigrateDbContext<IntegrationEventLogContext>((_, __) => { });
|
||||||
.Run();
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
.UseStartup<Startup>()
|
.CaptureStartupErrors(false)
|
||||||
|
.UseStartup<Startup>()
|
||||||
.UseApplicationInsights()
|
.UseApplicationInsights()
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
.UseWebRoot("Pics")
|
.UseWebRoot("Pics")
|
||||||
.ConfigureAppConfiguration((builderContext, config) =>
|
.UseConfiguration(configuration)
|
||||||
{
|
.UseSerilog()
|
||||||
var builtConfig = config.Build();
|
.Build();
|
||||||
|
|
||||||
var configurationBuilder = new ConfigurationBuilder();
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
return new LoggerConfiguration()
|
||||||
{
|
.MinimumLevel.Verbose()
|
||||||
configurationBuilder.AddAzureKeyVault(
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
.Enrich.FromLogContext()
|
||||||
builtConfig["Vault:ClientId"],
|
.WriteTo.Console()
|
||||||
builtConfig["Vault:ClientSecret"]);
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
}
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
configurationBuilder.AddEnvironmentVariables();
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
config.AddConfiguration(configurationBuilder.Build());
|
var config = builder.Build();
|
||||||
})
|
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
{
|
{
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
builder.AddAzureKeyVault(
|
||||||
builder.AddConsole();
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
builder.AddDebug();
|
config["Vault:ClientId"],
|
||||||
builder.AddAzureWebAppDiagnostics();
|
config["Vault:ClientSecret"]);
|
||||||
})
|
}
|
||||||
.UseSerilog((builderContext, config) =>
|
|
||||||
{
|
return builder.Build();
|
||||||
config
|
}
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,7 +13,10 @@
|
|||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "/swagger",
|
"launchUrl": "/swagger",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ConnectionString": "server=localhost,5433;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
|
"EventBusConnection": "localhost",
|
||||||
|
"Serilog:SeqServerUrl": "http://locahost:5340"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.eShopOnContainers.Services.Catalog.API": {
|
"Microsoft.eShopOnContainers.Services.Catalog.API": {
|
||||||
|
@ -60,17 +60,18 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
//Configure logs
|
//Configure logs
|
||||||
|
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
app.UsePathBase(pathBase);
|
app.UsePathBase(pathBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,15 @@
|
|||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
|
||||||
"PicBaseUrl": "http://localhost:5101/api/v1/catalog/items/[0]/pic/",
|
"PicBaseUrl": "http://localhost:5101/api/v1/catalog/items/[0]/pic/",
|
||||||
"UseCustomizationData": false,
|
"UseCustomizationData": false,
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Trace",
|
"Default": "Information",
|
||||||
"System": "Information",
|
"Override": {
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AzureServiceBusEnabled": false,
|
"AzureServiceBusEnabled": false,
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<system.webServer>
|
<system.webServer>
|
||||||
<handlers>
|
<handlers>
|
||||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
|
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
||||||
</handlers>
|
</handlers>
|
||||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="false" stdoutLogEnabled="false" />
|
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="false" stdoutLogEnabled="false">
|
||||||
|
<environmentVariables />
|
||||||
|
</aspNetCore>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
</configuration>
|
</configuration>
|
@ -51,7 +51,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
{
|
{
|
||||||
retryForAvaiability++;
|
retryForAvaiability++;
|
||||||
|
|
||||||
logger.LogError(ex.Message,$"There is an error migrating data for ApplicationDbContext");
|
logger.LogError(ex, "EXCEPTION ERROR while migrating {DbContextName}", nameof(ApplicationDbContext));
|
||||||
|
|
||||||
await SeedAsync(context,env,logger,settings, retryForAvaiability);
|
await SeedAsync(context,env,logger,settings, retryForAvaiability);
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex.Message);
|
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
|
|
||||||
return GetDefaultUser();
|
return GetDefaultUser();
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
.Skip(1) // skip header column
|
.Skip(1) // skip header column
|
||||||
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
|
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
|
||||||
.SelectTry(column => CreateApplicationUser(column, csvheaders))
|
.SelectTry(column => CreateApplicationUser(column, csvheaders))
|
||||||
.OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
|
.OnCaughtException(ex => { logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
|
||||||
.Where(x => x != null)
|
.Where(x => x != null)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
|
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
|
||||||
if (!File.Exists(imagesZipFile))
|
if (!File.Exists(imagesZipFile))
|
||||||
{
|
{
|
||||||
logger.LogError($" zip file '{imagesZipFile}' does not exists.");
|
logger.LogError("Zip file '{ZipFileName}' does not exists.", imagesZipFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,14 +221,14 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
|
logger.LogWarning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
|
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,25 +13,28 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
|
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />
|
||||||
|
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
|
||||||
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />
|
|
||||||
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.1.1" />
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="2.2.0-preview2-35157" />
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="2.2.0-preview2-35157" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.172" />
|
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.172" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
|
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
|
||||||
|
@ -14,70 +14,99 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
|
|||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args)
|
var configuration = GetConfiguration();
|
||||||
.MigrateDbContext<PersistedGrantDbContext>((_, __) => { })
|
|
||||||
.MigrateDbContext<ApplicationDbContext>((context, services) =>
|
|
||||||
{
|
|
||||||
var env = services.GetService<IHostingEnvironment>();
|
|
||||||
var logger = services.GetService<ILogger<ApplicationDbContextSeed>>();
|
|
||||||
var settings = services.GetService<IOptions<AppSettings>>();
|
|
||||||
|
|
||||||
new ApplicationDbContextSeed()
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
.SeedAsync(context, env, logger, settings)
|
|
||||||
.Wait();
|
|
||||||
})
|
|
||||||
.MigrateDbContext<ConfigurationDbContext>((context,services)=>
|
|
||||||
{
|
|
||||||
var configuration = services.GetService<IConfiguration>();
|
|
||||||
|
|
||||||
new ConfigurationDbContextSeed()
|
try
|
||||||
.SeedAsync(context, configuration)
|
{
|
||||||
.Wait();
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
}).Run();
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
|
||||||
|
host.MigrateDbContext<PersistedGrantDbContext>((_, __) => { })
|
||||||
|
.MigrateDbContext<ApplicationDbContext>((context, services) =>
|
||||||
|
{
|
||||||
|
var env = services.GetService<IHostingEnvironment>();
|
||||||
|
var logger = services.GetService<ILogger<ApplicationDbContextSeed>>();
|
||||||
|
var settings = services.GetService<IOptions<AppSettings>>();
|
||||||
|
|
||||||
|
new ApplicationDbContextSeed()
|
||||||
|
.SeedAsync(context, env, logger, settings)
|
||||||
|
.Wait();
|
||||||
|
})
|
||||||
|
.MigrateDbContext<ConfigurationDbContext>((context, services) =>
|
||||||
|
{
|
||||||
|
new ConfigurationDbContextSeed()
|
||||||
|
.SeedAsync(context, configuration)
|
||||||
|
.Wait();
|
||||||
|
});
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
.UseKestrel()
|
.CaptureStartupErrors(false)
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
|
||||||
.UseIISIntegration()
|
|
||||||
.UseStartup<Startup>()
|
.UseStartup<Startup>()
|
||||||
.ConfigureAppConfiguration((builderContext, config) =>
|
|
||||||
{
|
|
||||||
var builtConfig = config.Build();
|
|
||||||
|
|
||||||
var configurationBuilder = new ConfigurationBuilder();
|
|
||||||
|
|
||||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
|
||||||
{
|
|
||||||
configurationBuilder.AddAzureKeyVault(
|
|
||||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
|
||||||
builtConfig["Vault:ClientId"],
|
|
||||||
builtConfig["Vault:ClientSecret"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
configurationBuilder.AddEnvironmentVariables();
|
|
||||||
|
|
||||||
config.AddConfiguration(configurationBuilder.Build());
|
|
||||||
})
|
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddConsole();
|
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddAzureWebAppDiagnostics();
|
|
||||||
})
|
|
||||||
.UseApplicationInsights()
|
.UseApplicationInsights()
|
||||||
.UseSerilog((builderContext, config) =>
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
{
|
.UseConfiguration(configuration)
|
||||||
config
|
.UseSerilog()
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault(
|
||||||
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
|
config["Vault:ClientId"],
|
||||||
|
config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,12 +42,12 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
|
|||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddDbContext<ApplicationDbContext>(options =>
|
services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
options.UseSqlServer(Configuration["ConnectionString"],
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
{
|
{
|
||||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||||
@ -90,22 +90,22 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
|
|||||||
.AddConfigurationStore(options =>
|
.AddConfigurationStore(options =>
|
||||||
{
|
{
|
||||||
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
{
|
{
|
||||||
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
||||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.AddOperationalStore(options =>
|
.AddOperationalStore(options =>
|
||||||
{
|
{
|
||||||
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
{
|
{
|
||||||
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
||||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.Services.AddTransient<IProfileService, ProfileService>();
|
.Services.AddTransient<IProfileService, ProfileService>();
|
||||||
|
|
||||||
@ -117,8 +117,11 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
|
|||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// 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)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||||
|
//loggerFactory.AddDebug();
|
||||||
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
@ -133,7 +136,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API
|
|||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
app.UsePathBase(pathBase);
|
app.UsePathBase(pathBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,15 @@
|
|||||||
"SpaClient": "http://localhost:5104",
|
"SpaClient": "http://localhost:5104",
|
||||||
"XamarinCallback": "http://localhost:5105/xamarincallback",
|
"XamarinCallback": "http://localhost:5105/xamarincallback",
|
||||||
"UseCustomizationData": false,
|
"UseCustomizationData": false,
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Trace",
|
"Default": "Information",
|
||||||
"System": "Information",
|
"Override": {
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ApplicationInsights": {
|
"ApplicationInsights": {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Locations.API.IntegrationEvents.Events;
|
using Microsoft.eShopOnContainers.Services.Locations.API.IntegrationEvents.Events;
|
||||||
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
||||||
using Microsoft.eShopOnContainers.Services.Locations.API.ViewModel;
|
using Microsoft.eShopOnContainers.Services.Locations.API.ViewModel;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -14,11 +15,16 @@
|
|||||||
{
|
{
|
||||||
private readonly ILocationsRepository _locationsRepository;
|
private readonly ILocationsRepository _locationsRepository;
|
||||||
private readonly IEventBus _eventBus;
|
private readonly IEventBus _eventBus;
|
||||||
|
private readonly ILogger<LocationsService> _logger;
|
||||||
|
|
||||||
public LocationsService(ILocationsRepository locationsRepository, IEventBus eventBus)
|
public LocationsService(
|
||||||
|
ILocationsRepository locationsRepository,
|
||||||
|
IEventBus eventBus,
|
||||||
|
ILogger<LocationsService> logger)
|
||||||
{
|
{
|
||||||
_locationsRepository = locationsRepository ?? throw new ArgumentNullException(nameof(locationsRepository));
|
_locationsRepository = locationsRepository ?? throw new ArgumentNullException(nameof(locationsRepository));
|
||||||
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Locations> GetLocationAsync(int locationId)
|
public async Task<Locations> GetLocationAsync(int locationId)
|
||||||
@ -37,11 +43,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> AddOrUpdateUserLocationAsync(string userId, LocationRequest currentPosition)
|
public async Task<bool> AddOrUpdateUserLocationAsync(string userId, LocationRequest currentPosition)
|
||||||
{
|
{
|
||||||
// Get the list of ordered regions the user currently is within
|
// Get the list of ordered regions the user currently is within
|
||||||
var currentUserAreaLocationList = await _locationsRepository.GetCurrentUserRegionsListAsync(currentPosition);
|
var currentUserAreaLocationList = await _locationsRepository.GetCurrentUserRegionsListAsync(currentPosition);
|
||||||
|
|
||||||
if(currentUserAreaLocationList is null)
|
if (currentUserAreaLocationList is null)
|
||||||
{
|
{
|
||||||
throw new LocationDomainException("User current area not found");
|
throw new LocationDomainException("User current area not found");
|
||||||
}
|
}
|
||||||
@ -66,13 +72,17 @@
|
|||||||
{
|
{
|
||||||
var newUserLocations = MapUserLocationDetails(newLocations);
|
var newUserLocations = MapUserLocationDetails(newLocations);
|
||||||
var @event = new UserLocationUpdatedIntegrationEvent(userId, newUserLocations);
|
var @event = new UserLocationUpdatedIntegrationEvent(userId, newUserLocations);
|
||||||
|
|
||||||
|
_logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
_eventBus.Publish(@event);
|
_eventBus.Publish(@event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<UserLocationDetails> MapUserLocationDetails(List<Locations> newLocations)
|
private List<UserLocationDetails> MapUserLocationDetails(List<Locations> newLocations)
|
||||||
{
|
{
|
||||||
var result = new List<UserLocationDetails>();
|
var result = new List<UserLocationDetails>();
|
||||||
newLocations.ForEach(location => {
|
newLocations.ForEach(location =>
|
||||||
|
{
|
||||||
result.Add(new UserLocationDetails()
|
result.Add(new UserLocationDetails()
|
||||||
{
|
{
|
||||||
LocationId = location.LocationId,
|
LocationId = location.LocationId,
|
||||||
|
@ -6,28 +6,32 @@
|
|||||||
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
|
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="2.2.0" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
||||||
|
@ -11,48 +11,78 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
|
|||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args).Run();
|
var configuration = GetConfiguration();
|
||||||
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.CaptureStartupErrors(false)
|
||||||
.UseStartup<Startup>()
|
.UseStartup<Startup>()
|
||||||
.ConfigureAppConfiguration((builderContext, config) =>
|
|
||||||
{
|
|
||||||
var builtConfig = config.Build();
|
|
||||||
|
|
||||||
var configurationBuilder = new ConfigurationBuilder();
|
|
||||||
|
|
||||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
|
||||||
{
|
|
||||||
configurationBuilder.AddAzureKeyVault(
|
|
||||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
|
||||||
builtConfig["Vault:ClientId"],
|
|
||||||
builtConfig["Vault:ClientSecret"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
configurationBuilder.AddEnvironmentVariables();
|
|
||||||
|
|
||||||
config.AddConfiguration(configurationBuilder.Build());
|
|
||||||
})
|
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddConsole();
|
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddAzureWebAppDiagnostics();
|
|
||||||
})
|
|
||||||
.UseApplicationInsights()
|
.UseApplicationInsights()
|
||||||
.UseSerilog((builderContext, config) =>
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
{
|
.UseConfiguration(configuration)
|
||||||
config
|
.UseSerilog()
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault(
|
||||||
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
|
config["Vault:ClientId"],
|
||||||
|
config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -153,9 +153,10 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
@ -2,12 +2,15 @@
|
|||||||
"ConnectionString": "mongodb://nosql.data",
|
"ConnectionString": "mongodb://nosql.data",
|
||||||
"Database": "LocationsDb",
|
"Database": "LocationsDb",
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://localhost:5105",
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Trace",
|
"Default": "Information",
|
||||||
"System": "Information",
|
"Override": {
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AzureServiceBusEnabled": false,
|
"AzureServiceBusEnabled": false,
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
|
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
|
||||||
onRetry: (exception, timeSpan, retry, ctx) =>
|
onRetry: (exception, timeSpan, retry, ctx) =>
|
||||||
{
|
{
|
||||||
logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
|
logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", prefix, exception.GetType().Name, exception.Message, retry, retries);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
using Marketing.API.Model;
|
using Marketing.API.Model;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Repositories;
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Repositories;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -12,20 +14,29 @@
|
|||||||
: IIntegrationEventHandler<UserLocationUpdatedIntegrationEvent>
|
: IIntegrationEventHandler<UserLocationUpdatedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMarketingDataRepository _marketingDataRepository;
|
private readonly IMarketingDataRepository _marketingDataRepository;
|
||||||
|
private readonly ILogger<UserLocationUpdatedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public UserLocationUpdatedIntegrationEventHandler(IMarketingDataRepository repository)
|
public UserLocationUpdatedIntegrationEventHandler(
|
||||||
|
IMarketingDataRepository repository,
|
||||||
|
ILogger<UserLocationUpdatedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_marketingDataRepository = repository ?? throw new ArgumentNullException(nameof(repository));
|
_marketingDataRepository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(UserLocationUpdatedIntegrationEvent @event)
|
public async Task Handle(UserLocationUpdatedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var userMarketingData = await _marketingDataRepository.GetAsync(@event.UserId);
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
userMarketingData = userMarketingData ??
|
{
|
||||||
new MarketingData() { UserId = @event.UserId };
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
userMarketingData.Locations = MapUpdatedUserLocations(@event.LocationList);
|
var userMarketingData = await _marketingDataRepository.GetAsync(@event.UserId);
|
||||||
await _marketingDataRepository.UpdateLocationAsync(userMarketingData);
|
userMarketingData = userMarketingData ??
|
||||||
|
new MarketingData() { UserId = @event.UserId };
|
||||||
|
|
||||||
|
userMarketingData.Locations = MapUpdatedUserLocations(@event.LocationList);
|
||||||
|
await _marketingDataRepository.UpdateLocationAsync(userMarketingData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Location> MapUpdatedUserLocations(List<UserLocationDetails> newUserLocations)
|
private List<Location> MapUpdatedUserLocations(List<UserLocationDetails> newUserLocations)
|
||||||
|
@ -21,27 +21,30 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
|
||||||
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -12,59 +12,89 @@
|
|||||||
|
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args)
|
var configuration = GetConfiguration();
|
||||||
.MigrateDbContext<MarketingContext>((context, services) =>
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var logger = services.GetService<ILogger<MarketingContextSeed>>();
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
new MarketingContextSeed()
|
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
|
||||||
.SeedAsync(context,logger)
|
host.MigrateDbContext<MarketingContext>((context, services) =>
|
||||||
.Wait();
|
{
|
||||||
|
var logger = services.GetService<ILogger<MarketingContextSeed>>();
|
||||||
|
|
||||||
}).Run();
|
new MarketingContextSeed()
|
||||||
|
.SeedAsync(context, logger)
|
||||||
|
.Wait();
|
||||||
|
});
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
|
.CaptureStartupErrors(false)
|
||||||
|
.UseStartup<Startup>()
|
||||||
.UseApplicationInsights()
|
.UseApplicationInsights()
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
.UseStartup<Startup>()
|
|
||||||
.UseWebRoot("Pics")
|
.UseWebRoot("Pics")
|
||||||
.ConfigureAppConfiguration((builderContext, config) =>
|
.UseConfiguration(configuration)
|
||||||
{
|
.UseSerilog()
|
||||||
var builtConfig = config.Build();
|
|
||||||
|
|
||||||
var configurationBuilder = new ConfigurationBuilder();
|
|
||||||
|
|
||||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
|
||||||
{
|
|
||||||
configurationBuilder.AddAzureKeyVault(
|
|
||||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
|
||||||
builtConfig["Vault:ClientId"],
|
|
||||||
builtConfig["Vault:ClientSecret"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
configurationBuilder.AddEnvironmentVariables();
|
|
||||||
|
|
||||||
config.AddConfiguration(configurationBuilder.Build());
|
|
||||||
})
|
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddConsole();
|
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddAzureWebAppDiagnostics();
|
|
||||||
})
|
|
||||||
.UseApplicationInsights()
|
|
||||||
.UseSerilog((builderContext, config) =>
|
|
||||||
{
|
|
||||||
config
|
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault(
|
||||||
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
|
config["Vault:ClientId"],
|
||||||
|
config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,8 @@
|
|||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// 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)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Trace"
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word",
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word",
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.Behaviors
|
||||||
|
{
|
||||||
|
internal static class BehaviorsHelperExtensions
|
||||||
|
{
|
||||||
|
internal static string GetGenericTypeName(this object @object)
|
||||||
|
{
|
||||||
|
var typeName = string.Empty;
|
||||||
|
var type = @object.GetType();
|
||||||
|
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
var genericTypes = string.Join(",", type.GetGenericArguments().Select(t => t.Name).ToArray());
|
||||||
|
typeName = $"{type.Name.Remove(type.Name.IndexOf('`'))}<{genericTypes}>";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
typeName = type.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ordering.API.Infrastructure.Behaviors
|
namespace Ordering.API.Application.Behaviors
|
||||||
{
|
{
|
||||||
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||||
{
|
{
|
||||||
@ -12,9 +13,10 @@ namespace Ordering.API.Infrastructure.Behaviors
|
|||||||
|
|
||||||
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
|
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Handling {typeof(TRequest).Name}");
|
_logger.LogInformation("----- Handling command {CommandName} ({@Command})", request.GetGenericTypeName(), request);
|
||||||
var response = await next();
|
var response = await next();
|
||||||
_logger.LogInformation($"Handled {typeof(TResponse).Name}");
|
_logger.LogInformation("----- Command {CommandName} handled - response: {@Response}", request.GetGenericTypeName(), response);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,8 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.API.Application.IntegrationEvents;
|
using Ordering.API.Application.IntegrationEvents;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -28,33 +27,41 @@ namespace Ordering.API.Application.Behaviors
|
|||||||
|
|
||||||
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
|
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
|
||||||
{
|
{
|
||||||
TResponse response = default(TResponse);
|
var response = default(TResponse);
|
||||||
|
var typeName = request.GetGenericTypeName();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var strategy = _dbContext.Database.CreateExecutionStrategy();
|
if (_dbContext.HasActiveTransaction)
|
||||||
await strategy.ExecuteAsync(async () =>
|
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Begin transaction {typeof(TRequest).Name}");
|
return await next();
|
||||||
|
}
|
||||||
|
|
||||||
await _dbContext.BeginTransactionAsync();
|
var strategy = _dbContext.Database.CreateExecutionStrategy();
|
||||||
|
|
||||||
response = await next();
|
await strategy.ExecuteAsync(async () =>
|
||||||
|
{
|
||||||
|
using (var transaction = await _dbContext.BeginTransactionAsync())
|
||||||
|
using (LogContext.PushProperty("TransactionContext", transaction.TransactionId))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Begin transaction {TransactionId} for {CommandName} ({@Command})", transaction.TransactionId, typeName, request);
|
||||||
|
|
||||||
await _dbContext.CommitTransactionAsync();
|
response = await next();
|
||||||
|
|
||||||
_logger.LogInformation($"Committed transaction {typeof(TRequest).Name}");
|
_logger.LogInformation("----- Commit transaction {TransactionId} for {CommandName}", transaction.TransactionId, typeName);
|
||||||
|
|
||||||
|
await _dbContext.CommitTransactionAsync(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync();
|
await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Rollback transaction executed {typeof(TRequest).Name}");
|
_logger.LogError(ex, "ERROR Handling transaction for {CommandName} ({@Command})", typeName, request);
|
||||||
|
|
||||||
_dbContext.RollbackTransaction();
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,30 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.Domain.Exceptions;
|
using Ordering.Domain.Exceptions;
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ordering.API.Infrastructure.Behaviors
|
namespace Ordering.API.Application.Behaviors
|
||||||
{
|
{
|
||||||
public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||||
{
|
{
|
||||||
|
private readonly ILogger<ValidatorBehavior<TRequest, TResponse>> _logger;
|
||||||
private readonly IValidator<TRequest>[] _validators;
|
private readonly IValidator<TRequest>[] _validators;
|
||||||
public ValidatorBehavior(IValidator<TRequest>[] validators) => _validators = validators;
|
|
||||||
|
public ValidatorBehavior(IValidator<TRequest>[] validators, ILogger<ValidatorBehavior<TRequest, TResponse>> logger)
|
||||||
|
{
|
||||||
|
_validators = validators;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
|
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
|
||||||
{
|
{
|
||||||
|
var typeName = request.GetGenericTypeName();
|
||||||
|
|
||||||
|
_logger.LogInformation("----- Validating command {CommandType}", typeName);
|
||||||
|
|
||||||
var failures = _validators
|
var failures = _validators
|
||||||
.Select(v => v.Validate(request))
|
.Select(v => v.Validate(request))
|
||||||
.SelectMany(result => result.Errors)
|
.SelectMany(result => result.Errors)
|
||||||
@ -23,12 +33,13 @@ namespace Ordering.API.Infrastructure.Behaviors
|
|||||||
|
|
||||||
if (failures.Any())
|
if (failures.Any())
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("Validation errors - {CommandType} - Command: {@Command} - Errors: {@ValidationErrors}", typeName, request, failures);
|
||||||
|
|
||||||
throw new OrderingDomainException(
|
throw new OrderingDomainException(
|
||||||
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
|
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = await next();
|
return await next();
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -40,7 +41,11 @@ namespace Ordering.API.Application.Commands
|
|||||||
// Use for Idempotency in Command process
|
// Use for Idempotency in Command process
|
||||||
public class CancelOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CancelOrderCommand, bool>
|
public class CancelOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CancelOrderCommand, bool>
|
||||||
{
|
{
|
||||||
public CancelOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
|
public CancelOrderIdentifiedCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<CancelOrderCommand, bool>> logger)
|
||||||
|
: base(mediator, requestManager, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -18,17 +19,20 @@
|
|||||||
private readonly IIdentityService _identityService;
|
private readonly IIdentityService _identityService;
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
||||||
|
private readonly ILogger<CreateOrderCommandHandler> _logger;
|
||||||
|
|
||||||
// Using DI to inject infrastructure persistence Repositories
|
// Using DI to inject infrastructure persistence Repositories
|
||||||
public CreateOrderCommandHandler(IMediator mediator,
|
public CreateOrderCommandHandler(IMediator mediator,
|
||||||
IOrderingIntegrationEventService orderingIntegrationEventService,
|
IOrderingIntegrationEventService orderingIntegrationEventService,
|
||||||
IOrderRepository orderRepository,
|
IOrderRepository orderRepository,
|
||||||
IIdentityService identityService)
|
IIdentityService identityService,
|
||||||
|
ILogger<CreateOrderCommandHandler> logger)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||||
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
|
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> Handle(CreateOrderCommand message, CancellationToken cancellationToken)
|
public async Task<bool> Handle(CreateOrderCommand message, CancellationToken cancellationToken)
|
||||||
@ -36,20 +40,22 @@
|
|||||||
// Add Integration event to clean the basket
|
// Add Integration event to clean the basket
|
||||||
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(message.UserId);
|
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(message.UserId);
|
||||||
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStartedIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStartedIntegrationEvent);
|
||||||
|
|
||||||
// Add/Update the Buyer AggregateRoot
|
// Add/Update the Buyer AggregateRoot
|
||||||
// DDD patterns comment: Add child entities and value-objects through the Order Aggregate-Root
|
// DDD patterns comment: Add child entities and value-objects through the Order Aggregate-Root
|
||||||
// methods and constructor so validations, invariants and business logic
|
// methods and constructor so validations, invariants and business logic
|
||||||
// make sure that consistency is preserved across the whole aggregate
|
// make sure that consistency is preserved across the whole aggregate
|
||||||
var address = new Address(message.Street, message.City, message.State, message.Country, message.ZipCode);
|
var address = new Address(message.Street, message.City, message.State, message.Country, message.ZipCode);
|
||||||
var order = new Order(message.UserId, message.UserName, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration);
|
var order = new Order(message.UserId, message.UserName, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration);
|
||||||
|
|
||||||
foreach (var item in message.OrderItems)
|
foreach (var item in message.OrderItems)
|
||||||
{
|
{
|
||||||
order.AddOrderItem(item.ProductId, item.ProductName, item.UnitPrice, item.Discount, item.PictureUrl, item.Units);
|
order.AddOrderItem(item.ProductId, item.ProductName, item.UnitPrice, item.Discount, item.PictureUrl, item.Units);
|
||||||
}
|
}
|
||||||
|
|
||||||
_orderRepository.Add(order);
|
_logger.LogInformation("----- Creating Order - Order: {@Order}", order);
|
||||||
|
|
||||||
|
_orderRepository.Add(order);
|
||||||
|
|
||||||
return await _orderRepository.UnitOfWork
|
return await _orderRepository.UnitOfWork
|
||||||
.SaveEntitiesAsync();
|
.SaveEntitiesAsync();
|
||||||
@ -60,7 +66,11 @@
|
|||||||
// Use for Idempotency in Command process
|
// Use for Idempotency in Command process
|
||||||
public class CreateOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CreateOrderCommand, bool>
|
public class CreateOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CreateOrderCommand, bool>
|
||||||
{
|
{
|
||||||
public CreateOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
|
public CreateOrderIdentifiedCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<CreateOrderCommand, bool>> logger)
|
||||||
|
: base(mediator, requestManager, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
|
using Ordering.API.Application.Commands;
|
||||||
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -16,11 +20,16 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
|||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly IRequestManager _requestManager;
|
private readonly IRequestManager _requestManager;
|
||||||
|
private readonly ILogger<IdentifiedCommandHandler<T, R>> _logger;
|
||||||
|
|
||||||
public IdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager)
|
public IdentifiedCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<T, R>> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_requestManager = requestManager;
|
_requestManager = requestManager;
|
||||||
|
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -48,16 +57,60 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _requestManager.CreateRequestForCommandAsync<T>(message.Id);
|
await _requestManager.CreateRequestForCommandAsync<T>(message.Id);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Send the embeded business command to mediator so it runs its related CommandHandler
|
var command = message.Command;
|
||||||
var result = await _mediator.Send(message.Command);
|
var commandName = command.GetGenericTypeName();
|
||||||
return result;
|
var idProperty = string.Empty;
|
||||||
}
|
var commandId = string.Empty;
|
||||||
catch
|
|
||||||
{
|
switch (command)
|
||||||
return default(R);
|
{
|
||||||
}
|
case CreateOrderCommand createOrderCommand:
|
||||||
|
idProperty = nameof(createOrderCommand.UserId);
|
||||||
|
commandId = createOrderCommand.UserId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CancelOrderCommand cancelOrderCommand:
|
||||||
|
idProperty = nameof(cancelOrderCommand.OrderNumber);
|
||||||
|
commandId = $"{cancelOrderCommand.OrderNumber}";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ShipOrderCommand shipOrderCommand:
|
||||||
|
idProperty = nameof(shipOrderCommand.OrderNumber);
|
||||||
|
commandId = $"{shipOrderCommand.OrderNumber}";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
idProperty = "Id?";
|
||||||
|
commandId = "n/a";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
commandName,
|
||||||
|
idProperty,
|
||||||
|
commandId,
|
||||||
|
command);
|
||||||
|
|
||||||
|
// Send the embeded business command to mediator so it runs its related CommandHandler
|
||||||
|
var result = await _mediator.Send(command);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Command result: {@Result} - {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
result,
|
||||||
|
commandName,
|
||||||
|
idProperty,
|
||||||
|
commandId,
|
||||||
|
command);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return default(R);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -40,7 +41,11 @@ namespace Ordering.API.Application.Commands
|
|||||||
// Use for Idempotency in Command process
|
// Use for Idempotency in Command process
|
||||||
public class SetAwaitingValidationIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetAwaitingValidationOrderStatusCommand, bool>
|
public class SetAwaitingValidationIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetAwaitingValidationOrderStatusCommand, bool>
|
||||||
{
|
{
|
||||||
public SetAwaitingValidationIdentifiedOrderStatusCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
|
public SetAwaitingValidationIdentifiedOrderStatusCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<SetAwaitingValidationOrderStatusCommand, bool>> logger)
|
||||||
|
: base(mediator, requestManager, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -43,7 +44,11 @@ namespace Ordering.API.Application.Commands
|
|||||||
// Use for Idempotency in Command process
|
// Use for Idempotency in Command process
|
||||||
public class SetPaidIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetPaidOrderStatusCommand, bool>
|
public class SetPaidIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetPaidOrderStatusCommand, bool>
|
||||||
{
|
{
|
||||||
public SetPaidIdentifiedOrderStatusCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
|
public SetPaidIdentifiedOrderStatusCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<SetPaidOrderStatusCommand, bool>> logger)
|
||||||
|
: base(mediator, requestManager, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -43,7 +44,11 @@ namespace Ordering.API.Application.Commands
|
|||||||
// Use for Idempotency in Command process
|
// Use for Idempotency in Command process
|
||||||
public class SetStockConfirmedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler<SetStockConfirmedOrderStatusCommand, bool>
|
public class SetStockConfirmedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler<SetStockConfirmedOrderStatusCommand, bool>
|
||||||
{
|
{
|
||||||
public SetStockConfirmedOrderStatusIdenfifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
|
public SetStockConfirmedOrderStatusIdenfifiedCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<SetStockConfirmedOrderStatusCommand, bool>> logger)
|
||||||
|
: base(mediator, requestManager, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -44,7 +45,11 @@ namespace Ordering.API.Application.Commands
|
|||||||
// Use for Idempotency in Command process
|
// Use for Idempotency in Command process
|
||||||
public class SetStockRejectedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler<SetStockRejectedOrderStatusCommand, bool>
|
public class SetStockRejectedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler<SetStockRejectedOrderStatusCommand, bool>
|
||||||
{
|
{
|
||||||
public SetStockRejectedOrderStatusIdenfifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
|
public SetStockRejectedOrderStatusIdenfifiedCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<SetStockRejectedOrderStatusCommand, bool>> logger)
|
||||||
|
: base(mediator, requestManager, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ namespace Ordering.API.Application.Commands
|
|||||||
{
|
{
|
||||||
// Regular CommandHandler
|
// Regular CommandHandler
|
||||||
public class ShipOrderCommandHandler : IRequestHandler<ShipOrderCommand, bool>
|
public class ShipOrderCommandHandler : IRequestHandler<ShipOrderCommand, bool>
|
||||||
{
|
{
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
|
|
||||||
public ShipOrderCommandHandler(IOrderRepository orderRepository)
|
public ShipOrderCommandHandler(IOrderRepository orderRepository)
|
||||||
@ -26,7 +27,7 @@ namespace Ordering.API.Application.Commands
|
|||||||
public async Task<bool> Handle(ShipOrderCommand command, CancellationToken cancellationToken)
|
public async Task<bool> Handle(ShipOrderCommand command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber);
|
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber);
|
||||||
if(orderToUpdate == null)
|
if (orderToUpdate == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -40,7 +41,11 @@ namespace Ordering.API.Application.Commands
|
|||||||
// Use for Idempotency in Command process
|
// Use for Idempotency in Command process
|
||||||
public class ShipOrderIdentifiedCommandHandler : IdentifiedCommandHandler<ShipOrderCommand, bool>
|
public class ShipOrderIdentifiedCommandHandler : IdentifiedCommandHandler<ShipOrderCommand, bool>
|
||||||
{
|
{
|
||||||
public ShipOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
|
public ShipOrderIdentifiedCommandHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
IRequestManager requestManager,
|
||||||
|
ILogger<IdentifiedCommandHandler<ShipOrderCommand, bool>> logger)
|
||||||
|
: base(mediator, requestManager, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,16 +8,16 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVerified
|
namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVerified
|
||||||
{
|
{
|
||||||
public class UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler
|
public class UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler
|
||||||
: INotificationHandler<BuyerAndPaymentMethodVerifiedDomainEvent>
|
: INotificationHandler<BuyerAndPaymentMethodVerifiedDomainEvent>
|
||||||
{
|
{
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly ILoggerFactory _logger;
|
private readonly ILoggerFactory _logger;
|
||||||
|
|
||||||
public UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler(
|
public UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler(
|
||||||
IOrderRepository orderRepository, ILoggerFactory logger)
|
IOrderRepository orderRepository, ILoggerFactory logger)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,10 +28,11 @@ namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVeri
|
|||||||
{
|
{
|
||||||
var orderToUpdate = await _orderRepository.GetAsync(buyerPaymentMethodVerifiedEvent.OrderId);
|
var orderToUpdate = await _orderRepository.GetAsync(buyerPaymentMethodVerifiedEvent.OrderId);
|
||||||
orderToUpdate.SetBuyerId(buyerPaymentMethodVerifiedEvent.Buyer.Id);
|
orderToUpdate.SetBuyerId(buyerPaymentMethodVerifiedEvent.Buyer.Id);
|
||||||
orderToUpdate.SetPaymentId(buyerPaymentMethodVerifiedEvent.Payment.Id);
|
orderToUpdate.SetPaymentId(buyerPaymentMethodVerifiedEvent.Payment.Id);
|
||||||
|
|
||||||
_logger.CreateLogger(nameof(UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler))
|
_logger.CreateLogger<UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler>()
|
||||||
.LogTrace($"Order with Id: {buyerPaymentMethodVerifiedEvent.OrderId} has been successfully updated with a payment method id: { buyerPaymentMethodVerifiedEvent.Payment.Id }");
|
.LogTrace("Order with Id: {OrderId} has been successfully updated with a payment method {PaymentMethod} ({Id})",
|
||||||
|
buyerPaymentMethodVerifiedEvent.OrderId, nameof(buyerPaymentMethodVerifiedEvent.Payment), buyerPaymentMethodVerifiedEvent.Payment.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderCancelled
|
|||||||
|
|
||||||
public async Task Handle(OrderCancelledDomainEvent orderCancelledDomainEvent, CancellationToken cancellationToken)
|
public async Task Handle(OrderCancelledDomainEvent orderCancelledDomainEvent, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.CreateLogger(nameof(OrderCancelledDomainEvent))
|
_logger.CreateLogger<OrderCancelledDomainEvent>()
|
||||||
.LogTrace($"Order with Id: {orderCancelledDomainEvent.Order.Id} has been successfully updated with " +
|
.LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
|
||||||
$"a status order id: {OrderStatus.Shipped.Id}");
|
orderCancelledDomainEvent.Order.Id, nameof(OrderStatus.Cancelled), OrderStatus.Cancelled.Id);
|
||||||
|
|
||||||
var order = await _orderRepository.GetAsync(orderCancelledDomainEvent.Order.Id);
|
var order = await _orderRepository.GetAsync(orderCancelledDomainEvent.Order.Id);
|
||||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
||||||
|
@ -33,9 +33,9 @@
|
|||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent, CancellationToken cancellationToken)
|
public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.CreateLogger(nameof(OrderStatusChangedToAwaitingValidationDomainEvent))
|
_logger.CreateLogger<OrderStatusChangedToAwaitingValidationDomainEvent>()
|
||||||
.LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " +
|
.LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
|
||||||
$"a status order id: {OrderStatus.AwaitingValidation.Id}");
|
orderStatusChangedToAwaitingValidationDomainEvent.OrderId, nameof(OrderStatus.AwaitingValidation), OrderStatus.AwaitingValidation.Id);
|
||||||
|
|
||||||
var order = await _orderRepository.GetAsync(orderStatusChangedToAwaitingValidationDomainEvent.OrderId);
|
var order = await _orderRepository.GetAsync(orderStatusChangedToAwaitingValidationDomainEvent.OrderId);
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@
|
|||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent, CancellationToken cancellationToken)
|
public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.CreateLogger(nameof(OrderStatusChangedToPaidDomainEventHandler))
|
_logger.CreateLogger<OrderStatusChangedToPaidDomainEventHandler>()
|
||||||
.LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " +
|
.LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
|
||||||
$"a status order id: {OrderStatus.Paid.Id}");
|
orderStatusChangedToPaidDomainEvent.OrderId, nameof(OrderStatus.Paid), OrderStatus.Paid.Id);
|
||||||
|
|
||||||
var order = await _orderRepository.GetAsync(orderStatusChangedToPaidDomainEvent.OrderId);
|
var order = await _orderRepository.GetAsync(orderStatusChangedToPaidDomainEvent.OrderId);
|
||||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
||||||
|
@ -33,9 +33,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderShipped
|
|||||||
|
|
||||||
public async Task Handle(OrderShippedDomainEvent orderShippedDomainEvent, CancellationToken cancellationToken)
|
public async Task Handle(OrderShippedDomainEvent orderShippedDomainEvent, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.CreateLogger(nameof(OrderShippedDomainEvent))
|
_logger.CreateLogger<OrderShippedDomainEvent>()
|
||||||
.LogTrace($"Order with Id: {orderShippedDomainEvent.Order.Id} has been successfully updated with " +
|
.LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
|
||||||
$"a status order id: {OrderStatus.Shipped.Id}");
|
orderShippedDomainEvent.Order.Id, nameof(OrderStatus.Shipped), OrderStatus.Shipped.Id);
|
||||||
|
|
||||||
var order = await _orderRepository.GetAsync(orderShippedDomainEvent.Order.Id);
|
var order = await _orderRepository.GetAsync(orderShippedDomainEvent.Order.Id);
|
||||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
||||||
|
@ -61,7 +61,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
|
|||||||
var orderStatusChangedTosubmittedIntegrationEvent = new OrderStatusChangedToSubmittedIntegrationEvent(orderStartedEvent.Order.Id, orderStartedEvent.Order.OrderStatus.Name, buyer.Name);
|
var orderStatusChangedTosubmittedIntegrationEvent = new OrderStatusChangedToSubmittedIntegrationEvent(orderStartedEvent.Order.Id, orderStartedEvent.Order.OrderStatus.Name, buyer.Name);
|
||||||
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedTosubmittedIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedTosubmittedIntegrationEvent);
|
||||||
|
|
||||||
_logger.CreateLogger(nameof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler)).LogTrace($"Buyer {buyerUpdated.Id} and related payment method were validated or updated for orderId: {orderStartedEvent.Order.Id}.");
|
_logger.CreateLogger<ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler>()
|
||||||
|
.LogTrace("Buyer {BuyerId} and related payment method were validated or updated for orderId: {OrderId}.",
|
||||||
|
buyerUpdated.Id, orderStartedEvent.Order.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@
|
|||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToStockConfirmedDomainEvent orderStatusChangedToStockConfirmedDomainEvent, CancellationToken cancellationToken)
|
public async Task Handle(OrderStatusChangedToStockConfirmedDomainEvent orderStatusChangedToStockConfirmedDomainEvent, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.CreateLogger(nameof(OrderStatusChangedToStockConfirmedDomainEventHandler))
|
_logger.CreateLogger<OrderStatusChangedToStockConfirmedDomainEventHandler>()
|
||||||
.LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " +
|
.LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
|
||||||
$"a status order id: {OrderStatus.StockConfirmed.Id}");
|
orderStatusChangedToStockConfirmedDomainEvent.OrderId, nameof(OrderStatus.StockConfirmed), OrderStatus.StockConfirmed.Id);
|
||||||
|
|
||||||
var order = await _orderRepository.GetAsync(orderStatusChangedToStockConfirmedDomainEvent.OrderId);
|
var order = await _orderRepository.GetAsync(orderStatusChangedToStockConfirmedDomainEvent.OrderId);
|
||||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
using Ordering.API.Application.IntegrationEvents.Events;
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
||||||
@ -10,10 +14,14 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
|||||||
public class GracePeriodConfirmedIntegrationEventHandler : IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent>
|
public class GracePeriodConfirmedIntegrationEventHandler : IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private readonly ILogger<GracePeriodConfirmedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public GracePeriodConfirmedIntegrationEventHandler(IMediator mediator)
|
public GracePeriodConfirmedIntegrationEventHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
ILogger<GracePeriodConfirmedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
|
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -26,8 +34,21 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task Handle(GracePeriodConfirmedIntegrationEvent @event)
|
public async Task Handle(GracePeriodConfirmedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var command = new SetAwaitingValidationOrderStatusCommand(@event.OrderId);
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
await _mediator.Send(command);
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
var command = new SetAwaitingValidationOrderStatusCommand(@event.OrderId);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
command.GetGenericTypeName(),
|
||||||
|
nameof(command.OrderNumber),
|
||||||
|
command.OrderNumber,
|
||||||
|
command);
|
||||||
|
|
||||||
|
await _mediator.Send(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,13 @@
|
|||||||
{
|
{
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
using Ordering.API.Application.IntegrationEvents.Events;
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -12,16 +16,33 @@
|
|||||||
IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>
|
IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private readonly ILogger<OrderPaymentFailedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderPaymentFailedIntegrationEventHandler(IMediator mediator)
|
public OrderPaymentFailedIntegrationEventHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
ILogger<OrderPaymentFailedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderPaymentFailedIntegrationEvent @event)
|
public async Task Handle(OrderPaymentFailedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var command = new CancelOrderCommand(@event.OrderId);
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
await _mediator.Send(command);
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
var command = new CancelOrderCommand(@event.OrderId);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
command.GetGenericTypeName(),
|
||||||
|
nameof(command.OrderNumber),
|
||||||
|
command.OrderNumber,
|
||||||
|
command);
|
||||||
|
|
||||||
|
await _mediator.Send(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,13 @@
|
|||||||
{
|
{
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
using Ordering.API.Application.IntegrationEvents.Events;
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -12,16 +16,33 @@
|
|||||||
IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>
|
IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private readonly ILogger<OrderPaymentSuccededIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderPaymentSuccededIntegrationEventHandler(IMediator mediator)
|
public OrderPaymentSuccededIntegrationEventHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
ILogger<OrderPaymentSuccededIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderPaymentSuccededIntegrationEvent @event)
|
public async Task Handle(OrderPaymentSuccededIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var command = new SetPaidOrderStatusCommand(@event.OrderId);
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
await _mediator.Send(command);
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
var command = new SetPaidOrderStatusCommand(@event.OrderId);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
command.GetGenericTypeName(),
|
||||||
|
nameof(command.OrderNumber),
|
||||||
|
command.OrderNumber,
|
||||||
|
command);
|
||||||
|
|
||||||
|
await _mediator.Send(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,21 +7,42 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using System;
|
using System;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
|
|
||||||
public class OrderStockConfirmedIntegrationEventHandler :
|
public class OrderStockConfirmedIntegrationEventHandler :
|
||||||
IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>
|
IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private readonly ILogger<OrderStockConfirmedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStockConfirmedIntegrationEventHandler(IMediator mediator)
|
public OrderStockConfirmedIntegrationEventHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
ILogger<OrderStockConfirmedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderStockConfirmedIntegrationEvent @event)
|
public async Task Handle(OrderStockConfirmedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var command = new SetStockConfirmedOrderStatusCommand(@event.OrderId);
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
await _mediator.Send(command);
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
var command = new SetStockConfirmedOrderStatusCommand(@event.OrderId);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
command.GetGenericTypeName(),
|
||||||
|
nameof(command.OrderNumber),
|
||||||
|
command.OrderNumber,
|
||||||
|
command);
|
||||||
|
|
||||||
|
await _mediator.Send(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,25 +7,46 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
|
|
||||||
public class OrderStockRejectedIntegrationEventHandler : IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>
|
public class OrderStockRejectedIntegrationEventHandler : IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private readonly ILogger<OrderStockRejectedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStockRejectedIntegrationEventHandler(IMediator mediator)
|
public OrderStockRejectedIntegrationEventHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
ILogger<OrderStockRejectedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
|
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderStockRejectedIntegrationEvent @event)
|
public async Task Handle(OrderStockRejectedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var orderStockRejectedItems = @event.OrderStockItems
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
.FindAll(c => !c.HasStock)
|
{
|
||||||
.Select(c => c.ProductId)
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var command = new SetStockRejectedOrderStatusCommand(@event.OrderId, orderStockRejectedItems);
|
var orderStockRejectedItems = @event.OrderStockItems
|
||||||
await _mediator.Send(command);
|
.FindAll(c => !c.HasStock)
|
||||||
|
.Select(c => c.ProductId)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var command = new SetStockRejectedOrderStatusCommand(@event.OrderId, orderStockRejectedItems);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
command.GetGenericTypeName(),
|
||||||
|
nameof(command.OrderNumber),
|
||||||
|
command.OrderNumber,
|
||||||
|
command);
|
||||||
|
|
||||||
|
await _mediator.Send(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,48 +5,77 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.API.Application.IntegrationEvents.Events;
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
|
|
||||||
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
||||||
{
|
{
|
||||||
public class UserCheckoutAcceptedIntegrationEventHandler : IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>
|
public class UserCheckoutAcceptedIntegrationEventHandler : IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly ILoggerFactory _logger;
|
private readonly ILogger<UserCheckoutAcceptedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public UserCheckoutAcceptedIntegrationEventHandler(IMediator mediator,
|
public UserCheckoutAcceptedIntegrationEventHandler(
|
||||||
ILoggerFactory logger)
|
IMediator mediator,
|
||||||
|
ILogger<UserCheckoutAcceptedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Integration event handler which starts the create order process
|
/// Integration event handler which starts the create order process
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventMsg">
|
/// <param name="@event">
|
||||||
/// Integration event message which is sent by the
|
/// Integration event message which is sent by the
|
||||||
/// basket.api once it has successfully process the
|
/// basket.api once it has successfully process the
|
||||||
/// order items.
|
/// order items.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task Handle(UserCheckoutAcceptedIntegrationEvent eventMsg)
|
public async Task Handle(UserCheckoutAcceptedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
var result = false;
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
|
|
||||||
if (eventMsg.RequestId != Guid.Empty)
|
|
||||||
{
|
{
|
||||||
var createOrderCommand = new CreateOrderCommand(eventMsg.Basket.Items, eventMsg.UserId, eventMsg.UserName, eventMsg.City, eventMsg.Street,
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
eventMsg.State, eventMsg.Country, eventMsg.ZipCode,
|
|
||||||
eventMsg.CardNumber, eventMsg.CardHolderName, eventMsg.CardExpiration,
|
|
||||||
eventMsg.CardSecurityNumber, eventMsg.CardTypeId);
|
|
||||||
|
|
||||||
var requestCreateOrder = new IdentifiedCommand<CreateOrderCommand, bool>(createOrderCommand, eventMsg.RequestId);
|
var result = false;
|
||||||
result = await _mediator.Send(requestCreateOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.CreateLogger(nameof(UserCheckoutAcceptedIntegrationEventHandler))
|
if (@event.RequestId != Guid.Empty)
|
||||||
.LogTrace(result ? $"UserCheckoutAccepted integration event has been received and a create new order process is started with requestId: {eventMsg.RequestId}" :
|
{
|
||||||
$"UserCheckoutAccepted integration event has been received but a new order process has failed with requestId: {eventMsg.RequestId}");
|
using (LogContext.PushProperty("IdentifiedCommandId", @event.RequestId))
|
||||||
|
{
|
||||||
|
var createOrderCommand = new CreateOrderCommand(@event.Basket.Items, @event.UserId, @event.UserName, @event.City, @event.Street,
|
||||||
|
@event.State, @event.Country, @event.ZipCode,
|
||||||
|
@event.CardNumber, @event.CardHolderName, @event.CardExpiration,
|
||||||
|
@event.CardSecurityNumber, @event.CardTypeId);
|
||||||
|
|
||||||
|
var requestCreateOrder = new IdentifiedCommand<CreateOrderCommand, bool>(createOrderCommand, @event.RequestId);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
requestCreateOrder.GetGenericTypeName(),
|
||||||
|
nameof(requestCreateOrder.Id),
|
||||||
|
requestCreateOrder.Id,
|
||||||
|
requestCreateOrder);
|
||||||
|
|
||||||
|
result = await _mediator.Send(requestCreateOrder);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- CreateOrderCommand suceeded - RequestId: {RequestId}", @event.RequestId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("CreateOrderCommand failed - RequestId: {RequestId}", @event.RequestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Invalid IntegrationEvent - RequestId is missing - {@IntegrationEvent}", @event);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,9 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
|||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -21,39 +23,49 @@ namespace Ordering.API.Application.IntegrationEvents
|
|||||||
private readonly OrderingContext _orderingContext;
|
private readonly OrderingContext _orderingContext;
|
||||||
private readonly IntegrationEventLogContext _eventLogContext;
|
private readonly IntegrationEventLogContext _eventLogContext;
|
||||||
private readonly IIntegrationEventLogService _eventLogService;
|
private readonly IIntegrationEventLogService _eventLogService;
|
||||||
|
private readonly ILogger<OrderingIntegrationEventService> _logger;
|
||||||
|
|
||||||
public OrderingIntegrationEventService(IEventBus eventBus,
|
public OrderingIntegrationEventService(IEventBus eventBus,
|
||||||
OrderingContext orderingContext,
|
OrderingContext orderingContext,
|
||||||
IntegrationEventLogContext eventLogContext,
|
IntegrationEventLogContext eventLogContext,
|
||||||
Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
|
Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory,
|
||||||
|
ILogger<OrderingIntegrationEventService> logger)
|
||||||
{
|
{
|
||||||
_orderingContext = orderingContext ?? throw new ArgumentNullException(nameof(orderingContext));
|
_orderingContext = orderingContext ?? throw new ArgumentNullException(nameof(orderingContext));
|
||||||
_eventLogContext = eventLogContext ?? throw new ArgumentNullException(nameof(eventLogContext));
|
_eventLogContext = eventLogContext ?? throw new ArgumentNullException(nameof(eventLogContext));
|
||||||
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
|
_integrationEventLogServiceFactory = integrationEventLogServiceFactory ?? throw new ArgumentNullException(nameof(integrationEventLogServiceFactory));
|
||||||
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
_eventLogService = _integrationEventLogServiceFactory(_orderingContext.Database.GetDbConnection());
|
_eventLogService = _integrationEventLogServiceFactory(_orderingContext.Database.GetDbConnection());
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PublishEventsThroughEventBusAsync()
|
public async Task PublishEventsThroughEventBusAsync()
|
||||||
{
|
{
|
||||||
var pendindLogEvents = await _eventLogService.RetrieveEventLogsPendingToPublishAsync();
|
var pendindLogEvents = await _eventLogService.RetrieveEventLogsPendingToPublishAsync();
|
||||||
|
|
||||||
foreach (var logEvt in pendindLogEvents)
|
foreach (var logEvt in pendindLogEvents)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", logEvt.EventId, Program.AppName, logEvt.IntegrationEvent);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _eventLogService.MarkEventAsInProgressAsync(logEvt.EventId);
|
await _eventLogService.MarkEventAsInProgressAsync(logEvt.EventId);
|
||||||
_eventBus.Publish(logEvt.IntegrationEvent);
|
_eventBus.Publish(logEvt.IntegrationEvent);
|
||||||
await _eventLogService.MarkEventAsPublishedAsync(logEvt.EventId);
|
await _eventLogService.MarkEventAsPublishedAsync(logEvt.EventId);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_logger.LogError(ex, "ERROR publishing integration event: {IntegrationEventId} from {AppName}", logEvt.EventId, Program.AppName);
|
||||||
|
|
||||||
await _eventLogService.MarkEventAsFailedAsync(logEvt.EventId);
|
await _eventLogService.MarkEventAsFailedAsync(logEvt.EventId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddAndSaveEventAsync(IntegrationEvent evt)
|
public async Task AddAndSaveEventAsync(IntegrationEvent evt)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("----- Enqueuing integration event {IntegrationEventId} to repository ({@IntegrationEvent})", evt.Id, evt);
|
||||||
|
|
||||||
await _eventLogService.SaveEventAsync(evt, _orderingContext.GetCurrentTransaction.GetDbTransaction());
|
await _eventLogService.SaveEventAsync(evt, _orderingContext.GetCurrentTransaction.GetDbTransaction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -20,12 +22,18 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
|
|||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly IOrderQueries _orderQueries;
|
private readonly IOrderQueries _orderQueries;
|
||||||
private readonly IIdentityService _identityService;
|
private readonly IIdentityService _identityService;
|
||||||
|
private readonly ILogger<OrdersController> _logger;
|
||||||
|
|
||||||
public OrdersController(IMediator mediator, IOrderQueries orderQueries, IIdentityService identityService)
|
public OrdersController(
|
||||||
|
IMediator mediator,
|
||||||
|
IOrderQueries orderQueries,
|
||||||
|
IIdentityService identityService,
|
||||||
|
ILogger<OrdersController> logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
_orderQueries = orderQueries ?? throw new ArgumentNullException(nameof(orderQueries));
|
_orderQueries = orderQueries ?? throw new ArgumentNullException(nameof(orderQueries));
|
||||||
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("cancel")]
|
[Route("cancel")]
|
||||||
@ -39,6 +47,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
|
|||||||
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
|
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
|
||||||
{
|
{
|
||||||
var requestCancelOrder = new IdentifiedCommand<CancelOrderCommand, bool>(command, guid);
|
var requestCancelOrder = new IdentifiedCommand<CancelOrderCommand, bool>(command, guid);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
requestCancelOrder.GetGenericTypeName(),
|
||||||
|
nameof(requestCancelOrder.Command.OrderNumber),
|
||||||
|
requestCancelOrder.Command.OrderNumber,
|
||||||
|
requestCancelOrder);
|
||||||
|
|
||||||
commandResult = await _mediator.Send(requestCancelOrder);
|
commandResult = await _mediator.Send(requestCancelOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +77,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
|
|||||||
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
|
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
|
||||||
{
|
{
|
||||||
var requestShipOrder = new IdentifiedCommand<ShipOrderCommand, bool>(command, guid);
|
var requestShipOrder = new IdentifiedCommand<ShipOrderCommand, bool>(command, guid);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
requestShipOrder.GetGenericTypeName(),
|
||||||
|
nameof(requestShipOrder.Command.OrderNumber),
|
||||||
|
requestShipOrder.Command.OrderNumber,
|
||||||
|
requestShipOrder);
|
||||||
|
|
||||||
commandResult = await _mediator.Send(requestShipOrder);
|
commandResult = await _mediator.Send(requestShipOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +138,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<ActionResult<OrderDraftDTO>> CreateOrderDraftFromBasketDataAsync([FromBody] CreateOrderDraftCommand createOrderDraftCommand)
|
public async Task<ActionResult<OrderDraftDTO>> CreateOrderDraftFromBasketDataAsync([FromBody] CreateOrderDraftCommand createOrderDraftCommand)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
createOrderDraftCommand.GetGenericTypeName(),
|
||||||
|
nameof(createOrderDraftCommand.BuyerId),
|
||||||
|
createOrderDraftCommand.BuyerId,
|
||||||
|
createOrderDraftCommand);
|
||||||
|
|
||||||
return await _mediator.Send(createOrderDraftCommand);
|
return await _mediator.Send(createOrderDraftCommand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
|||||||
using Ordering.API.Application.Behaviors;
|
using Ordering.API.Application.Behaviors;
|
||||||
using Ordering.API.Application.DomainEventHandlers.OrderStartedEvent;
|
using Ordering.API.Application.DomainEventHandlers.OrderStartedEvent;
|
||||||
using Ordering.API.Application.Validations;
|
using Ordering.API.Application.Validations;
|
||||||
using Ordering.API.Infrastructure.Behaviors;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.AutofacModules
|
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.AutofacModules
|
||||||
{
|
{
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log.LogError(ex.Message);
|
log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
return GetPredefinedCardTypes();
|
return GetPredefinedCardTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@
|
|||||||
return File.ReadAllLines(csvFileCardTypes)
|
return File.ReadAllLines(csvFileCardTypes)
|
||||||
.Skip(1) // skip header column
|
.Skip(1) // skip header column
|
||||||
.SelectTry(x => CreateCardType(x, ref id))
|
.SelectTry(x => CreateCardType(x, ref id))
|
||||||
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
|
.OnCaughtException(ex => { log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
|
||||||
.Where(x => x != null);
|
.Where(x => x != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log.LogError(ex.Message);
|
log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
return GetPredefinedOrderStatus();
|
return GetPredefinedOrderStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@
|
|||||||
return File.ReadAllLines(csvFileOrderStatus)
|
return File.ReadAllLines(csvFileOrderStatus)
|
||||||
.Skip(1) // skip header row
|
.Skip(1) // skip header row
|
||||||
.SelectTry(x => CreateOrderStatus(x, ref id))
|
.SelectTry(x => CreateOrderStatus(x, ref id))
|
||||||
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
|
.OnCaughtException(ex => { log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); return null; })
|
||||||
.Where(x => x != null);
|
.Where(x => x != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@
|
|||||||
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
|
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
|
||||||
onRetry: (exception, timeSpan, retry, ctx) =>
|
onRetry: (exception, timeSpan, retry, ctx) =>
|
||||||
{
|
{
|
||||||
logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
|
logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", prefix, exception.GetType().Name, exception.Message, retry, retries);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<UserSecretsId>aspnet-Ordering.API-20161122013547</UserSecretsId>
|
<UserSecretsId>aspnet-Ordering.API-20161122013547</UserSecretsId>
|
||||||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
||||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -27,30 +28,33 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
||||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="5.1.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
|
<PackageReference Include="Dapper" Version="1.50.7" />
|
||||||
|
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.0" />
|
||||||
|
<PackageReference Include="MediatR" Version="5.1.0" />
|
||||||
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="5.1.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
<PackageReference Include="Polly" Version="6.0.1" />
|
||||||
<PackageReference Include="MediatR" Version="5.1.0" />
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
<PackageReference Include="System.Reflection" Version="4.3.0" />
|
<PackageReference Include="System.Reflection" Version="4.3.0" />
|
||||||
<PackageReference Include="Dapper" Version="1.50.7" />
|
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
<PackageReference Include="Polly" Version="6.0.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Setup\*">
|
<None Update="Setup\*">
|
||||||
|
@ -15,10 +15,22 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
|
|||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args)
|
var configuration = GetConfiguration();
|
||||||
.MigrateDbContext<OrderingContext>((context, services) =>
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
|
||||||
|
host.MigrateDbContext<OrderingContext>((context, services) =>
|
||||||
{
|
{
|
||||||
var env = services.GetService<IHostingEnvironment>();
|
var env = services.GetService<IHostingEnvironment>();
|
||||||
var settings = services.GetService<IOptions<OrderingSettings>>();
|
var settings = services.GetService<IOptions<OrderingSettings>>();
|
||||||
@ -28,47 +40,66 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
|
|||||||
.SeedAsync(context, env, settings, logger)
|
.SeedAsync(context, env, settings, logger)
|
||||||
.Wait();
|
.Wait();
|
||||||
})
|
})
|
||||||
.MigrateDbContext<IntegrationEventLogContext>((_,__)=>{})
|
.MigrateDbContext<IntegrationEventLogContext>((_, __) => { });
|
||||||
.Run();
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
|
.CaptureStartupErrors(false)
|
||||||
.UseStartup<Startup>()
|
.UseStartup<Startup>()
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
|
||||||
.ConfigureAppConfiguration((builderContext, config) =>
|
|
||||||
{
|
|
||||||
var builtConfig = config.Build();
|
|
||||||
|
|
||||||
var configurationBuilder = new ConfigurationBuilder();
|
|
||||||
|
|
||||||
if (Convert.ToBoolean(builtConfig["UseVault"]))
|
|
||||||
{
|
|
||||||
configurationBuilder.AddAzureKeyVault(
|
|
||||||
$"https://{builtConfig["Vault:Name"]}.vault.azure.net/",
|
|
||||||
builtConfig["Vault:ClientId"],
|
|
||||||
builtConfig["Vault:ClientSecret"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
configurationBuilder.AddEnvironmentVariables();
|
|
||||||
|
|
||||||
config.AddConfiguration(configurationBuilder.Build());
|
|
||||||
})
|
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddConsole();
|
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddAzureWebAppDiagnostics();
|
|
||||||
})
|
|
||||||
.UseApplicationInsights()
|
.UseApplicationInsights()
|
||||||
.UseSerilog((builderContext, config) =>
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
{
|
.UseConfiguration(configuration)
|
||||||
config
|
.UseSerilog()
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault(
|
||||||
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
|
config["Vault:ClientId"],
|
||||||
|
config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -74,14 +74,15 @@
|
|||||||
|
|
||||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
app.UsePathBase(pathBase);
|
app.UsePathBase(pathBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseCors("CorsPolicy");
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
@ -121,10 +122,9 @@
|
|||||||
eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>>();
|
eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>>();
|
||||||
eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>();
|
eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>();
|
||||||
eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>();
|
eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>();
|
||||||
eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>>();
|
eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
if (Configuration.GetValue<bool>("UseLoadTest"))
|
if (Configuration.GetValue<bool>("UseLoadTest"))
|
||||||
@ -167,7 +167,7 @@
|
|||||||
})
|
})
|
||||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
|
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
|
||||||
.AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
.AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
||||||
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
||||||
|
|
||||||
services.AddCors(options =>
|
services.AddCors(options =>
|
||||||
{
|
{
|
||||||
|
@ -2,12 +2,15 @@
|
|||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://localhost:5105",
|
||||||
"UseCustomizationData": false,
|
"UseCustomizationData": false,
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Trace",
|
"Default": "Information",
|
||||||
"System": "Information",
|
"Override": {
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AzureServiceBusEnabled": false,
|
"AzureServiceBusEnabled": false,
|
||||||
|
@ -24,7 +24,10 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,33 +1,75 @@
|
|||||||
using Microsoft.AspNetCore;
|
using Microsoft.AspNetCore;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Ordering.BackgroundTasks
|
namespace Ordering.BackgroundTasks
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace;
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args).Run();
|
var configuration = GetConfiguration();
|
||||||
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
.UseStartup<Startup>()
|
.CaptureStartupErrors(false)
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
.UseStartup<Startup>()
|
||||||
{
|
.UseConfiguration(configuration)
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
.UseSerilog()
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddConsole();
|
|
||||||
})
|
|
||||||
.UseSerilog((builderContext, config) =>
|
|
||||||
{
|
|
||||||
config
|
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,10 @@ namespace Ordering.BackgroundTasks.Tasks
|
|||||||
private readonly BackgroundTaskSettings _settings;
|
private readonly BackgroundTaskSettings _settings;
|
||||||
private readonly IEventBus _eventBus;
|
private readonly IEventBus _eventBus;
|
||||||
|
|
||||||
public GracePeriodManagerService(IOptions<BackgroundTaskSettings> settings,
|
public GracePeriodManagerService(
|
||||||
IEventBus eventBus,
|
IOptions<BackgroundTaskSettings> settings,
|
||||||
ILogger<GracePeriodManagerService> logger)
|
IEventBus eventBus,
|
||||||
|
ILogger<GracePeriodManagerService> logger)
|
||||||
{
|
{
|
||||||
_settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
|
_settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
|
||||||
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
@ -32,27 +33,27 @@ namespace Ordering.BackgroundTasks.Tasks
|
|||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
_logger.LogDebug($"GracePeriodManagerService is starting.");
|
_logger.LogDebug("GracePeriodManagerService is starting.");
|
||||||
|
|
||||||
stoppingToken.Register(() => _logger.LogDebug($"#1 GracePeriodManagerService background task is stopping."));
|
stoppingToken.Register(() => _logger.LogDebug("#1 GracePeriodManagerService background task is stopping."));
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_logger.LogDebug($"GracePeriodManagerService background task is doing background work.");
|
_logger.LogDebug("GracePeriodManagerService background task is doing background work.");
|
||||||
|
|
||||||
CheckConfirmedGracePeriodOrders();
|
CheckConfirmedGracePeriodOrders();
|
||||||
|
|
||||||
await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
|
await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug($"GracePeriodManagerService background task is stopping.");
|
_logger.LogDebug("GracePeriodManagerService background task is stopping.");
|
||||||
|
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckConfirmedGracePeriodOrders()
|
private void CheckConfirmedGracePeriodOrders()
|
||||||
{
|
{
|
||||||
_logger.LogDebug($"Checking confirmed grace period orders");
|
_logger.LogDebug("Checking confirmed grace period orders");
|
||||||
|
|
||||||
var orderIds = GetConfirmedGracePeriodOrders();
|
var orderIds = GetConfirmedGracePeriodOrders();
|
||||||
|
|
||||||
@ -60,6 +61,8 @@ namespace Ordering.BackgroundTasks.Tasks
|
|||||||
{
|
{
|
||||||
var confirmGracePeriodEvent = new GracePeriodConfirmedIntegrationEvent(orderId);
|
var confirmGracePeriodEvent = new GracePeriodConfirmedIntegrationEvent(orderId);
|
||||||
|
|
||||||
|
_logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", confirmGracePeriodEvent.Id, Program.AppName, confirmGracePeriodEvent);
|
||||||
|
|
||||||
_eventBus.Publish(confirmGracePeriodEvent);
|
_eventBus.Publish(confirmGracePeriodEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +84,7 @@ namespace Ordering.BackgroundTasks.Tasks
|
|||||||
}
|
}
|
||||||
catch (SqlException exception)
|
catch (SqlException exception)
|
||||||
{
|
{
|
||||||
_logger.LogCritical($"FATAL ERROR: Database connections could not be opened: {exception.Message}");
|
_logger.LogCritical(exception, "FATAL ERROR: Database connections could not be opened: {Message}", exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
{
|
{
|
||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"Debug": {
|
"MinimumLevel": {
|
||||||
"LogLevel": {
|
"Default": "Information",
|
||||||
"Default": "Debug"
|
"Override": {
|
||||||
}
|
"Microsoft": "Warning",
|
||||||
},
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
"Console": {
|
"System": "Warning"
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Debug"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -27,10 +27,12 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
|||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private IDbContextTransaction _currentTransaction;
|
private IDbContextTransaction _currentTransaction;
|
||||||
|
|
||||||
private OrderingContext(DbContextOptions<OrderingContext> options) : base (options) { }
|
private OrderingContext(DbContextOptions<OrderingContext> options) : base(options) { }
|
||||||
|
|
||||||
public IDbContextTransaction GetCurrentTransaction => _currentTransaction;
|
public IDbContextTransaction GetCurrentTransaction => _currentTransaction;
|
||||||
|
|
||||||
|
public bool HasActiveTransaction => _currentTransaction != null;
|
||||||
|
|
||||||
public OrderingContext(DbContextOptions<OrderingContext> options, IMediator mediator) : base(options)
|
public OrderingContext(DbContextOptions<OrderingContext> options, IMediator mediator) : base(options)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
@ -47,7 +49,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
|||||||
modelBuilder.ApplyConfiguration(new OrderItemEntityTypeConfiguration());
|
modelBuilder.ApplyConfiguration(new OrderItemEntityTypeConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new CardTypeEntityTypeConfiguration());
|
modelBuilder.ApplyConfiguration(new CardTypeEntityTypeConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new OrderStatusEntityTypeConfiguration());
|
modelBuilder.ApplyConfiguration(new OrderStatusEntityTypeConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new BuyerEntityTypeConfiguration());
|
modelBuilder.ApplyConfiguration(new BuyerEntityTypeConfiguration());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||||
@ -67,17 +69,24 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task BeginTransactionAsync()
|
public async Task<IDbContextTransaction> BeginTransactionAsync()
|
||||||
{
|
{
|
||||||
_currentTransaction = _currentTransaction ?? await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted);
|
if (_currentTransaction != null) return null;
|
||||||
|
|
||||||
|
_currentTransaction = await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted);
|
||||||
|
|
||||||
|
return _currentTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CommitTransactionAsync()
|
public async Task CommitTransactionAsync(IDbContextTransaction transaction)
|
||||||
{
|
{
|
||||||
|
if (transaction == null) throw new ArgumentNullException(nameof(transaction));
|
||||||
|
if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await SaveChangesAsync();
|
await SaveChangesAsync();
|
||||||
_currentTransaction?.Commit();
|
transaction.Commit();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -118,7 +127,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
|||||||
var optionsBuilder = new DbContextOptionsBuilder<OrderingContext>()
|
var optionsBuilder = new DbContextOptionsBuilder<OrderingContext>()
|
||||||
.UseSqlServer("Server=.;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;Integrated Security=true");
|
.UseSqlServer("Server=.;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;Integrated Security=true");
|
||||||
|
|
||||||
return new OrderingContext(optionsBuilder.Options,new NoMediator());
|
return new OrderingContext(optionsBuilder.Options, new NoMediator());
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoMediator : IMediator
|
class NoMediator : IMediator
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.SignalrHub.IntegrationEvents.Events;
|
using Ordering.SignalrHub.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -11,18 +13,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
|
|||||||
public class OrderStatusChangedToCancelledIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>
|
public class OrderStatusChangedToCancelledIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IHubContext<NotificationsHub> _hubContext;
|
private readonly IHubContext<NotificationsHub> _hubContext;
|
||||||
|
private readonly ILogger<OrderStatusChangedToCancelledIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToCancelledIntegrationEventHandler(IHubContext<NotificationsHub> hubContext)
|
public OrderStatusChangedToCancelledIntegrationEventHandler(
|
||||||
|
IHubContext<NotificationsHub> hubContext,
|
||||||
|
ILogger<OrderStatusChangedToCancelledIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToCancelledIntegrationEvent @event)
|
public async Task Handle(OrderStatusChangedToCancelledIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
await _hubContext.Clients
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
.Group(@event.BuyerName)
|
{
|
||||||
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
await _hubContext.Clients
|
||||||
|
.Group(@event.BuyerName)
|
||||||
|
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.SignalrHub.IntegrationEvents.Events;
|
using Ordering.SignalrHub.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -9,18 +11,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
|
|||||||
public class OrderStatusChangedToPaidIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent>
|
public class OrderStatusChangedToPaidIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IHubContext<NotificationsHub> _hubContext;
|
private readonly IHubContext<NotificationsHub> _hubContext;
|
||||||
|
private readonly ILogger<OrderStatusChangedToPaidIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToPaidIntegrationEventHandler(IHubContext<NotificationsHub> hubContext)
|
public OrderStatusChangedToPaidIntegrationEventHandler(
|
||||||
|
IHubContext<NotificationsHub> hubContext,
|
||||||
|
ILogger<OrderStatusChangedToPaidIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToPaidIntegrationEvent @event)
|
public async Task Handle(OrderStatusChangedToPaidIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
await _hubContext.Clients
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
.Group(@event.BuyerName)
|
{
|
||||||
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
await _hubContext.Clients
|
||||||
|
.Group(@event.BuyerName)
|
||||||
|
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.SignalrHub.IntegrationEvents.Events;
|
using Ordering.SignalrHub.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -11,18 +13,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
|
|||||||
public class OrderStatusChangedToShippedIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToShippedIntegrationEvent>
|
public class OrderStatusChangedToShippedIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToShippedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IHubContext<NotificationsHub> _hubContext;
|
private readonly IHubContext<NotificationsHub> _hubContext;
|
||||||
|
private readonly ILogger<OrderStatusChangedToShippedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToShippedIntegrationEventHandler(IHubContext<NotificationsHub> hubContext)
|
public OrderStatusChangedToShippedIntegrationEventHandler(
|
||||||
|
IHubContext<NotificationsHub> hubContext,
|
||||||
|
ILogger<OrderStatusChangedToShippedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToShippedIntegrationEvent @event)
|
public async Task Handle(OrderStatusChangedToShippedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
await _hubContext.Clients
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
.Group(@event.BuyerName)
|
{
|
||||||
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
await _hubContext.Clients
|
||||||
|
.Group(@event.BuyerName)
|
||||||
|
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.SignalrHub.IntegrationEvents.Events;
|
using Ordering.SignalrHub.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -12,18 +14,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
|
|||||||
IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent>
|
IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IHubContext<NotificationsHub> _hubContext;
|
private readonly IHubContext<NotificationsHub> _hubContext;
|
||||||
|
private readonly ILogger<OrderStatusChangedToStockConfirmedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToStockConfirmedIntegrationEventHandler(IHubContext<NotificationsHub> hubContext)
|
public OrderStatusChangedToStockConfirmedIntegrationEventHandler(
|
||||||
|
IHubContext<NotificationsHub> hubContext,
|
||||||
|
ILogger<OrderStatusChangedToStockConfirmedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event)
|
public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
await _hubContext.Clients
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
.Group(@event.BuyerName)
|
{
|
||||||
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
await _hubContext.Clients
|
||||||
|
.Group(@event.BuyerName)
|
||||||
|
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.SignalrHub.IntegrationEvents.Events;
|
using Ordering.SignalrHub.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -12,18 +14,27 @@ namespace Ordering.SignalrHub.IntegrationEvents.EventHandling
|
|||||||
IIntegrationEventHandler<OrderStatusChangedToSubmittedIntegrationEvent>
|
IIntegrationEventHandler<OrderStatusChangedToSubmittedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IHubContext<NotificationsHub> _hubContext;
|
private readonly IHubContext<NotificationsHub> _hubContext;
|
||||||
|
private readonly ILogger<OrderStatusChangedToSubmittedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToSubmittedIntegrationEventHandler(IHubContext<NotificationsHub> hubContext)
|
public OrderStatusChangedToSubmittedIntegrationEventHandler(
|
||||||
|
IHubContext<NotificationsHub> hubContext,
|
||||||
|
ILogger<OrderStatusChangedToSubmittedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToSubmittedIntegrationEvent @event)
|
public async Task Handle(OrderStatusChangedToSubmittedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
await _hubContext.Clients
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
.Group(@event.BuyerName)
|
{
|
||||||
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
await _hubContext.Clients
|
||||||
|
.Group(@event.BuyerName)
|
||||||
|
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -10,18 +12,27 @@ namespace Ordering.SignalrHub.IntegrationEvents
|
|||||||
public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent>
|
public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IHubContext<NotificationsHub> _hubContext;
|
private readonly IHubContext<NotificationsHub> _hubContext;
|
||||||
|
private readonly ILogger<OrderStatusChangedToAwaitingValidationIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(IHubContext<NotificationsHub> hubContext)
|
public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(
|
||||||
|
IHubContext<NotificationsHub> hubContext,
|
||||||
|
ILogger<OrderStatusChangedToAwaitingValidationIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event)
|
public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
await _hubContext.Clients
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
.Group(@event.BuyerName)
|
{
|
||||||
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
|
await _hubContext.Clients
|
||||||
|
.Group(@event.BuyerName)
|
||||||
|
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,23 +11,25 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Redis" Version="1.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Redis" Version="1.1.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0-preview3-35497" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -13,28 +13,67 @@ namespace Ordering.SignalrHub
|
|||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace;
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args).Run();
|
var configuration = GetConfiguration();
|
||||||
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
|
.CaptureStartupErrors(false)
|
||||||
.UseStartup<Startup>()
|
.UseStartup<Startup>()
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
.UseConfiguration(configuration)
|
||||||
{
|
.UseSerilog()
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddConsole();
|
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddAzureWebAppDiagnostics();
|
|
||||||
})
|
|
||||||
.UseSerilog((builderContext, config) =>
|
|
||||||
{
|
|
||||||
config
|
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ namespace Ordering.SignalrHub
|
|||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
@ -115,17 +117,18 @@ namespace Ordering.SignalrHub
|
|||||||
return new AutofacServiceProvider(container.Build());
|
return new AutofacServiceProvider(container.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||||
|
//loggerFactory.AddDebug();
|
||||||
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
app.UsePathBase(pathBase);
|
app.UsePathBase(pathBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,13 +159,13 @@ namespace Ordering.SignalrHub
|
|||||||
private void ConfigureEventBus(IApplicationBuilder app)
|
private void ConfigureEventBus(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
||||||
|
|
||||||
eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
|
eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
|
||||||
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>();
|
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>();
|
||||||
eventBus.Subscribe<OrderStatusChangedToStockConfirmedIntegrationEvent, OrderStatusChangedToStockConfirmedIntegrationEventHandler>();
|
eventBus.Subscribe<OrderStatusChangedToStockConfirmedIntegrationEvent, OrderStatusChangedToStockConfirmedIntegrationEventHandler>();
|
||||||
eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>();
|
eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>();
|
||||||
eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, OrderStatusChangedToCancelledIntegrationEventHandler>();
|
eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, OrderStatusChangedToCancelledIntegrationEventHandler>();
|
||||||
eventBus.Subscribe<OrderStatusChangedToSubmittedIntegrationEvent, OrderStatusChangedToSubmittedIntegrationEventHandler>();
|
eventBus.Subscribe<OrderStatusChangedToSubmittedIntegrationEvent, OrderStatusChangedToSubmittedIntegrationEventHandler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigureAuthService(IServiceCollection services)
|
private void ConfigureAuthService(IServiceCollection services)
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://localhost:5105",
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Trace",
|
"Default": "Information",
|
||||||
"System": "Information",
|
"Override": {
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AzureServiceBusEnabled": false,
|
"AzureServiceBusEnabled": false,
|
||||||
|
@ -8,6 +8,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -17,11 +18,13 @@ namespace UnitTest.Ordering.Application
|
|||||||
{
|
{
|
||||||
private readonly Mock<IRequestManager> _requestManager;
|
private readonly Mock<IRequestManager> _requestManager;
|
||||||
private readonly Mock<IMediator> _mediator;
|
private readonly Mock<IMediator> _mediator;
|
||||||
|
private readonly Mock<ILogger<IdentifiedCommandHandler<CreateOrderCommand, bool>>> _loggerMock;
|
||||||
|
|
||||||
public IdentifiedCommandHandlerTest()
|
public IdentifiedCommandHandlerTest()
|
||||||
{
|
{
|
||||||
_requestManager = new Mock<IRequestManager>();
|
_requestManager = new Mock<IRequestManager>();
|
||||||
_mediator = new Mock<IMediator>();
|
_mediator = new Mock<IMediator>();
|
||||||
|
_loggerMock = new Mock<ILogger<IdentifiedCommandHandler<CreateOrderCommand, bool>>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -38,7 +41,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var handler = new IdentifiedCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object);
|
var handler = new IdentifiedCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object, _loggerMock.Object);
|
||||||
var cltToken = new System.Threading.CancellationToken();
|
var cltToken = new System.Threading.CancellationToken();
|
||||||
var result = await handler.Handle(fakeOrderCmd, cltToken);
|
var result = await handler.Handle(fakeOrderCmd, cltToken);
|
||||||
|
|
||||||
@ -61,7 +64,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var handler = new IdentifiedCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object);
|
var handler = new IdentifiedCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object, _loggerMock.Object);
|
||||||
var cltToken = new System.Threading.CancellationToken();
|
var cltToken = new System.Threading.CancellationToken();
|
||||||
var result = await handler.Handle(fakeOrderCmd, cltToken);
|
var result = await handler.Handle(fakeOrderCmd, cltToken);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
using global::Ordering.API.Application.IntegrationEvents;
|
using global::Ordering.API.Application.IntegrationEvents;
|
||||||
using global::Ordering.API.Application.Models;
|
using global::Ordering.API.Application.Models;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -50,8 +51,9 @@ namespace UnitTest.Ordering.Application
|
|||||||
|
|
||||||
_identityServiceMock.Setup(svc => svc.GetUserIdentity()).Returns(buyerId);
|
_identityServiceMock.Setup(svc => svc.GetUserIdentity()).Returns(buyerId);
|
||||||
|
|
||||||
|
var LoggerMock = new Mock<ILogger<CreateOrderCommandHandler>>();
|
||||||
//Act
|
//Act
|
||||||
var handler = new CreateOrderCommandHandler(_mediator.Object, _orderingIntegrationEventService.Object, _orderRepositoryMock.Object, _identityServiceMock.Object);
|
var handler = new CreateOrderCommandHandler(_mediator.Object, _orderingIntegrationEventService.Object, _orderRepositoryMock.Object, _identityServiceMock.Object, LoggerMock.Object);
|
||||||
var cltToken = new System.Threading.CancellationToken();
|
var cltToken = new System.Threading.CancellationToken();
|
||||||
var result = await handler.Handle(fakeOrderCmd, cltToken);
|
var result = await handler.Handle(fakeOrderCmd, cltToken);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
using System;
|
using System;
|
||||||
@ -19,12 +20,14 @@ namespace UnitTest.Ordering.Application
|
|||||||
private readonly Mock<IMediator> _mediatorMock;
|
private readonly Mock<IMediator> _mediatorMock;
|
||||||
private readonly Mock<IOrderQueries> _orderQueriesMock;
|
private readonly Mock<IOrderQueries> _orderQueriesMock;
|
||||||
private readonly Mock<IIdentityService> _identityServiceMock;
|
private readonly Mock<IIdentityService> _identityServiceMock;
|
||||||
|
private readonly Mock<ILogger<OrdersController>> _loggerMock;
|
||||||
|
|
||||||
public OrdersWebApiTest()
|
public OrdersWebApiTest()
|
||||||
{
|
{
|
||||||
_mediatorMock = new Mock<IMediator>();
|
_mediatorMock = new Mock<IMediator>();
|
||||||
_orderQueriesMock = new Mock<IOrderQueries>();
|
_orderQueriesMock = new Mock<IOrderQueries>();
|
||||||
_identityServiceMock = new Mock<IIdentityService>();
|
_identityServiceMock = new Mock<IIdentityService>();
|
||||||
|
_loggerMock = new Mock<ILogger<OrdersController>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -35,7 +38,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
|
||||||
var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
|
var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -51,7 +54,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
|
||||||
var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), String.Empty) as BadRequestResult;
|
var actionResult = await orderController.CancelOrderAsync(new CancelOrderCommand(1), String.Empty) as BadRequestResult;
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -66,7 +69,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
|
||||||
var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
|
var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -82,7 +85,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
|
||||||
var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), String.Empty) as BadRequestResult;
|
var actionResult = await orderController.ShipOrderAsync(new ShipOrderCommand(1), String.Empty) as BadRequestResult;
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -102,7 +105,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(fakeDynamicResult));
|
.Returns(Task.FromResult(fakeDynamicResult));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
|
||||||
var actionResult = await orderController.GetOrdersAsync();
|
var actionResult = await orderController.GetOrdersAsync();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -119,7 +122,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(fakeDynamicResult));
|
.Returns(Task.FromResult(fakeDynamicResult));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
|
||||||
var actionResult = await orderController.GetOrderAsync(fakeOrderId) as OkObjectResult;
|
var actionResult = await orderController.GetOrderAsync(fakeOrderId) as OkObjectResult;
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -135,7 +138,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
.Returns(Task.FromResult(fakeDynamicResult));
|
.Returns(Task.FromResult(fakeDynamicResult));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
|
||||||
var actionResult = await orderController.GetCardTypesAsync();
|
var actionResult = await orderController.GetCardTypesAsync();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
|
@ -2,45 +2,58 @@
|
|||||||
{
|
{
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Payment.API.IntegrationEvents.Events;
|
using Payment.API.IntegrationEvents.Events;
|
||||||
|
using Serilog.Context;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public class OrderStatusChangedToStockConfirmedIntegrationEventHandler :
|
public class OrderStatusChangedToStockConfirmedIntegrationEventHandler :
|
||||||
IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent>
|
IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IEventBus _eventBus;
|
private readonly IEventBus _eventBus;
|
||||||
private readonly PaymentSettings _settings;
|
private readonly PaymentSettings _settings;
|
||||||
|
private readonly ILogger<OrderStatusChangedToStockConfirmedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public OrderStatusChangedToStockConfirmedIntegrationEventHandler(IEventBus eventBus,
|
public OrderStatusChangedToStockConfirmedIntegrationEventHandler(
|
||||||
IOptionsSnapshot<PaymentSettings> settings)
|
IEventBus eventBus,
|
||||||
|
IOptionsSnapshot<PaymentSettings> settings,
|
||||||
|
ILogger<OrderStatusChangedToStockConfirmedIntegrationEventHandler> logger)
|
||||||
{
|
{
|
||||||
_eventBus = eventBus;
|
_eventBus = eventBus;
|
||||||
_settings = settings.Value;
|
_settings = settings.Value;
|
||||||
}
|
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event)
|
public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
IntegrationEvent orderPaymentIntegrationEvent;
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
|
||||||
|
|
||||||
//Business feature comment:
|
|
||||||
// When OrderStatusChangedToStockConfirmed Integration Event is handled.
|
|
||||||
// Here we're simulating that we'd be performing the payment against any payment gateway
|
|
||||||
// Instead of a real payment we just take the env. var to simulate the payment
|
|
||||||
// The payment can be successful or it can fail
|
|
||||||
|
|
||||||
if (_settings.PaymentSucceded)
|
|
||||||
{
|
{
|
||||||
orderPaymentIntegrationEvent = new OrderPaymentSuccededIntegrationEvent(@event.OrderId);
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
orderPaymentIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_eventBus.Publish(orderPaymentIntegrationEvent);
|
IntegrationEvent orderPaymentIntegrationEvent;
|
||||||
|
|
||||||
await Task.CompletedTask;
|
//Business feature comment:
|
||||||
|
// When OrderStatusChangedToStockConfirmed Integration Event is handled.
|
||||||
|
// Here we're simulating that we'd be performing the payment against any payment gateway
|
||||||
|
// Instead of a real payment we just take the env. var to simulate the payment
|
||||||
|
// The payment can be successful or it can fail
|
||||||
|
|
||||||
|
if (_settings.PaymentSucceded)
|
||||||
|
{
|
||||||
|
orderPaymentIntegrationEvent = new OrderPaymentSuccededIntegrationEvent(@event.OrderId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
orderPaymentIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", orderPaymentIntegrationEvent.Id, Program.AppName, orderPaymentIntegrationEvent);
|
||||||
|
|
||||||
|
_eventBus.Publish(orderPaymentIntegrationEvent);
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,20 +7,23 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.2" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0-preview3-35497" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.2" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
|
@ -4,40 +4,85 @@ using Microsoft.AspNetCore.Hosting;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Payment.API
|
namespace Payment.API
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace;
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
BuildWebHost(args).Run();
|
var configuration = GetConfiguration();
|
||||||
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IWebHost BuildWebHost(string[] args) =>
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
WebHost.CreateDefaultBuilder(args)
|
WebHost.CreateDefaultBuilder(args)
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.CaptureStartupErrors(false)
|
||||||
.UseStartup<Startup>()
|
.UseStartup<Startup>()
|
||||||
.ConfigureAppConfiguration((builderContext, config) =>
|
|
||||||
{
|
|
||||||
config.AddEnvironmentVariables();
|
|
||||||
})
|
|
||||||
.ConfigureLogging((hostingContext, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddConsole();
|
|
||||||
builder.AddDebug();
|
|
||||||
builder.AddAzureWebAppDiagnostics();
|
|
||||||
})
|
|
||||||
.UseApplicationInsights()
|
.UseApplicationInsights()
|
||||||
.UseSerilog((builderContext, config) =>
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
{
|
.UseConfiguration(configuration)
|
||||||
config
|
.UseSerilog()
|
||||||
.MinimumLevel.Information()
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console();
|
|
||||||
})
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault(
|
||||||
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
|
config["Vault:ClientId"],
|
||||||
|
config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -91,7 +91,8 @@ namespace Payment.API
|
|||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// 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)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Serilog": {
|
||||||
"IncludeScopes": false,
|
"SeqServerUrl": null,
|
||||||
"LogLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Warning"
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PaymentSucceded": true,
|
"PaymentSucceded": true,
|
||||||
|
@ -15,7 +15,7 @@ namespace WebMVC.Infrastructure
|
|||||||
{
|
{
|
||||||
public static void Seed(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public static void Seed(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
var log = loggerFactory.CreateLogger("WebMVC seed");
|
var log = loggerFactory.CreateLogger<WebContextSeed>();
|
||||||
|
|
||||||
var settings = (AppSettings)applicationBuilder
|
var settings = (AppSettings)applicationBuilder
|
||||||
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
|
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
|
||||||
@ -39,7 +39,7 @@ namespace WebMVC.Infrastructure
|
|||||||
string overrideCssFile = Path.Combine(contentRootPath, "Setup", "override.css");
|
string overrideCssFile = Path.Combine(contentRootPath, "Setup", "override.css");
|
||||||
if (!File.Exists(overrideCssFile))
|
if (!File.Exists(overrideCssFile))
|
||||||
{
|
{
|
||||||
log.LogError($" override css file '{overrideCssFile}' does not exists.");
|
log.LogError("Override css file '{FileName}' does not exists.", overrideCssFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ namespace WebMVC.Infrastructure
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log.LogError($"Exception in method GetPreconfiguredCSS WebMVC. Exception Message={ex.Message}");
|
log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ namespace WebMVC.Infrastructure
|
|||||||
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
|
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
|
||||||
if (!File.Exists(imagesZipFile))
|
if (!File.Exists(imagesZipFile))
|
||||||
{
|
{
|
||||||
log.LogError($" zip file '{imagesZipFile}' does not exists.");
|
log.LogError("Zip file '{ZipFileName}' does not exists.", imagesZipFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,14 +81,14 @@ namespace WebMVC.Infrastructure
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
|
log.LogWarning("Skipped file '{FileName}' in zipfile '{ZipFileName}'", entry.Name, imagesZipFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( Exception ex )
|
catch ( Exception ex )
|
||||||
{
|
{
|
||||||
log.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
|
log.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user