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