Browse Source

add grpc basket

features/migration-dotnet3
Erik Pique 5 years ago
parent
commit
fe0fd36e0f
22 changed files with 476 additions and 124 deletions
  1. +6
    -0
      docker-compose.override.yml
  2. +3
    -4
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs
  3. +1
    -1
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs
  4. +2
    -2
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile
  5. +12
    -7
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs
  6. +10
    -3
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs
  7. +9
    -30
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
  8. +41
    -0
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs
  9. +101
    -12
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs
  10. +23
    -8
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs
  11. +1
    -1
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs
  12. +38
    -41
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
  13. +5
    -0
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.json
  14. +15
    -0
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json
  15. +9
    -0
      src/Services/Basket/Basket.API/Basket.API.csproj
  16. +100
    -0
      src/Services/Basket/Basket.API/Grpc/BasketService.cs
  17. +1
    -1
      src/Services/Basket/Basket.API/Infrastructure/Repositories/RedisBasketRepository.cs
  18. +24
    -3
      src/Services/Basket/Basket.API/Program.cs
  19. +38
    -0
      src/Services/Basket/Basket.API/Proto/basket.proto
  20. +31
    -11
      src/Services/Basket/Basket.API/Startup.cs
  21. +5
    -0
      src/Services/Basket/Basket.API/appsettings.json
  22. +1
    -0
      src/_build/dependencies.props

+ 6
- 0
docker-compose.override.yml View File

@ -219,6 +219,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
ports: ports:
- "5200:80" - "5200:80"
volumes: volumes:
@ -235,6 +236,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
ports: ports:
- "5201:80" - "5201:80"
volumes: volumes:
@ -251,6 +253,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
ports: ports:
- "5202:80" - "5202:80"
volumes: volumes:
@ -267,6 +270,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
ports: ports:
- "5203:80" - "5203:80"
volumes: volumes:
@ -286,6 +290,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
ports: ports:
- "5120:80" - "5120:80"
@ -303,6 +308,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
ports: ports:
- "5121:80" - "5121:80"


+ 3
- 4
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/BasketController.cs View File

@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -36,7 +35,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
} }
// Retrieve the current basket // Retrieve the current basket
var basket = await _basket.GetByIdAsync(data.BuyerId) ?? new BasketData(data.BuyerId);
var basket = await _basket.GetById(data.BuyerId) ?? new BasketData(data.BuyerId);
var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId)); var catalogItems = await _catalog.GetCatalogItemsAsync(data.Items.Select(x => x.ProductId));
@ -76,7 +75,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
} }
// Retrieve the current basket // Retrieve the current basket
var currentBasket = await _basket.GetByIdAsync(data.BasketId);
var currentBasket = await _basket.GetById(data.BasketId);
if (currentBasket == null) if (currentBasket == null)
{ {
return BadRequest($"Basket with id {data.BasketId} not found."); return BadRequest($"Basket with id {data.BasketId} not found.");
@ -118,7 +117,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
//item.PictureUri = //item.PictureUri =
// Step 2: Get current basket status // Step 2: Get current basket status
var currentBasket = (await _basket.GetByIdAsync(data.BasketId)) ?? new BasketData(data.BasketId);
var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId);
// Step 3: Merge current status with new product // Step 3: Merge current status with new product
currentBasket.Items.Add(new BasketDataItem() currentBasket.Items.Add(new BasketDataItem()
{ {


+ 1
- 1
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Controllers/OrderController.cs View File

@ -32,7 +32,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers
return BadRequest("Need a valid basketid"); return BadRequest("Need a valid basketid");
} }
// Get the basket data and build a order draft based on it // Get the basket data and build a order draft based on it
var basket = await _basketService.GetByIdAsync(basketId);
var basket = await _basketService.GetById(basketId);
if (basket == null) if (basket == null)
{ {


+ 2
- 2
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src WORKDIR /src
COPY scripts scripts/ COPY scripts scripts/


+ 12
- 7
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs View File

@ -1,7 +1,7 @@
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters
{ {
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Swashbuckle.AspNetCore.Swagger;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -10,7 +10,7 @@
{ {
public class AuthorizeCheckOperationFilter : IOperationFilter public class AuthorizeCheckOperationFilter : IOperationFilter
{ {
public void Apply(Operation operation, OperationFilterContext context)
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{ {
// Check for authorize attribute // Check for authorize attribute
var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() || var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() ||
@ -18,14 +18,19 @@
if (!hasAuthorize) return; if (!hasAuthorize) return;
operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new Response { Description = "Forbidden" });
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
operation.Security = new List<IDictionary<string, IEnumerable<string>>>
var oAuthScheme = new OpenApiSecurityScheme
{ {
new Dictionary<string, IEnumerable<string>>
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
};
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{ {
{ "oauth2", new [] { "Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator" } }
[ oAuthScheme ] = new [] { "Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator" }
} }
}; };
} }


+ 10
- 3
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/HttpClientAuthorizationDelegatingHandler.cs View File

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
@ -8,18 +9,22 @@ using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure
{ {
public class HttpClientAuthorizationDelegatingHandler
: DelegatingHandler
public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler
{ {
private readonly IHttpContextAccessor _httpContextAccesor; private readonly IHttpContextAccessor _httpContextAccesor;
private readonly ILogger<HttpClientAuthorizationDelegatingHandler> _logger;
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor, ILogger<HttpClientAuthorizationDelegatingHandler> logger)
{ {
_httpContextAccesor = httpContextAccesor; _httpContextAccesor = httpContextAccesor;
_logger = logger;
} }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{ {
request.Version = new System.Version(2, 0);
request.Method = HttpMethod.Get;
var authorizationHeader = _httpContextAccesor.HttpContext var authorizationHeader = _httpContextAccesor.HttpContext
.Request.Headers["Authorization"]; .Request.Headers["Authorization"];
@ -35,6 +40,8 @@ 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);
} }


+ 9
- 30
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj View File

@ -1,4 +1,4 @@
<!--<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>$(NetCoreTargetVersion)</TargetFramework> <TargetFramework>$(NetCoreTargetVersion)</TargetFramework>
@ -17,6 +17,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="$(AspNetCore_HealthChecks_Uris)" /> <PackageReference Include="AspNetCore.HealthChecks.Uris" Version="$(AspNetCore_HealthChecks_Uris)" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="$(AspNetCore_HealthChecks_UI_Client)" /> <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="$(AspNetCore_HealthChecks_UI_Client)" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="$(Grpc_AspNetCore_Server_ClientFactory)" />
<PackageReference Include="Google.Protobuf" Version="$(Google_Protobuf)" />
<PackageReference Include="Grpc.Core" Version="1.22.0" />
<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)" />
@ -24,41 +28,16 @@
<PackageReference Include="Swashbuckle.AspNetCore" Version="$(Swashbuckle_AspNetCore)" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="$(Swashbuckle_AspNetCore)" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="$(Microsoft_Extensions_Http_Polly)" /> <PackageReference Include="Microsoft.Extensions.Http.Polly" Version="$(Microsoft_Extensions_Http_Polly)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(Microsoft_AspNetCore_Authentication_JwtBearer)" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(Microsoft_AspNetCore_Authentication_JwtBearer)" />
<PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.5.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" /> <ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" />
</ItemGroup> </ItemGroup>
</Project>-->
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<LangVersion>$(LangVersion)</LangVersion>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="2.2.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.3" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" />
<Protobuf Include="..\..\..\Services\Basket\Basket.API\Proto\basket.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\Services\Catalog\Catalog.API\Proto\catalog.proto" GrpcServices="Client" />
</ItemGroup> </ItemGroup>
</Project> </Project>


+ 41
- 0
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs View File

@ -1,13 +1,21 @@
using Microsoft.AspNetCore; using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Serilog; using Serilog;
using System.IO;
using System.Net;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{ {
public class Program public class Program
{ {
private static IConfiguration _configuration;
public static void Main(string[] args) public static void Main(string[] args)
{ {
_configuration = GetConfiguration();
BuildWebHost(args).Run(); BuildWebHost(args).Run();
} }
@ -24,6 +32,20 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
ReloadOnChange = false ReloadOnChange = 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>()
.UseSerilog((builderContext, config) => .UseSerilog((builderContext, config) =>
{ {
@ -33,5 +55,24 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
.WriteTo.Console(); .WriteTo.Console();
}) })
.Build(); .Build();
private static IConfiguration GetConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
var config = 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);
}
} }
} }

+ 101
- 12
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs View File

@ -1,41 +1,130 @@
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using grpc;
using Grpc.Net.Client;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using static grpc.Basket;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{ {
public class BasketService : IBasketService public class BasketService : IBasketService
{ {
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly ILogger<BasketService> _logger;
private readonly UrlsConfig _urls; private readonly UrlsConfig _urls;
private readonly ILogger<BasketService> _logger;
public BasketService(HttpClient httpClient, ILogger<BasketService> logger, IOptions<UrlsConfig> config)
public BasketService(HttpClient httpClient, IOptions<UrlsConfig> config, ILogger<BasketService> logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_logger = logger;
_urls = config.Value; _urls = config.Value;
_logger = logger;
} }
public async Task<BasketData> GetByIdAsync(string id)
public async Task<BasketData> GetById(string id)
{ {
var data = await _httpClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id));
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ GetById @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Http2UnencryptedSupport disable @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
_httpClient.BaseAddress = new Uri("http://localhost:5001");
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ {_httpClient.BaseAddress} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", _httpClient.BaseAddress);
var client = GrpcClient.Create<BasketClient>(_httpClient);
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ client create @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id });
_logger.LogInformation("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ call grpc server @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
_logger.LogInformation("############## DATA: {@a}", response.Buyerid);
//if (streaming.IsCompleted)
//{
// _logger.LogInformation("############## DATA: {@a}", streaming.GetResult());
//}
//var streaming = client.GetBasketById(new BasketRequest { Id = id });
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
return basket;
//var status = streaming.GetStatus();
//if (status.StatusCode == Grpc.Core.StatusCode.OK)
//{
// return null;
//}
return null;
//return MapToBasketData(response.ResponseStream);
} }
public async Task UpdateAsync(BasketData currentBasket) public async Task UpdateAsync(BasketData currentBasket)
{ {
var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json");
_httpClient.BaseAddress = new Uri(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket());
var client = GrpcClient.Create<BasketClient>(_httpClient);
var request = MapToCustomerBasketRequest(currentBasket);
await client.UpdateBasketAsync(request);
}
private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest)
{
if (customerBasketRequest == null)
{
return null;
}
var map = new BasketData
{
BuyerId = customerBasketRequest.Buyerid
};
customerBasketRequest.Items.ToList().ForEach(item => map.Items.Add(new BasketDataItem
{
Id = item.Id,
OldUnitPrice = (decimal)item.Oldunitprice,
PictureUrl = item.Pictureurl,
ProductId = item.Productid,
ProductName = item.Productname,
Quantity = item.Quantity,
UnitPrice = (decimal)item.Unitprice
}));
return map;
}
private CustomerBasketRequest MapToCustomerBasketRequest(BasketData basketData)
{
if (basketData == null)
{
return null;
}
var map = new CustomerBasketRequest
{
Buyerid = basketData.BuyerId
};
basketData.Items.ToList().ForEach(item => map.Items.Add(new BasketItemResponse
{
Id = item.Id,
Oldunitprice = (double)item.OldUnitPrice,
Pictureurl = item.PictureUrl,
Productid = item.ProductId,
Productname = item.ProductName,
Quantity = item.Quantity,
Unitprice = (double)item.UnitPrice
}));
var data = await _httpClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent);
return map;
} }
} }
} }

+ 23
- 8
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/CatalogService.cs View File

@ -1,33 +1,37 @@
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using CatalogApi;
using Grpc.Net.Client;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using static CatalogApi.Catalog;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{ {
public class CatalogService : ICatalogService public class CatalogService : ICatalogService
{ {
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly ILogger<CatalogService> _logger;
private readonly UrlsConfig _urls; private readonly UrlsConfig _urls;
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<UrlsConfig> config)
public CatalogService(HttpClient httpClient, IOptions<UrlsConfig> config)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_logger = logger;
_urls = config.Value; _urls = config.Value;
} }
public async Task<CatalogItem> GetCatalogItemAsync(int id) public async Task<CatalogItem> GetCatalogItemAsync(int id)
{ {
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent);
_httpClient.BaseAddress = new Uri(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
return catalogItem;
var client = GrpcClient.Create<CatalogClient>(_httpClient);
var request = new CatalogItemRequest { Id = id };
var response = await client.GetItemByIdAsync(request);
return MapToCatalogItemResponse(response);
} }
public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids) public async Task<IEnumerable<CatalogItem>> GetCatalogItemsAsync(IEnumerable<int> ids)
@ -37,5 +41,16 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
return catalogItems; return catalogItems;
} }
private CatalogItem MapToCatalogItemResponse(CatalogItemResponse catalogItemResponse)
{
return new CatalogItem
{
Id = catalogItemResponse.Id,
Name = catalogItemResponse.Name,
PictureUri = catalogItemResponse.PictureUri,
Price = (decimal)catalogItemResponse.Price
};
}
} }
} }

+ 1
- 1
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs View File

@ -5,7 +5,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{ {
public interface IBasketService public interface IBasketService
{ {
Task<BasketData> GetByIdAsync(string id);
Task<BasketData> GetById(string id);
Task UpdateAsync(BasketData currentBasket); Task UpdateAsync(BasketData currentBasket);


+ 38
- 41
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs View File

@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
@ -14,9 +13,9 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Polly; using Polly;
using Polly.Extensions.Http; using Polly.Extensions.Http;
using Swashbuckle.AspNetCore.Swagger;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
@ -63,19 +62,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
app.UsePathBase(pathBase); app.UsePathBase(pathBase);
} }
app.UseHealthChecks("/hc", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.UseHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
app.UseCors("CorsPolicy");
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
@ -86,15 +72,31 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
app.UseHsts(); app.UseHsts();
} }
app.UseAuthentication();
app.UseCors("CorsPolicy");
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseMvc();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
app.UseSwagger().UseSwaggerUI(c => app.UseSwagger().UseSwaggerUI(c =>
{ {
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
c.OAuthClientId("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui");
c.OAuthClientId("mobileshoppingaggswaggerui");
c.OAuthClientSecret(string.Empty); c.OAuthClientSecret(string.Empty);
c.OAuthRealm(string.Empty); c.OAuthRealm(string.Empty);
c.OAuthAppName("Purchase BFF Swagger UI"); c.OAuthAppName("Purchase BFF Swagger UI");
@ -109,29 +111,32 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddOptions(); services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls")); services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddControllers()
.AddNewtonsoftJson();
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
options.DescribeAllEnumsAsStrings(); options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
options.SwaggerDoc("v1", new OpenApiInfo
{ {
Title = "Shopping Aggregator for Mobile Clients", Title = "Shopping Aggregator for Mobile Clients",
Version = "v1", Version = "v1",
Description = "Shopping Aggregator for Mobile Clients",
TermsOfService = "Terms Of Service"
Description = "Shopping Aggregator for Mobile Clients"
}); });
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{ {
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
Scopes = new Dictionary<string, string>()
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows()
{ {
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"),
TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"),
Scopes = new Dictionary<string, string>()
{
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
}
}
} }
}); });
@ -152,7 +157,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
} }
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
{ {
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = configuration.GetValue<string>("urls:identity"); var identityUrl = configuration.GetValue<string>("urls:identity");
services.AddAuthentication(options => services.AddAuthentication(options =>
@ -166,15 +172,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
options.Authority = identityUrl; options.Authority = identityUrl;
options.RequireHttpsMetadata = false; options.RequireHttpsMetadata = false;
options.Audience = "mobileshoppingagg"; options.Audience = "mobileshoppingagg";
options.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = async ctx =>
{
},
OnTokenValidated = async ctx =>
{
}
};
}); });
return services; return services;


+ 5
- 0
src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.json View File

@ -1,4 +1,9 @@
{ {
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
},
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"Debug": { "Debug": {


+ 15
- 0
src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.localhost.json View File

@ -4,5 +4,20 @@
"catalog": "http://localhost:55101", "catalog": "http://localhost:55101",
"orders": "http://localhost:55102", "orders": "http://localhost:55102",
"identity": "http://localhost:55105" "identity": "http://localhost:55105"
},
"IdentityUrlExternal": "http://localhost:5105",
"IdentityUrl": "http://localhost:5105",
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Debug"
}
},
"Console": {
"LogLevel": {
"Default": "Debug"
}
}
} }
} }

+ 9
- 0
src/Services/Basket/Basket.API/Basket.API.csproj View File

@ -21,6 +21,9 @@
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="$(AspNetCore_HealthChecks_Redis)" /> <PackageReference Include="AspNetCore.HealthChecks.Redis" Version="$(AspNetCore_HealthChecks_Redis)" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="$(AspNetCore_HealthChecks_UI_Client)" /> <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="$(AspNetCore_HealthChecks_UI_Client)" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="$(Autofac_Extensions_DependencyInjection)" /> <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="$(Autofac_Extensions_DependencyInjection)" />
<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.ApplicationInsights.AspNetCore" Version="$(Microsoft_ApplicationInsights_AspNetCore)" /> <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="$(Microsoft_ApplicationInsights_AspNetCore)" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="$(Microsoft_ApplicationInsights_DependencyCollector)" /> <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="$(Microsoft_ApplicationInsights_DependencyCollector)" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="$(Microsoft_ApplicationInsights_Kubernetes)" /> <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="$(Microsoft_ApplicationInsights_Kubernetes)" />
@ -39,6 +42,12 @@
<PackageReference Include="Swashbuckle.AspNetCore" Version="$(Swashbuckle_AspNetCore)" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="$(Swashbuckle_AspNetCore)" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Protobuf Include="Proto\basket.proto" GrpcServices="Server" Generator="MSBuild:Compile" />
<Content Include="@(Protobuf)" />
<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" />


+ 100
- 0
src/Services/Basket/Basket.API/Grpc/BasketService.cs View File

@ -0,0 +1,100 @@
using Grpc.Core;
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Threading.Tasks;
namespace grpc
{
public class BasketService : Basket.BasketBase
{
private readonly IBasketRepository _repository;
private readonly ILogger<BasketService> _logger;
public BasketService(IBasketRepository repository, ILogger<BasketService> logger)
{
_repository = repository;
_logger = logger;
}
public override async Task<CustomerBasketResponse> GetBasketById(BasketRequest request, ServerCallContext context)
{
_logger.LogInformation($"Begin grpc call from method {context.Method} for basket id {request.Id}");
var data = await _repository.GetBasketAsync(request.Id);
if (data != null)
{
context.Status = new Status(StatusCode.OK, $"Basket with id {request.Id} do exist");
return MapToCustomerBasketResponse(data);
}
else
{
context.Status = new Status(StatusCode.NotFound, $"Basket with id {request.Id} do not exist");
}
return null;
}
public override async Task<CustomerBasketResponse> UpdateBasket(CustomerBasketRequest request, ServerCallContext context)
{
_logger.LogInformation($"Begin grpc call BasketService.UpdateBasketAsync for buyer id {request.Buyerid}");
var customerBasket = MapToCustomerBasket(request);
var response = await _repository.UpdateBasketAsync(customerBasket);
if (response != null)
{
return MapToCustomerBasketResponse(response);
}
context.Status = new Status(StatusCode.NotFound, $"Basket with buyer id {request.Buyerid} do not exist");
return null;
}
private CustomerBasketResponse MapToCustomerBasketResponse(CustomerBasket customerBasket)
{
var response = new CustomerBasketResponse
{
Buyerid = customerBasket.BuyerId
};
customerBasket.Items.ForEach(item => response.Items.Add(new BasketItemResponse
{
Id = item.Id,
Oldunitprice = (double)item.OldUnitPrice,
Pictureurl = item.PictureUrl,
Productid = item.ProductId,
Productname = item.ProductName,
Quantity = item.Quantity,
Unitprice = (double)item.UnitPrice
}));
return response;
}
private CustomerBasket MapToCustomerBasket(CustomerBasketRequest customerBasketRequest)
{
var response = new CustomerBasket
{
BuyerId = customerBasketRequest.Buyerid
};
customerBasketRequest.Items.ToList().ForEach(item => response.Items.Add(new BasketItem
{
Id = item.Id,
OldUnitPrice = (decimal)item.Oldunitprice,
PictureUrl = item.Pictureurl,
ProductId = item.Productid,
ProductName = item.Productname,
Quantity = item.Quantity,
UnitPrice = (decimal)item.Unitprice
}));
return response;
}
}
}

+ 1
- 1
src/Services/Basket/Basket.API/Infrastructure/Repositories/RedisBasketRepository.cs View File

@ -28,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Infrastructure.Reposit
public IEnumerable<string> GetUsers() public IEnumerable<string> GetUsers()
{ {
var server = GetServer();
var server = GetServer();
var data = server.Keys(); var data = server.Keys();
return data?.Select(k => k.ToString()); return data?.Select(k => k.ToString());


+ 24
- 3
src/Services/Basket/Basket.API/Program.cs View File

@ -2,11 +2,12 @@
using Microsoft.AspNetCore; using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog; using Serilog;
using System; using System;
using System.IO; using System.IO;
using System.Net;
namespace Microsoft.eShopOnContainers.Services.Basket.API namespace Microsoft.eShopOnContainers.Services.Basket.API
{ {
@ -45,8 +46,21 @@ namespace Microsoft.eShopOnContainers.Services.Basket.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)
.UseFailing(options =>
options.ConfigPath = "/Failing")
.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;
});
})
.UseFailing(options => options.ConfigPath = "/Failing")
.UseStartup<Startup>() .UseStartup<Startup>()
.UseApplicationInsights() .UseApplicationInsights()
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
@ -88,5 +102,12 @@ namespace Microsoft.eShopOnContainers.Services.Basket.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);
}
} }
} }

+ 38
- 0
src/Services/Basket/Basket.API/Proto/basket.proto View File

@ -0,0 +1,38 @@
syntax = "proto3";
option csharp_namespace = "grpc";
package BasketApi;
service Basket {
rpc GetBasketById(BasketRequest) returns (CustomerBasketResponse) {
option (google.api.http) = {
get: "/GetBasketById"
};
}
rpc UpdateBasket(CustomerBasketRequest) returns (CustomerBasketResponse) {}
}
message BasketRequest {
string id = 1;
}
message CustomerBasketRequest {
string buyerid = 1;
repeated BasketItemResponse items = 2;
}
message CustomerBasketResponse {
string buyerid = 1;
repeated BasketItemResponse items = 2;
}
message BasketItemResponse {
string id = 1;
string productid = 2;
string productname = 3;
double unitprice = 4;
double oldunitprice = 5;
int32 quantity = 6;
string pictureurl = 7;
}

+ 31
- 11
src/Services/Basket/Basket.API/Startup.cs View File

@ -4,6 +4,7 @@ using Basket.API.Infrastructure.Filters;
using Basket.API.Infrastructure.Middlewares; using Basket.API.Infrastructure.Middlewares;
using Basket.API.IntegrationEvents.EventHandling; using Basket.API.IntegrationEvents.EventHandling;
using Basket.API.IntegrationEvents.Events; using Basket.API.IntegrationEvents.Events;
using grpc;
using HealthChecks.UI.Client; using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
@ -32,6 +33,7 @@ using StackExchange.Redis;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.IO;
namespace Microsoft.eShopOnContainers.Services.Basket.API namespace Microsoft.eShopOnContainers.Services.Basket.API
{ {
@ -47,6 +49,11 @@ 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 virtual IServiceProvider ConfigureServices(IServiceCollection services) public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{ {
services.AddGrpc(options =>
{
options.EnableDetailedErrors = true;
});
RegisterAppInsights(services); RegisterAppInsights(services);
services.AddControllers(options => services.AddControllers(options =>
@ -84,10 +91,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
} }
} }
}); });
options.OperationFilter<AuthorizeCheckOperationFilter>(); options.OperationFilter<AuthorizeCheckOperationFilter>();
}); });
ConfigureAuthService(services); ConfigureAuthService(services);
@ -192,6 +198,14 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
app.UsePathBase(pathBase); app.UsePathBase(pathBase);
} }
app.UseSwagger()
.UseSwaggerUI(setup =>
{
setup.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
setup.OAuthClientId("basketswaggerui");
setup.OAuthAppName("Basket Swagger UI");
});
app.UseRouting(); app.UseRouting();
ConfigureAuth(app); ConfigureAuth(app);
@ -202,6 +216,21 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
{ {
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.MapGrpcService<BasketService>();
endpoints.MapHealthChecks("/hc", new HealthCheckOptions() endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
{ {
Predicate = _ => true, Predicate = _ => true,
@ -212,15 +241,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
Predicate = r => r.Name.Contains("self") Predicate = r => r.Name.Contains("self")
}); });
}); });
app.UseSwagger()
.UseSwaggerUI(setup =>
{
setup.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
setup.OAuthClientId("basketswaggerui");
setup.OAuthAppName("Basket Swagger UI");
});
ConfigureEventBus(app); ConfigureEventBus(app);
} }


+ 5
- 0
src/Services/Basket/Basket.API/appsettings.json View File

@ -11,6 +11,11 @@
} }
} }
}, },
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
},
"SubscriptionClientName": "Basket", "SubscriptionClientName": "Basket",
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""


+ 1
- 0
src/_build/dependencies.props View File

@ -19,6 +19,7 @@
<Grpc_AspNetCore_Server>0.1.22-pre1</Grpc_AspNetCore_Server> <Grpc_AspNetCore_Server>0.1.22-pre1</Grpc_AspNetCore_Server>
<Google_Protobuf>3.9.0-rc1</Google_Protobuf> <Google_Protobuf>3.9.0-rc1</Google_Protobuf>
<Grpc_Tools>1.22.0</Grpc_Tools> <Grpc_Tools>1.22.0</Grpc_Tools>
<Grpc_AspNetCore_Server_ClientFactory>0.1.22-pre2</Grpc_AspNetCore_Server_ClientFactory>
<Microsoft_Extensions_Hosting>3.0.0-preview7.19362.4</Microsoft_Extensions_Hosting> <Microsoft_Extensions_Hosting>3.0.0-preview7.19362.4</Microsoft_Extensions_Hosting>
<Microsoft_VisualStudio_Azure_Containers_Tools_Targets>1.7.9</Microsoft_VisualStudio_Azure_Containers_Tools_Targets> <Microsoft_VisualStudio_Azure_Containers_Tools_Targets>1.7.9</Microsoft_VisualStudio_Azure_Containers_Tools_Targets>


Loading…
Cancel
Save