fix grpc call from mobile bff to basket.api and add ordering, in ordering controller

This commit is contained in:
ericuss 2019-08-27 14:07:39 +02:00
parent 016089fb5f
commit 3f61eb0ef9
20 changed files with 350 additions and 54 deletions

View File

@ -115,6 +115,7 @@ services:
- Serilog__MinimumLevel__Override__Ordering.API=Verbose - Serilog__MinimumLevel__Override__Ordering.API=Verbose
ports: ports:
- "5102:80" - "5102:80"
- "5581:5001"
ordering.backgroundtasks: ordering.backgroundtasks:
environment: environment:
@ -284,6 +285,8 @@ services:
- urls__catalog=http://catalog.api - urls__catalog=http://catalog.api
- urls__orders=http://ordering.api - urls__orders=http://ordering.api
- urls__identity=http://identity.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 - CatalogUrlHC=http://catalog.api/hc
- OrderingUrlHC=http://ordering.api/hc - OrderingUrlHC=http://ordering.api/hc
- IdentityUrlHC=http://identity.api/hc - IdentityUrlHC=http://identity.api/hc
@ -291,7 +294,7 @@ services:
- MarketingUrlHC=http://marketing.api/hc - MarketingUrlHC=http://marketing.api/hc
- PaymentUrlHC=http://payment.api/hc - PaymentUrlHC=http://payment.api/hc
- LocationUrlHC=http://locations.api/hc - LocationUrlHC=http://locations.api/hc
- IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 - IdentityUrlExternal=http://10.0.75.1:5105
ports: ports:
- "5120:80" - "5120:80"

View File

@ -27,5 +27,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config
public string Basket { get; set; } public string Basket { get; set; }
public string Catalog { get; set; } public string Catalog { get; set; }
public string Orders { get; set; } public string Orders { get; set; }
public string GrpcBasket { get; set; }
public string GrpcOrdering { get; set; }
} }
} }

View File

@ -13,12 +13,12 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
public class OrderController : ControllerBase public class OrderController : ControllerBase
{ {
private readonly IBasketService _basketService; 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; _basketService = basketService;
_orderClient = orderClient; _orderingService = orderingService;
} }
[Route("draft/{basketId}")] [Route("draft/{basketId}")]
@ -39,7 +39,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
return BadRequest($"No basket found for id {basketId}"); return BadRequest($"No basket found for id {basketId}");
} }
return await _orderClient.GetOrderDraftFromBasketAsync(basket); return await _orderingService.GetOrderDraftAsync(basket);
} }
} }
} }

View File

@ -40,8 +40,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastruct
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
} }
_logger.LogInformation("@@@@@@@@@@@@@@@@@ {@request}", request);
return await base.SendAsync(request, cancellationToken); return await base.SendAsync(request, cancellationToken);
} }

View File

@ -20,7 +20,7 @@
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="$(Grpc_AspNetCore_Server_ClientFactory)" /> <PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="$(Grpc_AspNetCore_Server_ClientFactory)" />
<PackageReference Include="Google.Protobuf" Version="$(Google_Protobuf)" /> <PackageReference Include="Google.Protobuf" Version="$(Google_Protobuf)" />
<PackageReference Include="Grpc.Core" Version="1.22.0" /> <PackageReference Include="Grpc.Core" Version="1.22.0" />
<PackageReference Include="Grpc.Tools" Version="$(Grpc_Tools)" PrivateAssets="All" /> <PackageReference Include="Grpc.Tools" Version="$(Grpc_Tools)" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="$(Microsoft_AspNetCore_Diagnostics_HealthChecks)" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="$(Microsoft_AspNetCore_Diagnostics_HealthChecks)" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="$(Microsoft_Extensions_Diagnostics_HealthChecks)" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="$(Microsoft_Extensions_Diagnostics_HealthChecks)" />
<PackageReference Include="Serilog.AspNetCore" Version="$(Serilog_AspNetCore)" /> <PackageReference Include="Serilog.AspNetCore" Version="$(Serilog_AspNetCore)" />
@ -34,10 +34,11 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" /> <ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Protobuf Include="..\..\..\Services\Basket\Basket.API\Proto\basket.proto" GrpcServices="Client" /> <Protobuf Include="..\..\..\Services\Basket\Basket.API\Proto\basket.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\Services\Catalog\Catalog.API\Proto\catalog.proto" GrpcServices="Client" /> <Protobuf Include="..\..\..\Services\Catalog\Catalog.API\Proto\catalog.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\Services\Ordering\Ordering.API\Proto\ordering.proto" GrpcServices="Client" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -6,7 +6,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
{ {
public string BuyerId { get; set; } public string BuyerId { get; set; }
public List<BasketDataItem> Items { get; set; } public List<BasketDataItem> Items { get; set; } = new List<BasketDataItem>();
public BasketData() public BasketData()
{ {
@ -16,7 +16,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
public BasketData(string buyerId) public BasketData(string buyerId)
{ {
BuyerId = buyerId; BuyerId = buyerId;
Items = new List<BasketDataItem>();
} }
} }

View File

@ -1,7 +1,5 @@
using System; using System;
using System.Collections.Generic; 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
{ {
@ -28,6 +26,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
public string Buyer { get; set; } public string Buyer { get; set; }
public List<OrderItemData> OrderItems { get; } = new List<OrderItemData>(); public List<OrderItemData> OrderItems { get; } = new List<OrderItemData>();
} }
} }

View File

@ -1,9 +1,4 @@
using System; namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models
{ {
public class OrderItemData public class OrderItemData
{ {

View File

@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
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
{ {

View File

@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
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
{ {

View File

@ -27,9 +27,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
public async Task<BasketData> GetById(string id) public async Task<BasketData> GetById(string id)
{ {
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ GetById @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", 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; }; httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
using (var httpClient = new HttpClient(httpClientHandler)) 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.LogDebug("Creating grpc client for basket {@httpClient.BaseAddress} ", httpClient.BaseAddress);
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ {httpClient.BaseAddress} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ " + httpClient.BaseAddress, httpClient.BaseAddress);
var client = GrpcClient.Create<Basket.BasketClient>(httpClient); var client = GrpcClient.Create<Basket.BasketClient>(httpClient);
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ client create @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); _logger.LogDebug("grpc client created, request = {@id}", id);
try try
{ {
var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id }); var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id });
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ call grpc server @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
_logger.LogInformation("############## DATA: {@a}", response.Buyerid); _logger.LogDebug("grpc response {@response}", response);
_logger.LogInformation("############## DATA:response {@response}", response);
return MapToBasketData(response); return MapToBasketData(response);
} }
@ -66,11 +60,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
} }
} }
return null; // temp return null;
// var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id));
// var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
// return basket;
} }
public async Task UpdateAsync(BasketData currentBasket) public async Task UpdateAsync(BasketData currentBasket)

View File

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

View File

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

View File

@ -131,11 +131,9 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{ {
Implicit = new OpenApiOAuthFlow() Implicit = new OpenApiOAuthFlow()
{ {
// AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"), AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"),
// TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"), TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"),
AuthorizationUrl = new Uri($"http://localhost:5105/connect/authorize"),
TokenUrl = new Uri($"http://localhost:5105/connect/token"),
Scopes = new Dictionary<string, string>() Scopes = new Dictionary<string, string>()
{ {
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } { "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
@ -188,7 +186,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//register http services //register http services
services.AddHttpClient<IBasketService, BasketService>() services
.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy())
@ -204,6 +203,11 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
.AddPolicyHandler(GetCircuitBreakerPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport(); .AddDevspacesSupport();
services.AddHttpClient<IOrderingService, OrderingService>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
return services; return services;
} }

View File

@ -3,7 +3,9 @@
"basket": "http://localhost:55105", "basket": "http://localhost:55105",
"catalog": "http://localhost:55101", "catalog": "http://localhost:55101",
"orders": "http://localhost:55102", "orders": "http://localhost:55102",
"identity": "http://localhost:55105" "identity": "http://localhost:55105",
"grpcBasket": "http://localhost:5580",
"grpcOrdering": "http://localhost:5581"
}, },
"IdentityUrlExternal": "http://localhost:5105", "IdentityUrlExternal": "http://localhost:5105",
"IdentityUrl": "http://localhost:5105", "IdentityUrl": "http://localhost:5105",

View File

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

View File

@ -19,6 +19,13 @@
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Protobuf Include="Proto\ordering.proto" GrpcServices="Server" Generator="MSBuild:Compile" />
<Content Include="Proto\ordering.proto" />
<None Remove="@(Protobuf)" />
</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" />
@ -30,7 +37,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(Microsoft_AspNetCore_Mvc_NewtonsoftJson)"/> <PackageReference Include="Grpc.AspNetCore.Server" Version="$(Grpc_AspNetCore_Server)" />
<PackageReference Include="Google.Protobuf" Version="$(Google_Protobuf)" />
<PackageReference Include="Grpc.Tools" Version="$(Grpc_Tools)" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(Microsoft_AspNetCore_Mvc_NewtonsoftJson)" />
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="$(AspNetCore_HealthChecks_AzureServiceBus)" /> <PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="$(AspNetCore_HealthChecks_AzureServiceBus)" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="$(AspNetCore_HealthChecks_Rabbitmq)" /> <PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="$(AspNetCore_HealthChecks_Rabbitmq)" />
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="$(AspNetCore_HealthChecks_SqlServer)" /> <PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="$(AspNetCore_HealthChecks_SqlServer)" />

View File

@ -1,5 +1,6 @@
using Microsoft.AspNetCore; using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
@ -10,6 +11,7 @@ using Microsoft.Extensions.Options;
using Serilog; using Serilog;
using System; using System;
using System.IO; using System.IO;
using System.Net;
namespace Microsoft.eShopOnContainers.Services.Ordering.API namespace Microsoft.eShopOnContainers.Services.Ordering.API
{ {
@ -61,6 +63,20 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) => private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args) WebHost.CreateDefaultBuilder(args)
.CaptureStartupErrors(false) .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<Startup>() .UseStartup<Startup>()
.UseApplicationInsights() .UseApplicationInsights()
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
@ -102,5 +118,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
return builder.Build(); 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);
}
} }
} }

View File

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

View File

@ -7,12 +7,14 @@
using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Application.IntegrationEvents.Events;
using global::Ordering.API.Infrastructure.Filters; using global::Ordering.API.Infrastructure.Filters;
using global::Ordering.API.Infrastructure.Middlewares; using global::Ordering.API.Infrastructure.Middlewares;
using GrpcOrdering;
using HealthChecks.UI.Client; using HealthChecks.UI.Client;
using Infrastructure.AutofacModules; using Infrastructure.AutofacModules;
using Infrastructure.Filters; using Infrastructure.Filters;
using Infrastructure.Services; using Infrastructure.Services;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -34,6 +36,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Reflection; using System.Reflection;
public class Startup public class Startup
@ -47,7 +50,13 @@
public virtual IServiceProvider ConfigureServices(IServiceCollection services) public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{ {
services.AddApplicationInsights(Configuration) services
.AddGrpc(options =>
{
options.EnableDetailedErrors = true;
})
.Services
.AddApplicationInsights(Configuration)
.AddCustomMvc() .AddCustomMvc()
.AddHealthChecks(Configuration) .AddHealthChecks(Configuration)
.AddCustomDbContext(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.AddAzureWebAppDiagnostics();
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); //loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
@ -87,8 +96,23 @@
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {
endpoints.MapGrpcService<OrderingService>();
endpoints.MapDefaultControllerRoute(); endpoints.MapDefaultControllerRoute();
endpoints.MapControllers(); 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() endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
{ {
Predicate = _ => true, Predicate = _ => true,