Browse Source

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

basket api net 5 migration
pull/1551/head
Miguel Veloso 4 years ago
committed by GitHub
parent
commit
86e563f76e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 355 additions and 305 deletions
  1. +43
    -0
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/GrpcExceptionInterceptor.cs
  2. +1
    -0
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
  3. +22
    -48
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs
  4. +12
    -26
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs
  5. +19
    -5
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
  6. +2
    -2
      src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
  7. +43
    -0
      src/ApiGateways/Web.Bff.Shopping/aggregator/Infrastructure/GrpcExceptionInterceptor.cs
  8. +24
    -33
      src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs
  9. +11
    -22
      src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs
  10. +20
    -8
      src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs
  11. +14
    -13
      src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj
  12. +18
    -18
      src/Services/Basket/Basket.API/Basket.API.csproj
  13. +2
    -2
      src/Services/Basket/Basket.API/Dockerfile
  14. +12
    -12
      src/Services/Basket/Basket.API/Model/BasketCheckout.cs
  15. +6
    -6
      src/Services/Basket/Basket.API/Model/BasketItem.cs
  16. +2
    -2
      src/Services/Basket/Basket.API/Model/CustomerBasket.cs
  17. +86
    -90
      src/Services/Basket/Basket.API/Program.cs
  18. +6
    -6
      src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj
  19. +8
    -8
      src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj
  20. +4
    -4
      src/Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj

+ 43
- 0
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Infrastructure/GrpcExceptionInterceptor.cs 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;
}
}
}
}

+ 1
- 0
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj View File

@ -20,6 +20,7 @@
<PackageReference Include="Google.Protobuf" Version="3.11.2" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" 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="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />


+ 22
- 48
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs View File

@ -1,55 +1,29 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
using Serilog;
using System.IO;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{
public class Program
{
private static IConfiguration _configuration;
public static void Main(string[] args)
BuildWebHost(args).Run();
IWebHost BuildWebHost(string[] args) =>
WebHost
.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb =>
{
_configuration = GetConfiguration();
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost
.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb =>
{
var sources = cb.Sources;
sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource()
{
Optional = true,
Path = "appsettings.localhost.json",
ReloadOnChange = false
});
})
.UseStartup<Startup>()
.UseSerilog((builderContext, config) =>
{
config
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console();
})
.Build();
private static IConfiguration GetConfiguration()
var sources = cb.Sources;
sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource()
{
Optional = true,
Path = "appsettings.localhost.json",
ReloadOnChange = false
});
})
.UseStartup<Startup>()
.UseSerilog((builderContext, config) =>
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
var config = builder.Build();
return builder.Build();
}
}
}
config
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console();
})
.Build();

+ 12
- 26
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/BasketService.cs 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.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{
public class BasketService : IBasketService
{
private readonly HttpClient _httpClient;
private readonly UrlsConfig _urls;
private readonly Basket.BasketClient _basketClient;
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;
_urls = config.Value;
_basketClient = basketClient;
_logger = logger;
}
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);
var response = await client.GetBasketByIdAsync(new BasketRequest { Id = id });
_logger.LogDebug("grpc response {@response}", response);
_logger.LogDebug("grpc client created, request = {@id}", id);
var response = await _basketClient.GetBasketByIdAsync(new BasketRequest { Id = id });
_logger.LogDebug("grpc response {@response}", response);
return MapToBasketData(response);
});
return MapToBasketData(response);
}
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);
var request = MapToCustomerBasketRequest(currentBasket);
_logger.LogDebug("Grpc update basket request {@request}", request);
_logger.LogDebug("Grpc update basket currentBasket {@currentBasket}", currentBasket);
var request = MapToCustomerBasketRequest(currentBasket);
_logger.LogDebug("Grpc update basket request {@request}", request);
return await client.UpdateBasketAsync(request);
});
await _basketClient.UpdateBasketAsync(request);
}
private BasketData MapToBasketData(CustomerBasketResponse customerBasketRequest)


+ 19
- 5
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs View File

@ -1,4 +1,5 @@
using Devspaces.Support;
using GrpcBasket;
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
@ -14,6 +15,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
@ -46,7 +48,8 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddDevspaces()
.AddHttpServices();
.AddHttpServices()
.AddGrpcServices();
}
// 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>();
//register http services
services
.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddDevspacesSupport();
services.AddHttpClient<ICatalogService, CatalogService>()
.AddDevspacesSupport();
@ -194,5 +193,20 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
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;
}
}
}

+ 2
- 2
src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile 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
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
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles


+ 43
- 0
src/ApiGateways/Web.Bff.Shopping/aggregator/Infrastructure/GrpcExceptionInterceptor.cs 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;
}
}
}
}

+ 24
- 33
src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs View File

@ -1,38 +1,29 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator;
using Serilog;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost
.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb =>
{
var sources = cb.Sources;
sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource()
{
Optional = true,
Path = "appsettings.localhost.json",
ReloadOnChange = false
});
})
.UseStartup<Startup>()
.UseSerilog((builderContext, config) =>
{
config
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console();
})
.Build();
BuildWebHost(args).Run();
}
}
IWebHost BuildWebHost(string[] args) =>
WebHost
.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb =>
{
var sources = cb.Sources;
sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource()
{
Optional = true,
Path = "appsettings.localhost.json",
ReloadOnChange = false
});
})
.UseStartup<Startup>()
.UseSerilog((builderContext, config) =>
{
config
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console();
})
.Build();

+ 11
- 22
src/ApiGateways/Web.Bff.Shopping/aggregator/Services/BasketService.cs View File

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


+ 20
- 8
src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs View File

@ -1,4 +1,5 @@
using Devspaces.Support;
using GrpcBasket;
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
@ -14,6 +15,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
@ -42,11 +44,12 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
.AddUrlGroup(new Uri(Configuration["MarketingUrlHC"]), name: "marketingapi-check", tags: new string[] { "marketingapi" })
.AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" })
.AddUrlGroup(new Uri(Configuration["LocationUrlHC"]), name: "locationapi-check", tags: new string[] { "locationapi" });
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddDevspaces()
.AddApplicationServices();
.AddApplicationServices()
.AddGrpcServices();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -63,7 +66,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseSwagger().UseSwaggerUI(c =>
@ -139,7 +142,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
Version = "v1",
Description = "Shopping Aggregator for Web Clients"
});
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
@ -181,10 +184,6 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
//register http services
services.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddDevspacesSupport();
services.AddHttpClient<ICatalogService, CatalogService>()
.AddDevspacesSupport();
@ -199,6 +198,19 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
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;
}
}
}

+ 14
- 13
src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
@ -15,20 +15,21 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="3.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="3.0.0" />
<PackageReference Include="Google.Protobuf" Version="3.11.2" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.25.0" />
<PackageReference Include="Grpc.Core" Version="2.25.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.25.0" />
<PackageReference Include="Grpc.Tools" Version="2.25.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="3.1.2" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="3.1.2" />
<PackageReference Include="Google.Protobuf" Version="3.14.0" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.34.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.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.Mvc.NewtonsoftJson" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="3.1.0" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<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" />-->
</ItemGroup>


+ 18
- 18
src/Services/Basket/Basket.API/Basket.API.csproj View File

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


+ 2
- 2
src/Services/Basket/Basket.API/Dockerfile 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
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
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles


+ 12
- 12
src/Services/Basket/Basket.API/Model/BasketCheckout.cs View File

@ -2,29 +2,29 @@
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; }
}


+ 6
- 6
src/Services/Basket/Basket.API/Model/BasketItem.cs View File

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


+ 2
- 2
src/Services/Basket/Basket.API/Model/CustomerBasket.cs View File

@ -2,9 +2,9 @@
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>();


+ 86
- 90
src/Services/Basket/Basket.API/Program.cs View File

@ -3,113 +3,109 @@ using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.eShopOnContainers.Services.Basket.API;
using Microsoft.Extensions.Configuration;
using Serilog;
using System;
using System.IO;
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);
var configuration = GetConfiguration();
public static int Main(string[] args)
{
var configuration = GetConfiguration();
Log.Logger = CreateSerilogLogger(configuration);
Log.Logger = CreateSerilogLogger(configuration);
try
{
Log.Information("Configuring web host ({ApplicationContext})...", Program.AppName);
var host = BuildWebHost(configuration, args);
try
{
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
var host = BuildWebHost(configuration, args);
Log.Information("Starting web host ({ApplicationContext})...", Program.AppName);
host.Run();
Log.Information("Starting web host ({ApplicationContext})...", AppName);
host.Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", Program.AppName);
return 1;
}
finally
{
Log.CloseAndFlush();
}
return 0;
}
catch (Exception ex)
IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
.CaptureStartupErrors(false)
.ConfigureKestrel(options =>
{
var ports = GetDefinedPorts(configuration);
options.Listen(IPAddress.Any, ports.httpPort, listenOptions =>
{
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
return 1;
}
finally
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
});
options.Listen(IPAddress.Any, ports.grpcPort, listenOptions =>
{
Log.CloseAndFlush();
}
}
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
WebHost.CreateDefaultBuilder(args)
.CaptureStartupErrors(false)
.ConfigureKestrel(options =>
{
var ports = GetDefinedPorts(configuration);
options.Listen(IPAddress.Any, ports.httpPort, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
});
options.Listen(IPAddress.Any, ports.grpcPort, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
})
.ConfigureAppConfiguration(x => x.AddConfiguration(configuration))
.UseFailing(options => {
options.ConfigPath = "/Failing";
options.NotFilteredPaths.AddRange(new[] {"/hc","/liveness"});
})
.UseStartup<Startup>()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseSerilog()
.Build();
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
{
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
var logstashUrl = configuration["Serilog:LogstashgUrl"];
return new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.WithProperty("ApplicationContext", AppName)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
.ReadFrom.Configuration(configuration)
.CreateLogger();
}
private static IConfiguration GetConfiguration()
listenOptions.Protocols = HttpProtocols.Http2;
});
})
.ConfigureAppConfiguration(x => x.AddConfiguration(configuration))
.UseFailing(options =>
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
options.ConfigPath = "/Failing";
options.NotFilteredPaths.AddRange(new[] { "/hc", "/liveness" });
})
.UseStartup<Startup>()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseSerilog()
.Build();
var config = builder.Build();
ILogger CreateSerilogLogger(IConfiguration configuration)
{
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
var logstashUrl = configuration["Serilog:LogstashgUrl"];
return new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.WithProperty("ApplicationContext", Program.AppName)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
.ReadFrom.Configuration(configuration)
.CreateLogger();
}
if (config.GetValue<bool>("UseVault", false))
{
builder.AddAzureKeyVault(
$"https://{config["Vault:Name"]}.vault.azure.net/",
config["Vault:ClientId"],
config["Vault:ClientSecret"]);
}
IConfiguration GetConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
return builder.Build();
}
var config = 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);
}
if (config.GetValue<bool>("UseVault", false))
{
builder.AddAzureKeyVault(
$"https://{config["Vault:Name"]}.vault.azure.net/",
config["Vault:ClientId"],
config["Vault:ClientSecret"]);
}
return builder.Build();
}
(int httpPort, int grpcPort) GetDefinedPorts(IConfiguration config)
{
var grpcPort = config.GetValue("GRPC_PORT", 5001);
var port = config.GetValue("PORT", 80);
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);
}

+ 6
- 6
src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj View File

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


+ 8
- 8
src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj View File

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


+ 4
- 4
src/Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
@ -67,10 +67,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.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>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>


Loading…
Cancel
Save