From 3f61eb0ef93c4c2ad45238f4268dbf9516d7d543 Mon Sep 17 00:00:00 2001 From: ericuss Date: Tue, 27 Aug 2019 14:07:39 +0200 Subject: [PATCH] fix grpc call from mobile bff to basket.api and add ordering, in ordering controller --- docker-compose.override.yml | 5 +- .../aggregator/Config/UrlsConfig.cs | 2 + .../aggregator/Controllers/OrderController.cs | 8 +- ...ttpClientAuthorizationDelegatingHandler.cs | 2 - .../Mobile.Shopping.HttpAggregator.csproj | 5 +- .../aggregator/Models/BasketData.cs | 3 +- .../aggregator/Models/OrderData.cs | 4 +- .../aggregator/Models/OrderItemData.cs | 7 +- .../Models/UpdateBasketItemsRequest.cs | 5 +- .../aggregator/Models/UpdateBasketRequest.cs | 5 +- .../aggregator/Services/BasketService.cs | 22 +--- .../aggregator/Services/IOrderingService.cs | 10 ++ .../aggregator/Services/OrderingService.cs | 113 ++++++++++++++++++ .../Mobile.Bff.Shopping/aggregator/Startup.cs | 16 ++- .../aggregator/appsettings.localhost.json | 4 +- .../Ordering.API/Grpc/OrderingService.cs | 92 ++++++++++++++ .../Ordering/Ordering.API/Ordering.API.csproj | 12 +- src/Services/Ordering/Ordering.API/Program.cs | 22 ++++ .../Ordering.API/Proto/ordering.proto | 39 ++++++ src/Services/Ordering/Ordering.API/Startup.cs | 28 ++++- 20 files changed, 350 insertions(+), 54 deletions(-) create mode 100644 src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderingService.cs create mode 100644 src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderingService.cs create mode 100644 src/Services/Ordering/Ordering.API/Grpc/OrderingService.cs create mode 100644 src/Services/Ordering/Ordering.API/Proto/ordering.proto diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 4428a9330..5c1a9082c 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -115,6 +115,7 @@ services: - Serilog__MinimumLevel__Override__Ordering.API=Verbose ports: - "5102:80" + - "5581:5001" ordering.backgroundtasks: environment: @@ -284,6 +285,8 @@ services: - urls__catalog=http://catalog.api - urls__orders=http://ordering.api - urls__identity=http://identity.api + - urls__grpcBasket=http://10.0.75.1:5580 + - urls__grpcOrdering=http://10.0.75.1:5581 - CatalogUrlHC=http://catalog.api/hc - OrderingUrlHC=http://ordering.api/hc - IdentityUrlHC=http://identity.api/hc @@ -291,7 +294,7 @@ services: - MarketingUrlHC=http://marketing.api/hc - PaymentUrlHC=http://payment.api/hc - LocationUrlHC=http://locations.api/hc - - IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 + - IdentityUrlExternal=http://10.0.75.1:5105 ports: - "5120:80" diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs index e920fbbb2..7fd7cb5f3 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Config/UrlsConfig.cs @@ -27,5 +27,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config public string Basket { get; set; } public string Catalog { get; set; } public string Orders { get; set; } + public string GrpcBasket { get; set; } + public string GrpcOrdering { get; set; } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs index ac359b4b5..8bacc80d4 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs @@ -13,12 +13,12 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers public class OrderController : ControllerBase { private readonly IBasketService _basketService; - private readonly IOrderApiClient _orderClient; + private readonly IOrderingService _orderingService; - public OrderController(IBasketService basketService, IOrderApiClient orderClient) + public OrderController(IBasketService basketService, IOrderingService orderingService) { _basketService = basketService; - _orderClient = orderClient; + _orderingService = orderingService; } [Route("draft/{basketId}")] @@ -39,7 +39,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers return BadRequest($"No basket found for id {basketId}"); } - return await _orderClient.GetOrderDraftFromBasketAsync(basket); + return await _orderingService.GetOrderDraftAsync(basket); } } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs index 4562139df..bfc705b5c 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs @@ -40,8 +40,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastruct request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); } - _logger.LogInformation("@@@@@@@@@@@@@@@@@ {@request}", request); - return await base.SendAsync(request, cancellationToken); } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj index ca8768a66..40060ea29 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj @@ -20,7 +20,7 @@ - + @@ -34,10 +34,11 @@ - + + diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs index 302f6bd32..e2888f92e 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/BasketData.cs @@ -6,7 +6,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { public string BuyerId { get; set; } - public List Items { get; set; } + public List Items { get; set; } = new List(); public BasketData() { @@ -16,7 +16,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models public BasketData(string buyerId) { BuyerId = buyerId; - Items = new List(); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs index e87cc18f0..e63b453a4 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderData.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { @@ -28,6 +26,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models public string Buyer { get; set; } - public List OrderItems { get; } = new List(); + public List OrderItems { get; } = new List(); } } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs index b0179e470..023cf20e5 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/OrderItemData.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models +namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { public class OrderItemData { diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs index 43cc81b89..35b3e76c0 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs index cb22bf55f..b377921be 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketRequest.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models { diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs index 44e13dd91..fa1fc9ffe 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs @@ -27,9 +27,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services public async Task GetById(string id) { - - _logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ GetById @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); @@ -38,24 +35,21 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; using (var httpClient = new HttpClient(httpClientHandler)) { - _logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Http2UnencryptedSupport disable @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + //httpClient.BaseAddress = new Uri("http://10.0.75.1:5580"); + httpClient.BaseAddress = new Uri(_urls.GrpcBasket); - httpClient.BaseAddress = new Uri("http://localhost:5580"); - - _logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ {httpClient.BaseAddress} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ " + httpClient.BaseAddress, httpClient.BaseAddress); + _logger.LogDebug("Creating grpc client for basket {@httpClient.BaseAddress} ", httpClient.BaseAddress); var client = GrpcClient.Create(httpClient); - _logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ client create @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + _logger.LogDebug("grpc client created, request = {@id}", id); try { var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id }); - _logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ call grpc server @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - _logger.LogInformation("############## DATA: {@a}", response.Buyerid); - _logger.LogInformation("############## DATA:response {@response}", response); + _logger.LogDebug("grpc response {@response}", response); return MapToBasketData(response); } @@ -66,11 +60,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services } } - return null; // temp - // var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id)); - // var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject(data) : null; - - // return basket; + return null; } public async Task UpdateAsync(BasketData currentBasket) diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderingService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderingService.cs new file mode 100644 index 000000000..5518a4bbf --- /dev/null +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IOrderingService.cs @@ -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 GetOrderDraftAsync(BasketData basketData); + } +} \ No newline at end of file diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderingService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderingService.cs new file mode 100644 index 000000000..f1e56c2ef --- /dev/null +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/OrderingService.cs @@ -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 _logger; + + public OrderingService(HttpClient httpClient, IOptions config, ILogger logger) + { + _httpClient = httpClient; + _urls = config.Value; + _logger = logger; + } + + public async Task 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(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; + } + + } +} diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs index 8d7f7dbbe..f08514177 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs @@ -131,11 +131,9 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator { Implicit = new OpenApiOAuthFlow() { - // AuthorizationUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), - // TokenUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/token"), - - AuthorizationUrl = new Uri($"http://localhost:5105/connect/authorize"), - TokenUrl = new Uri($"http://localhost:5105/connect/token"), + AuthorizationUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() { { "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } @@ -188,7 +186,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator services.AddSingleton(); //register http services - services.AddHttpClient() + services + .AddHttpClient() .AddHttpMessageHandler() .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy()) @@ -204,6 +203,11 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator .AddPolicyHandler(GetCircuitBreakerPolicy()) .AddDevspacesSupport(); + services.AddHttpClient() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()) + .AddDevspacesSupport(); + return services; } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json index 91bbf5f87..f14ca24b9 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json @@ -3,7 +3,9 @@ "basket": "http://localhost:55105", "catalog": "http://localhost:55101", "orders": "http://localhost:55102", - "identity": "http://localhost:55105" + "identity": "http://localhost:55105", + "grpcBasket": "http://localhost:5580", + "grpcOrdering": "http://localhost:5581" }, "IdentityUrlExternal": "http://localhost:5105", "IdentityUrl": "http://localhost:5105", diff --git a/src/Services/Ordering/Ordering.API/Grpc/OrderingService.cs b/src/Services/Ordering/Ordering.API/Grpc/OrderingService.cs new file mode 100644 index 000000000..af59420e7 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Grpc/OrderingService.cs @@ -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 _logger; + + public OrderingService(IMediator mediator, ILogger logger) + { + _mediator = mediator; + _logger = logger; + } + + public override async Task 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 MapBasketItems(RepeatedField 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, + }); + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 1b3c36daa..fdd681eab 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -19,6 +19,13 @@ + + + + + + + @@ -30,7 +37,10 @@ - + + + + diff --git a/src/Services/Ordering/Ordering.API/Program.cs b/src/Services/Ordering/Ordering.API/Program.cs index 50f53360c..899871b3d 100644 --- a/src/Services/Ordering/Ordering.API/Program.cs +++ b/src/Services/Ordering/Ordering.API/Program.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; @@ -10,6 +11,7 @@ using Microsoft.Extensions.Options; using Serilog; using System; using System.IO; +using System.Net; namespace Microsoft.eShopOnContainers.Services.Ordering.API { @@ -61,6 +63,20 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) => WebHost.CreateDefaultBuilder(args) .CaptureStartupErrors(false) + .ConfigureKestrel(options => + { + var ports = GetDefinedPorts(configuration); + options.Listen(IPAddress.Any, ports.httpPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2; + }); + + options.Listen(IPAddress.Any, ports.grpcPort, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + + }) .UseStartup() .UseApplicationInsights() .UseContentRoot(Directory.GetCurrentDirectory()) @@ -102,5 +118,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API return builder.Build(); } + private static (int httpPort, int grpcPort) GetDefinedPorts(IConfiguration config) + { + var grpcPort = config.GetValue("GRPC_PORT", 5001); + var port = config.GetValue("PORT", 80); + return (port, grpcPort); + } } } \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Proto/ordering.proto b/src/Services/Ordering/Ordering.API/Proto/ordering.proto new file mode 100644 index 000000000..988f3465b --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Proto/ordering.proto @@ -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; +} + diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index fca490f28..09f4c379b 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -7,12 +7,14 @@ using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Infrastructure.Filters; using global::Ordering.API.Infrastructure.Middlewares; + using GrpcOrdering; using HealthChecks.UI.Client; using Infrastructure.AutofacModules; using Infrastructure.Filters; using Infrastructure.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; + using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.ServiceBus; using Microsoft.EntityFrameworkCore; @@ -34,6 +36,7 @@ using System.Collections.Generic; using System.Data.Common; using System.IdentityModel.Tokens.Jwt; + using System.IO; using System.Reflection; public class Startup @@ -47,7 +50,13 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddApplicationInsights(Configuration) + services + .AddGrpc(options => + { + options.EnableDetailedErrors = true; + }) + .Services + .AddApplicationInsights(Configuration) .AddCustomMvc() .AddHealthChecks(Configuration) .AddCustomDbContext(Configuration) @@ -68,7 +77,7 @@ } - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //loggerFactory.AddAzureWebAppDiagnostics(); //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); @@ -87,8 +96,23 @@ app.UseEndpoints(endpoints => { + endpoints.MapGrpcService(); endpoints.MapDefaultControllerRoute(); endpoints.MapControllers(); + endpoints.MapGet("/_proto/", async ctx => + { + ctx.Response.ContentType = "text/plain"; + using var fs = new FileStream(Path.Combine(env.ContentRootPath, "Proto", "basket.proto"), FileMode.Open, FileAccess.Read); + using var sr = new StreamReader(fs); + while (!sr.EndOfStream) + { + var line = await sr.ReadLineAsync(); + if (line != "/* >>" || line != "<< */") + { + await ctx.Response.WriteAsync(line); + } + } + }); endpoints.MapHealthChecks("/hc", new HealthCheckOptions() { Predicate = _ => true,