@ -0,0 +1,10 @@ | |||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; | |||
using System.Threading.Tasks; | |||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services | |||
{ | |||
public interface IOrderingService | |||
{ | |||
Task<OrderData> GetOrderDraftAsync(BasketData basketData); | |||
} | |||
} |
@ -0,0 +1,113 @@ | |||
using Grpc.Net.Client; | |||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; | |||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
using System; | |||
using System.Linq; | |||
using System.Net.Http; | |||
using System.Threading.Tasks; | |||
using GrpcOrdering; | |||
using Grpc.Core; | |||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services | |||
{ | |||
public class OrderingService : IOrderingService | |||
{ | |||
private readonly HttpClient _httpClient; | |||
private readonly UrlsConfig _urls; | |||
private readonly ILogger<OrderingService> _logger; | |||
public OrderingService(HttpClient httpClient, IOptions<UrlsConfig> config, ILogger<OrderingService> logger) | |||
{ | |||
_httpClient = httpClient; | |||
_urls = config.Value; | |||
_logger = logger; | |||
} | |||
public async Task<OrderData> GetOrderDraftAsync(BasketData basketData) | |||
{ | |||
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); | |||
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); | |||
using (var httpClientHandler = new HttpClientHandler()) | |||
{ | |||
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; | |||
using (var httpClient = new HttpClient(httpClientHandler)) | |||
{ | |||
httpClient.BaseAddress = new Uri(_urls.GrpcOrdering); | |||
_logger.LogDebug(" Creating grpc client for ordering {@httpClient.BaseAddress}", httpClient.BaseAddress); | |||
var client = GrpcClient.Create<OrderingGrpc.OrderingGrpcClient>(httpClient); | |||
_logger.LogDebug(" grpc client created, basketData={@basketData}", basketData); | |||
try | |||
{ | |||
var command = MapToOrderDraftCommand(basketData); | |||
var response = await client.CreateOrderDraftFromBasketDataAsync(command); | |||
_logger.LogDebug(" grpc response: {@response}", response); | |||
return MapToResponse(response); | |||
} | |||
catch (RpcException e) | |||
{ | |||
_logger.LogError($"Error calling via grpc to ordering: {e.Status} - {e.Message}"); | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
private OrderData MapToResponse(GrpcOrdering.OrderDraftDTO orderDraft) | |||
{ | |||
if (orderDraft == null) | |||
{ | |||
return null; | |||
} | |||
var data = new OrderData | |||
{ | |||
Total = (decimal)orderDraft.Total, | |||
}; | |||
orderDraft.OrderItems.ToList().ForEach(o => data.OrderItems.Add(new OrderItemData | |||
{ | |||
Discount = (decimal)o.Discount, | |||
PictureUrl = o.PictureUrl, | |||
ProductId = o.ProductId, | |||
ProductName = o.ProductName, | |||
UnitPrice = (decimal)o.UnitPrice, | |||
Units = o.Units, | |||
})); | |||
return data; | |||
} | |||
private CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData) | |||
{ | |||
var command = new CreateOrderDraftCommand | |||
{ | |||
BuyerId = basketData.BuyerId, | |||
}; | |||
basketData.Items.ForEach(i => command.Items.Add(new BasketItem | |||
{ | |||
Id = i.Id, | |||
OldUnitPrice = (double)i.OldUnitPrice, | |||
PictureUrl = i.PictureUrl, | |||
ProductId = i.ProductId, | |||
ProductName = i.ProductName, | |||
Quantity = i.Quantity, | |||
UnitPrice = (double)i.UnitPrice, | |||
})); | |||
return command; | |||
} | |||
} | |||
} |
@ -0,0 +1,92 @@ | |||
using Microsoft.AspNetCore.Authorization; | |||
using Microsoft.Extensions.Logging; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions; | |||
using MediatR; | |||
using Grpc.Core; | |||
using AppCommand = Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||
using ApiModels = Ordering.API.Application.Models; | |||
using Google.Protobuf.Collections; | |||
using System.Collections.Generic; | |||
namespace GrpcOrdering | |||
{ | |||
public class OrderingService : OrderingGrpc.OrderingGrpcBase | |||
{ | |||
private readonly IMediator _mediator; | |||
private readonly ILogger<OrderingService> _logger; | |||
public OrderingService(IMediator mediator, ILogger<OrderingService> logger) | |||
{ | |||
_mediator = mediator; | |||
_logger = logger; | |||
} | |||
public override async Task<OrderDraftDTO> CreateOrderDraftFromBasketData(CreateOrderDraftCommand createOrderDraftCommand, ServerCallContext context) | |||
{ | |||
_logger.LogInformation($"Begin grpc call from method {context.Method} for ordering get order draft {createOrderDraftCommand}"); | |||
_logger.LogInformation( | |||
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})", | |||
createOrderDraftCommand.GetGenericTypeName(), | |||
nameof(createOrderDraftCommand.BuyerId), | |||
createOrderDraftCommand.BuyerId, | |||
createOrderDraftCommand); | |||
var command = new AppCommand.CreateOrderDraftCommand( | |||
createOrderDraftCommand.BuyerId, | |||
this.MapBasketItems(createOrderDraftCommand.Items)); | |||
var data = await _mediator.Send(command); | |||
if (data != null) | |||
{ | |||
context.Status = new Status(StatusCode.OK, $" ordering get order draft {createOrderDraftCommand} do exist"); | |||
return this.MapResponse(data); | |||
} | |||
else | |||
{ | |||
context.Status = new Status(StatusCode.NotFound, $" ordering get order draft {createOrderDraftCommand} do not exist"); | |||
} | |||
return new OrderDraftDTO(); | |||
} | |||
public OrderDraftDTO MapResponse(AppCommand.OrderDraftDTO order) | |||
{ | |||
var result = new OrderDraftDTO() | |||
{ | |||
Total = (double)order.Total, | |||
}; | |||
order.OrderItems.ToList().ForEach(i => result.OrderItems.Add(new OrderItemDTO() | |||
{ | |||
Discount = (double)i.Discount, | |||
PictureUrl = i.PictureUrl, | |||
ProductId = i.ProductId, | |||
ProductName = i.ProductName, | |||
UnitPrice = (double)i.UnitPrice, | |||
Units = i.Units, | |||
})); | |||
return result; | |||
} | |||
public IEnumerable<ApiModels.BasketItem> MapBasketItems(RepeatedField<BasketItem> items) | |||
{ | |||
return items.Select(x => new ApiModels.BasketItem() | |||
{ | |||
Id = x.Id, | |||
ProductId = x.ProductId, | |||
ProductName = x.ProductName, | |||
UnitPrice = (decimal)x.UnitPrice, | |||
OldUnitPrice = (decimal)x.OldUnitPrice, | |||
Quantity = x.Quantity, | |||
PictureUrl = x.PictureUrl, | |||
}); | |||
} | |||
} | |||
} |
@ -0,0 +1,39 @@ | |||
syntax = "proto3"; | |||
option csharp_namespace = "GrpcOrdering"; | |||
package OrderingApi; | |||
service OrderingGrpc { | |||
rpc CreateOrderDraftFromBasketData(CreateOrderDraftCommand) returns (OrderDraftDTO) {} | |||
} | |||
message CreateOrderDraftCommand { | |||
string buyerId = 1; | |||
repeated BasketItem items = 2; | |||
} | |||
message BasketItem { | |||
string id = 1; | |||
string productId = 2; | |||
string productName = 3; | |||
double unitPrice = 4; | |||
double oldUnitPrice = 5; | |||
int32 quantity = 6; | |||
string pictureUrl = 7; | |||
} | |||
message OrderDraftDTO { | |||
double total = 1; | |||
repeated OrderItemDTO orderItems = 2; | |||
} | |||
message OrderItemDTO { | |||
int32 productId = 1; | |||
string productName = 2; | |||
double unitPrice = 3; | |||
double discount = 4; | |||
int32 units = 5; | |||
string pictureUrl = 6; | |||
} | |||