Merge pull request #1547 from borjasanes/feature/basket-api-migration

basket api net 5 migration
This commit is contained in:
Miguel Veloso 2020-12-16 12:04:12 +00:00 committed by GitHub
commit 86e563f76e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 365 additions and 315 deletions

View File

@ -0,0 +1,43 @@
using Grpc.Core;
using Grpc.Core.Interceptors;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure
{
public class GrpcExceptionInterceptor : Interceptor
{
private readonly ILogger<GrpcExceptionInterceptor> _logger;
public GrpcExceptionInterceptor(ILogger<GrpcExceptionInterceptor> logger)
{
_logger = logger;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var call = continuation(request, context);
return new AsyncUnaryCall<TResponse>(HandleResponse(call.ResponseAsync), call.ResponseHeadersAsync, call.GetStatus, call.GetTrailers, call.Dispose);
}
private async Task<TResponse> HandleResponse<TResponse>(Task<TResponse> t)
{
try
{
var response = await t;
_logger.LogDebug($"Response received: {response}");
return response;
}
catch (RpcException e)
{
_logger.LogError("Error calling via grpc: {Status} - {Message}", e.Status, e.Message);
return default;
}
}
}
}

View File

@ -20,6 +20,7 @@
<PackageReference Include="Google.Protobuf" Version="3.11.2" /> <PackageReference Include="Google.Protobuf" Version="3.11.2" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.25.0" /> <PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.25.0" />
<PackageReference Include="Grpc.Core" Version="2.25.0" /> <PackageReference Include="Grpc.Core" Version="2.25.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.25.0" />
<PackageReference Include="Grpc.Tools" Version="2.25.0" PrivateAssets="All" /> <PackageReference Include="Grpc.Tools" Version="2.25.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />

View File

@ -1,23 +1,11 @@
using Microsoft.AspNetCore; using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
using Serilog; using Serilog;
using System.IO;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{
public class Program
{
private static IConfiguration _configuration;
public static void Main(string[] args)
{
_configuration = GetConfiguration();
BuildWebHost(args).Run(); BuildWebHost(args).Run();
} IWebHost BuildWebHost(string[] args) =>
public static IWebHost BuildWebHost(string[] args) =>
WebHost WebHost
.CreateDefaultBuilder(args) .CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb => .ConfigureAppConfiguration(cb =>
@ -39,17 +27,3 @@ 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();
}
}
}

View File

@ -1,54 +1,40 @@
using Grpc.Net.Client; using GrpcBasket;
using GrpcBasket;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; 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 System.Linq; using System.Linq;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
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 Basket.BasketClient _basketClient;
private readonly UrlsConfig _urls;
private readonly ILogger<BasketService> _logger; private readonly ILogger<BasketService> _logger;
public BasketService(HttpClient httpClient, IOptions<UrlsConfig> config, ILogger<BasketService> logger) public BasketService(Basket.BasketClient basketClient, ILogger<BasketService> logger)
{ {
_httpClient = httpClient; _basketClient = basketClient;
_urls = config.Value;
_logger = logger; _logger = logger;
} }
public async Task<BasketData> GetById(string id) public async Task<BasketData> GetById(string id)
{ {
return await GrpcCallerService.CallService(_urls.GrpcBasket, async channel =>
{
var client = new Basket.BasketClient(channel);
_logger.LogDebug("grpc client created, request = {@id}", id); _logger.LogDebug("grpc client created, request = {@id}", id);
var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id }); var response = await _basketClient.GetBasketByIdAsync(new BasketRequest { Id = id });
_logger.LogDebug("grpc response {@response}", response); _logger.LogDebug("grpc response {@response}", response);
return MapToBasketData(response); return MapToBasketData(response);
});
} }
public async Task UpdateAsync(BasketData currentBasket) public async Task UpdateAsync(BasketData currentBasket)
{ {
await GrpcCallerService.CallService(_urls.GrpcBasket, async httpClient =>
{
var channel = GrpcChannel.ForAddress(_urls.GrpcBasket);
var client = new Basket.BasketClient(channel);
_logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket); _logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket);
var request = MapToCustomerBasketRequest(currentBasket); var request = MapToCustomerBasketRequest(currentBasket);
_logger.LogDebug("Grpc update basket request {@request}", request); _logger.LogDebug("Grpc update basket request {@request}", request);
return await client.UpdateBasketAsync(request); await _basketClient.UpdateBasketAsync(request);
});
} }
private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest) private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest)

View File

@ -1,4 +1,5 @@
using Devspaces.Support; using Devspaces.Support;
using GrpcBasket;
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;
@ -14,6 +15,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -46,7 +48,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddCustomMvc(Configuration) services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration) .AddCustomAuthentication(Configuration)
.AddDevspaces() .AddDevspaces()
.AddHttpServices(); .AddHttpServices()
.AddGrpcServices();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -177,10 +180,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//register http services //register http services
services
.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddDevspacesSupport();
services.AddHttpClient<ICatalogService, CatalogService>() services.AddHttpClient<ICatalogService, CatalogService>()
.AddDevspacesSupport(); .AddDevspacesSupport();
@ -194,5 +193,20 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
return services; return services;
} }
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
{
services.AddSingleton<GrpcExceptionInterceptor>();
services.AddScoped<IBasketService, BasketService>();
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
{
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
options.Address = new Uri(basketApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
return services;
}
} }
} }

View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles # It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles

View File

@ -0,0 +1,43 @@
using Grpc.Core;
using Grpc.Core.Interceptors;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure
{
public class GrpcExceptionInterceptor : Interceptor
{
private readonly ILogger<GrpcExceptionInterceptor> _logger;
public GrpcExceptionInterceptor(ILogger<GrpcExceptionInterceptor> logger)
{
_logger = logger;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var call = continuation(request, context);
return new AsyncUnaryCall<TResponse>(HandleResponse(call.ResponseAsync), call.ResponseHeadersAsync, call.GetStatus, call.GetTrailers, call.Dispose);
}
private async Task<TResponse> HandleResponse<TResponse>(Task<TResponse> t)
{
try
{
var response = await t;
_logger.LogDebug($"Response received: {response}");
return response;
}
catch (RpcException e)
{
_logger.LogError("Error calling via grpc: {Status} - {Message}", e.Status, e.Message);
return default;
}
}
}
}

View File

@ -1,17 +1,11 @@
using Microsoft.AspNetCore; using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator;
using Serilog; using Serilog;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run(); BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) => IWebHost BuildWebHost(string[] args) =>
WebHost WebHost
.CreateDefaultBuilder(args) .CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb => .ConfigureAppConfiguration(cb =>
@ -33,6 +27,3 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
.WriteTo.Console(); .WriteTo.Console();
}) })
.Build(); .Build();
}
}

View File

@ -4,49 +4,38 @@ using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
{ {
public class BasketService : IBasketService public class BasketService : IBasketService
{ {
private readonly UrlsConfig _urls; private readonly Basket.BasketClient _basketClient;
public readonly HttpClient _httpClient;
private readonly ILogger<BasketService> _logger; private readonly ILogger<BasketService> _logger;
public BasketService(HttpClient httpClient, IOptions<UrlsConfig> config, ILogger<BasketService> logger) public BasketService(Basket.BasketClient basketClient, ILogger<BasketService> logger)
{ {
_urls = config.Value; _basketClient = basketClient;
_httpClient = httpClient;
_logger = logger; _logger = logger;
} }
public async Task<BasketData> GetById(string id) public async Task<BasketData> GetById(string id)
{ {
return await GrpcCallerService.CallService(_urls.GrpcBasket, async channel =>
{
var client = new Basket.BasketClient(channel);
_logger.LogDebug("grpc client created, request = {@id}", id); _logger.LogDebug("grpc client created, request = {@id}", id);
var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id }); var response = await _basketClient.GetBasketByIdAsync(new BasketRequest { Id = id });
_logger.LogDebug("grpc response {@response}", response); _logger.LogDebug("grpc response {@response}", response);
return MapToBasketData(response); return MapToBasketData(response);
});
} }
public async Task UpdateAsync(BasketData currentBasket) public async Task UpdateAsync(BasketData currentBasket)
{ {
await GrpcCallerService.CallService(_urls.GrpcBasket, async channel =>
{
var client = new Basket.BasketClient(channel);
_logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket); _logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket);
var request = MapToCustomerBasketRequest(currentBasket); var request = MapToCustomerBasketRequest(currentBasket);
_logger.LogDebug("Grpc update basket request {@request}", request); _logger.LogDebug("Grpc update basket request {@request}", request);
return await client.UpdateBasketAsync(request); await _basketClient.UpdateBasketAsync(request);
});
} }
private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest) private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest)

View File

@ -1,4 +1,5 @@
using Devspaces.Support; using Devspaces.Support;
using GrpcBasket;
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;
@ -14,6 +15,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -46,7 +48,8 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
services.AddCustomMvc(Configuration) services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration) .AddCustomAuthentication(Configuration)
.AddDevspaces() .AddDevspaces()
.AddApplicationServices(); .AddApplicationServices()
.AddGrpcServices();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -181,10 +184,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
//register http services //register http services
services.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddDevspacesSupport();
services.AddHttpClient<ICatalogService, CatalogService>() services.AddHttpClient<ICatalogService, CatalogService>()
.AddDevspacesSupport(); .AddDevspacesSupport();
@ -199,6 +198,19 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
return services; return services;
} }
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
{
services.AddSingleton<GrpcExceptionInterceptor>();
services.AddScoped<IBasketService, BasketService>();
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
{
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
options.Address = new Uri(basketApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
return services;
}
} }
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName> <AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace> <RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
@ -15,20 +15,21 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="3.0.0" /> <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="3.1.2" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="3.0.0" /> <PackageReference Include="AspNetCore.HealthChecks.Uris" Version="3.1.2" />
<PackageReference Include="Google.Protobuf" Version="3.11.2" /> <PackageReference Include="Google.Protobuf" Version="3.14.0" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.25.0" /> <PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.25.0" /> <PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.25.0" /> <PackageReference Include="Grpc.Net.Client" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.25.0" PrivateAssets="All" /> <PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" /> <PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc5" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<!--<PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.6.0-rc1.19456.4" />--> <!--<PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.6.0-rc1.19456.4" />-->
</ItemGroup> </ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks> <GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
@ -16,30 +16,30 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="3.0.0" /> <PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="3.2.2" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="3.0.3" /> <PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="3.1.4" />
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="3.0.0" /> <PackageReference Include="AspNetCore.HealthChecks.Redis" Version="3.1.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="3.0.0" /> <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="3.1.2" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="5.0.1" /> <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />
<PackageReference Include="Google.Protobuf" Version="3.11.2" /> <PackageReference Include="Google.Protobuf" Version="3.14.0" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.25.0" /> <PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.25.0" PrivateAssets="All" /> <PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.12.0" /> <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.16.0" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.12.0" /> <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.16.0" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.1.1" /> <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" /> <PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.10" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="5.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.1-dev-00216" /> <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.1-dev-00216" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
<PackageReference Include="Serilog.Sinks.Http" Version="5.2.0" /> <PackageReference Include="Serilog.Sinks.Http" Version="7.2.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" /> <PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc5" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles # It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles

View File

@ -2,29 +2,29 @@
namespace Basket.API.Model namespace Basket.API.Model
{ {
public class BasketCheckout public record BasketCheckout
{ {
public string City { get; set; } public string City { get; init; }
public string Street { get; set; } public string Street { get; init; }
public string State { get; set; } public string State { get; init; }
public string Country { get; set; } public string Country { get; init; }
public string ZipCode { get; set; } public string ZipCode { get; init; }
public string CardNumber { get; set; } public string CardNumber { get; init; }
public string CardHolderName { get; set; } public string CardHolderName { get; init; }
public DateTime CardExpiration { get; set; } public DateTime CardExpiration { get; init; }
public string CardSecurityNumber { get; set; } public string CardSecurityNumber { get; init; }
public int CardTypeId { get; set; } public int CardTypeId { get; init; }
public string Buyer { get; set; } public string Buyer { get; init; }
public Guid RequestId { get; set; } public Guid RequestId { get; set; }
} }

View File

@ -3,15 +3,15 @@ using System.ComponentModel.DataAnnotations;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
{ {
public class BasketItem : IValidatableObject public record BasketItem : IValidatableObject
{ {
public string Id { get; set; } public string Id { get; init; }
public int ProductId { get; set; } public int ProductId { get; init; }
public string ProductName { get; set; } public string ProductName { get; init; }
public decimal UnitPrice { get; set; } public decimal UnitPrice { get; set; }
public decimal OldUnitPrice { get; set; } public decimal OldUnitPrice { get; set; }
public int Quantity { get; set; } public int Quantity { get; init; }
public string PictureUrl { get; set; } public string PictureUrl { get; init; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{ {
var results = new List<ValidationResult>(); var results = new List<ValidationResult>();

View File

@ -2,9 +2,9 @@
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
{ {
public class CustomerBasket public record CustomerBasket
{ {
public string BuyerId { get; set; } public string BuyerId { get; init; }
public List<BasketItem> Items { get; set; } = new List<BasketItem>(); public List<BasketItem> Items { get; set; } = new List<BasketItem>();

View File

@ -3,47 +3,38 @@ 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.AspNetCore.Server.Kestrel.Core;
using Microsoft.eShopOnContainers.Services.Basket.API;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Serilog; using Serilog;
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
namespace Microsoft.eShopOnContainers.Services.Basket.API
{
public class Program
{
public static readonly string Namespace = typeof(Program).Namespace;
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
public static int Main(string[] args)
{
var configuration = GetConfiguration(); var configuration = GetConfiguration();
Log.Logger = CreateSerilogLogger(configuration); Log.Logger = CreateSerilogLogger(configuration);
try try
{ {
Log.Information("Configuring web host ({ApplicationContext})...", AppName); Log.Information("Configuring web host ({ApplicationContext})...", Program.AppName);
var host = BuildWebHost(configuration, args); var host = BuildWebHost(configuration, args);
Log.Information("Starting web host ({ApplicationContext})...", AppName); Log.Information("Starting web host ({ApplicationContext})...", Program.AppName);
host.Run(); host.Run();
return 0; return 0;
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName); Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", Program.AppName);
return 1; return 1;
} }
finally finally
{ {
Log.CloseAndFlush(); Log.CloseAndFlush();
} }
}
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) => IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args) WebHost.CreateDefaultBuilder(args)
.CaptureStartupErrors(false) .CaptureStartupErrors(false)
.ConfigureKestrel(options => .ConfigureKestrel(options =>
@ -61,7 +52,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
}) })
.ConfigureAppConfiguration(x => x.AddConfiguration(configuration)) .ConfigureAppConfiguration(x => x.AddConfiguration(configuration))
.UseFailing(options => { .UseFailing(options =>
{
options.ConfigPath = "/Failing"; options.ConfigPath = "/Failing";
options.NotFilteredPaths.AddRange(new[] { "/hc", "/liveness" }); options.NotFilteredPaths.AddRange(new[] { "/hc", "/liveness" });
}) })
@ -70,13 +62,13 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
.UseSerilog() .UseSerilog()
.Build(); .Build();
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration) ILogger CreateSerilogLogger(IConfiguration configuration)
{ {
var seqServerUrl = configuration["Serilog:SeqServerUrl"]; var seqServerUrl = configuration["Serilog:SeqServerUrl"];
var logstashUrl = configuration["Serilog:LogstashgUrl"]; var logstashUrl = configuration["Serilog:LogstashgUrl"];
return new LoggerConfiguration() return new LoggerConfiguration()
.MinimumLevel.Verbose() .MinimumLevel.Verbose()
.Enrich.WithProperty("ApplicationContext", AppName) .Enrich.WithProperty("ApplicationContext", Program.AppName)
.Enrich.FromLogContext() .Enrich.FromLogContext()
.WriteTo.Console() .WriteTo.Console()
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl) .WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
@ -85,7 +77,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
.CreateLogger(); .CreateLogger();
} }
private static IConfiguration GetConfiguration() IConfiguration GetConfiguration()
{ {
var builder = new ConfigurationBuilder() var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory()) .SetBasePath(Directory.GetCurrentDirectory())
@ -105,11 +97,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
return builder.Build(); return builder.Build();
} }
private static (int httpPort, int grpcPort) GetDefinedPorts(IConfiguration config) (int httpPort, int grpcPort) GetDefinedPorts(IConfiguration config)
{ {
var grpcPort = config.GetValue("GRPC_PORT", 5001); var grpcPort = config.GetValue("GRPC_PORT", 5001);
var port = config.GetValue("PORT", 80); var port = config.GetValue("PORT", 80);
return (port, grpcPort); return (port, grpcPort);
} }
}
public class Program {
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
@ -16,11 +16,11 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Moq" Version="4.13.1" /> <PackageReference Include="Moq" Version="4.15.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,19 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks> <GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MediatR" Version="7.0.0" /> <PackageReference Include="MediatR" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="3.1.0" /> <PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" />
<PackageReference Include="Moq" Version="4.13.1" /> <PackageReference Include="Moq" Version="4.15.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
@ -67,10 +67,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.1" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>