Merge 775366adf17cf2adb4fdd34a5f8eb6b33b862835 into df010635fc7eca4e489a2cf848cf9883576d6bc9
This commit is contained in:
commit
667bfdb5f3
@ -68,10 +68,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Health
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebStatus", "src\Web\WebStatus\WebStatus.csproj", "{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resilience", "Resilience", "{FBF43D93-F2E7-4FF8-B4AB-186895949B88}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resilience.Http", "src\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj", "{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{022E145D-1593-47EE-9608-8E323D3C63F5}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{022E145D-1593-47EE-9608-8E323D3C63F5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{1A01AF82-6FCB-464C-B39C-F127AEBD315D}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{1A01AF82-6FCB-464C-B39C-F127AEBD315D}"
|
||||||
@ -130,7 +126,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ordering.SignalrHub", "src\Services\Ordering\Ordering.SignalrHub\Ordering.SignalrHub.csproj", "{E1D2B260-4E7F-4A88-BC13-9910F7C44623}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.SignalrHub", "src\Services\Ordering\Ordering.SignalrHub\Ordering.SignalrHub.csproj", "{E1D2B260-4E7F-4A88-BC13-9910F7C44623}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -866,54 +862,6 @@ Global
|
|||||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x64.Build.0 = Release|Any CPU
|
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.ActiveCfg = Release|Any CPU
|
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.Build.0 = Release|Any CPU
|
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x64.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.AppStore|x86.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
{1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
@ -1617,8 +1565,6 @@ Global
|
|||||||
{A81ECBC2-6B00-4DCD-8388-469174033379} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
{A81ECBC2-6B00-4DCD-8388-469174033379} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
||||||
{942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
{942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||||
{FBF43D93-F2E7-4FF8-B4AB-186895949B88} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
|
||||||
{D1C47FF1-91F1-4CAF-9ABB-AD642B821502} = {FBF43D93-F2E7-4FF8-B4AB-186895949B88}
|
|
||||||
{022E145D-1593-47EE-9608-8E323D3C63F5} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
{022E145D-1593-47EE-9608-8E323D3C63F5} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||||
{1A01AF82-6FCB-464C-B39C-F127AEBD315D} = {022E145D-1593-47EE-9608-8E323D3C63F5}
|
{1A01AF82-6FCB-464C-B39C-F127AEBD315D} = {022E145D-1593-47EE-9608-8E323D3C63F5}
|
||||||
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
FROM microsoft/aspnetcore:2.0 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/
|
COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/
|
||||||
RUN dotnet restore src/ApiGateways/ApiGw-Base/
|
RUN dotnet restore src/ApiGateways/ApiGw-Base/
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -9,8 +9,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Ocelot" Version="3.0.0" />
|
<PackageReference Include="Ocelot" Version="3.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator
|
WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure
|
||||||
|
{
|
||||||
|
public class HttpClientAuthorizationDelegatingHandler
|
||||||
|
: DelegatingHandler
|
||||||
|
{
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccesor;
|
||||||
|
|
||||||
|
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)
|
||||||
|
{
|
||||||
|
_httpContextAccesor = httpContextAccesor;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var authorizationHeader = _httpContextAccesor.HttpContext
|
||||||
|
.Request.Headers["Authorization"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(authorizationHeader))
|
||||||
|
{
|
||||||
|
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = await GetToken();
|
||||||
|
|
||||||
|
if (token != null)
|
||||||
|
{
|
||||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await base.SendAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<string> GetToken()
|
||||||
|
{
|
||||||
|
const string ACCESS_TOKEN = "access_token";
|
||||||
|
|
||||||
|
return await _httpContextAccesor.HttpContext
|
||||||
|
.GetTokenAsync(ACCESS_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
|
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
|
||||||
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
|
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
|
||||||
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
@ -12,16 +12,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.1.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.1.0" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,53 +1,41 @@
|
|||||||
using System;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
||||||
using System.Collections.Generic;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
using System.Net.Http;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
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 IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<BasketService> _logger;
|
private readonly ILogger<BasketService> _logger;
|
||||||
private readonly UrlsConfig _urls;
|
private readonly UrlsConfig _urls;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
||||||
|
|
||||||
public BasketService(IHttpClient httpClient, IHttpContextAccessor httpContextAccessor, ILogger<BasketService> logger, IOptionsSnapshot<UrlsConfig> config)
|
public BasketService(HttpClient httpClient, ILogger<BasketService> logger, IOptions<UrlsConfig> config)
|
||||||
{
|
{
|
||||||
_apiClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_urls = config.Value;
|
_urls = config.Value;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<BasketData> GetById(string id)
|
public async Task<BasketData> GetById(string id)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var data = await _httpClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id));
|
||||||
var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id), token);
|
|
||||||
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
|
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
|
||||||
|
|
||||||
return basket;
|
return basket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Update(BasketData currentBasket)
|
public async Task Update(BasketData currentBasket)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json");
|
||||||
var data = await _apiClient.PostAsync<BasketData>(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), currentBasket, token);
|
|
||||||
int i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task<string> GetUserTokenAsync()
|
var data = await _httpClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent);
|
||||||
{
|
|
||||||
var context = _httpContextAccessor.HttpContext;
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,41 @@
|
|||||||
using System;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
||||||
using System.Collections.Generic;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
using System.Collections.Generic;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
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 IHttpClient _apiClient;
|
|
||||||
private readonly ILogger<CatalogService> _logger;
|
private readonly ILogger<CatalogService> _logger;
|
||||||
private readonly UrlsConfig _urls;
|
private readonly UrlsConfig _urls;
|
||||||
|
|
||||||
public CatalogService(IHttpClient httpClient, ILogger<CatalogService> logger, IOptionsSnapshot<UrlsConfig> config)
|
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<UrlsConfig> config)
|
||||||
{
|
{
|
||||||
_apiClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_urls = config.Value;
|
_urls = config.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CatalogItem> GetCatalogItem(int id)
|
public async Task<CatalogItem> GetCatalogItem(int id)
|
||||||
{
|
{
|
||||||
var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
|
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
|
||||||
var item = JsonConvert.DeserializeObject<CatalogItem>(data);
|
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent);
|
||||||
return item;
|
|
||||||
|
return catalogItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids)
|
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids)
|
||||||
{
|
{
|
||||||
var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
|
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
|
||||||
var item = JsonConvert.DeserializeObject<CatalogItem[]>(data);
|
var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);
|
||||||
return item;
|
|
||||||
|
|
||||||
|
return catalogItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,20 @@
|
|||||||
using System;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
||||||
using System.Collections.Generic;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
using System.Net.Http;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
|
||||||
{
|
{
|
||||||
public class OrderApiClient : IOrderApiClient
|
public class OrderApiClient : IOrderApiClient
|
||||||
{
|
{
|
||||||
|
private readonly HttpClient _apiClient;
|
||||||
private readonly IHttpClient _apiClient;
|
|
||||||
private readonly ILogger<OrderApiClient> _logger;
|
private readonly ILogger<OrderApiClient> _logger;
|
||||||
private readonly UrlsConfig _urls;
|
private readonly UrlsConfig _urls;
|
||||||
|
|
||||||
public OrderApiClient(IHttpClient httpClient, ILogger<OrderApiClient> logger, IOptionsSnapshot<UrlsConfig> config)
|
public OrderApiClient(HttpClient httpClient, ILogger<OrderApiClient> logger, IOptions<UrlsConfig> config)
|
||||||
{
|
{
|
||||||
_apiClient = httpClient;
|
_apiClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -27,11 +23,15 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
|
|||||||
|
|
||||||
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket)
|
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket)
|
||||||
{
|
{
|
||||||
var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
|
var uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
|
||||||
var response = await _apiClient.PostAsync<BasketData>(url, basket);
|
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
var response = await _apiClient.PostAsync(uri, content);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
|
||||||
return JsonConvert.DeserializeObject<OrderData>(jsonResponse);
|
var ordersDraftResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject<OrderData>(ordersDraftResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,138 +1,183 @@
|
|||||||
using System;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
|
||||||
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
|
||||||
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Polly;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
|
using Polly.Extensions.Http;
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
|
|
||||||
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
|
|
||||||
using Swashbuckle.AspNetCore.Swagger;
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
|
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
// 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 void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddCustomMvc(Configuration)
|
||||||
services.AddSingleton<IHttpClient, StandardHttpClient>();
|
.AddCustomAuthentication(Configuration)
|
||||||
services.AddTransient<ICatalogService, CatalogService>();
|
.AddHttpServices();
|
||||||
services.AddTransient<IBasketService, BasketService>();
|
}
|
||||||
services.AddTransient<IOrderApiClient, OrderApiClient>();
|
|
||||||
|
|
||||||
services.AddOptions();
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
services.Configure<UrlsConfig>(Configuration.GetSection("urls"));
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
|
||||||
services.AddMvc();
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
{
|
||||||
|
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
||||||
|
app.UsePathBase(pathBase);
|
||||||
|
}
|
||||||
|
|
||||||
services.AddSwaggerGen(options =>
|
app.UseCors("CorsPolicy");
|
||||||
{
|
|
||||||
options.DescribeAllEnumsAsStrings();
|
|
||||||
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
|
||||||
{
|
|
||||||
Title = "Shopping Aggregator for Mobile Clients",
|
|
||||||
Version = "v1",
|
|
||||||
Description = "Shopping Aggregator for Mobile Clients",
|
|
||||||
TermsOfService = "Terms Of Service"
|
|
||||||
});
|
|
||||||
|
|
||||||
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
Type = "oauth2",
|
app.UseDeveloperExceptionPage();
|
||||||
Flow = "implicit",
|
}
|
||||||
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
|
||||||
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
|
||||||
Scopes = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
app.UseAuthentication();
|
||||||
});
|
|
||||||
|
|
||||||
services.AddCors(options =>
|
app.UseMvc();
|
||||||
{
|
|
||||||
options.AddPolicy("CorsPolicy",
|
app.UseSwagger().UseSwaggerUI(c =>
|
||||||
builder => builder.AllowAnyOrigin()
|
{
|
||||||
.AllowAnyMethod()
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
|
||||||
.AllowAnyHeader()
|
c.ConfigureOAuth2("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI");
|
||||||
.AllowCredentials());
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
|
||||||
|
|
||||||
|
services.AddMvc().SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
|
||||||
|
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.DescribeAllEnumsAsStrings();
|
||||||
|
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
||||||
|
{
|
||||||
|
Title = "Shopping Aggregator for Mobile Clients",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "Shopping Aggregator for Mobile Clients",
|
||||||
|
TermsOfService = "Terms Of Service"
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
||||||
|
{
|
||||||
|
Type = "oauth2",
|
||||||
|
Flow = "implicit",
|
||||||
|
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
||||||
|
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
||||||
|
Scopes = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||||
|
var identityUrl = configuration.GetValue<string>("urls:identity");
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
|
||||||
|
}).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = identityUrl;
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.Audience = "mobileshoppingagg";
|
||||||
|
options.Events = new JwtBearerEvents()
|
||||||
|
{
|
||||||
|
OnAuthenticationFailed = async ctx =>
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
},
|
||||||
|
OnTokenValidated = async ctx =>
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
public static IServiceCollection AddHttpServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
//register delegating handlers
|
||||||
|
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
|
||||||
|
services.AddHttpContextAccessor();
|
||||||
|
|
||||||
|
//register http services
|
||||||
|
services.AddHttpClient<IBasketService, BasketService>()
|
||||||
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<ICatalogService, CatalogService>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
|
||||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
|
||||||
var identityUrl = Configuration.GetValue<string>("urls:identity");
|
|
||||||
services.AddAuthentication(options =>
|
|
||||||
{
|
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
|
|
||||||
}).AddJwtBearer(options =>
|
return services;
|
||||||
{
|
}
|
||||||
options.Authority = identityUrl;
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.Audience = "mobileshoppingagg";
|
|
||||||
options.Events = new JwtBearerEvents()
|
|
||||||
{
|
|
||||||
OnAuthenticationFailed = async ctx =>
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
},
|
|
||||||
OnTokenValidated = async ctx =>
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
{
|
||||||
{
|
return HttpPolicyExtensions
|
||||||
|
.HandleTransientHttpError()
|
||||||
|
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||||
|
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
}
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
return HttpPolicyExtensions
|
||||||
app.UsePathBase(pathBase);
|
.HandleTransientHttpError()
|
||||||
}
|
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
|
||||||
|
}
|
||||||
app.UseCors("CorsPolicy");
|
}
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
|
||||||
|
|
||||||
app.UseMvc();
|
|
||||||
|
|
||||||
app.UseSwagger().UseSwaggerUI(c =>
|
|
||||||
{
|
|
||||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
|
|
||||||
c.ConfigureOAuth2("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI");
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -96,18 +96,6 @@
|
|||||||
"UpstreamPathTemplate": "/catalog-api/{everything}",
|
"UpstreamPathTemplate": "/catalog-api/{everything}",
|
||||||
"UpstreamHttpMethod": []
|
"UpstreamHttpMethod": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"DownstreamPathTemplate": "/{everything}",
|
|
||||||
"DownstreamScheme": "http",
|
|
||||||
"DownstreamHostAndPorts": [
|
|
||||||
{
|
|
||||||
"Host": "marketing.api",
|
|
||||||
"Port": 80
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"UpstreamPathTemplate": "/marketing-api/{everything}",
|
|
||||||
"UpstreamHttpMethod": []
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/{everything}",
|
"DownstreamPathTemplate": "/{everything}",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
@ -119,18 +107,6 @@
|
|||||||
],
|
],
|
||||||
"UpstreamPathTemplate": "/payment-api/{everything}",
|
"UpstreamPathTemplate": "/payment-api/{everything}",
|
||||||
"UpstreamHttpMethod": []
|
"UpstreamHttpMethod": []
|
||||||
},
|
|
||||||
{
|
|
||||||
"DownstreamPathTemplate": "/{everything}",
|
|
||||||
"DownstreamScheme": "http",
|
|
||||||
"DownstreamHostAndPorts": [
|
|
||||||
{
|
|
||||||
"Host": "locations.api",
|
|
||||||
"Port": 80
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"UpstreamPathTemplate": "/location-api/{everything}",
|
|
||||||
"UpstreamHttpMethod": []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/ApiGateways/Web.Bff.Shopping/aggregator
|
WORKDIR /src/src/ApiGateways/Web.Bff.Shopping/aggregator
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure
|
||||||
|
{
|
||||||
|
public class HttpClientAuthorizationDelegatingHandler
|
||||||
|
: DelegatingHandler
|
||||||
|
{
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccesor;
|
||||||
|
|
||||||
|
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)
|
||||||
|
{
|
||||||
|
_httpContextAccesor = httpContextAccesor;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var authorizationHeader = _httpContextAccesor.HttpContext
|
||||||
|
.Request.Headers["Authorization"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(authorizationHeader))
|
||||||
|
{
|
||||||
|
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = await GetToken();
|
||||||
|
|
||||||
|
if (token != null)
|
||||||
|
{
|
||||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await base.SendAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<string> GetToken()
|
||||||
|
{
|
||||||
|
const string ACCESS_TOKEN = "access_token";
|
||||||
|
|
||||||
|
return await _httpContextAccesor.HttpContext
|
||||||
|
.GetTokenAsync(ACCESS_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,53 +1,39 @@
|
|||||||
using System;
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
||||||
using System.Collections.Generic;
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
using System.Net.Http;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
|
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 IHttpClient _apiClient;
|
private readonly HttpClient _apiClient;
|
||||||
private readonly ILogger<BasketService> _logger;
|
private readonly ILogger<BasketService> _logger;
|
||||||
private readonly UrlsConfig _urls;
|
private readonly UrlsConfig _urls;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
||||||
|
|
||||||
public BasketService(IHttpClient httpClient, IHttpContextAccessor httpContextAccessor, ILogger<BasketService> logger, IOptionsSnapshot<UrlsConfig> config)
|
public BasketService(HttpClient httpClient,ILogger<BasketService> logger, IOptions<UrlsConfig> config)
|
||||||
{
|
{
|
||||||
_apiClient = httpClient;
|
_apiClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_urls = config.Value;
|
_urls = config.Value;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<BasketData> GetById(string id)
|
public async Task<BasketData> GetById(string id)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id));
|
||||||
var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id), token);
|
|
||||||
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
|
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
|
||||||
return basket;
|
return basket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Update(BasketData currentBasket)
|
public async Task Update(BasketData currentBasket)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json");
|
||||||
var data = await _apiClient.PostAsync<BasketData>(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), currentBasket, token);
|
|
||||||
int i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task<string> GetUserTokenAsync()
|
var data = await _apiClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent);
|
||||||
{
|
|
||||||
var context = _httpContextAccessor.HttpContext;
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,42 @@
|
|||||||
using System;
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
||||||
using System.Collections.Generic;
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
using System.Collections.Generic;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
|
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
|
||||||
{
|
{
|
||||||
public class CatalogService : ICatalogService
|
public class CatalogService : ICatalogService
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<CatalogService> _logger;
|
private readonly ILogger<CatalogService> _logger;
|
||||||
private readonly UrlsConfig _urls;
|
private readonly UrlsConfig _urls;
|
||||||
|
|
||||||
public CatalogService(IHttpClient httpClient, ILogger<CatalogService> logger, IOptionsSnapshot<UrlsConfig> config)
|
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<UrlsConfig> config)
|
||||||
{
|
{
|
||||||
_apiClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_urls = config.Value;
|
_urls = config.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CatalogItem> GetCatalogItem(int id)
|
public async Task<CatalogItem> GetCatalogItem(int id)
|
||||||
{
|
{
|
||||||
var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
|
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
|
||||||
var item = JsonConvert.DeserializeObject<CatalogItem>(data);
|
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent);
|
||||||
return item;
|
|
||||||
|
return catalogItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids)
|
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids)
|
||||||
{
|
{
|
||||||
var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
|
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
|
||||||
var item = JsonConvert.DeserializeObject<CatalogItem[]>(data);
|
var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);
|
||||||
return item;
|
|
||||||
|
|
||||||
|
return catalogItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
using System;
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
||||||
using System.Collections.Generic;
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
using System.Net.Http;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
|
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
|
||||||
{
|
{
|
||||||
public class OrderApiClient : IOrderApiClient
|
public class OrderApiClient : IOrderApiClient
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _apiClient;
|
||||||
private readonly ILogger<OrderApiClient> _logger;
|
private readonly ILogger<OrderApiClient> _logger;
|
||||||
private readonly UrlsConfig _urls;
|
private readonly UrlsConfig _urls;
|
||||||
|
|
||||||
public OrderApiClient(IHttpClient httpClient, ILogger<OrderApiClient> logger, IOptionsSnapshot<UrlsConfig> config)
|
public OrderApiClient(HttpClient httpClient, ILogger<OrderApiClient> logger, IOptions<UrlsConfig> config)
|
||||||
{
|
{
|
||||||
_apiClient = httpClient;
|
_apiClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -28,10 +25,14 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
|
|||||||
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket)
|
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket)
|
||||||
{
|
{
|
||||||
var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
|
var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
|
||||||
var response = await _apiClient.PostAsync<BasketData>(url, basket);
|
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
var response = await _apiClient.PostAsync(url, content);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
|
||||||
return JsonConvert.DeserializeObject<OrderData>(jsonResponse);
|
var ordersDraftResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject<OrderData>(ordersDraftResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
using System;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
||||||
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
|
||||||
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure;
|
||||||
|
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Polly;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
|
using Polly.Extensions.Http;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
|
using Polly.Timeout;
|
||||||
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
|
|
||||||
using Swashbuckle.AspNetCore.Swagger;
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
|
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
|
||||||
{
|
{
|
||||||
@ -31,55 +32,48 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
|
|||||||
// 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 void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddCustomMvc(Configuration)
|
||||||
services.AddSingleton<IHttpClient, StandardHttpClient>();
|
.AddCustomAuthentication(Configuration)
|
||||||
services.AddTransient<ICatalogService, CatalogService>();
|
.AddApplicationServices();
|
||||||
services.AddTransient<IBasketService, BasketService>();
|
}
|
||||||
services.AddTransient<IOrderApiClient, OrderApiClient>();
|
|
||||||
|
|
||||||
services.AddOptions();
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
services.Configure<UrlsConfig>(Configuration.GetSection("urls"));
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
services.AddMvc();
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
services.AddSwaggerGen(options =>
|
|
||||||
{
|
{
|
||||||
options.DescribeAllEnumsAsStrings();
|
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
||||||
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
app.UsePathBase(pathBase);
|
||||||
{
|
}
|
||||||
Title = "Shopping Aggregator for Web Clients",
|
|
||||||
Version = "v1",
|
|
||||||
Description = "Shopping Aggregator for Web Clients",
|
|
||||||
TermsOfService = "Terms Of Service"
|
|
||||||
});
|
|
||||||
|
|
||||||
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
app.UseCors("CorsPolicy");
|
||||||
{
|
|
||||||
Type = "oauth2",
|
|
||||||
Flow = "implicit",
|
|
||||||
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
|
||||||
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
|
||||||
Scopes = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "webshoppingagg", "Shopping Aggregator for Web Clients" }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
if (env.IsDevelopment())
|
||||||
});
|
|
||||||
|
|
||||||
services.AddCors(options =>
|
|
||||||
{
|
{
|
||||||
options.AddPolicy("CorsPolicy",
|
app.UseDeveloperExceptionPage();
|
||||||
builder => builder.AllowAnyOrigin()
|
}
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowAnyHeader()
|
app.UseAuthentication();
|
||||||
.AllowCredentials());
|
|
||||||
});
|
app.UseMvc();
|
||||||
|
|
||||||
|
app.UseSwagger().UseSwaggerUI(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
|
||||||
|
//c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||||
var identityUrl = Configuration.GetValue<string>("urls:identity");
|
var identityUrl = configuration.GetValue<string>("urls:identity");
|
||||||
services.AddAuthentication(options =>
|
services.AddAuthentication(options =>
|
||||||
{
|
{
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
@ -102,37 +96,92 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
|
||||||
|
|
||||||
|
services.AddMvc().SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
|
||||||
|
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.DescribeAllEnumsAsStrings();
|
||||||
|
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
||||||
|
{
|
||||||
|
Title = "Shopping Aggregator for Web Clients",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "Shopping Aggregator for Web Clients",
|
||||||
|
TermsOfService = "Terms Of Service"
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
||||||
|
{
|
||||||
|
Type = "oauth2",
|
||||||
|
Flow = "implicit",
|
||||||
|
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
||||||
|
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
||||||
|
Scopes = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "webshoppingagg", "Shopping Aggregator for Web Clients" }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
//register delegating handlers
|
||||||
|
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
|
||||||
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
|
||||||
|
//register http services
|
||||||
|
|
||||||
|
services.AddHttpClient<IBasketService, BasketService>()
|
||||||
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<ICatalogService, CatalogService>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
|
||||||
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
|
||||||
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
|
||||||
{
|
{
|
||||||
|
return HttpPolicyExtensions
|
||||||
|
.HandleTransientHttpError()
|
||||||
|
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||||
|
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
}
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
return HttpPolicyExtensions
|
||||||
app.UsePathBase(pathBase);
|
.HandleTransientHttpError()
|
||||||
}
|
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
|
||||||
|
|
||||||
app.UseCors("CorsPolicy");
|
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
|
||||||
|
|
||||||
app.UseMvc();
|
|
||||||
|
|
||||||
app.UseSwagger().UseSwaggerUI(c =>
|
|
||||||
{
|
|
||||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
|
|
||||||
c.ConfigureOAuth2("Microsoft.eShopOnContainers.Web.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI");
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</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>
|
||||||
@ -12,16 +12,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.1.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.4.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -108,18 +108,6 @@
|
|||||||
"UpstreamPathTemplate": "/catalog-api/{everything}",
|
"UpstreamPathTemplate": "/catalog-api/{everything}",
|
||||||
"UpstreamHttpMethod": []
|
"UpstreamHttpMethod": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"DownstreamPathTemplate": "/{everything}",
|
|
||||||
"DownstreamScheme": "http",
|
|
||||||
"DownstreamHostAndPorts": [
|
|
||||||
{
|
|
||||||
"Host": "marketing.api",
|
|
||||||
"Port": 80
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"UpstreamPathTemplate": "/marketing-api/{everything}",
|
|
||||||
"UpstreamHttpMethod": []
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/{everything}",
|
"DownstreamPathTemplate": "/{everything}",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
@ -131,18 +119,6 @@
|
|||||||
],
|
],
|
||||||
"UpstreamPathTemplate": "/payment-api/{everything}",
|
"UpstreamPathTemplate": "/payment-api/{everything}",
|
||||||
"UpstreamHttpMethod": []
|
"UpstreamHttpMethod": []
|
||||||
},
|
|
||||||
{
|
|
||||||
"DownstreamPathTemplate": "/{everything}",
|
|
||||||
"DownstreamScheme": "http",
|
|
||||||
"DownstreamHostAndPorts": [
|
|
||||||
{
|
|
||||||
"Host": "locations.api",
|
|
||||||
"Port": 80
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"UpstreamPathTemplate": "/location-api/{everything}",
|
|
||||||
"UpstreamHttpMethod": []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -6,13 +6,13 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac" Version="4.6.2" />
|
<PackageReference Include="Autofac" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.4.1" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="Polly" Version="5.8.0" />
|
<PackageReference Include="Polly" Version="6.0.1" />
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="5.0.1" />
|
<PackageReference Include="RabbitMQ.Client" Version="5.0.1" />
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus</RootNamespace>
|
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac" Version="4.6.2" />
|
<PackageReference Include="Autofac" Version="4.2.1" />
|
||||||
<PackageReference Include="Microsoft.Azure.ServiceBus" Version="2.0.0" />
|
<PackageReference Include="Microsoft.Azure.ServiceBus" Version="3.0.2" />
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.4.1" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\EventBus\EventBus.csproj" />
|
<ProjectReference Include="..\EventBus\EventBus.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -6,18 +6,12 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
|
</ItemGroup>
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\EventBus\EventBus.csproj" />
|
<ProjectReference Include="..\EventBus\EventBus.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\common\Guard.cs" Link="Internal\Guard.cs" />
|
<Compile Include="..\common\Guard.cs" Link="Internal\Guard.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
<ProjectReference Include="..\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -16,10 +16,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.1.1" />
|
||||||
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
|
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
|
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.4.0" />
|
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.0" />
|
||||||
<PackageReference Include="WindowsAzure.Storage" Version="9.1.0" />
|
<PackageReference Include="WindowsAzure.Storage" Version="9.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Data.SqlClient" Version="4.4.2" />
|
<PackageReference Include="System.Data.SqlClient" Version="4.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\common\Guard.cs" Link="Internal\Guard.cs" />
|
<Compile Include="..\common\Guard.cs" Link="Internal\Guard.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
|
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
|
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.4.0" />
|
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
|
||||||
{
|
|
||||||
public interface IHttpClient
|
|
||||||
{
|
|
||||||
Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer");
|
|
||||||
|
|
||||||
Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
|
|
||||||
|
|
||||||
Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
|
|
||||||
|
|
||||||
Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
|
||||||
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http</RootNamespace>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.1" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
|
|
||||||
<PackageReference Include="Polly" Version="5.8.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,191 +0,0 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Polly;
|
|
||||||
using Polly.Wrap;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// HttpClient wrapper that integrates Retry and Circuit
|
|
||||||
/// breaker policies when invoking HTTP services.
|
|
||||||
/// Based on Polly library: https://github.com/App-vNext/Polly
|
|
||||||
/// </summary>
|
|
||||||
public class ResilientHttpClient : IHttpClient
|
|
||||||
{
|
|
||||||
private readonly HttpClient _client;
|
|
||||||
private readonly ILogger<ResilientHttpClient> _logger;
|
|
||||||
private readonly Func<string, IEnumerable<Policy>> _policyCreator;
|
|
||||||
private ConcurrentDictionary<string, PolicyWrap> _policyWrappers;
|
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
||||||
|
|
||||||
public ResilientHttpClient(Func<string, IEnumerable<Policy>> policyCreator, ILogger<ResilientHttpClient> logger, IHttpContextAccessor httpContextAccessor)
|
|
||||||
{
|
|
||||||
_client = new HttpClient();
|
|
||||||
_logger = logger;
|
|
||||||
_policyCreator = policyCreator;
|
|
||||||
_policyWrappers = new ConcurrentDictionary<string, PolicyWrap>();
|
|
||||||
_httpContextAccessor = httpContextAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
return DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
return DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
var origin = GetOriginFromUri(uri);
|
|
||||||
|
|
||||||
return HttpInvoker(origin, async () =>
|
|
||||||
{
|
|
||||||
var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);
|
|
||||||
|
|
||||||
SetAuthorizationHeader(requestMessage);
|
|
||||||
|
|
||||||
if (authorizationToken != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestId != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Add("x-requestid", requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await _client.SendAsync(requestMessage);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
var origin = GetOriginFromUri(uri);
|
|
||||||
|
|
||||||
return HttpInvoker(origin, async () =>
|
|
||||||
{
|
|
||||||
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
|
|
||||||
|
|
||||||
SetAuthorizationHeader(requestMessage);
|
|
||||||
|
|
||||||
if (authorizationToken != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await _client.SendAsync(requestMessage);
|
|
||||||
|
|
||||||
// raise exception if HttpResponseCode 500
|
|
||||||
// needed for circuit breaker to track fails
|
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.InternalServerError)
|
|
||||||
{
|
|
||||||
throw new HttpRequestException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await response.Content.ReadAsStringAsync();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
if (method != HttpMethod.Post && method != HttpMethod.Put)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Value must be either post or put.", nameof(method));
|
|
||||||
}
|
|
||||||
|
|
||||||
// a new StringContent must be created for each retry
|
|
||||||
// as it is disposed after each call
|
|
||||||
var origin = GetOriginFromUri(uri);
|
|
||||||
|
|
||||||
return HttpInvoker(origin, async () =>
|
|
||||||
{
|
|
||||||
var requestMessage = new HttpRequestMessage(method, uri);
|
|
||||||
|
|
||||||
SetAuthorizationHeader(requestMessage);
|
|
||||||
|
|
||||||
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
if (authorizationToken != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestId != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Add("x-requestid", requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await _client.SendAsync(requestMessage);
|
|
||||||
|
|
||||||
// raise exception if HttpResponseCode 500
|
|
||||||
// needed for circuit breaker to track fails
|
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.InternalServerError)
|
|
||||||
{
|
|
||||||
throw new HttpRequestException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<T> HttpInvoker<T>(string origin, Func<Task<T>> action)
|
|
||||||
{
|
|
||||||
var normalizedOrigin = NormalizeOrigin(origin);
|
|
||||||
|
|
||||||
if (!_policyWrappers.TryGetValue(normalizedOrigin, out PolicyWrap policyWrap))
|
|
||||||
{
|
|
||||||
policyWrap = Policy.WrapAsync(_policyCreator(normalizedOrigin).ToArray());
|
|
||||||
_policyWrappers.TryAdd(normalizedOrigin, policyWrap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executes the action applying all
|
|
||||||
// the policies defined in the wrapper
|
|
||||||
return await policyWrap.ExecuteAsync(action, new Context(normalizedOrigin));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static string NormalizeOrigin(string origin)
|
|
||||||
{
|
|
||||||
return origin?.Trim()?.ToLower();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetOriginFromUri(string uri)
|
|
||||||
{
|
|
||||||
var url = new Uri(uri);
|
|
||||||
|
|
||||||
var origin = $"{url.Scheme}://{url.DnsSafeHost}:{url.Port}";
|
|
||||||
|
|
||||||
return origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetAuthorizationHeader(HttpRequestMessage requestMessage)
|
|
||||||
{
|
|
||||||
var authorizationHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
|
|
||||||
if (!string.IsNullOrEmpty(authorizationHeader))
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Add("Authorization", new List<string>() { authorizationHeader });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
|
|
||||||
{
|
|
||||||
public class StandardHttpClient : IHttpClient
|
|
||||||
{
|
|
||||||
private HttpClient _client;
|
|
||||||
private ILogger<StandardHttpClient> _logger;
|
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
||||||
|
|
||||||
public StandardHttpClient(ILogger<StandardHttpClient> logger, IHttpContextAccessor httpContextAccessor)
|
|
||||||
{
|
|
||||||
_client = new HttpClient();
|
|
||||||
_logger = logger;
|
|
||||||
_httpContextAccessor = httpContextAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
|
|
||||||
|
|
||||||
SetAuthorizationHeader(requestMessage);
|
|
||||||
|
|
||||||
if (authorizationToken != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await _client.SendAsync(requestMessage);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await response.Content.ReadAsStringAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
if (method != HttpMethod.Post && method != HttpMethod.Put)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Value must be either post or put.", nameof(method));
|
|
||||||
}
|
|
||||||
|
|
||||||
// a new StringContent must be created for each retry
|
|
||||||
// as it is disposed after each call
|
|
||||||
|
|
||||||
var requestMessage = new HttpRequestMessage(method, uri);
|
|
||||||
|
|
||||||
SetAuthorizationHeader(requestMessage);
|
|
||||||
|
|
||||||
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
if (authorizationToken != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestId != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Add("x-requestid", requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await _client.SendAsync(requestMessage);
|
|
||||||
|
|
||||||
// raise exception if HttpResponseCode 500
|
|
||||||
// needed for circuit breaker to track fails
|
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.InternalServerError)
|
|
||||||
{
|
|
||||||
throw new HttpRequestException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
return await DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, requestId, authorizationMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
return await DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, requestId, authorizationMethod);
|
|
||||||
}
|
|
||||||
public async Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
|
|
||||||
{
|
|
||||||
var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);
|
|
||||||
|
|
||||||
SetAuthorizationHeader(requestMessage);
|
|
||||||
|
|
||||||
if (authorizationToken != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestId != null)
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Add("x-requestid", requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await _client.SendAsync(requestMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetAuthorizationHeader(HttpRequestMessage requestMessage)
|
|
||||||
{
|
|
||||||
var authorizationHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
|
|
||||||
if (!string.IsNullOrEmpty(authorizationHeader))
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Add("Authorization", new List<string>() { authorizationHeader });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Polly" Version="5.8.0" />
|
<PackageReference Include="Polly" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -27,9 +27,9 @@ namespace Microsoft.AspNetCore.Hosting
|
|||||||
var retry = Policy.Handle<SqlException>()
|
var retry = Policy.Handle<SqlException>()
|
||||||
.WaitAndRetry(new TimeSpan[]
|
.WaitAndRetry(new TimeSpan[]
|
||||||
{
|
{
|
||||||
|
TimeSpan.FromSeconds(3),
|
||||||
TimeSpan.FromSeconds(5),
|
TimeSpan.FromSeconds(5),
|
||||||
TimeSpan.FromSeconds(10),
|
TimeSpan.FromSeconds(8),
|
||||||
TimeSpan.FromSeconds(15),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
retry.Execute(() =>
|
retry.Execute(() =>
|
||||||
|
@ -1,33 +1,35 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</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>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Update="web.config">
|
<Content Update="web.config">
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
</ItemGroup>
|
<PackageReference Include="StackExchange.Redis.StrongName" Version="1.2.6" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
|
</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" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -36,7 +36,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
|||||||
var basket = await _repository.GetBasketAsync(id);
|
var basket = await _repository.GetBasketAsync(id);
|
||||||
if (basket == null)
|
if (basket == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return Ok(new CustomerBasket(id) { });
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(basket);
|
return Ok(basket);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Basket/Basket.API
|
WORKDIR /src/src/Services/Basket/Basket.API
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Azure.ServiceBus;
|
using Microsoft.Azure.ServiceBus;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
@ -34,281 +35,288 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
|
||||||
// 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 IServiceProvider ConfigureServices(IServiceCollection services)
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
RegisterAppInsights(services);
|
RegisterAppInsights(services);
|
||||||
|
|
||||||
// Add framework services.
|
services.Configure<ApiBehaviorOptions>(opt =>
|
||||||
services.AddMvc(options =>
|
{
|
||||||
{
|
opt.SuppressModelStateInvalidFilter = true;
|
||||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
});
|
||||||
options.Filters.Add(typeof(ValidateModelStateFilter));
|
|
||||||
|
|
||||||
}).AddControllersAsServices();
|
// Add framework services.
|
||||||
|
services.AddMvc(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
|
options.Filters.Add(typeof(ValidateModelStateFilter));
|
||||||
|
|
||||||
ConfigureAuthService(services);
|
})
|
||||||
|
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1)
|
||||||
|
.AddControllersAsServices();
|
||||||
|
|
||||||
services.AddHealthChecks(checks =>
|
ConfigureAuthService(services);
|
||||||
{
|
|
||||||
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")),
|
|
||||||
TimeSpan.Zero //No cache for this HealthCheck, better just for demos
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
services.Configure<BasketSettings>(Configuration);
|
services.AddHealthChecks(checks =>
|
||||||
|
{
|
||||||
|
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")),
|
||||||
|
TimeSpan.Zero //No cache for this HealthCheck, better just for demos
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
//By connecting here we are making sure that our service
|
services.Configure<BasketSettings>(Configuration);
|
||||||
//cannot start until redis is ready. This might slow down startup,
|
|
||||||
//but given that there is a delay on resolving the ip address
|
|
||||||
//and then creating the connection it seems reasonable to move
|
|
||||||
//that cost to startup instead of having the first request pay the
|
|
||||||
//penalty.
|
|
||||||
services.AddSingleton<ConnectionMultiplexer>(sp =>
|
|
||||||
{
|
|
||||||
var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
|
|
||||||
var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true);
|
|
||||||
|
|
||||||
configuration.ResolveDns = true;
|
//By connecting here we are making sure that our service
|
||||||
|
//cannot start until redis is ready. This might slow down startup,
|
||||||
|
//but given that there is a delay on resolving the ip address
|
||||||
|
//and then creating the connection it seems reasonable to move
|
||||||
|
//that cost to startup instead of having the first request pay the
|
||||||
|
//penalty.
|
||||||
|
services.AddSingleton<ConnectionMultiplexer>(sp =>
|
||||||
|
{
|
||||||
|
var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
|
||||||
|
var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true);
|
||||||
|
|
||||||
return ConnectionMultiplexer.Connect(configuration);
|
configuration.ResolveDns = true;
|
||||||
});
|
|
||||||
|
return ConnectionMultiplexer.Connect(configuration);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
{
|
{
|
||||||
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||||
{
|
{
|
||||||
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
||||||
|
|
||||||
var serviceBusConnectionString = Configuration["EventBusConnection"];
|
var serviceBusConnectionString = Configuration["EventBusConnection"];
|
||||||
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
||||||
|
|
||||||
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
||||||
{
|
{
|
||||||
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
||||||
|
|
||||||
var factory = new ConnectionFactory()
|
var factory = new ConnectionFactory()
|
||||||
{
|
{
|
||||||
HostName = Configuration["EventBusConnection"]
|
HostName = Configuration["EventBusConnection"]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
|
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
|
||||||
{
|
{
|
||||||
factory.UserName = Configuration["EventBusUserName"];
|
factory.UserName = Configuration["EventBusUserName"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
|
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
|
||||||
{
|
{
|
||||||
factory.Password = Configuration["EventBusPassword"];
|
factory.Password = Configuration["EventBusPassword"];
|
||||||
}
|
}
|
||||||
|
|
||||||
var retryCount = 5;
|
var retryCount = 5;
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||||
{
|
{
|
||||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterEventBus(services);
|
RegisterEventBus(services);
|
||||||
|
|
||||||
services.AddSwaggerGen(options =>
|
services.AddSwaggerGen(options =>
|
||||||
{
|
{
|
||||||
options.DescribeAllEnumsAsStrings();
|
options.DescribeAllEnumsAsStrings();
|
||||||
options.SwaggerDoc("v1", new Info
|
options.SwaggerDoc("v1", new Info
|
||||||
{
|
{
|
||||||
Title = "Basket HTTP API",
|
Title = "Basket HTTP API",
|
||||||
Version = "v1",
|
Version = "v1",
|
||||||
Description = "The Basket Service HTTP API",
|
Description = "The Basket Service HTTP API",
|
||||||
TermsOfService = "Terms Of Service"
|
TermsOfService = "Terms Of Service"
|
||||||
});
|
});
|
||||||
|
|
||||||
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
||||||
{
|
{
|
||||||
Type = "oauth2",
|
Type = "oauth2",
|
||||||
Flow = "implicit",
|
Flow = "implicit",
|
||||||
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
||||||
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
||||||
Scopes = new Dictionary<string, string>()
|
Scopes = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "basket", "Basket API" }
|
{ "basket", "Basket API" }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddCors(options =>
|
services.AddCors(options =>
|
||||||
{
|
{
|
||||||
options.AddPolicy("CorsPolicy",
|
options.AddPolicy("CorsPolicy",
|
||||||
builder => builder.AllowAnyOrigin()
|
builder => builder.AllowAnyOrigin()
|
||||||
.AllowAnyMethod()
|
.AllowAnyMethod()
|
||||||
.AllowAnyHeader()
|
.AllowAnyHeader()
|
||||||
.AllowCredentials());
|
.AllowCredentials());
|
||||||
});
|
});
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
||||||
services.AddTransient<IIdentityService, IdentityService>();
|
services.AddTransient<IIdentityService, IdentityService>();
|
||||||
|
|
||||||
services.AddOptions();
|
services.AddOptions();
|
||||||
|
|
||||||
var container = new ContainerBuilder();
|
var container = new ContainerBuilder();
|
||||||
container.Populate(services);
|
container.Populate(services);
|
||||||
|
|
||||||
return new AutofacServiceProvider(container.Build());
|
return new AutofacServiceProvider(container.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
loggerFactory.AddAzureWebAppDiagnostics();
|
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
app.UsePathBase(pathBase);
|
loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
}
|
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
{
|
||||||
|
app.UsePathBase(pathBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
||||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseCors("CorsPolicy");
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
ConfigureAuth(app);
|
ConfigureAuth(app);
|
||||||
|
|
||||||
app.UseMvcWithDefaultRoute();
|
app.UseMvcWithDefaultRoute();
|
||||||
|
|
||||||
app.UseSwagger()
|
app.UseSwagger()
|
||||||
.UseSwaggerUI(c =>
|
.UseSwaggerUI(c =>
|
||||||
{
|
{
|
||||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
|
||||||
c.OAuthClientId ("basketswaggerui");
|
c.OAuthClientId("basketswaggerui");
|
||||||
c.OAuthAppName("Basket Swagger UI");
|
c.OAuthAppName("Basket Swagger UI");
|
||||||
});
|
});
|
||||||
|
|
||||||
ConfigureEventBus(app);
|
ConfigureEventBus(app);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterAppInsights(IServiceCollection services)
|
private void RegisterAppInsights(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddApplicationInsightsTelemetry(Configuration);
|
services.AddApplicationInsightsTelemetry(Configuration);
|
||||||
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
||||||
|
|
||||||
if (orchestratorType?.ToUpper() == "K8S")
|
|
||||||
{
|
|
||||||
// Enable K8s telemetry initializer
|
|
||||||
services.EnableKubernetes();
|
|
||||||
}
|
|
||||||
if (orchestratorType?.ToUpper() == "SF")
|
|
||||||
{
|
|
||||||
// Enable SF telemetry initializer
|
|
||||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
|
||||||
new FabricTelemetryInitializer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConfigureAuthService(IServiceCollection services)
|
if (orchestratorType?.ToUpper() == "K8S")
|
||||||
{
|
{
|
||||||
// prevent from mapping "sub" claim to nameidentifier.
|
// Enable K8s telemetry initializer
|
||||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
services.EnableKubernetes();
|
||||||
|
}
|
||||||
|
if (orchestratorType?.ToUpper() == "SF")
|
||||||
|
{
|
||||||
|
// Enable SF telemetry initializer
|
||||||
|
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||||
|
new FabricTelemetryInitializer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
private void ConfigureAuthService(IServiceCollection services)
|
||||||
|
{
|
||||||
services.AddAuthentication(options =>
|
// prevent from mapping "sub" claim to nameidentifier.
|
||||||
{
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
|
|
||||||
}).AddJwtBearer(options =>
|
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
||||||
{
|
|
||||||
options.Authority = identityUrl;
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.Audience = "basket";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
services.AddAuthentication(options =>
|
||||||
{
|
{
|
||||||
if (Configuration.GetValue<bool>("UseLoadTest"))
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
{
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
app.UseMiddleware<ByPassAuthMiddleware>();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
}).AddJwtBearer(options =>
|
||||||
}
|
{
|
||||||
|
options.Authority = identityUrl;
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.Audience = "basket";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void RegisterEventBus(IServiceCollection services)
|
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
var subscriptionClientName = Configuration["SubscriptionClientName"];
|
if (Configuration.GetValue<bool>("UseLoadTest"))
|
||||||
|
{
|
||||||
|
app.UseMiddleware<ByPassAuthMiddleware>();
|
||||||
|
}
|
||||||
|
|
||||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
app.UseAuthentication();
|
||||||
{
|
}
|
||||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
|
||||||
{
|
|
||||||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
|
||||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
|
||||||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
|
||||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
|
||||||
|
|
||||||
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
private void RegisterEventBus(IServiceCollection services)
|
||||||
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
{
|
||||||
});
|
var subscriptionClientName = Configuration["SubscriptionClientName"];
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
|
|
||||||
{
|
|
||||||
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
|
|
||||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
|
||||||
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
|
|
||||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
|
||||||
|
|
||||||
var retryCount = 5;
|
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
{
|
||||||
{
|
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
{
|
||||||
}
|
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
||||||
});
|
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
|
||||||
|
{
|
||||||
|
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
var retryCount = 5;
|
||||||
|
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
services.AddTransient<ProductPriceChangedIntegrationEventHandler>();
|
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||||
services.AddTransient<OrderStartedIntegrationEventHandler>();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigureEventBus(IApplicationBuilder app)
|
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||||
{
|
|
||||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
|
||||||
|
|
||||||
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>();
|
services.AddTransient<ProductPriceChangedIntegrationEventHandler>();
|
||||||
eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>();
|
services.AddTransient<OrderStartedIntegrationEventHandler>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void ConfigureEventBus(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
||||||
|
|
||||||
|
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>();
|
||||||
|
eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<DebugType>portable</DebugType>
|
<DebugType>portable</DebugType>
|
||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
<AssemblyName>Catalog.API</AssemblyName>
|
<AssemblyName>Catalog.API</AssemblyName>
|
||||||
@ -34,20 +34,17 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
|
|
||||||
</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" />
|
||||||
|
@ -15,6 +15,7 @@ using System.Threading.Tasks;
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||||
{
|
{
|
||||||
[Route("api/v1/[controller]")]
|
[Route("api/v1/[controller]")]
|
||||||
|
[ApiController]
|
||||||
public class CatalogController : ControllerBase
|
public class CatalogController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly CatalogContext _catalogContext;
|
private readonly CatalogContext _catalogContext;
|
||||||
@ -25,8 +26,8 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
{
|
{
|
||||||
_catalogContext = context ?? throw new ArgumentNullException(nameof(context));
|
_catalogContext = context ?? throw new ArgumentNullException(nameof(context));
|
||||||
_catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService));
|
_catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService));
|
||||||
|
|
||||||
_settings = settings.Value;
|
_settings = settings.Value;
|
||||||
|
|
||||||
((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
|||||||
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||||
{
|
{
|
||||||
public class PicController : Controller
|
public class PicController : Controller
|
||||||
{
|
{
|
||||||
private readonly IHostingEnvironment _env;
|
private readonly IHostingEnvironment _env;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Catalog/Catalog.API
|
WORKDIR /src/src/Services/Catalog/Catalog.API
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Catalog.API.Infrastructure.ActionResults;
|
using Catalog.API.Infrastructure.ActionResults;
|
||||||
using Catalog.API.Infrastructure.Exceptions;
|
using Catalog.API.Infrastructure.Exceptions;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -27,12 +28,16 @@ namespace Catalog.API.Infrastructure.Filters
|
|||||||
|
|
||||||
if (context.Exception.GetType() == typeof(CatalogDomainException))
|
if (context.Exception.GetType() == typeof(CatalogDomainException))
|
||||||
{
|
{
|
||||||
var json = new JsonErrorResponse
|
var problemDetails = new ValidationProblemDetails()
|
||||||
{
|
{
|
||||||
Messages = new[] { context.Exception.Message }
|
Instance = context.HttpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest,
|
||||||
|
Detail = "Please refer to the errors property for additional details."
|
||||||
};
|
};
|
||||||
|
|
||||||
context.Result = new BadRequestObjectResult(json);
|
problemDetails.Errors.Add("DomainValidations", new string[] { context.Exception.Message.ToString() });
|
||||||
|
|
||||||
|
context.Result = new BadRequestObjectResult(problemDetails);
|
||||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1,35 +1,37 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
using Autofac;
|
||||||
{
|
using Autofac.Extensions.DependencyInjection;
|
||||||
using Autofac;
|
using global::Catalog.API.Infrastructure.Filters;
|
||||||
using Autofac.Extensions.DependencyInjection;
|
using global::Catalog.API.IntegrationEvents;
|
||||||
using global::Catalog.API.Infrastructure.Filters;
|
using Microsoft.ApplicationInsights.Extensibility;
|
||||||
using global::Catalog.API.IntegrationEvents;
|
using Microsoft.ApplicationInsights.ServiceFabric;
|
||||||
using Microsoft.ApplicationInsights.Extensibility;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.ApplicationInsights.ServiceFabric;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Azure.ServiceBus;
|
using Microsoft.Azure.ServiceBus;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.HealthChecks;
|
using Microsoft.Extensions.HealthChecks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
using System;
|
using System;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||||
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
@ -41,21 +43,95 @@
|
|||||||
|
|
||||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
// Add framework services.
|
services.AddAppInsight(Configuration)
|
||||||
|
.AddCustomMVC(Configuration)
|
||||||
|
.AddCustomDbContext(Configuration)
|
||||||
|
.AddCustomOptions(Configuration)
|
||||||
|
.AddIntegrationServices(Configuration)
|
||||||
|
.AddEventBus(Configuration)
|
||||||
|
.AddSwagger();
|
||||||
|
|
||||||
RegisterAppInsights(services);
|
var container = new ContainerBuilder();
|
||||||
|
container.Populate(services);
|
||||||
|
return new AutofacServiceProvider(container.Build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
//Configure logs
|
||||||
|
|
||||||
|
loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
{
|
||||||
|
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
||||||
|
app.UsePathBase(pathBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
||||||
|
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
|
||||||
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
|
app.UseMvcWithDefaultRoute();
|
||||||
|
|
||||||
|
app.UseSwagger()
|
||||||
|
.UseSwaggerUI(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Catalog.API V1");
|
||||||
|
});
|
||||||
|
|
||||||
|
ConfigureEventBus(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ConfigureEventBus(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CustomExtensionMethods
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddApplicationInsightsTelemetry(configuration);
|
||||||
|
var orchestratorType = configuration.GetValue<string>("OrchestratorType");
|
||||||
|
|
||||||
|
if (orchestratorType?.ToUpper() == "K8S")
|
||||||
|
{
|
||||||
|
// Enable K8s telemetry initializer
|
||||||
|
services.EnableKubernetes();
|
||||||
|
}
|
||||||
|
if (orchestratorType?.ToUpper() == "SF")
|
||||||
|
{
|
||||||
|
// Enable SF telemetry initializer
|
||||||
|
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||||
|
new FabricTelemetryInitializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
services.AddHealthChecks(checks =>
|
services.AddHealthChecks(checks =>
|
||||||
{
|
{
|
||||||
var minutes = 1;
|
var minutes = 1;
|
||||||
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
|
if (int.TryParse(configuration["HealthCheck:Timeout"], out var minutesParsed))
|
||||||
{
|
{
|
||||||
minutes = minutesParsed;
|
minutes = minutesParsed;
|
||||||
}
|
}
|
||||||
checks.AddSqlCheck("CatalogDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
|
checks.AddSqlCheck("CatalogDb", configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
|
||||||
|
|
||||||
var accountName = Configuration.GetValue<string>("AzureStorageAccountName");
|
var accountName = configuration.GetValue<string>("AzureStorageAccountName");
|
||||||
var accountKey = Configuration.GetValue<string>("AzureStorageAccountKey");
|
var accountKey = configuration.GetValue<string>("AzureStorageAccountKey");
|
||||||
if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey))
|
if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey))
|
||||||
{
|
{
|
||||||
checks.AddAzureBlobStorageCheck(accountName, accountKey);
|
checks.AddAzureBlobStorageCheck(accountName, accountKey);
|
||||||
@ -65,11 +141,27 @@
|
|||||||
services.AddMvc(options =>
|
services.AddMvc(options =>
|
||||||
{
|
{
|
||||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
}).AddControllersAsServices();
|
})
|
||||||
|
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
|
||||||
|
.AddControllersAsServices();
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
services.AddDbContext<CatalogContext>(options =>
|
services.AddDbContext<CatalogContext>(options =>
|
||||||
{
|
{
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
options.UseSqlServer(configuration["ConnectionString"],
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
{
|
{
|
||||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
@ -85,7 +177,7 @@
|
|||||||
|
|
||||||
services.AddDbContext<IntegrationEventLogContext>(options =>
|
services.AddDbContext<IntegrationEventLogContext>(options =>
|
||||||
{
|
{
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
options.UseSqlServer(configuration["ConnectionString"],
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
{
|
{
|
||||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
@ -94,9 +186,35 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
services.Configure<CatalogSettings>(Configuration);
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
// Add framework services.
|
public static IServiceCollection AddCustomOptions(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.Configure<CatalogSettings>(configuration);
|
||||||
|
services.Configure<ApiBehaviorOptions>(options =>
|
||||||
|
{
|
||||||
|
options.InvalidModelStateResponseFactory = context =>
|
||||||
|
{
|
||||||
|
var problemDetails = new ValidationProblemDetails(context.ModelState)
|
||||||
|
{
|
||||||
|
Instance = context.HttpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest,
|
||||||
|
Detail = "Please refer to the errors property for additional details."
|
||||||
|
};
|
||||||
|
|
||||||
|
return new BadRequestObjectResult(problemDetails)
|
||||||
|
{
|
||||||
|
ContentTypes = { "application/problem+json", "application/problem+xml" }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddSwagger(this IServiceCollection services)
|
||||||
|
{
|
||||||
services.AddSwaggerGen(options =>
|
services.AddSwaggerGen(options =>
|
||||||
{
|
{
|
||||||
options.DescribeAllEnumsAsStrings();
|
options.DescribeAllEnumsAsStrings();
|
||||||
@ -109,21 +227,18 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddCors(options =>
|
return services;
|
||||||
{
|
|
||||||
options.AddPolicy("CorsPolicy",
|
|
||||||
builder => builder.AllowAnyOrigin()
|
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowCredentials());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||||
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
||||||
|
|
||||||
services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>();
|
services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>();
|
||||||
|
|
||||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
{
|
{
|
||||||
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||||
{
|
{
|
||||||
@ -144,93 +259,37 @@
|
|||||||
|
|
||||||
var factory = new ConnectionFactory()
|
var factory = new ConnectionFactory()
|
||||||
{
|
{
|
||||||
HostName = Configuration["EventBusConnection"]
|
HostName = configuration["EventBusConnection"]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
|
if (!string.IsNullOrEmpty(configuration["EventBusUserName"]))
|
||||||
{
|
{
|
||||||
factory.UserName = Configuration["EventBusUserName"];
|
factory.UserName = configuration["EventBusUserName"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
|
if (!string.IsNullOrEmpty(configuration["EventBusPassword"]))
|
||||||
{
|
{
|
||||||
factory.Password = Configuration["EventBusPassword"];
|
factory.Password = configuration["EventBusPassword"];
|
||||||
}
|
}
|
||||||
|
|
||||||
var retryCount = 5;
|
var retryCount = 5;
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
{
|
{
|
||||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterEventBus(services);
|
return services;
|
||||||
|
|
||||||
var container = new ContainerBuilder();
|
|
||||||
container.Populate(services);
|
|
||||||
return new AutofacServiceProvider(container.Build());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
//Configure logs
|
var subscriptionClientName = configuration["SubscriptionClientName"];
|
||||||
|
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
loggerFactory.AddDebug();
|
|
||||||
loggerFactory.AddAzureWebAppDiagnostics();
|
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
|
||||||
{
|
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
|
||||||
app.UsePathBase(pathBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
|
||||||
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
|
||||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
|
||||||
|
|
||||||
app.UseCors("CorsPolicy");
|
|
||||||
|
|
||||||
app.UseMvcWithDefaultRoute();
|
|
||||||
|
|
||||||
app.UseSwagger()
|
|
||||||
.UseSwaggerUI(c =>
|
|
||||||
{
|
|
||||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Catalog.API V1");
|
|
||||||
});
|
|
||||||
|
|
||||||
ConfigureEventBus(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterAppInsights(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddApplicationInsightsTelemetry(Configuration);
|
|
||||||
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
|
||||||
|
|
||||||
if (orchestratorType?.ToUpper() == "K8S")
|
|
||||||
{
|
|
||||||
// Enable K8s telemetry initializer
|
|
||||||
services.EnableKubernetes();
|
|
||||||
}
|
|
||||||
if (orchestratorType?.ToUpper() == "SF")
|
|
||||||
{
|
|
||||||
// Enable SF telemetry initializer
|
|
||||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
|
||||||
new FabricTelemetryInitializer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterEventBus(IServiceCollection services)
|
|
||||||
{
|
|
||||||
var subscriptionClientName = Configuration["SubscriptionClientName"];
|
|
||||||
|
|
||||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
|
||||||
{
|
{
|
||||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||||
{
|
{
|
||||||
@ -254,9 +313,9 @@
|
|||||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
var retryCount = 5;
|
var retryCount = 5;
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
{
|
{
|
||||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||||
@ -266,12 +325,8 @@
|
|||||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||||
services.AddTransient<OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
|
services.AddTransient<OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
|
||||||
services.AddTransient<OrderStatusChangedToPaidIntegrationEventHandler>();
|
services.AddTransient<OrderStatusChangedToPaidIntegrationEventHandler>();
|
||||||
}
|
|
||||||
protected virtual void ConfigureEventBus(IApplicationBuilder app)
|
return services;
|
||||||
{
|
|
||||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
|
||||||
eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
|
|
||||||
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"directory": "wwwroot/lib"
|
"directory": "wwwroot/lib",
|
||||||
|
"registry": "https://registry.bower.io"
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Identity.API
|
namespace Microsoft.eShopOnContainers.Services.Identity.API
|
||||||
{
|
{
|
||||||
public class AppSettings
|
public class AppSettings
|
||||||
{
|
{
|
||||||
public string MvcClient { get; set; }
|
public string MvcClient { get; set; }
|
||||||
|
|
||||||
public bool UseCustomizationData { get; set; }
|
public bool UseCustomizationData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,252 +4,256 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
|
||||||
{
|
{
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
// ApiResources define the apis in your system
|
// ApiResources define the apis in your system
|
||||||
public static IEnumerable<ApiResource> GetApis()
|
public static IEnumerable<ApiResource> GetApis()
|
||||||
{
|
{
|
||||||
return new List<ApiResource>
|
return new List<ApiResource>
|
||||||
{
|
{
|
||||||
new ApiResource("orders", "Orders Service"),
|
new ApiResource("orders", "Orders Service"),
|
||||||
new ApiResource("basket", "Basket Service"),
|
new ApiResource("basket", "Basket Service"),
|
||||||
new ApiResource("marketing", "Marketing Service"),
|
new ApiResource("marketing", "Marketing Service"),
|
||||||
new ApiResource("locations", "Locations Service"),
|
new ApiResource("locations", "Locations Service"),
|
||||||
new ApiResource("mobileshoppingagg", "Mobile Shopping Aggregator"),
|
new ApiResource("mobileshoppingagg", "Mobile Shopping Aggregator"),
|
||||||
new ApiResource("webshoppingagg", "Web Shopping Aggregator"),
|
new ApiResource("webshoppingagg", "Web Shopping Aggregator"),
|
||||||
new ApiResource("orders.signalrhub", "Ordering Signalr Hub")
|
new ApiResource("orders.signalrhub", "Ordering SignalR Hub")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identity resources are data like user ID, name, or email address of a user
|
// Identity resources are data like user ID, name, or email address of a user
|
||||||
// see: http://docs.identityserver.io/en/release/configuration/resources.html
|
// see: http://docs.identityserver.io/en/release/configuration/resources.html
|
||||||
public static IEnumerable<IdentityResource> GetResources()
|
public static IEnumerable<IdentityResource> GetResources()
|
||||||
{
|
{
|
||||||
return new List<IdentityResource>
|
return new List<IdentityResource>
|
||||||
{
|
{
|
||||||
new IdentityResources.OpenId(),
|
new IdentityResources.OpenId(),
|
||||||
new IdentityResources.Profile()
|
new IdentityResources.Profile()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// client want to access resources (aka scopes)
|
// client want to access resources (aka scopes)
|
||||||
public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
|
public static IEnumerable<Client> GetClients(Dictionary<string, string> clientsUrl)
|
||||||
{
|
{
|
||||||
return new List<Client>
|
return new List<Client>
|
||||||
{
|
{
|
||||||
// JavaScript Client
|
// JavaScript Client
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "js",
|
ClientId = "js",
|
||||||
ClientName = "eShop SPA OpenId Client",
|
ClientName = "eShop SPA OpenId Client",
|
||||||
AllowedGrantTypes = GrantTypes.Implicit,
|
AllowedGrantTypes = GrantTypes.Implicit,
|
||||||
AllowAccessTokensViaBrowser = true,
|
AllowAccessTokensViaBrowser = true,
|
||||||
RedirectUris = { $"{clientsUrl["Spa"]}/" },
|
RedirectUris = { $"{clientsUrl["Spa"]}/" },
|
||||||
RequireConsent = false,
|
RequireConsent = false,
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["Spa"]}/" },
|
PostLogoutRedirectUris = { $"{clientsUrl["Spa"]}/" },
|
||||||
AllowedCorsOrigins = { $"{clientsUrl["Spa"]}" },
|
AllowedCorsOrigins = { $"{clientsUrl["Spa"]}" },
|
||||||
AllowedScopes =
|
AllowedScopes =
|
||||||
{
|
{
|
||||||
IdentityServerConstants.StandardScopes.OpenId,
|
IdentityServerConstants.StandardScopes.OpenId,
|
||||||
IdentityServerConstants.StandardScopes.Profile,
|
IdentityServerConstants.StandardScopes.Profile,
|
||||||
"orders",
|
"orders",
|
||||||
"basket",
|
"basket",
|
||||||
"locations",
|
"locations",
|
||||||
"marketing",
|
"marketing",
|
||||||
"webshoppingagg",
|
"webshoppingagg",
|
||||||
"orders.signalrhub"
|
"orders.signalrhub"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "xamarin",
|
ClientId = "xamarin",
|
||||||
ClientName = "eShop Xamarin OpenId Client",
|
ClientName = "eShop Xamarin OpenId Client",
|
||||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||||
//Used to retrieve the access token on the back channel.
|
//Used to retrieve the access token on the back channel.
|
||||||
ClientSecrets =
|
ClientSecrets =
|
||||||
{
|
{
|
||||||
new Secret("secret".Sha256())
|
new Secret("secret".Sha256())
|
||||||
},
|
},
|
||||||
RedirectUris = { clientsUrl["Xamarin"] },
|
RedirectUris = { clientsUrl["Xamarin"] },
|
||||||
RequireConsent = false,
|
RequireConsent = false,
|
||||||
RequirePkce = true,
|
RequirePkce = true,
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
|
PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
|
||||||
AllowedCorsOrigins = { "http://eshopxamarin" },
|
AllowedCorsOrigins = { "http://eshopxamarin" },
|
||||||
AllowedScopes = new List<string>
|
AllowedScopes = new List<string>
|
||||||
{
|
{
|
||||||
IdentityServerConstants.StandardScopes.OpenId,
|
IdentityServerConstants.StandardScopes.OpenId,
|
||||||
IdentityServerConstants.StandardScopes.Profile,
|
IdentityServerConstants.StandardScopes.Profile,
|
||||||
IdentityServerConstants.StandardScopes.OfflineAccess,
|
IdentityServerConstants.StandardScopes.OfflineAccess,
|
||||||
"orders",
|
"orders",
|
||||||
"basket",
|
"basket",
|
||||||
"locations",
|
"locations",
|
||||||
"marketing",
|
"marketing",
|
||||||
"mobileshoppingagg"
|
"mobileshoppingagg"
|
||||||
},
|
},
|
||||||
//Allow requesting refresh tokens for long lived API access
|
//Allow requesting refresh tokens for long lived API access
|
||||||
AllowOfflineAccess = true,
|
AllowOfflineAccess = true,
|
||||||
AllowAccessTokensViaBrowser = true
|
AllowAccessTokensViaBrowser = true
|
||||||
},
|
},
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "mvc",
|
ClientId = "mvc",
|
||||||
ClientName = "MVC Client",
|
ClientName = "MVC Client",
|
||||||
ClientSecrets = new List<Secret>
|
ClientSecrets = new List<Secret>
|
||||||
{
|
{
|
||||||
new Secret("secret".Sha256())
|
new Secret("secret".Sha256())
|
||||||
},
|
},
|
||||||
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
|
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
|
||||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||||
AllowAccessTokensViaBrowser = false,
|
AllowAccessTokensViaBrowser = false,
|
||||||
RequireConsent = false,
|
RequireConsent = false,
|
||||||
AllowOfflineAccess = true,
|
AllowOfflineAccess = true,
|
||||||
AlwaysIncludeUserClaimsInIdToken = true,
|
AlwaysIncludeUserClaimsInIdToken = true,
|
||||||
RedirectUris = new List<string>
|
RedirectUris = new List<string>
|
||||||
{
|
{
|
||||||
$"{clientsUrl["Mvc"]}/signin-oidc"
|
$"{clientsUrl["Mvc"]}/signin-oidc"
|
||||||
},
|
},
|
||||||
PostLogoutRedirectUris = new List<string>
|
PostLogoutRedirectUris = new List<string>
|
||||||
{
|
{
|
||||||
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
|
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
|
||||||
},
|
},
|
||||||
AllowedScopes = new List<string>
|
AllowedCorsOrigins = new List<string>
|
||||||
{
|
{
|
||||||
IdentityServerConstants.StandardScopes.OpenId,
|
$"{clientsUrl["Mvc"]}"
|
||||||
IdentityServerConstants.StandardScopes.Profile,
|
},
|
||||||
IdentityServerConstants.StandardScopes.OfflineAccess,
|
AllowedScopes = new List<string>
|
||||||
"orders",
|
{
|
||||||
"basket",
|
IdentityServerConstants.StandardScopes.OpenId,
|
||||||
"locations",
|
IdentityServerConstants.StandardScopes.Profile,
|
||||||
"marketing",
|
IdentityServerConstants.StandardScopes.OfflineAccess,
|
||||||
"webshoppingagg",
|
"orders",
|
||||||
"orders.signalrhub"
|
"basket",
|
||||||
},
|
"locations",
|
||||||
},
|
"marketing",
|
||||||
new Client
|
"webshoppingagg",
|
||||||
{
|
"orders.signalrhub"
|
||||||
ClientId = "mvctest",
|
},
|
||||||
ClientName = "MVC Client Test",
|
},
|
||||||
ClientSecrets = new List<Secret>
|
new Client
|
||||||
{
|
{
|
||||||
new Secret("secret".Sha256())
|
ClientId = "mvctest",
|
||||||
},
|
ClientName = "MVC Client Test",
|
||||||
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
|
ClientSecrets = new List<Secret>
|
||||||
AllowedGrantTypes = GrantTypes.Hybrid,
|
{
|
||||||
AllowAccessTokensViaBrowser = true,
|
new Secret("secret".Sha256())
|
||||||
RequireConsent = false,
|
},
|
||||||
AllowOfflineAccess = true,
|
ClientUri = $"{clientsUrl["Mvc"]}", // public uri of the client
|
||||||
RedirectUris = new List<string>
|
AllowedGrantTypes = GrantTypes.Hybrid,
|
||||||
{
|
AllowAccessTokensViaBrowser = true,
|
||||||
$"{clientsUrl["Mvc"]}/signin-oidc"
|
RequireConsent = false,
|
||||||
},
|
AllowOfflineAccess = true,
|
||||||
PostLogoutRedirectUris = new List<string>
|
RedirectUris = new List<string>
|
||||||
{
|
{
|
||||||
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
|
$"{clientsUrl["Mvc"]}/signin-oidc"
|
||||||
},
|
},
|
||||||
AllowedScopes = new List<string>
|
PostLogoutRedirectUris = new List<string>
|
||||||
{
|
{
|
||||||
IdentityServerConstants.StandardScopes.OpenId,
|
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
|
||||||
IdentityServerConstants.StandardScopes.Profile,
|
},
|
||||||
IdentityServerConstants.StandardScopes.OfflineAccess,
|
AllowedScopes = new List<string>
|
||||||
"orders",
|
{
|
||||||
"basket",
|
IdentityServerConstants.StandardScopes.OpenId,
|
||||||
"locations",
|
IdentityServerConstants.StandardScopes.Profile,
|
||||||
"marketing",
|
IdentityServerConstants.StandardScopes.OfflineAccess,
|
||||||
"webshoppingagg"
|
"orders",
|
||||||
},
|
"basket",
|
||||||
},
|
"locations",
|
||||||
new Client
|
"marketing",
|
||||||
{
|
"webshoppingagg"
|
||||||
ClientId = "locationsswaggerui",
|
},
|
||||||
ClientName = "Locations Swagger UI",
|
},
|
||||||
AllowedGrantTypes = GrantTypes.Implicit,
|
new Client
|
||||||
AllowAccessTokensViaBrowser = true,
|
{
|
||||||
|
ClientId = "locationsswaggerui",
|
||||||
|
ClientName = "Locations Swagger UI",
|
||||||
|
AllowedGrantTypes = GrantTypes.Implicit,
|
||||||
|
AllowAccessTokensViaBrowser = true,
|
||||||
|
|
||||||
RedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/o2c.html" },
|
RedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/oauth2-redirect.html" },
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/" },
|
PostLogoutRedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/" },
|
||||||
|
|
||||||
AllowedScopes =
|
AllowedScopes =
|
||||||
{
|
{
|
||||||
"locations"
|
"locations"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "marketingswaggerui",
|
ClientId = "marketingswaggerui",
|
||||||
ClientName = "Marketing Swagger UI",
|
ClientName = "Marketing Swagger UI",
|
||||||
AllowedGrantTypes = GrantTypes.Implicit,
|
AllowedGrantTypes = GrantTypes.Implicit,
|
||||||
AllowAccessTokensViaBrowser = true,
|
AllowAccessTokensViaBrowser = true,
|
||||||
|
|
||||||
RedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/o2c.html" },
|
RedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/oauth2-redirect.html" },
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/" },
|
PostLogoutRedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/" },
|
||||||
|
|
||||||
AllowedScopes =
|
AllowedScopes =
|
||||||
{
|
{
|
||||||
"marketing"
|
"marketing"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "basketswaggerui",
|
ClientId = "basketswaggerui",
|
||||||
ClientName = "Basket Swagger UI",
|
ClientName = "Basket Swagger UI",
|
||||||
AllowedGrantTypes = GrantTypes.Implicit,
|
AllowedGrantTypes = GrantTypes.Implicit,
|
||||||
AllowAccessTokensViaBrowser = true,
|
AllowAccessTokensViaBrowser = true,
|
||||||
|
|
||||||
RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/o2c.html" },
|
RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/oauth2-redirect.html" },
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" },
|
PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" },
|
||||||
|
|
||||||
AllowedScopes =
|
AllowedScopes =
|
||||||
{
|
{
|
||||||
"basket"
|
"basket"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "orderingswaggerui",
|
ClientId = "orderingswaggerui",
|
||||||
ClientName = "Ordering Swagger UI",
|
ClientName = "Ordering Swagger UI",
|
||||||
AllowedGrantTypes = GrantTypes.Implicit,
|
AllowedGrantTypes = GrantTypes.Implicit,
|
||||||
AllowAccessTokensViaBrowser = true,
|
AllowAccessTokensViaBrowser = true,
|
||||||
|
|
||||||
RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/o2c.html" },
|
RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/oauth2-redirect.html" },
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" },
|
PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" },
|
||||||
|
|
||||||
AllowedScopes =
|
AllowedScopes =
|
||||||
{
|
{
|
||||||
"orders"
|
"orders"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "mobileshoppingaggswaggerui",
|
ClientId = "mobileshoppingaggswaggerui",
|
||||||
ClientName = "Mobile Shopping Aggregattor Swagger UI",
|
ClientName = "Mobile Shopping Aggregattor Swagger UI",
|
||||||
AllowedGrantTypes = GrantTypes.Implicit,
|
AllowedGrantTypes = GrantTypes.Implicit,
|
||||||
AllowAccessTokensViaBrowser = true,
|
AllowAccessTokensViaBrowser = true,
|
||||||
|
|
||||||
RedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/o2c.html" },
|
RedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/oauth2-redirect.html" },
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/" },
|
PostLogoutRedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/" },
|
||||||
|
|
||||||
AllowedScopes =
|
AllowedScopes =
|
||||||
{
|
{
|
||||||
"mobileshoppingagg"
|
"mobileshoppingagg"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Client
|
new Client
|
||||||
{
|
{
|
||||||
ClientId = "webshoppingaggswaggerui",
|
ClientId = "webshoppingaggswaggerui",
|
||||||
ClientName = "Web Shopping Aggregattor Swagger UI",
|
ClientName = "Web Shopping Aggregattor Swagger UI",
|
||||||
AllowedGrantTypes = GrantTypes.Implicit,
|
AllowedGrantTypes = GrantTypes.Implicit,
|
||||||
AllowAccessTokensViaBrowser = true,
|
AllowAccessTokensViaBrowser = true,
|
||||||
|
|
||||||
RedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/o2c.html" },
|
RedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/oauth2-redirect.html" },
|
||||||
PostLogoutRedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/" },
|
PostLogoutRedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/" },
|
||||||
|
|
||||||
AllowedScopes =
|
AllowedScopes =
|
||||||
{
|
{
|
||||||
"webshoppingagg"
|
"webshoppingagg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,220 +16,220 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public class ApplicationDbContextSeed
|
public class ApplicationDbContextSeed
|
||||||
{
|
{
|
||||||
private readonly IPasswordHasher<ApplicationUser> _passwordHasher = new PasswordHasher<ApplicationUser>();
|
private readonly IPasswordHasher<ApplicationUser> _passwordHasher = new PasswordHasher<ApplicationUser>();
|
||||||
|
|
||||||
public async Task SeedAsync(ApplicationDbContext context,IHostingEnvironment env,
|
public async Task SeedAsync(ApplicationDbContext context, IHostingEnvironment env,
|
||||||
ILogger<ApplicationDbContextSeed> logger, IOptions<AppSettings> settings,int? retry = 0)
|
ILogger<ApplicationDbContextSeed> logger, IOptions<AppSettings> settings, int? retry = 0)
|
||||||
{
|
{
|
||||||
int retryForAvaiability = retry.Value;
|
int retryForAvaiability = retry.Value;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var useCustomizationData = settings.Value.UseCustomizationData;
|
var useCustomizationData = settings.Value.UseCustomizationData;
|
||||||
var contentRootPath = env.ContentRootPath;
|
var contentRootPath = env.ContentRootPath;
|
||||||
var webroot = env.WebRootPath;
|
var webroot = env.WebRootPath;
|
||||||
|
|
||||||
if (!context.Users.Any())
|
if (!context.Users.Any())
|
||||||
{
|
{
|
||||||
context.Users.AddRange(useCustomizationData
|
context.Users.AddRange(useCustomizationData
|
||||||
? GetUsersFromFile(contentRootPath, logger)
|
? GetUsersFromFile(contentRootPath, logger)
|
||||||
: GetDefaultUser());
|
: GetDefaultUser());
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useCustomizationData)
|
if (useCustomizationData)
|
||||||
{
|
{
|
||||||
GetPreconfiguredImages(contentRootPath, webroot, logger);
|
GetPreconfiguredImages(contentRootPath, webroot, logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (retryForAvaiability < 10)
|
if (retryForAvaiability < 10)
|
||||||
{
|
{
|
||||||
retryForAvaiability++;
|
retryForAvaiability++;
|
||||||
|
|
||||||
logger.LogError(ex.Message,$"There is an error migrating data for ApplicationDbContext");
|
|
||||||
|
|
||||||
await SeedAsync(context,env,logger,settings, retryForAvaiability);
|
logger.LogError(ex.Message, $"There is an error migrating data for ApplicationDbContext");
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<ApplicationUser> GetUsersFromFile(string contentRootPath, ILogger logger)
|
await SeedAsync(context, env, logger, settings, retryForAvaiability);
|
||||||
{
|
}
|
||||||
string csvFileUsers = Path.Combine(contentRootPath, "Setup", "Users.csv");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!File.Exists(csvFileUsers))
|
private IEnumerable<ApplicationUser> GetUsersFromFile(string contentRootPath, ILogger logger)
|
||||||
{
|
{
|
||||||
return GetDefaultUser();
|
string csvFileUsers = Path.Combine(contentRootPath, "Setup", "Users.csv");
|
||||||
}
|
|
||||||
|
|
||||||
string[] csvheaders;
|
if (!File.Exists(csvFileUsers))
|
||||||
try
|
{
|
||||||
{
|
return GetDefaultUser();
|
||||||
string[] requiredHeaders = {
|
}
|
||||||
"cardholdername", "cardnumber", "cardtype", "city", "country",
|
|
||||||
"email", "expiration", "lastname", "name", "phonenumber",
|
|
||||||
"username", "zipcode", "state", "street", "securitynumber",
|
|
||||||
"normalizedemail", "normalizedusername", "password"
|
|
||||||
};
|
|
||||||
csvheaders = GetHeaders(requiredHeaders, csvFileUsers);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.LogError(ex.Message);
|
|
||||||
|
|
||||||
return GetDefaultUser();
|
string[] csvheaders;
|
||||||
}
|
try
|
||||||
|
{
|
||||||
|
string[] requiredHeaders = {
|
||||||
|
"cardholdername", "cardnumber", "cardtype", "city", "country",
|
||||||
|
"email", "expiration", "lastname", "name", "phonenumber",
|
||||||
|
"username", "zipcode", "state", "street", "securitynumber",
|
||||||
|
"normalizedemail", "normalizedusername", "password"
|
||||||
|
};
|
||||||
|
csvheaders = GetHeaders(requiredHeaders, csvFileUsers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex.Message);
|
||||||
|
|
||||||
List<ApplicationUser> users = File.ReadAllLines(csvFileUsers)
|
return GetDefaultUser();
|
||||||
.Skip(1) // skip header column
|
}
|
||||||
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
|
|
||||||
.SelectTry(column => CreateApplicationUser(column, csvheaders))
|
|
||||||
.OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
|
|
||||||
.Where(x => x != null)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return users;
|
List<ApplicationUser> users = File.ReadAllLines(csvFileUsers)
|
||||||
}
|
.Skip(1) // skip header column
|
||||||
|
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"))
|
||||||
|
.SelectTry(column => CreateApplicationUser(column, csvheaders))
|
||||||
|
.OnCaughtException(ex => { logger.LogError(ex.Message); return null; })
|
||||||
|
.Where(x => x != null)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
private ApplicationUser CreateApplicationUser(string[] column, string[] headers)
|
return users;
|
||||||
{
|
}
|
||||||
if (column.Count() != headers.Count())
|
|
||||||
{
|
|
||||||
throw new Exception($"column count '{column.Count()}' not the same as headers count'{headers.Count()}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
string cardtypeString = column[Array.IndexOf(headers, "cardtype")].Trim('"').Trim();
|
private ApplicationUser CreateApplicationUser(string[] column, string[] headers)
|
||||||
if (!int.TryParse(cardtypeString, out int cardtype))
|
{
|
||||||
{
|
if (column.Count() != headers.Count())
|
||||||
throw new Exception($"cardtype='{cardtypeString}' is not a number");
|
{
|
||||||
}
|
throw new Exception($"column count '{column.Count()}' not the same as headers count'{headers.Count()}'");
|
||||||
|
}
|
||||||
|
|
||||||
var user = new ApplicationUser
|
string cardtypeString = column[Array.IndexOf(headers, "cardtype")].Trim('"').Trim();
|
||||||
{
|
if (!int.TryParse(cardtypeString, out int cardtype))
|
||||||
CardHolderName = column[Array.IndexOf(headers, "cardholdername")].Trim('"').Trim(),
|
{
|
||||||
CardNumber = column[Array.IndexOf(headers, "cardnumber")].Trim('"').Trim(),
|
throw new Exception($"cardtype='{cardtypeString}' is not a number");
|
||||||
CardType = cardtype,
|
}
|
||||||
City = column[Array.IndexOf(headers, "city")].Trim('"').Trim(),
|
|
||||||
Country = column[Array.IndexOf(headers, "country")].Trim('"').Trim(),
|
|
||||||
Email = column[Array.IndexOf(headers, "email")].Trim('"').Trim(),
|
|
||||||
Expiration = column[Array.IndexOf(headers, "expiration")].Trim('"').Trim(),
|
|
||||||
Id = Guid.NewGuid().ToString(),
|
|
||||||
LastName = column[Array.IndexOf(headers, "lastname")].Trim('"').Trim(),
|
|
||||||
Name = column[Array.IndexOf(headers, "name")].Trim('"').Trim(),
|
|
||||||
PhoneNumber = column[Array.IndexOf(headers, "phonenumber")].Trim('"').Trim(),
|
|
||||||
UserName = column[Array.IndexOf(headers, "username")].Trim('"').Trim(),
|
|
||||||
ZipCode = column[Array.IndexOf(headers, "zipcode")].Trim('"').Trim(),
|
|
||||||
State = column[Array.IndexOf(headers, "state")].Trim('"').Trim(),
|
|
||||||
Street = column[Array.IndexOf(headers, "street")].Trim('"').Trim(),
|
|
||||||
SecurityNumber = column[Array.IndexOf(headers, "securitynumber")].Trim('"').Trim(),
|
|
||||||
NormalizedEmail = column[Array.IndexOf(headers, "normalizedemail")].Trim('"').Trim(),
|
|
||||||
NormalizedUserName = column[Array.IndexOf(headers, "normalizedusername")].Trim('"').Trim(),
|
|
||||||
SecurityStamp = Guid.NewGuid().ToString("D"),
|
|
||||||
PasswordHash = column[Array.IndexOf(headers, "password")].Trim('"').Trim(), // Note: This is the password
|
|
||||||
};
|
|
||||||
|
|
||||||
user.PasswordHash = _passwordHasher.HashPassword(user, user.PasswordHash);
|
var user = new ApplicationUser
|
||||||
|
{
|
||||||
|
CardHolderName = column[Array.IndexOf(headers, "cardholdername")].Trim('"').Trim(),
|
||||||
|
CardNumber = column[Array.IndexOf(headers, "cardnumber")].Trim('"').Trim(),
|
||||||
|
CardType = cardtype,
|
||||||
|
City = column[Array.IndexOf(headers, "city")].Trim('"').Trim(),
|
||||||
|
Country = column[Array.IndexOf(headers, "country")].Trim('"').Trim(),
|
||||||
|
Email = column[Array.IndexOf(headers, "email")].Trim('"').Trim(),
|
||||||
|
Expiration = column[Array.IndexOf(headers, "expiration")].Trim('"').Trim(),
|
||||||
|
Id = Guid.NewGuid().ToString(),
|
||||||
|
LastName = column[Array.IndexOf(headers, "lastname")].Trim('"').Trim(),
|
||||||
|
Name = column[Array.IndexOf(headers, "name")].Trim('"').Trim(),
|
||||||
|
PhoneNumber = column[Array.IndexOf(headers, "phonenumber")].Trim('"').Trim(),
|
||||||
|
UserName = column[Array.IndexOf(headers, "username")].Trim('"').Trim(),
|
||||||
|
ZipCode = column[Array.IndexOf(headers, "zipcode")].Trim('"').Trim(),
|
||||||
|
State = column[Array.IndexOf(headers, "state")].Trim('"').Trim(),
|
||||||
|
Street = column[Array.IndexOf(headers, "street")].Trim('"').Trim(),
|
||||||
|
SecurityNumber = column[Array.IndexOf(headers, "securitynumber")].Trim('"').Trim(),
|
||||||
|
NormalizedEmail = column[Array.IndexOf(headers, "normalizedemail")].Trim('"').Trim(),
|
||||||
|
NormalizedUserName = column[Array.IndexOf(headers, "normalizedusername")].Trim('"').Trim(),
|
||||||
|
SecurityStamp = Guid.NewGuid().ToString("D"),
|
||||||
|
PasswordHash = column[Array.IndexOf(headers, "password")].Trim('"').Trim(), // Note: This is the password
|
||||||
|
};
|
||||||
|
|
||||||
return user;
|
user.PasswordHash = _passwordHasher.HashPassword(user, user.PasswordHash);
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<ApplicationUser> GetDefaultUser()
|
return user;
|
||||||
{
|
}
|
||||||
var user =
|
|
||||||
new ApplicationUser()
|
|
||||||
{
|
|
||||||
CardHolderName = "DemoUser",
|
|
||||||
CardNumber = "4012888888881881",
|
|
||||||
CardType = 1,
|
|
||||||
City = "Redmond",
|
|
||||||
Country = "U.S.",
|
|
||||||
Email = "demouser@microsoft.com",
|
|
||||||
Expiration = "12/20",
|
|
||||||
Id = Guid.NewGuid().ToString(),
|
|
||||||
LastName = "DemoLastName",
|
|
||||||
Name = "DemoUser",
|
|
||||||
PhoneNumber = "1234567890",
|
|
||||||
UserName = "demouser@microsoft.com",
|
|
||||||
ZipCode = "98052",
|
|
||||||
State = "WA",
|
|
||||||
Street = "15703 NE 61st Ct",
|
|
||||||
SecurityNumber = "535",
|
|
||||||
NormalizedEmail = "DEMOUSER@MICROSOFT.COM",
|
|
||||||
NormalizedUserName = "DEMOUSER@MICROSOFT.COM",
|
|
||||||
SecurityStamp = Guid.NewGuid().ToString("D"),
|
|
||||||
};
|
|
||||||
|
|
||||||
user.PasswordHash = _passwordHasher.HashPassword(user, "Pass@word1");
|
private IEnumerable<ApplicationUser> GetDefaultUser()
|
||||||
|
{
|
||||||
|
var user =
|
||||||
|
new ApplicationUser()
|
||||||
|
{
|
||||||
|
CardHolderName = "DemoUser",
|
||||||
|
CardNumber = "4012888888881881",
|
||||||
|
CardType = 1,
|
||||||
|
City = "Redmond",
|
||||||
|
Country = "U.S.",
|
||||||
|
Email = "demouser@microsoft.com",
|
||||||
|
Expiration = "12/20",
|
||||||
|
Id = Guid.NewGuid().ToString(),
|
||||||
|
LastName = "DemoLastName",
|
||||||
|
Name = "DemoUser",
|
||||||
|
PhoneNumber = "1234567890",
|
||||||
|
UserName = "demouser@microsoft.com",
|
||||||
|
ZipCode = "98052",
|
||||||
|
State = "WA",
|
||||||
|
Street = "15703 NE 61st Ct",
|
||||||
|
SecurityNumber = "535",
|
||||||
|
NormalizedEmail = "DEMOUSER@MICROSOFT.COM",
|
||||||
|
NormalizedUserName = "DEMOUSER@MICROSOFT.COM",
|
||||||
|
SecurityStamp = Guid.NewGuid().ToString("D"),
|
||||||
|
};
|
||||||
|
|
||||||
return new List<ApplicationUser>()
|
user.PasswordHash = _passwordHasher.HashPassword(user, "Pass@word1");
|
||||||
{
|
|
||||||
user
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static string[] GetHeaders(string[] requiredHeaders, string csvfile)
|
return new List<ApplicationUser>()
|
||||||
{
|
{
|
||||||
string[] csvheaders = File.ReadLines(csvfile).First().ToLowerInvariant().Split(',');
|
user
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (csvheaders.Count() != requiredHeaders.Count())
|
static string[] GetHeaders(string[] requiredHeaders, string csvfile)
|
||||||
{
|
{
|
||||||
throw new Exception($"requiredHeader count '{ requiredHeaders.Count()}' is different then read header '{csvheaders.Count()}'");
|
string[] csvheaders = File.ReadLines(csvfile).First().ToLowerInvariant().Split(',');
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var requiredHeader in requiredHeaders)
|
if (csvheaders.Count() != requiredHeaders.Count())
|
||||||
{
|
{
|
||||||
if (!csvheaders.Contains(requiredHeader))
|
throw new Exception($"requiredHeader count '{ requiredHeaders.Count()}' is different then read header '{csvheaders.Count()}'");
|
||||||
{
|
}
|
||||||
throw new Exception($"does not contain required header '{requiredHeader}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return csvheaders;
|
foreach (var requiredHeader in requiredHeaders)
|
||||||
}
|
{
|
||||||
|
if (!csvheaders.Contains(requiredHeader))
|
||||||
|
{
|
||||||
|
throw new Exception($"does not contain required header '{requiredHeader}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void GetPreconfiguredImages(string contentRootPath, string webroot, ILogger logger)
|
return csvheaders;
|
||||||
{
|
}
|
||||||
try
|
|
||||||
{
|
|
||||||
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
|
|
||||||
if (!File.Exists(imagesZipFile))
|
|
||||||
{
|
|
||||||
logger.LogError($" zip file '{imagesZipFile}' does not exists.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string imagePath = Path.Combine(webroot, "images");
|
static void GetPreconfiguredImages(string contentRootPath, string webroot, ILogger logger)
|
||||||
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
|
||||||
|
if (!File.Exists(imagesZipFile))
|
||||||
|
{
|
||||||
|
logger.LogError($" zip file '{imagesZipFile}' does not exists.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
|
string imagePath = Path.Combine(webroot, "images");
|
||||||
{
|
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
|
||||||
foreach (ZipArchiveEntry entry in zip.Entries)
|
|
||||||
{
|
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
|
||||||
if (imageFiles.Contains(entry.Name))
|
{
|
||||||
{
|
foreach (ZipArchiveEntry entry in zip.Entries)
|
||||||
string destinationFilename = Path.Combine(imagePath, entry.Name);
|
{
|
||||||
if (File.Exists(destinationFilename))
|
if (imageFiles.Contains(entry.Name))
|
||||||
{
|
{
|
||||||
File.Delete(destinationFilename);
|
string destinationFilename = Path.Combine(imagePath, entry.Name);
|
||||||
}
|
if (File.Exists(destinationFilename))
|
||||||
entry.ExtractToFile(destinationFilename);
|
{
|
||||||
}
|
File.Delete(destinationFilename);
|
||||||
else
|
}
|
||||||
{
|
entry.ExtractToFile(destinationFilename);
|
||||||
logger.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
}
|
logger.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
}
|
||||||
logger.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
}
|
logger.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
using IdentityServer4.EntityFramework.DbContexts;
|
using IdentityServer4.EntityFramework.DbContexts;
|
||||||
|
using IdentityServer4.EntityFramework.Entities;
|
||||||
using IdentityServer4.EntityFramework.Mappers;
|
using IdentityServer4.EntityFramework.Mappers;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
|
using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -30,16 +33,37 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
{
|
{
|
||||||
foreach (var client in Config.GetClients(clientUrls))
|
foreach (var client in Config.GetClients(clientUrls))
|
||||||
{
|
{
|
||||||
await context.Clients.AddAsync(client.ToEntity());
|
context.Clients.Add(client.ToEntity());
|
||||||
}
|
}
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
// Checking always for old redirects to fix existing deployments
|
||||||
|
// to use new swagger-ui redirect uri as of v3.0.0
|
||||||
|
// There should be no problem for new ones
|
||||||
|
// ref: https://github.com/dotnet-architecture/eShopOnContainers/issues/586
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<ClientRedirectUri> oldRedirects = (await context.Clients.Include(c => c.RedirectUris).ToListAsync())
|
||||||
|
.SelectMany(c => c.RedirectUris)
|
||||||
|
.Where(ru => ru.RedirectUri.EndsWith("/o2c.html"))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (oldRedirects.Any())
|
||||||
|
{
|
||||||
|
foreach (var ru in oldRedirects)
|
||||||
|
{
|
||||||
|
ru.RedirectUri = ru.RedirectUri.Replace("/o2c.html", "/oauth2-redirect.html");
|
||||||
|
context.Update(ru.Client);
|
||||||
|
}
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!context.IdentityResources.Any())
|
if (!context.IdentityResources.Any())
|
||||||
{
|
{
|
||||||
foreach (var resource in Config.GetResources())
|
foreach (var resource in Config.GetResources())
|
||||||
{
|
{
|
||||||
await context.IdentityResources.AddAsync(resource.ToEntity());
|
context.IdentityResources.Add(resource.ToEntity());
|
||||||
}
|
}
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
@ -48,7 +72,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
|
|||||||
{
|
{
|
||||||
foreach (var api in Config.GetApis())
|
foreach (var api in Config.GetApis())
|
||||||
{
|
{
|
||||||
await context.ApiResources.AddAsync(api.ToEntity());
|
context.ApiResources.Add(api.ToEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
@ -1,12 +1,26 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS sdk-with-node
|
||||||
|
ENV NODE_VERSION 8.11.1
|
||||||
|
ENV NODE_DOWNLOAD_SHA 0e20787e2eda4cc31336d8327556ebc7417e8ee0a6ba0de96a09b0ec2b841f60
|
||||||
|
RUN curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \
|
||||||
|
&& echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \
|
||||||
|
&& tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \
|
||||||
|
&& rm nodejs.tar.gz \
|
||||||
|
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
|
||||||
|
|
||||||
|
FROM sdk-with-node AS updated-npm
|
||||||
|
RUN npm i -g npm
|
||||||
|
|
||||||
|
|
||||||
|
FROM updated-npm as build
|
||||||
|
RUN npm install -g bower@1.8.4
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Identity/Identity.API
|
WORKDIR /src/src/Services/Identity/Identity.API
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -1,62 +1,59 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
|
||||||
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
</PropertyGroup>
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Setup\**\*;">
|
<Content Include="Setup\**\*;">
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
|
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.1.1" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.1" />
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.3" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
|
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
|
||||||
<Exec Command="bower install --allow-root" />
|
<Exec Command="bower install --allow-root" />
|
||||||
<Exec Command="dotnet bundle" Condition="'$(ASPNETCORE_ENVIRONMENT)'!='Development'" />
|
<Exec Command="dotnet bundle" Condition="'$(ASPNETCORE_ENVIRONMENT)'!='Development'" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<DotNetCliToolReference Include="BundlerMinifier.Core" Version="2.5.357" />
|
<DotNetCliToolReference Include="BundlerMinifier.Core" Version="2.7.385" />
|
||||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
|
</ItemGroup>
|
||||||
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" />
|
|
||||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Certificate\idsrv3test.pfx" />
|
<EmbeddedResource Include="Certificate\idsrv3test.pfx" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Setup\*">
|
<None Update="Setup\*">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Extensions\" />
|
<Folder Include="Extensions\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -6,6 +6,7 @@ using Microsoft.ApplicationInsights.ServiceFabric;
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.eShopOnContainers.Services.Identity.API.Certificates;
|
using Microsoft.eShopOnContainers.Services.Identity.API.Certificates;
|
||||||
@ -22,162 +23,203 @@ using System.Reflection;
|
|||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Identity.API
|
namespace Microsoft.eShopOnContainers.Services.Identity.API
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
// 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 IServiceProvider ConfigureServices(IServiceCollection services)
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
RegisterAppInsights(services);
|
services.Configure<CookiePolicyOptions>(options =>
|
||||||
|
{
|
||||||
|
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
|
||||||
|
options.CheckConsentNeeded = context => true;
|
||||||
|
options.MinimumSameSitePolicy = SameSiteMode.None;
|
||||||
|
});
|
||||||
|
|
||||||
// Add framework services.
|
RegisterAppInsights(services);
|
||||||
services.AddDbContext<ApplicationDbContext>(options =>
|
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
|
||||||
{
|
|
||||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
|
||||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
|
||||||
}));
|
|
||||||
|
|
||||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
// Add framework services.
|
||||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
.AddDefaultTokenProviders();
|
options.UseSqlServer(Configuration["ConnectionString"],
|
||||||
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
}));
|
||||||
|
|
||||||
services.Configure<AppSettings>(Configuration);
|
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||||
|
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||||
|
.AddDefaultTokenProviders();
|
||||||
|
|
||||||
services.AddMvc();
|
services.Configure<AppSettings>(Configuration);
|
||||||
|
|
||||||
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
|
services
|
||||||
{
|
.AddMvc()
|
||||||
services.AddDataProtection(opts =>
|
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
|
||||||
{
|
|
||||||
opts.ApplicationDiscriminator = "eshop.identity";
|
|
||||||
})
|
|
||||||
.PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys");
|
|
||||||
}
|
|
||||||
|
|
||||||
services.AddHealthChecks(checks =>
|
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
|
||||||
{
|
{
|
||||||
var minutes = 1;
|
services.AddDataProtection(opts =>
|
||||||
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
|
{
|
||||||
{
|
opts.ApplicationDiscriminator = "eshop.identity";
|
||||||
minutes = minutesParsed;
|
})
|
||||||
}
|
.PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys");
|
||||||
checks.AddSqlCheck("Identity_Db", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
|
}
|
||||||
});
|
|
||||||
|
|
||||||
services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();
|
services.AddHealthChecks(checks =>
|
||||||
services.AddTransient<IRedirectService, RedirectService>();
|
{
|
||||||
|
var minutes = 1;
|
||||||
|
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
|
||||||
|
{
|
||||||
|
minutes = minutesParsed;
|
||||||
|
}
|
||||||
|
checks.AddSqlCheck("Identity_Db", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
|
||||||
|
});
|
||||||
|
|
||||||
var connectionString = Configuration["ConnectionString"];
|
services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();
|
||||||
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
|
services.AddTransient<IRedirectService, RedirectService>();
|
||||||
|
|
||||||
// Adds IdentityServer
|
var connectionString = Configuration["ConnectionString"];
|
||||||
services.AddIdentityServer(x => x.IssuerUri = "null")
|
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
|
||||||
.AddSigningCredential(Certificate.Get())
|
|
||||||
.AddAspNetIdentity<ApplicationUser>()
|
|
||||||
.AddConfigurationStore(options =>
|
|
||||||
{
|
|
||||||
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
|
||||||
{
|
|
||||||
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
|
||||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.AddOperationalStore(options =>
|
|
||||||
{
|
|
||||||
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
|
||||||
{
|
|
||||||
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
|
||||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.Services.AddTransient<IProfileService, ProfileService>();
|
|
||||||
|
|
||||||
var container = new ContainerBuilder();
|
services.AddCors(opt =>
|
||||||
container.Populate(services);
|
{
|
||||||
|
opt.AddDefaultPolicy(builder =>
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyOrigin()
|
||||||
|
.AllowCredentials();
|
||||||
|
});
|
||||||
|
opt.AddPolicy("default", builder =>
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyOrigin()
|
||||||
|
.AllowCredentials();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
return new AutofacServiceProvider(container.Build());
|
// Adds IdentityServer
|
||||||
}
|
services.AddIdentityServer(x =>
|
||||||
|
{
|
||||||
|
x.IssuerUri = Configuration["IdentityServer"];
|
||||||
|
x.Cors.CorsPolicyName = "default";
|
||||||
|
x.Cors.PreflightCacheDuration = TimeSpan.FromDays(10);
|
||||||
|
})
|
||||||
|
.AddSigningCredential(Certificate.Get())
|
||||||
|
.AddAspNetIdentity<ApplicationUser>()
|
||||||
|
.AddConfigurationStore(options =>
|
||||||
|
{
|
||||||
|
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
||||||
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
||||||
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.AddOperationalStore(options =>
|
||||||
|
{
|
||||||
|
options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString,
|
||||||
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(migrationsAssembly);
|
||||||
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.AddConfigurationStoreCache()
|
||||||
|
//.AddClientStoreCache()
|
||||||
|
//.AddCorsPolicyCache()
|
||||||
|
//.AddCorsPolicyService()
|
||||||
|
.Services.AddTransient<IProfileService, ProfileService>();
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
var container = new ContainerBuilder();
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
container.Populate(services);
|
||||||
{
|
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
|
||||||
loggerFactory.AddDebug();
|
|
||||||
loggerFactory.AddAzureWebAppDiagnostics();
|
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
return new AutofacServiceProvider(container.Build());
|
||||||
{
|
}
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
app.UseDatabaseErrorPage();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
app.UseExceptionHandler("/Home/Error");
|
|
||||||
}
|
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||||
app.UsePathBase(pathBase);
|
loggerFactory.AddDebug();
|
||||||
}
|
loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
app.UseDatabaseErrorPage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
app.UseExceptionHandler("/Home/Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
{
|
||||||
|
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
||||||
|
app.UsePathBase(pathBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
||||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
app.UseCookiePolicy();
|
||||||
|
|
||||||
|
|
||||||
// Make work identity server redirections in Edge and lastest versions of browers. WARN: Not valid in a production environment.
|
// Make work identity server redirections in Edge and lastest versions of browers. WARN: Not valid in a production environment.
|
||||||
app.Use(async (context, next) =>
|
app.Use(async (context, next) =>
|
||||||
{
|
{
|
||||||
context.Response.Headers.Add("Content-Security-Policy", "script-src 'unsafe-inline'");
|
context.Response.Headers.Add("Content-Security-Policy", "script-src 'unsafe-inline'");
|
||||||
await next();
|
await next();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Adds IdentityServer
|
app.UseCors();
|
||||||
app.UseIdentityServer();
|
// Adds IdentityServer
|
||||||
|
app.UseIdentityServer();
|
||||||
|
|
||||||
app.UseMvc(routes =>
|
app.UseMvc(routes =>
|
||||||
{
|
{
|
||||||
routes.MapRoute(
|
routes.MapRoute(
|
||||||
name: "default",
|
name: "default",
|
||||||
template: "{controller=Home}/{action=Index}/{id?}");
|
template: "{controller=Home}/{action=Index}/{id?}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterAppInsights(IServiceCollection services)
|
private void RegisterAppInsights(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddApplicationInsightsTelemetry(Configuration);
|
services.AddApplicationInsightsTelemetry(Configuration);
|
||||||
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
||||||
|
|
||||||
if (orchestratorType?.ToUpper() == "K8S")
|
if (orchestratorType?.ToUpper() == "K8S")
|
||||||
{
|
{
|
||||||
// Enable K8s telemetry initializer
|
// Enable K8s telemetry initializer
|
||||||
services.EnableKubernetes();
|
services.EnableKubernetes();
|
||||||
}
|
}
|
||||||
if (orchestratorType?.ToUpper() == "SF")
|
if (orchestratorType?.ToUpper() == "SF")
|
||||||
{
|
{
|
||||||
// Enable SF telemetry initializer
|
// Enable SF telemetry initializer
|
||||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||||
new FabricTelemetryInitializer());
|
new FabricTelemetryInitializer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
{
|
{
|
||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word;",
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word;",
|
||||||
"IsClusterEnv": "False",
|
"IsClusterEnv": "False",
|
||||||
"MvcClient": "http://localhost:5100",
|
"IdentityServer": "http://localhost:5105",
|
||||||
"SpaClient": "http://localhost:5104",
|
"MvcClient": "http://localhost:5100",
|
||||||
"XamarinCallback": "http://localhost:5105/xamarincallback",
|
"SpaClient": "http://localhost:5104",
|
||||||
"UseCustomizationData": false,
|
"XamarinCallback": "http://localhost:5105/xamarincallback",
|
||||||
"Logging": {
|
"UseCustomizationData": false,
|
||||||
"IncludeScopes": false,
|
"Logging": {
|
||||||
"LogLevel": {
|
"IncludeScopes": false,
|
||||||
"Default": "Trace",
|
"LogLevel": {
|
||||||
"System": "Information",
|
"Default": "Trace",
|
||||||
"Microsoft": "Information"
|
"System": "Information",
|
||||||
}
|
"Microsoft": "Information"
|
||||||
},
|
}
|
||||||
"ApplicationInsights": {
|
},
|
||||||
"InstrumentationKey": ""
|
"ApplicationInsights": {
|
||||||
}
|
"InstrumentationKey": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
14
src/Services/Identity/Identity.API/npm-shrinkwrap.json
generated
Normal file
14
src/Services/Identity/Identity.API/npm-shrinkwrap.json
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "asp.net",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"bower": {
|
||||||
|
"version": "1.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/bower/-/bower-1.8.4.tgz",
|
||||||
|
"integrity": "sha1-54dqB23rgTf30GUl3F6MZtuC8oo=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
src/Services/Identity/Identity.API/package.json
Normal file
8
src/Services/Identity/Identity.API/package.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"name": "asp.net",
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"bower": "^1.8.4"
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Location/Locations.API
|
WORKDIR /src/src/Services/Location/Locations.API
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
|
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.2.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.4.0" />
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
|
@ -45,7 +45,9 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
|
|||||||
services.AddMvc(options =>
|
services.AddMvc(options =>
|
||||||
{
|
{
|
||||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
}).AddControllersAsServices();
|
})
|
||||||
|
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1)
|
||||||
|
.AddControllersAsServices();
|
||||||
|
|
||||||
ConfigureAuthService(services);
|
ConfigureAuthService(services);
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Marketing/Marketing.API
|
WORKDIR /src/src/Services/Marketing/Marketing.API
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -1,56 +1,54 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
<RootNamespace>Microsoft.eShopOnContainers.Services.Marketing.API</RootNamespace>
|
<RootNamespace>Microsoft.eShopOnContainers.Services.Marketing.API</RootNamespace>
|
||||||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
||||||
<UserSecretsId>aspnet-Marketing.API-20161122013619</UserSecretsId>
|
<UserSecretsId>aspnet-Marketing.API-20161122013619</UserSecretsId>
|
||||||
<AssemblyName />
|
<AssemblyName />
|
||||||
<ApplicationInsightsResourceId>/subscriptions/6c22bb55-0221-4ce4-9bf1-3c4a10a7294c/resourcegroups/eshop-log/providers/microsoft.insights/components/eshopappinsights</ApplicationInsightsResourceId>
|
<ApplicationInsightsResourceId>/subscriptions/6c22bb55-0221-4ce4-9bf1-3c4a10a7294c/resourcegroups/eshop-log/providers/microsoft.insights/components/eshopappinsights</ApplicationInsightsResourceId>
|
||||||
<ApplicationInsightsAnnotationResourceId>/subscriptions/6c22bb55-0221-4ce4-9bf1-3c4a10a7294c/resourcegroups/eshop-log/providers/microsoft.insights/components/eshopappinsights</ApplicationInsightsAnnotationResourceId>
|
<ApplicationInsightsAnnotationResourceId>/subscriptions/6c22bb55-0221-4ce4-9bf1-3c4a10a7294c/resourcegroups/eshop-log/providers/microsoft.insights/components/eshopappinsights</ApplicationInsightsAnnotationResourceId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Connected Services\" />
|
<Folder Include="Connected Services\" />
|
||||||
<Folder Include="Infrastructure\MarketingMigrations\" />
|
<Folder Include="Infrastructure\MarketingMigrations\" />
|
||||||
<Content Include="Pics\**\*;">
|
<Content Include="Pics\**\*;">
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Folder Include="Infrastructure\MarketingMigrations\" />
|
<Folder Include="Infrastructure\MarketingMigrations\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
|
||||||
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />
|
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
|
||||||
<ItemGroup>
|
</ItemGroup>
|
||||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
|
<ItemGroup>
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
<ItemGroup>
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.AzureStorage\Microsoft.Extensions.HealthChecks.AzureStorage.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.AzureStorage\Microsoft.Extensions.HealthChecks.AzureStorage.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
</ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Pics\*">
|
<None Update="Pics\*">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<WCFMetadata Include="Connected Services" />
|
<WCFMetadata Include="Connected Services" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -53,7 +53,9 @@
|
|||||||
services.AddMvc(options =>
|
services.AddMvc(options =>
|
||||||
{
|
{
|
||||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
}).AddControllersAsServices(); //Injecting Controllers themselves thru DIFor further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
})
|
||||||
|
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1)
|
||||||
|
.AddControllersAsServices(); //Injecting Controllers themselves thru DIFor further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
||||||
|
|
||||||
services.Configure<MarketingSettings>(Configuration);
|
services.Configure<MarketingSettings>(Configuration);
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderCancelled
|
|||||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
|
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
|
||||||
|
_orderingIntegrationEventService = orderingIntegrationEventService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(OrderCancelledDomainEvent orderCancelledDomainEvent, CancellationToken cancellationToken)
|
public async Task Handle(OrderCancelledDomainEvent orderCancelledDomainEvent, CancellationToken cancellationToken)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries
|
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries
|
||||||
{
|
{
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -7,7 +8,7 @@
|
|||||||
{
|
{
|
||||||
Task<Order> GetOrderAsync(int id);
|
Task<Order> GetOrderAsync(int id);
|
||||||
|
|
||||||
Task<IEnumerable<OrderSummary>> GetOrdersAsync();
|
Task<IEnumerable<OrderSummary>> GetOrdersFromUserAsync(Guid userId);
|
||||||
|
|
||||||
Task<IEnumerable<CardType>> GetCardTypesAsync();
|
Task<IEnumerable<CardType>> GetCardTypesAsync();
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class OrderQueries
|
public class OrderQueries
|
||||||
:IOrderQueries
|
: IOrderQueries
|
||||||
{
|
{
|
||||||
private string _connectionString = string.Empty;
|
private string _connectionString = string.Empty;
|
||||||
|
|
||||||
@ -42,18 +42,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<OrderSummary>> GetOrdersAsync()
|
public async Task<IEnumerable<OrderSummary>> GetOrdersFromUserAsync(Guid userId)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(_connectionString))
|
using (var connection = new SqlConnection(_connectionString))
|
||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
return await connection.QueryAsync<OrderSummary>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status],SUM(oi.units*oi.unitprice) as total
|
return await connection.QueryAsync<OrderSummary>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status], SUM(oi.units*oi.unitprice) as total
|
||||||
FROM [ordering].[Orders] o
|
FROM [ordering].[Orders] o
|
||||||
LEFT JOIN[ordering].[orderitems] oi ON o.Id = oi.orderid
|
LEFT JOIN[ordering].[orderitems] oi ON o.Id = oi.orderid
|
||||||
LEFT JOIN[ordering].[orderstatus] os on o.OrderStatusId = os.Id
|
LEFT JOIN[ordering].[orderstatus] os on o.OrderStatusId = os.Id
|
||||||
|
LEFT JOIN[ordering].[buyers] ob on o.BuyerId = ob.Id
|
||||||
|
WHERE ob.IdentityGuid = @userId
|
||||||
GROUP BY o.[Id], o.[OrderDate], os.[Name]
|
GROUP BY o.[Id], o.[OrderDate], os.[Name]
|
||||||
ORDER BY o.[Id]");
|
ORDER BY o.[Id]", new { userId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
using Ordering.API.Application.Commands;
|
using Ordering.API.Application.Commands;
|
||||||
using Ordering.API.Application.Models;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@ -15,6 +14,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
|
|||||||
{
|
{
|
||||||
[Route("api/v1/[controller]")]
|
[Route("api/v1/[controller]")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
public class OrdersController : Controller
|
public class OrdersController : Controller
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
@ -87,8 +87,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
|
|||||||
[ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)]
|
||||||
public async Task<IActionResult> GetOrders()
|
public async Task<IActionResult> GetOrders()
|
||||||
{
|
{
|
||||||
var orders = await _orderQueries.GetOrdersAsync();
|
var userid = _identityService.GetUserIdentity();
|
||||||
|
var orders = await _orderQueries.GetOrdersFromUserAsync(Guid.Parse(userid));
|
||||||
return Ok(orders);
|
return Ok(orders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Ordering/Ordering.API
|
WORKDIR /src/src/Services/Ordering/Ordering.API
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
using AspNetCore.Mvc;
|
using AspNetCore.Mvc;
|
||||||
using global::Ordering.Domain.Exceptions;
|
using global::Ordering.Domain.Exceptions;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -25,16 +26,18 @@
|
|||||||
context.Exception,
|
context.Exception,
|
||||||
context.Exception.Message);
|
context.Exception.Message);
|
||||||
|
|
||||||
if (context.Exception.GetType() == typeof(OrderingDomainException))
|
if (context.Exception.GetType() == typeof(OrderingDomainException))
|
||||||
{
|
{
|
||||||
var json = new JsonErrorResponse
|
var problemDetails = new ValidationProblemDetails()
|
||||||
{
|
{
|
||||||
Messages = new[] { context.Exception.Message }
|
Instance = context.HttpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest,
|
||||||
|
Detail = "Please refer to the errors property for additional details."
|
||||||
};
|
};
|
||||||
|
|
||||||
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
problemDetails.Errors.Add("DomainValidations", new string[] { context.Exception.Message.ToString() });
|
||||||
//It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
|
||||||
context.Result = new BadRequestObjectResult(json);
|
context.Result = new BadRequestObjectResult(problemDetails);
|
||||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -52,7 +55,7 @@
|
|||||||
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
||||||
// It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
// It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
||||||
context.Result = new InternalServerErrorObjectResult(json);
|
context.Result = new InternalServerErrorObjectResult(json);
|
||||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||||
}
|
}
|
||||||
context.ExceptionHandled = true;
|
context.ExceptionHandled = true;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<UserSecretsId>aspnet-Ordering.API-20161122013547</UserSecretsId>
|
<UserSecretsId>aspnet-Ordering.API-20161122013547</UserSecretsId>
|
||||||
<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>
|
||||||
@ -30,26 +30,22 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.0" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="4.0.0" />
|
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
|
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
|
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
|
||||||
<PackageReference Include="MediatR" Version="4.0.1" />
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />
|
|
||||||
<PackageReference Include="System.Reflection" Version="4.3.0" />
|
|
||||||
<PackageReference Include="Dapper" Version="1.50.4" />
|
<PackageReference Include="Dapper" Version="1.50.4" />
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
|
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.0" />
|
||||||
<PackageReference Include="Polly" Version="5.8.0" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.1" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
|
<PackageReference Include="MediatR" Version="4.1.0" />
|
||||||
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Polly" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
|
||||||
|
<PackageReference Include="System.Reflection" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Setup\*">
|
<None Update="Setup\*">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
public string EventBusConnection { get; set; }
|
public string EventBusConnection { get; set; }
|
||||||
|
|
||||||
public int GracePeriodTime { get; set; }
|
|
||||||
|
|
||||||
public int CheckUpdateTime { get; set; }
|
public int CheckUpdateTime { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Azure.ServiceBus;
|
using Microsoft.Azure.ServiceBus;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||||
@ -47,144 +48,15 @@
|
|||||||
|
|
||||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
RegisterAppInsights(services);
|
services.AddApplicationInsights(Configuration)
|
||||||
|
.AddCustomMvc()
|
||||||
// Add framework services.
|
.AddHealthChecks(Configuration)
|
||||||
services.AddMvc(options =>
|
.AddCustomDbContext(Configuration)
|
||||||
{
|
.AddCustomSwagger(Configuration)
|
||||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
.AddCustomIntegrations(Configuration)
|
||||||
}).AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
.AddCustomConfiguration(Configuration)
|
||||||
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
.AddEventBus(Configuration)
|
||||||
|
.AddCustomAuthentication(Configuration);
|
||||||
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
|
||||||
|
|
||||||
services.AddHealthChecks(checks =>
|
|
||||||
{
|
|
||||||
var minutes = 1;
|
|
||||||
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
|
|
||||||
{
|
|
||||||
minutes = minutesParsed;
|
|
||||||
}
|
|
||||||
checks.AddSqlCheck("OrderingDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddEntityFrameworkSqlServer()
|
|
||||||
.AddDbContext<OrderingContext>(options =>
|
|
||||||
{
|
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
|
||||||
{
|
|
||||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
ServiceLifetime.Scoped //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request)
|
|
||||||
);
|
|
||||||
|
|
||||||
services.AddDbContext<IntegrationEventLogContext>(options =>
|
|
||||||
{
|
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
|
||||||
{
|
|
||||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
|
||||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
|
||||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
services.Configure<OrderingSettings>(Configuration);
|
|
||||||
|
|
||||||
services.AddSwaggerGen(options =>
|
|
||||||
{
|
|
||||||
options.DescribeAllEnumsAsStrings();
|
|
||||||
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
|
||||||
{
|
|
||||||
Title = "Ordering HTTP API",
|
|
||||||
Version = "v1",
|
|
||||||
Description = "The Ordering Service HTTP API",
|
|
||||||
TermsOfService = "Terms Of Service"
|
|
||||||
});
|
|
||||||
|
|
||||||
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
|
||||||
{
|
|
||||||
Type = "oauth2",
|
|
||||||
Flow = "implicit",
|
|
||||||
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
|
||||||
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
|
||||||
Scopes = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "orders", "Ordering API" }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddCors(options =>
|
|
||||||
{
|
|
||||||
options.AddPolicy("CorsPolicy",
|
|
||||||
builder => builder.AllowAnyOrigin()
|
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowCredentials());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add application services.
|
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
|
||||||
services.AddTransient<IIdentityService, IdentityService>();
|
|
||||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
|
||||||
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
|
||||||
|
|
||||||
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
|
||||||
|
|
||||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
|
||||||
{
|
|
||||||
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
|
||||||
{
|
|
||||||
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
|
||||||
|
|
||||||
var serviceBusConnectionString = Configuration["EventBusConnection"];
|
|
||||||
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
|
||||||
|
|
||||||
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
|
||||||
{
|
|
||||||
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
|
||||||
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory()
|
|
||||||
{
|
|
||||||
HostName = Configuration["EventBusConnection"]
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
|
|
||||||
{
|
|
||||||
factory.UserName = Configuration["EventBusUserName"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
|
|
||||||
{
|
|
||||||
factory.Password = Configuration["EventBusPassword"];
|
|
||||||
}
|
|
||||||
|
|
||||||
var retryCount = 5;
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
|
||||||
{
|
|
||||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
RegisterEventBus(services);
|
|
||||||
ConfigureAuthService(services);
|
|
||||||
services.AddOptions();
|
|
||||||
|
|
||||||
//configure autofac
|
//configure autofac
|
||||||
|
|
||||||
@ -200,8 +72,6 @@
|
|||||||
|
|
||||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
|
||||||
loggerFactory.AddDebug();
|
|
||||||
loggerFactory.AddAzureWebAppDiagnostics();
|
loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
@ -219,7 +89,7 @@
|
|||||||
app.UseCors("CorsPolicy");
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
ConfigureAuth(app);
|
ConfigureAuth(app);
|
||||||
|
|
||||||
app.UseMvcWithDefaultRoute();
|
app.UseMvcWithDefaultRoute();
|
||||||
|
|
||||||
app.UseSwagger()
|
app.UseSwagger()
|
||||||
@ -233,23 +103,6 @@
|
|||||||
ConfigureEventBus(app);
|
ConfigureEventBus(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterAppInsights(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddApplicationInsightsTelemetry(Configuration);
|
|
||||||
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
|
||||||
|
|
||||||
if (orchestratorType?.ToUpper() == "K8S")
|
|
||||||
{
|
|
||||||
// Enable K8s telemetry initializer
|
|
||||||
services.EnableKubernetes();
|
|
||||||
}
|
|
||||||
if (orchestratorType?.ToUpper() == "SF")
|
|
||||||
{
|
|
||||||
// Enable SF telemetry initializer
|
|
||||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
|
||||||
new FabricTelemetryInitializer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConfigureEventBus(IApplicationBuilder app)
|
private void ConfigureEventBus(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
@ -263,25 +116,6 @@
|
|||||||
eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>>();
|
eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigureAuthService(IServiceCollection services)
|
|
||||||
{
|
|
||||||
// prevent from mapping "sub" claim to nameidentifier.
|
|
||||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
|
|
||||||
|
|
||||||
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
|
||||||
|
|
||||||
services.AddAuthentication(options =>
|
|
||||||
{
|
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
|
|
||||||
}).AddJwtBearer(options =>
|
|
||||||
{
|
|
||||||
options.Authority = identityUrl;
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.Audience = "orders";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
@ -292,19 +126,221 @@
|
|||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void RegisterEventBus(IServiceCollection services)
|
static class CustomExtensionsMethods
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddApplicationInsights(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
var subscriptionClientName = Configuration["SubscriptionClientName"];
|
services.AddApplicationInsightsTelemetry(configuration);
|
||||||
|
var orchestratorType = configuration.GetValue<string>("OrchestratorType");
|
||||||
|
|
||||||
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
if (orchestratorType?.ToUpper() == "K8S")
|
||||||
|
{
|
||||||
|
// Enable K8s telemetry initializer
|
||||||
|
services.EnableKubernetes();
|
||||||
|
}
|
||||||
|
if (orchestratorType?.ToUpper() == "SF")
|
||||||
|
{
|
||||||
|
// Enable SF telemetry initializer
|
||||||
|
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||||
|
new FabricTelemetryInitializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
// Add framework services.
|
||||||
|
services.AddMvc(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
|
})
|
||||||
|
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
|
||||||
|
.AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
||||||
|
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddHealthChecks(checks =>
|
||||||
|
{
|
||||||
|
var minutes = 1;
|
||||||
|
if (int.TryParse(configuration["HealthCheck:Timeout"], out var minutesParsed))
|
||||||
|
{
|
||||||
|
minutes = minutesParsed;
|
||||||
|
}
|
||||||
|
checks.AddSqlCheck("OrderingDb", configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddEntityFrameworkSqlServer()
|
||||||
|
.AddDbContext<OrderingContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseSqlServer(configuration["ConnectionString"],
|
||||||
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ServiceLifetime.Scoped //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request)
|
||||||
|
);
|
||||||
|
|
||||||
|
services.AddDbContext<IntegrationEventLogContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseSqlServer(configuration["ConnectionString"],
|
||||||
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomSwagger(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.DescribeAllEnumsAsStrings();
|
||||||
|
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
||||||
|
{
|
||||||
|
Title = "Ordering HTTP API",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "The Ordering Service HTTP API",
|
||||||
|
TermsOfService = "Terms Of Service"
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
||||||
|
{
|
||||||
|
Type = "oauth2",
|
||||||
|
Flow = "implicit",
|
||||||
|
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
||||||
|
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
||||||
|
Scopes = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "orders", "Ordering API" }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomIntegrations(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
services.AddTransient<IIdentityService, IdentityService>();
|
||||||
|
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||||
|
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
||||||
|
|
||||||
|
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
||||||
|
|
||||||
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||||
|
{
|
||||||
|
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
||||||
|
|
||||||
|
var serviceBusConnectionString = configuration["EventBusConnection"];
|
||||||
|
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
||||||
|
|
||||||
|
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
||||||
|
{
|
||||||
|
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
||||||
|
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory()
|
||||||
|
{
|
||||||
|
HostName = configuration["EventBusConnection"]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusUserName"]))
|
||||||
|
{
|
||||||
|
factory.UserName = configuration["EventBusUserName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusPassword"]))
|
||||||
|
{
|
||||||
|
factory.Password = configuration["EventBusPassword"];
|
||||||
|
}
|
||||||
|
|
||||||
|
var retryCount = 5;
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomConfiguration(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
services.Configure<OrderingSettings>(configuration);
|
||||||
|
services.Configure<ApiBehaviorOptions>(options =>
|
||||||
|
{
|
||||||
|
options.InvalidModelStateResponseFactory = context =>
|
||||||
|
{
|
||||||
|
var problemDetails = new ValidationProblemDetails(context.ModelState)
|
||||||
|
{
|
||||||
|
Instance = context.HttpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest,
|
||||||
|
Detail = "Please refer to the errors property for additional details."
|
||||||
|
};
|
||||||
|
|
||||||
|
return new BadRequestObjectResult(problemDetails)
|
||||||
|
{
|
||||||
|
ContentTypes = { "application/problem+json", "application/problem+xml" }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var subscriptionClientName = configuration["SubscriptionClientName"];
|
||||||
|
|
||||||
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
{
|
{
|
||||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||||
{
|
{
|
||||||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
||||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
||||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
||||||
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
||||||
@ -320,9 +356,9 @@
|
|||||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
var retryCount = 5;
|
var retryCount = 5;
|
||||||
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
{
|
{
|
||||||
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||||
@ -330,6 +366,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
// prevent from mapping "sub" claim to nameidentifier.
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
|
||||||
|
|
||||||
|
var identityUrl = configuration.GetValue<string>("IdentityUrl");
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
|
||||||
|
}).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = identityUrl;
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.Audience = "orders";
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
{
|
{
|
||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://localhost:5105",
|
||||||
"UseCustomizationData": false,
|
"UseCustomizationData": false,
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": false,
|
"IncludeScopes": false,
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Trace",
|
"Default": "Trace",
|
||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AzureServiceBusEnabled": false,
|
"AzureServiceBusEnabled": false,
|
||||||
"SubscriptionClientName": "Ordering",
|
"SubscriptionClientName": "Ordering",
|
||||||
"GracePeriodTime": "1",
|
"CheckUpdateTime": "30000",
|
||||||
"CheckUpdateTime": "30000",
|
"ApplicationInsights": {
|
||||||
"ApplicationInsights": {
|
"InstrumentationKey": ""
|
||||||
"InstrumentationKey": ""
|
},
|
||||||
},
|
"EventBusRetryCount": 5,
|
||||||
"EventBusRetryCount": 5,
|
"EventBusConnection": "localhost"
|
||||||
"EventBusConnection": "localhost"
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks
|
WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</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>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="wwwroot\" />
|
<Compile Remove="wwwroot\**" />
|
||||||
|
<Content Remove="wwwroot\**" />
|
||||||
|
<EmbeddedResource Remove="wwwroot\**" />
|
||||||
|
<None Remove="wwwroot\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Dapper" Version="1.50.4" />
|
<PackageReference Include="Dapper" Version="1.50.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -110,7 +110,7 @@ namespace Ordering.BackgroundTasks
|
|||||||
|
|
||||||
|
|
||||||
// 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.
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHostingEnvironment env)
|
||||||
{
|
{
|
||||||
|
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
FROM microsoft/aspnetcore:2.0 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY eShopOnContainers-ServicesAndWebApps.sln ./
|
|
||||||
COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/
|
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
COPY . .
|
COPY . .
|
||||||
WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub
|
WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub
|
||||||
RUN dotnet build Ordering.SignalrHub.csproj -c Release -o /app
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
|
RUN dotnet build --no-restore Ordering.SignalrHub.csproj -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
RUN dotnet publish Ordering.SignalrHub.csproj -c Release -o /app
|
RUN dotnet publish --no-restore Ordering.SignalrHub.csproj -c Release -o /app
|
||||||
|
|
||||||
FROM base AS final
|
FROM base AS final
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
@ -13,13 +13,13 @@ namespace Ordering.SignalrHub
|
|||||||
|
|
||||||
public override async Task OnConnectedAsync()
|
public override async Task OnConnectedAsync()
|
||||||
{
|
{
|
||||||
await Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);
|
await Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
|
||||||
await base.OnConnectedAsync();
|
await base.OnConnectedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnDisconnectedAsync(Exception ex)
|
public override async Task OnDisconnectedAsync(Exception ex)
|
||||||
{
|
{
|
||||||
await Groups.RemoveAsync(Context.ConnectionId, Context.User.Identity.Name);
|
await Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
|
||||||
await base.OnDisconnectedAsync(ex);
|
await base.OnDisconnectedAsync(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,31 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="wwwroot\" />
|
<Folder Include="wwwroot\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0-preview2-final" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.0.0-preview2-final" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Redis" Version="1.0.0-preview2-final" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Redis" Version="1.0.2" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.1" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
|
</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" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -46,13 +46,6 @@ namespace Ordering.SignalrHub
|
|||||||
services
|
services
|
||||||
.AddSignalR()
|
.AddSignalR()
|
||||||
.AddRedis(Configuration["SignalrStoreConnectionString"]);
|
.AddRedis(Configuration["SignalrStoreConnectionString"]);
|
||||||
|
|
||||||
//services
|
|
||||||
// .AddSignalR()
|
|
||||||
// .AddRedis(options => options.Factory = writer =>
|
|
||||||
// {
|
|
||||||
// return ConnectionMultiplexer.Connect(Configuration["SignalrStoreConnectionString"], writer);
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -141,7 +134,7 @@ namespace Ordering.SignalrHub
|
|||||||
app.UseSignalR(routes =>
|
app.UseSignalR(routes =>
|
||||||
{
|
{
|
||||||
routes.MapHub<NotificationsHub>("/notificationhub", options =>
|
routes.MapHub<NotificationsHub>("/notificationhub", options =>
|
||||||
options.Transports = Microsoft.AspNetCore.Http.Connections.TransportType.All);
|
options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransports.All);
|
||||||
});
|
});
|
||||||
|
|
||||||
ConfigureEventBus(app);
|
ConfigureEventBus(app);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Services/Payment/Payment.API
|
WORKDIR /src/src/Services/Payment/Payment.API
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -1,30 +1,28 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.0" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta6" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
|
||||||
<ItemGroup>
|
</ItemGroup>
|
||||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
|
<ItemGroup>
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
<ItemGroup>
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" />
|
</ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"directory": "wwwroot/lib"
|
"directory": "wwwroot/lib",
|
||||||
|
"registry": "https://registry.bower.io"
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
|||||||
{
|
{
|
||||||
public class AppSettings
|
public class AppSettings
|
||||||
{
|
{
|
||||||
public Connectionstrings ConnectionStrings { get; set; }
|
//public Connectionstrings ConnectionStrings { get; set; }
|
||||||
public string MarketingUrl { get; set; }
|
public string MarketingUrl { get; set; }
|
||||||
|
|
||||||
public string PurchaseUrl { get; set; }
|
public string PurchaseUrl { get; set; }
|
||||||
public string SignalrHubUrl { get; set; }
|
public string SignalrHubUrl { get; set; }
|
||||||
public bool ActivateCampaignDetailFunction { get; set; }
|
public bool ActivateCampaignDetailFunction { get; set; }
|
||||||
|
@ -71,7 +71,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
{
|
{
|
||||||
var user = _appUserParser.Parse(HttpContext.User);
|
var user = _appUserParser.Parse(HttpContext.User);
|
||||||
await _basketSvc.AddItemToBasket(user, productDetails.Id);
|
await _basketSvc.AddItemToBasket(user, productDetails.Id);
|
||||||
//await _basketSvc.AddItemToBasket(user, product);
|
|
||||||
}
|
}
|
||||||
return RedirectToAction("Index", "Catalog");
|
return RedirectToAction("Index", "Catalog");
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
using System;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using System.Net.Http;
|
|
||||||
using Polly.CircuitBreaker;
|
using Polly.CircuitBreaker;
|
||||||
using WebMVC.Models;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||||
{
|
{
|
||||||
@ -52,11 +47,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(BrokenCircuitException)
|
catch (BrokenCircuitException)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
|
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
|
||||||
}
|
}
|
||||||
return View("Create", model);
|
|
||||||
|
return View("Create", model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> Cancel(string orderId)
|
public async Task<IActionResult> Cancel(string orderId)
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using System;
|
using Newtonsoft.Json;
|
||||||
using System.Collections.Generic;
|
using System.Net.Http;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace WebMVC.Controllers
|
namespace WebMVC.Controllers
|
||||||
@ -14,6 +11,7 @@ namespace WebMVC.Controllers
|
|||||||
class TestPayload
|
class TestPayload
|
||||||
{
|
{
|
||||||
public int CatalogItemId { get; set; }
|
public int CatalogItemId { get; set; }
|
||||||
|
|
||||||
public string BasketId { get; set; }
|
public string BasketId { get; set; }
|
||||||
|
|
||||||
public int Quantity { get; set; }
|
public int Quantity { get; set; }
|
||||||
@ -22,9 +20,10 @@ namespace WebMVC.Controllers
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class TestController : Controller
|
public class TestController : Controller
|
||||||
{
|
{
|
||||||
private readonly IHttpClient _client;
|
private readonly IHttpClientFactory _client;
|
||||||
private readonly IIdentityParser<ApplicationUser> _appUserParser;
|
private readonly IIdentityParser<ApplicationUser> _appUserParser;
|
||||||
public TestController(IHttpClient client, IIdentityParser<ApplicationUser> identityParser)
|
|
||||||
|
public TestController(IHttpClientFactory client, IIdentityParser<ApplicationUser> identityParser)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_appUserParser = identityParser;
|
_appUserParser = identityParser;
|
||||||
@ -33,18 +32,24 @@ namespace WebMVC.Controllers
|
|||||||
public async Task<IActionResult> Ocelot()
|
public async Task<IActionResult> Ocelot()
|
||||||
{
|
{
|
||||||
var url = "http://apigw/shopping/api/v1/basket/items";
|
var url = "http://apigw/shopping/api/v1/basket/items";
|
||||||
|
|
||||||
var payload = new TestPayload()
|
var payload = new TestPayload()
|
||||||
{
|
{
|
||||||
CatalogItemId = 1,
|
CatalogItemId = 1,
|
||||||
Quantity = 1,
|
Quantity = 1,
|
||||||
BasketId = _appUserParser.Parse(User).Id
|
BasketId = _appUserParser.Parse(User).Id
|
||||||
};
|
};
|
||||||
var token = await HttpContext.GetTokenAsync("access_token");
|
|
||||||
var response = await _client.PostAsync<TestPayload>(url, payload, token);
|
var content = new StringContent(JsonConvert.SerializeObject(payload), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
|
||||||
|
var response = await _client.CreateClient(nameof(IBasketService))
|
||||||
|
.PostAsync(url, content);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
var str = await response.Content.ReadAsStringAsync();
|
var str = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
return Ok(str);
|
return Ok(str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1,12 +1,25 @@
|
|||||||
FROM microsoft/aspnetcore:2.0.5 AS base
|
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
|
FROM microsoft/dotnet:2.1-sdk AS sdk-with-node
|
||||||
|
ENV NODE_VERSION 8.11.1
|
||||||
|
ENV NODE_DOWNLOAD_SHA 0e20787e2eda4cc31336d8327556ebc7417e8ee0a6ba0de96a09b0ec2b841f60
|
||||||
|
RUN curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \
|
||||||
|
&& echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \
|
||||||
|
&& tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \
|
||||||
|
&& rm nodejs.tar.gz \
|
||||||
|
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
|
||||||
|
|
||||||
|
FROM sdk-with-node AS updated-npm
|
||||||
|
RUN npm i -g npm
|
||||||
|
|
||||||
|
FROM updated-npm as build
|
||||||
|
RUN npm install -g bower@1.8.4
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN dotnet restore -nowarn:msb3202,nu1503
|
|
||||||
WORKDIR /src/src/Web/WebMVC
|
WORKDIR /src/src/Web/WebMVC
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
RUN dotnet build --no-restore -c Release -o /app
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebMVC.Infrastructure
|
||||||
|
{
|
||||||
|
public class HttpClientAuthorizationDelegatingHandler
|
||||||
|
: DelegatingHandler
|
||||||
|
{
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccesor;
|
||||||
|
|
||||||
|
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)
|
||||||
|
{
|
||||||
|
_httpContextAccesor = httpContextAccesor;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var authorizationHeader = _httpContextAccesor.HttpContext
|
||||||
|
.Request.Headers["Authorization"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(authorizationHeader))
|
||||||
|
{
|
||||||
|
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = await GetToken();
|
||||||
|
|
||||||
|
if (token != null)
|
||||||
|
{
|
||||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await base.SendAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<string> GetToken()
|
||||||
|
{
|
||||||
|
const string ACCESS_TOKEN = "access_token";
|
||||||
|
|
||||||
|
return await _httpContextAccesor.HttpContext
|
||||||
|
.GetTokenAsync(ACCESS_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebMVC.Infrastructure
|
||||||
|
{
|
||||||
|
public class HttpClientRequestIdDelegatingHandler
|
||||||
|
: DelegatingHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
public HttpClientRequestIdDelegatingHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (request.Method == HttpMethod.Post || request.Method == HttpMethod.Put)
|
||||||
|
{
|
||||||
|
request.Headers.Add("x-requestid", Guid.NewGuid().ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return await base.SendAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
|
||||||
{
|
|
||||||
public interface IResilientHttpClientFactory
|
|
||||||
{
|
|
||||||
ResilientHttpClient CreateResilientHttpClient();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Polly;
|
|
||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
|
|
||||||
{
|
|
||||||
public class ResilientHttpClientFactory : IResilientHttpClientFactory
|
|
||||||
{
|
|
||||||
private readonly ILogger<ResilientHttpClient> _logger;
|
|
||||||
private readonly int _retryCount;
|
|
||||||
private readonly int _exceptionsAllowedBeforeBreaking;
|
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
||||||
|
|
||||||
public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
|
|
||||||
_retryCount = retryCount;
|
|
||||||
_httpContextAccessor = httpContextAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ResilientHttpClient CreateResilientHttpClient()
|
|
||||||
=> new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor);
|
|
||||||
|
|
||||||
private Policy[] CreatePolicies()
|
|
||||||
=> new Policy[]
|
|
||||||
{
|
|
||||||
Policy.Handle<HttpRequestException>()
|
|
||||||
.WaitAndRetryAsync(
|
|
||||||
// number of retries
|
|
||||||
_retryCount,
|
|
||||||
// exponential backofff
|
|
||||||
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
|
||||||
// on retry
|
|
||||||
(exception, timeSpan, retryCount, context) =>
|
|
||||||
{
|
|
||||||
var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
|
|
||||||
$"of {context.PolicyKey} " +
|
|
||||||
$"at {context.ExecutionKey}, " +
|
|
||||||
$"due to: {exception}.";
|
|
||||||
_logger.LogWarning(msg);
|
|
||||||
_logger.LogDebug(msg);
|
|
||||||
}),
|
|
||||||
Policy.Handle<HttpRequestException>()
|
|
||||||
.CircuitBreakerAsync(
|
|
||||||
// number of exceptions before breaking circuit
|
|
||||||
_exceptionsAllowedBeforeBreaking,
|
|
||||||
// time circuit opened before retry
|
|
||||||
TimeSpan.FromMinutes(1),
|
|
||||||
(exception, duration) =>
|
|
||||||
{
|
|
||||||
// on circuit opened
|
|
||||||
_logger.LogTrace("Circuit breaker opened");
|
|
||||||
},
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
// on circuit closed
|
|
||||||
_logger.LogTrace("Circuit breaker reset");
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,8 +17,8 @@ namespace WebMVC.Infrastructure
|
|||||||
{
|
{
|
||||||
var log = loggerFactory.CreateLogger("WebMVC seed");
|
var log = loggerFactory.CreateLogger("WebMVC seed");
|
||||||
|
|
||||||
var settings = (AppSettings)applicationBuilder
|
var settings = applicationBuilder
|
||||||
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
|
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
|
||||||
|
|
||||||
var useCustomizationData = settings.UseCustomizationData;
|
var useCustomizationData = settings.UseCustomizationData;
|
||||||
var contentRootPath = env.ContentRootPath;
|
var contentRootPath = env.ContentRootPath;
|
||||||
@ -66,9 +66,9 @@ namespace WebMVC.Infrastructure
|
|||||||
string imagePath = Path.Combine(webroot, "images");
|
string imagePath = Path.Combine(webroot, "images");
|
||||||
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
|
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
|
||||||
|
|
||||||
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
|
using (var zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
|
||||||
{
|
{
|
||||||
foreach (ZipArchiveEntry entry in zip.Entries)
|
foreach (var entry in zip.Entries)
|
||||||
{
|
{
|
||||||
if (imageFiles.Contains(entry.Name))
|
if (imageFiles.Contains(entry.Name))
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
},
|
||||||
|
"use64Bit": true
|
||||||
},
|
},
|
||||||
"Microsoft.eShopOnContainers.WebMVC": {
|
"Microsoft.eShopOnContainers.WebMVC": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
using WebMVC.Models;
|
using WebMVC.Models;
|
||||||
@ -14,42 +12,40 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class BasketService : IBasketService
|
public class BasketService : IBasketService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _apiClient;
|
||||||
private readonly string _basketByPassUrl;
|
private readonly string _basketByPassUrl;
|
||||||
private readonly string _purchaseUrl;
|
private readonly string _purchaseUrl;
|
||||||
private readonly IHttpContextAccessor _httpContextAccesor;
|
|
||||||
|
|
||||||
private readonly string _bffUrl;
|
private readonly string _bffUrl;
|
||||||
|
|
||||||
public BasketService(IOptionsSnapshot<AppSettings> settings,
|
public BasketService(HttpClient httpClient, IOptions<AppSettings> settings)
|
||||||
IHttpContextAccessor httpContextAccesor, IHttpClient httpClient)
|
|
||||||
{
|
{
|
||||||
|
_apiClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
|
||||||
_basketByPassUrl = $"{_settings.Value.PurchaseUrl}/api/v1/b/basket";
|
_basketByPassUrl = $"{_settings.Value.PurchaseUrl}/api/v1/b/basket";
|
||||||
_purchaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1";
|
_purchaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1";
|
||||||
_httpContextAccesor = httpContextAccesor;
|
|
||||||
_apiClient = httpClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Basket> GetBasket(ApplicationUser user)
|
public async Task<Basket> GetBasket(ApplicationUser user)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Basket.GetBasket(_basketByPassUrl, user.Id);
|
||||||
var getBasketUri = API.Basket.GetBasket(_basketByPassUrl, user.Id);
|
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(getBasketUri, token);
|
var responseString = await _apiClient.GetStringAsync(uri);
|
||||||
|
|
||||||
return string.IsNullOrEmpty(dataString) ?
|
return string.IsNullOrEmpty(responseString) ?
|
||||||
new Basket() { BuyerId = user.Id} :
|
new Basket() { BuyerId = user.Id } :
|
||||||
JsonConvert.DeserializeObject<Basket>(dataString);
|
JsonConvert.DeserializeObject<Basket>(responseString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Basket> UpdateBasket(Basket basket)
|
public async Task<Basket> UpdateBasket(Basket basket)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Basket.UpdateBasket(_basketByPassUrl);
|
||||||
var updateBasketUri = API.Basket.UpdateBasket(_basketByPassUrl);
|
|
||||||
|
|
||||||
var response = await _apiClient.PostAsync(updateBasketUri, basket, token);
|
var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
var response = await _apiClient.PostAsync(uri, basketContent);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
@ -58,65 +54,64 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task Checkout(BasketDTO basket)
|
public async Task Checkout(BasketDTO basket)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Basket.CheckoutBasket(_basketByPassUrl);
|
||||||
var updateBasketUri = API.Basket.CheckoutBasket(_basketByPassUrl);
|
var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var response = await _apiClient.PostAsync(updateBasketUri, basket, token);
|
var response = await _apiClient.PostAsync(uri, basketContent);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities)
|
public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities)
|
||||||
{
|
{
|
||||||
|
var uri = API.Purchase.UpdateBasketItem(_purchaseUrl);
|
||||||
|
|
||||||
var token = await GetUserTokenAsync();
|
var basketUpdate = new
|
||||||
var updateBasketUri = API.Purchase.UpdateBasketItem(_purchaseUrl);
|
|
||||||
var userId = user.Id;
|
|
||||||
|
|
||||||
var response = await _apiClient.PutAsync(updateBasketUri, new
|
|
||||||
{
|
{
|
||||||
BasketId = userId,
|
BasketId = user.Id,
|
||||||
Updates = quantities.Select(kvp => new
|
Updates = quantities.Select(kvp => new
|
||||||
{
|
{
|
||||||
BasketItemId = kvp.Key,
|
BasketItemId = kvp.Key,
|
||||||
NewQty = kvp.Value
|
NewQty = kvp.Value
|
||||||
}).ToArray()
|
}).ToArray()
|
||||||
}, token);
|
};
|
||||||
|
|
||||||
|
var basketContent = new StringContent(JsonConvert.SerializeObject(basketUpdate), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
var response = await _apiClient.PutAsync(uri, basketContent);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
return JsonConvert.DeserializeObject<Basket>(jsonResponse);
|
return JsonConvert.DeserializeObject<Basket>(jsonResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Order> GetOrderDraft(string basketId)
|
public async Task<Order> GetOrderDraft(string basketId)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
|
||||||
var draftOrderUri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
|
|
||||||
var json = await _apiClient.GetStringAsync(draftOrderUri, token);
|
var responseString = await _apiClient.GetStringAsync(uri);
|
||||||
return JsonConvert.DeserializeObject<Order>(json);
|
|
||||||
|
var response = JsonConvert.DeserializeObject<Order>(responseString);
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task AddItemToBasket(ApplicationUser user, int productId)
|
public async Task AddItemToBasket(ApplicationUser user, int productId)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Purchase.AddItemToBasket(_purchaseUrl);
|
||||||
var updateBasketUri = API.Purchase.AddItemToBasket(_purchaseUrl);
|
|
||||||
var userId = user.Id;
|
|
||||||
|
|
||||||
var response = await _apiClient.PostAsync(updateBasketUri, new
|
var newItem = new
|
||||||
{
|
{
|
||||||
CatalogItemId = productId,
|
CatalogItemId = productId,
|
||||||
BasketId = userId,
|
BasketId = user.Id,
|
||||||
Quantity = 1
|
Quantity = 1
|
||||||
}, token);
|
};
|
||||||
|
|
||||||
}
|
var basketContent = new StringContent(JsonConvert.SerializeObject(newItem), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
async Task<string> GetUserTokenAsync()
|
var response = await _apiClient.PostAsync(uri, basketContent);
|
||||||
{
|
|
||||||
var context = _httpContextAccesor.HttpContext;
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,69 +1,49 @@
|
|||||||
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||||
{
|
{
|
||||||
using global::WebMVC.Infrastructure;
|
using global::WebMVC.Infrastructure;
|
||||||
using AspNetCore.Authentication;
|
|
||||||
using AspNetCore.Http;
|
|
||||||
using BuildingBlocks.Resilience.Http;
|
|
||||||
using ViewModels;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ViewModels;
|
||||||
|
|
||||||
public class CampaignService : ICampaignService
|
public class CampaignService : ICampaignService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<CampaignService> _logger;
|
private readonly ILogger<CampaignService> _logger;
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
private readonly IHttpContextAccessor _httpContextAccesor;
|
|
||||||
|
|
||||||
public CampaignService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient,
|
public CampaignService(IOptions<AppSettings> settings, HttpClient httpClient, ILogger<CampaignService> logger)
|
||||||
ILogger<CampaignService> logger, IHttpContextAccessor httpContextAccesor)
|
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_apiClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/";
|
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/";
|
||||||
_httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Campaign> GetCampaigns(int pageSize, int pageIndex)
|
public async Task<Campaign> GetCampaigns(int pageSize, int pageIndex)
|
||||||
{
|
{
|
||||||
var allCampaignItemsUri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl,
|
var uri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl, pageSize, pageIndex);
|
||||||
pageSize, pageIndex);
|
|
||||||
|
|
||||||
var authorizationToken = await GetUserTokenAsync();
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
var dataString = await _apiClient.GetStringAsync(allCampaignItemsUri, authorizationToken);
|
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<Campaign>(dataString);
|
var response = JsonConvert.DeserializeObject<Campaign>(responseString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CampaignItem> GetCampaignById(int id)
|
public async Task<CampaignItem> GetCampaignById(int id)
|
||||||
{
|
{
|
||||||
var campaignByIdItemUri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
|
var uri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
|
||||||
|
|
||||||
var authorizationToken = await GetUserTokenAsync();
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
var dataString = await _apiClient.GetStringAsync(campaignByIdItemUri, authorizationToken);
|
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<CampaignItem>(dataString);
|
var response = JsonConvert.DeserializeObject<CampaignItem>(responseString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetUserIdentity()
|
|
||||||
{
|
|
||||||
return _httpContextAccesor.HttpContext.User.FindFirst("sub").Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetUserTokenAsync()
|
|
||||||
{
|
|
||||||
var context = _httpContextAccesor.HttpContext;
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
|
|
||||||
@ -13,16 +13,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class CatalogService : ICatalogService
|
public class CatalogService : ICatalogService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<CatalogService> _logger;
|
private readonly ILogger<CatalogService> _logger;
|
||||||
|
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
|
|
||||||
public CatalogService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient, ILogger<CatalogService> logger)
|
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<AppSettings> settings)
|
||||||
{
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_apiClient = httpClient;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1/c/catalog/";
|
_remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1/c/catalog/";
|
||||||
@ -30,25 +30,26 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task<Catalog> GetCatalogItems(int page, int take, int? brand, int? type)
|
public async Task<Catalog> GetCatalogItems(int page, int take, int? brand, int? type)
|
||||||
{
|
{
|
||||||
var allcatalogItemsUri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type);
|
var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type);
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(allcatalogItemsUri);
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<Catalog>(dataString);
|
var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
|
||||||
|
|
||||||
return response;
|
return catalog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SelectListItem>> GetBrands()
|
public async Task<IEnumerable<SelectListItem>> GetBrands()
|
||||||
{
|
{
|
||||||
var getBrandsUri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl);
|
var uri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl);
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(getBrandsUri);
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
|
|
||||||
var items = new List<SelectListItem>();
|
var items = new List<SelectListItem>();
|
||||||
|
|
||||||
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
|
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
|
||||||
|
|
||||||
var brands = JArray.Parse(dataString);
|
var brands = JArray.Parse(responseString);
|
||||||
|
|
||||||
foreach (var brand in brands.Children<JObject>())
|
foreach (var brand in brands.Children<JObject>())
|
||||||
{
|
{
|
||||||
@ -64,14 +65,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public async Task<IEnumerable<SelectListItem>> GetTypes()
|
public async Task<IEnumerable<SelectListItem>> GetTypes()
|
||||||
{
|
{
|
||||||
var getTypesUri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl);
|
var uri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl);
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(getTypesUri);
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
|
|
||||||
var items = new List<SelectListItem>();
|
var items = new List<SelectListItem>();
|
||||||
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
|
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
|
||||||
|
|
||||||
var brands = JArray.Parse(dataString);
|
var brands = JArray.Parse(responseString);
|
||||||
foreach (var brand in brands.Children<JObject>())
|
foreach (var brand in brands.Children<JObject>())
|
||||||
{
|
{
|
||||||
items.Add(new SelectListItem()
|
items.Add(new SelectListItem()
|
||||||
@ -80,6 +81,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
Text = brand.Value<string>("type")
|
Text = brand.Value<string>("type")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,37 +8,36 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||||
{
|
{
|
||||||
public class IdentityParser:IIdentityParser<ApplicationUser>
|
public class IdentityParser : IIdentityParser<ApplicationUser>
|
||||||
{
|
{
|
||||||
public ApplicationUser Parse(IPrincipal principal)
|
public ApplicationUser Parse(IPrincipal principal)
|
||||||
{
|
{
|
||||||
// Pattern matching 'is' expression
|
// Pattern matching 'is' expression
|
||||||
// assigns "claims" if "principal" is a "ClaimsPrincipal"
|
// assigns "claims" if "principal" is a "ClaimsPrincipal"
|
||||||
if (principal is ClaimsPrincipal claims)
|
if (principal is ClaimsPrincipal claims)
|
||||||
{
|
{
|
||||||
return new ApplicationUser
|
return new ApplicationUser
|
||||||
{
|
{
|
||||||
|
CardHolderName = claims.Claims.FirstOrDefault(x => x.Type == "card_holder")?.Value ?? "",
|
||||||
CardHolderName = claims.Claims.FirstOrDefault(x => x.Type == "card_holder")?.Value ?? "",
|
CardNumber = claims.Claims.FirstOrDefault(x => x.Type == "card_number")?.Value ?? "",
|
||||||
CardNumber = claims.Claims.FirstOrDefault(x => x.Type == "card_number")?.Value ?? "",
|
Expiration = claims.Claims.FirstOrDefault(x => x.Type == "card_expiration")?.Value ?? "",
|
||||||
Expiration = claims.Claims.FirstOrDefault(x => x.Type == "card_expiration")?.Value ?? "",
|
CardType = int.Parse(claims.Claims.FirstOrDefault(x => x.Type == "missing")?.Value ?? "0"),
|
||||||
CardType = int.Parse(claims.Claims.FirstOrDefault(x => x.Type == "missing")?.Value ?? "0"),
|
City = claims.Claims.FirstOrDefault(x => x.Type == "address_city")?.Value ?? "",
|
||||||
City = claims.Claims.FirstOrDefault(x => x.Type == "address_city")?.Value ?? "",
|
Country = claims.Claims.FirstOrDefault(x => x.Type == "address_country")?.Value ?? "",
|
||||||
Country = claims.Claims.FirstOrDefault(x => x.Type == "address_country")?.Value ?? "",
|
Email = claims.Claims.FirstOrDefault(x => x.Type == "email")?.Value ?? "",
|
||||||
Email = claims.Claims.FirstOrDefault(x => x.Type == "email")?.Value ?? "",
|
Id = claims.Claims.FirstOrDefault(x => x.Type == "sub")?.Value ?? "",
|
||||||
Id = claims.Claims.FirstOrDefault(x => x.Type == "sub")?.Value ?? "",
|
LastName = claims.Claims.FirstOrDefault(x => x.Type == "last_name")?.Value ?? "",
|
||||||
LastName = claims.Claims.FirstOrDefault(x => x.Type == "last_name")?.Value ?? "",
|
Name = claims.Claims.FirstOrDefault(x => x.Type == "name")?.Value ?? "",
|
||||||
Name = claims.Claims.FirstOrDefault(x => x.Type == "name")?.Value ?? "",
|
PhoneNumber = claims.Claims.FirstOrDefault(x => x.Type == "phone_number")?.Value ?? "",
|
||||||
PhoneNumber = claims.Claims.FirstOrDefault(x => x.Type == "phone_number")?.Value ?? "",
|
SecurityNumber = claims.Claims.FirstOrDefault(x => x.Type == "card_security_number")?.Value ?? "",
|
||||||
SecurityNumber = claims.Claims.FirstOrDefault(x => x.Type == "card_security_number")?.Value ?? "",
|
State = claims.Claims.FirstOrDefault(x => x.Type == "address_state")?.Value ?? "",
|
||||||
State = claims.Claims.FirstOrDefault(x => x.Type == "address_state")?.Value ?? "",
|
Street = claims.Claims.FirstOrDefault(x => x.Type == "address_street")?.Value ?? "",
|
||||||
Street = claims.Claims.FirstOrDefault(x => x.Type == "address_street")?.Value ?? "",
|
ZipCode = claims.Claims.FirstOrDefault(x => x.Type == "address_zip_code")?.Value ?? ""
|
||||||
ZipCode = claims.Claims.FirstOrDefault(x => x.Type == "address_zip_code")?.Value ?? ""
|
};
|
||||||
};
|
}
|
||||||
}
|
throw new ArgumentException(message: "The principal must be a ClaimsPrincipal", paramName: nameof(principal));
|
||||||
throw new ArgumentException(message: "The principal must be a ClaimsPrincipal", paramName: nameof(principal));
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.eShopOnContainers.WebMVC;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System;
|
using Newtonsoft.Json;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
using WebMVC.Models;
|
using WebMVC.Models;
|
||||||
@ -14,36 +12,27 @@ namespace WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class LocationService : ILocationService
|
public class LocationService : ILocationService
|
||||||
{
|
{
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpClient _apiClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<CampaignService> _logger;
|
private readonly ILogger<CampaignService> _logger;
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
private readonly IHttpContextAccessor _httpContextAccesor;
|
|
||||||
|
|
||||||
public LocationService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient,
|
public LocationService(HttpClient httpClient, IOptions<AppSettings> settings, ILogger<CampaignService> logger)
|
||||||
ILogger<CampaignService> logger, IHttpContextAccessor httpContextAccesor)
|
|
||||||
{
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_apiClient = httpClient;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/l/locations/";
|
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/l/locations/";
|
||||||
_httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateOrUpdateUserLocation(LocationDTO location)
|
public async Task CreateOrUpdateUserLocation(LocationDTO location)
|
||||||
{
|
{
|
||||||
var createOrUpdateUserLocationUri = API.Locations.CreateOrUpdateUserLocation(_remoteServiceBaseUrl);
|
var uri = API.Locations.CreateOrUpdateUserLocation(_remoteServiceBaseUrl);
|
||||||
|
var locationContent = new StringContent(JsonConvert.SerializeObject(location), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var authorizationToken = await GetUserTokenAsync();
|
var response = await _httpClient.PostAsync(uri, locationContent);
|
||||||
var response = await _apiClient.PostAsync(createOrUpdateUserLocationUri, location, authorizationToken);
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetUserTokenAsync()
|
|
||||||
{
|
|
||||||
var context = _httpContextAccesor.HttpContext;
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
using WebMVC.Models;
|
using WebMVC.Models;
|
||||||
@ -14,69 +12,54 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
{
|
{
|
||||||
public class OrderingService : IOrderingService
|
public class OrderingService : IOrderingService
|
||||||
{
|
{
|
||||||
private IHttpClient _apiClient;
|
private HttpClient _httpClient;
|
||||||
private readonly string _remoteServiceBaseUrl;
|
private readonly string _remoteServiceBaseUrl;
|
||||||
private readonly IOptionsSnapshot<AppSettings> _settings;
|
private readonly IOptions<AppSettings> _settings;
|
||||||
private readonly IHttpContextAccessor _httpContextAccesor;
|
|
||||||
|
|
||||||
public OrderingService(IOptionsSnapshot<AppSettings> settings, IHttpContextAccessor httpContextAccesor, IHttpClient httpClient)
|
|
||||||
|
public OrderingService(HttpClient httpClient, IOptions<AppSettings> settings)
|
||||||
{
|
{
|
||||||
_remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders";
|
_httpClient = httpClient;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_httpContextAccesor = httpContextAccesor;
|
|
||||||
_apiClient = httpClient;
|
_remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders";
|
||||||
}
|
}
|
||||||
|
|
||||||
async public Task<Order> GetOrder(ApplicationUser user, string id)
|
async public Task<Order> GetOrder(ApplicationUser user, string id)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Order.GetOrder(_remoteServiceBaseUrl, id);
|
||||||
var getOrderUri = API.Order.GetOrder(_remoteServiceBaseUrl, id);
|
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(getOrderUri, token);
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<Order>(dataString);
|
var response = JsonConvert.DeserializeObject<Order>(responseString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async public Task<List<Order>> GetMyOrders(ApplicationUser user)
|
async public Task<List<Order>> GetMyOrders(ApplicationUser user)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
var uri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl);
|
||||||
var allMyOrdersUri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl);
|
|
||||||
|
|
||||||
var dataString = await _apiClient.GetStringAsync(allMyOrdersUri, token);
|
var responseString = await _httpClient.GetStringAsync(uri);
|
||||||
var response = JsonConvert.DeserializeObject<List<Order>>(dataString);
|
|
||||||
|
var response = JsonConvert.DeserializeObject<List<Order>>(responseString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
|
|
||||||
{
|
|
||||||
order.City = user.City;
|
|
||||||
order.Street = user.Street;
|
|
||||||
order.State = user.State;
|
|
||||||
order.Country = user.Country;
|
|
||||||
order.ZipCode = user.ZipCode;
|
|
||||||
|
|
||||||
order.CardNumber = user.CardNumber;
|
|
||||||
order.CardHolderName = user.CardHolderName;
|
|
||||||
order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1);
|
|
||||||
order.CardSecurityNumber = user.SecurityNumber;
|
|
||||||
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
|
|
||||||
async public Task CancelOrder(string orderId)
|
async public Task CancelOrder(string orderId)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
|
||||||
var order = new OrderDTO()
|
var order = new OrderDTO()
|
||||||
{
|
{
|
||||||
OrderNumber = orderId
|
OrderNumber = orderId
|
||||||
};
|
};
|
||||||
|
|
||||||
var cancelOrderUri = API.Order.CancelOrder(_remoteServiceBaseUrl);
|
var uri = API.Order.CancelOrder(_remoteServiceBaseUrl);
|
||||||
|
var orderContent = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json");
|
||||||
var response = await _apiClient.PutAsync(cancelOrderUri, order, token, Guid.NewGuid().ToString());
|
|
||||||
|
var response = await _httpClient.PutAsync(uri, orderContent);
|
||||||
|
|
||||||
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
||||||
{
|
{
|
||||||
@ -88,15 +71,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
async public Task ShipOrder(string orderId)
|
async public Task ShipOrder(string orderId)
|
||||||
{
|
{
|
||||||
var token = await GetUserTokenAsync();
|
|
||||||
var order = new OrderDTO()
|
var order = new OrderDTO()
|
||||||
{
|
{
|
||||||
OrderNumber = orderId
|
OrderNumber = orderId
|
||||||
};
|
};
|
||||||
|
|
||||||
var shipOrderUri = API.Order.ShipOrder(_remoteServiceBaseUrl);
|
var uri = API.Order.ShipOrder(_remoteServiceBaseUrl);
|
||||||
|
var orderContent = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var response = await _apiClient.PutAsync(shipOrderUri, order, token, Guid.NewGuid().ToString());
|
var response = await _httpClient.PutAsync(uri, orderContent);
|
||||||
|
|
||||||
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
||||||
{
|
{
|
||||||
@ -120,6 +103,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
destination.CardSecurityNumber = original.CardSecurityNumber;
|
destination.CardSecurityNumber = original.CardSecurityNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
|
||||||
|
{
|
||||||
|
order.City = user.City;
|
||||||
|
order.Street = user.Street;
|
||||||
|
order.State = user.State;
|
||||||
|
order.Country = user.Country;
|
||||||
|
order.ZipCode = user.ZipCode;
|
||||||
|
|
||||||
|
order.CardNumber = user.CardNumber;
|
||||||
|
order.CardHolderName = user.CardHolderName;
|
||||||
|
order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1);
|
||||||
|
order.CardSecurityNumber = user.SecurityNumber;
|
||||||
|
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
public BasketDTO MapOrderToBasket(Order order)
|
public BasketDTO MapOrderToBasket(Order order)
|
||||||
{
|
{
|
||||||
order.CardExpirationApiFormat();
|
order.CardExpirationApiFormat();
|
||||||
@ -140,18 +139,5 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
RequestId = order.RequestId
|
RequestId = order.RequestId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFakeIdToProducts(Order order)
|
|
||||||
{
|
|
||||||
var id = 1;
|
|
||||||
order.OrderItems.ForEach(x => { x.ProductId = id; id++; });
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task<string> GetUserTokenAsync()
|
|
||||||
{
|
|
||||||
var context = _httpContextAccesor.HttpContext;
|
|
||||||
|
|
||||||
return await context.GetTokenAsync("access_token");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,214 +1,289 @@
|
|||||||
using Microsoft.ApplicationInsights.Extensibility;
|
using Microsoft.ApplicationInsights.Extensibility;
|
||||||
using Microsoft.ApplicationInsights.ServiceFabric;
|
using Microsoft.ApplicationInsights.ServiceFabric;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Infrastructure;
|
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.HealthChecks;
|
using Microsoft.Extensions.HealthChecks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Polly;
|
||||||
|
using Polly.Extensions.Http;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using System;
|
using System;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Net.Http;
|
||||||
using WebMVC.Infrastructure;
|
using WebMVC.Infrastructure;
|
||||||
using WebMVC.Infrastructure.Middlewares;
|
using WebMVC.Infrastructure.Middlewares;
|
||||||
using WebMVC.Services;
|
using WebMVC.Services;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC
|
namespace Microsoft.eShopOnContainers.WebMVC
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
// 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 IoC container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
RegisterAppInsights(services);
|
services.Configure<CookiePolicyOptions>(options =>
|
||||||
|
{
|
||||||
|
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
|
||||||
|
options.CheckConsentNeeded = context => true;
|
||||||
|
options.MinimumSameSitePolicy = SameSiteMode.None;
|
||||||
|
});
|
||||||
|
services.AddAppInsight(Configuration)
|
||||||
|
.AddHealthChecks(Configuration)
|
||||||
|
.AddCustomMvc(Configuration)
|
||||||
|
.AddHttpClientServices(Configuration)
|
||||||
|
.AddHttpClientLogging(Configuration) //Opt-in HttpClientLogging config
|
||||||
|
.AddCustomAuthentication(Configuration);
|
||||||
|
}
|
||||||
|
|
||||||
services.AddMvc();
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||||
|
|
||||||
services.AddSession();
|
loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
services.AddDataProtection(opts =>
|
app.UseDeveloperExceptionPage();
|
||||||
{
|
}
|
||||||
opts.ApplicationDiscriminator = "eshop.webmvc";
|
else
|
||||||
})
|
{
|
||||||
.PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys");
|
app.UseExceptionHandler("/Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
services.Configure<AppSettings>(Configuration);
|
app.UseCookiePolicy();
|
||||||
|
|
||||||
services.AddHealthChecks(checks =>
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
{
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
var minutes = 1;
|
{
|
||||||
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
|
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
||||||
{
|
app.UsePathBase(pathBase);
|
||||||
minutes = minutesParsed;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
checks.AddUrlCheck(Configuration["CatalogUrlHC"], TimeSpan.FromMinutes(minutes));
|
|
||||||
checks.AddUrlCheck(Configuration["OrderingUrlHC"], TimeSpan.FromMinutes(minutes));
|
|
||||||
checks.AddUrlCheck(Configuration["BasketUrlHC"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
|
|
||||||
checks.AddUrlCheck(Configuration["IdentityUrlHC"], TimeSpan.FromMinutes(minutes));
|
|
||||||
checks.AddUrlCheck(Configuration["MarketingUrlHC"], TimeSpan.FromMinutes(minutes));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add application services.
|
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
|
||||||
services.AddTransient<ICatalogService, CatalogService>();
|
|
||||||
services.AddTransient<IOrderingService, OrderingService>();
|
|
||||||
services.AddTransient<IBasketService, BasketService>();
|
|
||||||
services.AddTransient<ICampaignService, CampaignService>();
|
|
||||||
services.AddTransient<ILocationService, LocationService>();
|
|
||||||
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
|
|
||||||
|
|
||||||
if (Configuration.GetValue<string>("UseResilientHttp") == bool.TrueString)
|
|
||||||
{
|
|
||||||
services.AddSingleton<IResilientHttpClientFactory, ResilientHttpClientFactory>(sp =>
|
|
||||||
{
|
|
||||||
var logger = sp.GetRequiredService<ILogger<ResilientHttpClient>>();
|
|
||||||
var httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
|
|
||||||
|
|
||||||
var retryCount = 6;
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["HttpClientRetryCount"]))
|
|
||||||
{
|
|
||||||
retryCount = int.Parse(Configuration["HttpClientRetryCount"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var exceptionsAllowedBeforeBreaking = 5;
|
|
||||||
if (!string.IsNullOrEmpty(Configuration["HttpClientExceptionsAllowedBeforeBreaking"]))
|
|
||||||
{
|
|
||||||
exceptionsAllowedBeforeBreaking = int.Parse(Configuration["HttpClientExceptionsAllowedBeforeBreaking"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ResilientHttpClientFactory(logger, httpContextAccessor, exceptionsAllowedBeforeBreaking, retryCount);
|
|
||||||
});
|
|
||||||
services.AddSingleton<IHttpClient, ResilientHttpClient>(sp => sp.GetService<IResilientHttpClientFactory>().CreateResilientHttpClient());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.AddSingleton<IHttpClient, StandardHttpClient>();
|
|
||||||
}
|
|
||||||
var useLoadTest = Configuration.GetValue<bool>("UseLoadTest");
|
|
||||||
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
|
||||||
var callBackUrl = Configuration.GetValue<string>("CallBackUrl");
|
|
||||||
|
|
||||||
// Add Authentication services
|
|
||||||
|
|
||||||
services.AddAuthentication(options => {
|
|
||||||
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
|
||||||
})
|
|
||||||
.AddCookie()
|
|
||||||
.AddOpenIdConnect(options => {
|
|
||||||
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
|
||||||
options.Authority = identityUrl.ToString();
|
|
||||||
options.SignedOutRedirectUri = callBackUrl.ToString();
|
|
||||||
options.ClientId = useLoadTest ? "mvctest" : "mvc";
|
|
||||||
options.ClientSecret = "secret";
|
|
||||||
options.ResponseType = useLoadTest ? "code id_token token" : "code id_token";
|
|
||||||
options.SaveTokens = true;
|
|
||||||
options.GetClaimsFromUserInfoEndpoint = true;
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.Scope.Add("openid");
|
|
||||||
options.Scope.Add("profile");
|
|
||||||
options.Scope.Add("orders");
|
|
||||||
options.Scope.Add("basket");
|
|
||||||
options.Scope.Add("marketing");
|
|
||||||
options.Scope.Add("locations");
|
|
||||||
options.Scope.Add("webshoppingagg");
|
|
||||||
options.Scope.Add("orders.signalrhub");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
|
||||||
|
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
|
||||||
loggerFactory.AddDebug();
|
|
||||||
loggerFactory.AddAzureWebAppDiagnostics();
|
|
||||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
app.UseBrowserLink();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
app.UseExceptionHandler("/Error");
|
|
||||||
}
|
|
||||||
|
|
||||||
var pathBase = Configuration["PATH_BASE"];
|
|
||||||
if (!string.IsNullOrEmpty(pathBase))
|
|
||||||
{
|
|
||||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
|
|
||||||
app.UsePathBase(pathBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
|
||||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||||
|
|
||||||
app.UseSession();
|
app.UseSession();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
if (Configuration.GetValue<bool>("UseLoadTest"))
|
if (Configuration.GetValue<bool>("UseLoadTest"))
|
||||||
{
|
{
|
||||||
app.UseMiddleware<ByPassAuthMiddleware>();
|
app.UseMiddleware<ByPassAuthMiddleware>();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseAuthentication();
|
|
||||||
|
|
||||||
var log = loggerFactory.CreateLogger("identity");
|
app.UseAuthentication();
|
||||||
|
|
||||||
WebContextSeed.Seed(app, env, loggerFactory);
|
var log = loggerFactory.CreateLogger("identity");
|
||||||
|
|
||||||
app.UseMvc(routes =>
|
WebContextSeed.Seed(app, env, loggerFactory);
|
||||||
{
|
|
||||||
routes.MapRoute(
|
|
||||||
name: "default",
|
|
||||||
template: "{controller=Catalog}/{action=Index}/{id?}");
|
|
||||||
|
|
||||||
routes.MapRoute(
|
app.UseMvc(routes =>
|
||||||
name: "defaultError",
|
{
|
||||||
template: "{controller=Error}/{action=Error}");
|
routes.MapRoute(
|
||||||
});
|
name: "default",
|
||||||
}
|
template: "{controller=Catalog}/{action=Index}/{id?}");
|
||||||
|
|
||||||
private void RegisterAppInsights(IServiceCollection services)
|
routes.MapRoute(
|
||||||
{
|
name: "defaultError",
|
||||||
services.AddApplicationInsightsTelemetry(Configuration);
|
template: "{controller=Error}/{action=Error}");
|
||||||
var orchestratorType = Configuration.GetValue<string>("OrchestratorType");
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (orchestratorType?.ToUpper() == "K8S")
|
static class ServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
// Enable K8s telemetry initializer
|
|
||||||
services.EnableKubernetes();
|
public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration)
|
||||||
}
|
{
|
||||||
if (orchestratorType?.ToUpper() == "SF")
|
services.AddApplicationInsightsTelemetry(configuration);
|
||||||
{
|
var orchestratorType = configuration.GetValue<string>("OrchestratorType");
|
||||||
// Enable SF telemetry initializer
|
|
||||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
if (orchestratorType?.ToUpper() == "K8S")
|
||||||
new FabricTelemetryInitializer());
|
{
|
||||||
}
|
// Enable K8s telemetry initializer
|
||||||
}
|
services.EnableKubernetes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (orchestratorType?.ToUpper() == "SF")
|
||||||
|
{
|
||||||
|
// Enable SF telemetry initializer
|
||||||
|
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||||
|
new FabricTelemetryInitializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddHealthChecks(checks =>
|
||||||
|
{
|
||||||
|
var minutes = 1;
|
||||||
|
if (int.TryParse(configuration["HealthCheck:Timeout"], out var minutesParsed))
|
||||||
|
{
|
||||||
|
minutes = minutesParsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
checks.AddUrlCheck(configuration["CatalogUrlHC"], TimeSpan.FromMinutes(minutes));
|
||||||
|
checks.AddUrlCheck(configuration["OrderingUrlHC"], TimeSpan.FromMinutes(minutes));
|
||||||
|
checks.AddUrlCheck(configuration["BasketUrlHC"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
|
||||||
|
checks.AddUrlCheck(configuration["IdentityUrlHC"], TimeSpan.FromMinutes(minutes));
|
||||||
|
checks.AddUrlCheck(configuration["MarketingUrlHC"], TimeSpan.FromMinutes(minutes));
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
services.Configure<AppSettings>(configuration);
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddMvc()
|
||||||
|
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
|
||||||
|
|
||||||
|
services.AddSession();
|
||||||
|
|
||||||
|
if (configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
|
||||||
|
{
|
||||||
|
services.AddDataProtection(opts =>
|
||||||
|
{
|
||||||
|
opts.ApplicationDiscriminator = "eshop.webmvc";
|
||||||
|
})
|
||||||
|
.PersistKeysToRedis(ConnectionMultiplexer.Connect(configuration["DPConnectionString"]), "DataProtection-Keys");
|
||||||
|
}
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds all Http client services (like Service-Agents) using resilient Http requests based on HttpClient factory and Polly's policies
|
||||||
|
public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
|
||||||
|
//register delegating handlers
|
||||||
|
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
|
||||||
|
services.AddTransient<HttpClientRequestIdDelegatingHandler>();
|
||||||
|
|
||||||
|
//set 5 min as the lifetime for each HttpMessageHandler int the pool
|
||||||
|
services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(TimeSpan.FromMinutes(5));
|
||||||
|
|
||||||
|
//add http client services
|
||||||
|
services.AddHttpClient<IBasketService, BasketService>()
|
||||||
|
.SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Sample. Default lifetime is 2 minutes
|
||||||
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<ICatalogService, CatalogService>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<IOrderingService, OrderingService>()
|
||||||
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddHttpMessageHandler<HttpClientRequestIdDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<ICampaignService, CampaignService>()
|
||||||
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
services.AddHttpClient<ILocationService, LocationService>()
|
||||||
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
//add custom application services
|
||||||
|
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddHttpClientLogging(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddLogging(b =>
|
||||||
|
{
|
||||||
|
b.AddFilter((category, level) => true); // Spam the world with logs.
|
||||||
|
|
||||||
|
// Add console logger so we can see all the logging produced by the client by default.
|
||||||
|
b.AddConsole(c => c.IncludeScopes = true);
|
||||||
|
|
||||||
|
// Add console logger
|
||||||
|
b.AddDebug();
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var useLoadTest = configuration.GetValue<bool>("UseLoadTest");
|
||||||
|
var identityUrl = configuration.GetValue<string>("IdentityUrl");
|
||||||
|
var callBackUrl = configuration.GetValue<string>("CallBackUrl");
|
||||||
|
|
||||||
|
// Add Authentication services
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
//options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
||||||
|
})
|
||||||
|
.AddCookie()
|
||||||
|
.AddOpenIdConnect(options =>
|
||||||
|
{
|
||||||
|
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
options.Authority = identityUrl.ToString();
|
||||||
|
options.SignedOutRedirectUri = callBackUrl.ToString();
|
||||||
|
options.ClientId = useLoadTest ? "mvctest" : "mvc";
|
||||||
|
options.ClientSecret = "secret";
|
||||||
|
options.ResponseType = useLoadTest ? "code id_token token" : "code id_token";
|
||||||
|
options.SaveTokens = true;
|
||||||
|
options.GetClaimsFromUserInfoEndpoint = true;
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.Scope.Add("openid");
|
||||||
|
options.Scope.Add("profile");
|
||||||
|
options.Scope.Add("orders");
|
||||||
|
options.Scope.Add("basket");
|
||||||
|
options.Scope.Add("marketing");
|
||||||
|
options.Scope.Add("locations");
|
||||||
|
options.Scope.Add("webshoppingagg");
|
||||||
|
options.Scope.Add("orders.signalrhub");
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
|
||||||
|
=> HttpPolicyExtensions
|
||||||
|
.HandleTransientHttpError()
|
||||||
|
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||||
|
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
|
||||||
|
|
||||||
|
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
|
||||||
|
=> HttpPolicyExtensions
|
||||||
|
.HandleTransientHttpError()
|
||||||
|
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,28 +6,29 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Annotations
|
namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Annotations
|
||||||
{
|
{
|
||||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
|
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
|
||||||
public class CardExpirationAttribute : ValidationAttribute
|
public class CardExpirationAttribute : ValidationAttribute
|
||||||
{
|
{
|
||||||
public override bool IsValid(object value)
|
public override bool IsValid(object value)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var monthString = value.ToString().Split('/')[0];
|
var monthString = value.ToString().Split('/')[0];
|
||||||
var yearString = $"20{value.ToString().Split('/')[1]}";
|
var yearString = $"20{value.ToString().Split('/')[1]}";
|
||||||
// Use the 'out' variable initializer to simplify
|
// Use the 'out' variable initializer to simplify
|
||||||
// the logic of validating the expiration date
|
// the logic of validating the expiration date
|
||||||
if ((int.TryParse(monthString, out var month)) &&
|
if ((int.TryParse(monthString, out var month)) &&
|
||||||
(int.TryParse(yearString, out var year)))
|
(int.TryParse(yearString, out var year)))
|
||||||
{
|
{
|
||||||
DateTime d = new DateTime(year, month, 1);
|
DateTime d = new DateTime(year, month, 1);
|
||||||
|
|
||||||
return d > DateTime.UtcNow;
|
return d > DateTime.UtcNow;
|
||||||
} else
|
}
|
||||||
{
|
else
|
||||||
return false;
|
{
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user