Browse Source

Merge pull request #2 from sicsbd/dev-asp.netcore2.1enhancements

Update to ASP.NET Core 2.1.3
pull/714/head
Rafsanul Hasan 6 years ago
committed by GitHub
parent
commit
9d9d85efa4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 5711 additions and 5476 deletions
  1. BIN
      Certificates/DotNet Foundation CA.pfx
  2. BIN
      Certificates/eShopOnContainers.pfx
  3. +1
    -1
      docker-compose.dcproj
  4. +20
    -9
      docker-compose.override.yml
  5. +2
    -2
      src/ApiGateways/ApiGw-Base/Dockerfile
  6. +11
    -10
      src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj
  7. +2
    -1
      src/ApiGateways/ApiGw-Base/Properties/launchSettings.json
  8. +2
    -2
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile
  9. +15
    -14
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
  10. +2
    -1
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Properties/launchSettings.json
  11. +172
    -162
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
  12. +21
    -13
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.json
  13. +2
    -2
      src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
  14. +2
    -1
      src/ApiGateways/Web.Bff.Shopping/aggregator/Properties/launchSettings.json
  15. +174
    -165
      src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs
  16. +17
    -15
      src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj
  17. +4
    -4
      src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj
  18. +1
    -1
      src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj
  19. +3
    -3
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj
  20. +2
    -2
      src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj
  21. +1
    -1
      src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj
  22. +30
    -29
      src/Services/Basket/Basket.API/Basket.API.csproj
  23. +2
    -2
      src/Services/Basket/Basket.API/Dockerfile
  24. +2
    -1
      src/Services/Basket/Basket.API/Properties/launchSettings.json
  25. +274
    -272
      src/Services/Basket/Basket.API/Startup.cs
  26. +22
    -22
      src/Services/Basket/Basket.API/appsettings.json
  27. +6
    -6
      src/Services/Catalog/Catalog.API/Catalog.API.csproj
  28. +2
    -2
      src/Services/Catalog/Catalog.API/Dockerfile
  29. +2
    -1
      src/Services/Catalog/Catalog.API/Properties/launchSettings.json
  30. +294
    -291
      src/Services/Catalog/Catalog.API/Startup.cs
  31. +4
    -2
      src/Services/Identity/Identity.API/Dockerfile
  32. +62
    -56
      src/Services/Identity/Identity.API/Identity.API.csproj
  33. +4
    -3
      src/Services/Identity/Identity.API/Properties/launchSettings.json
  34. BIN
      src/Services/Identity/Identity.API/Setup/DotNet Foundation CA.pfx
  35. BIN
      src/Services/Identity/Identity.API/Setup/eShopOnContainers.pfx
  36. +168
    -154
      src/Services/Identity/Identity.API/Startup.cs
  37. +31
    -23
      src/Services/Identity/Identity.API/appsettings.json
  38. +2
    -2
      src/Services/Location/Locations.API/Dockerfile
  39. +29
    -28
      src/Services/Location/Locations.API/Locations.API.csproj
  40. +2
    -1
      src/Services/Location/Locations.API/Properties/launchSettings.json
  41. +2
    -2
      src/Services/Marketing/Marketing.API/Dockerfile
  42. +50
    -49
      src/Services/Marketing/Marketing.API/Marketing.API.csproj
  43. +2
    -1
      src/Services/Marketing/Marketing.API/Properties/launchSettings.json
  44. +2
    -2
      src/Services/Ordering/Ordering.API/Dockerfile
  45. +50
    -49
      src/Services/Ordering/Ordering.API/Ordering.API.csproj
  46. +2
    -1
      src/Services/Ordering/Ordering.API/Properties/launchSettings.json
  47. +2
    -2
      src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
  48. +25
    -24
      src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj
  49. +3
    -2
      src/Services/Ordering/Ordering.BackgroundTasks/Properties/launchSettings.json
  50. +3
    -3
      src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj
  51. +2
    -2
      src/Services/Ordering/Ordering.SignalrHub/Dockerfile
  52. +25
    -24
      src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj
  53. +3
    -2
      src/Services/Ordering/Ordering.SignalrHub/Properties/launchSettings.json
  54. +2
    -2
      src/Services/Payment/Payment.API/Dockerfile
  55. +24
    -23
      src/Services/Payment/Payment.API/Payment.API.csproj
  56. +2
    -1
      src/Services/Payment/Payment.API/Properties/launchSettings.json
  57. +13
    -0
      src/Web/WebMVC/Controllers/HomeController.cs
  58. +4
    -2
      src/Web/WebMVC/Dockerfile
  59. +11
    -10
      src/Web/WebMVC/Properties/launchSettings.json
  60. +5
    -4
      src/Web/WebMVC/Services/CatalogService.cs
  61. +269
    -249
      src/Web/WebMVC/Startup.cs
  62. +22
    -20
      src/Web/WebMVC/Views/Campaigns/Details.cshtml
  63. +60
    -57
      src/Web/WebMVC/Views/Campaigns/Index.cshtml
  64. +7
    -7
      src/Web/WebMVC/Views/Cart/Index.cshtml
  65. +44
    -44
      src/Web/WebMVC/Views/Catalog/Index.cshtml
  66. +6
    -0
      src/Web/WebMVC/Views/Home/Privacy.cshtml
  67. +93
    -91
      src/Web/WebMVC/Views/Order/Create.cshtml
  68. +71
    -70
      src/Web/WebMVC/Views/Order/Detail.cshtml
  69. +38
    -36
      src/Web/WebMVC/Views/Order/Index.cshtml
  70. +33
    -32
      src/Web/WebMVC/Views/OrderManagement/Index.cshtml
  71. +41
    -0
      src/Web/WebMVC/Views/Shared/_CookieConsentPartial.cshtml
  72. +1
    -0
      src/Web/WebMVC/Views/Shared/_Layout.cshtml
  73. +46
    -48
      src/Web/WebMVC/WebMVC.csproj
  74. +34
    -25
      src/Web/WebMVC/appsettings.json
  75. +2835
    -2833
      src/Web/WebMVC/wwwroot/js/site.js
  76. +6
    -6
      src/Web/WebMVC/wwwroot/js/site.min.js
  77. +4
    -2
      src/Web/WebSPA/Dockerfile
  78. +17
    -16
      src/Web/WebSPA/Properties/launchSettings.json
  79. BIN
      src/Web/WebSPA/Setup/DotNet Foundation CA.pfx
  80. BIN
      src/Web/WebSPA/Setup/eShopOnContainers.pfx
  81. +144
    -133
      src/Web/WebSPA/Startup.cs
  82. +172
    -164
      src/Web/WebSPA/WebSPA.csproj
  83. +26
    -18
      src/Web/WebSPA/appsettings.json
  84. +0
    -0
      src/Web/WebSPA/npm-shrinkwrap.json
  85. +3
    -2
      src/Web/WebStatus/Dockerfile
  86. +2
    -1
      src/Web/WebStatus/Properties/launchSettings.json
  87. +96
    -95
      src/Web/WebStatus/Startup.cs
  88. +19
    -18
      src/Web/WebStatus/WebStatus.csproj

BIN
Certificates/DotNet Foundation CA.pfx View File


BIN
Certificates/eShopOnContainers.pfx View File


+ 1
- 1
docker-compose.dcproj View File

@ -3,7 +3,7 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>fea0c318-ffed-4d39-8781-265718ca43dd</ProjectGuid> <ProjectGuid>fea0c318-ffed-4d39-8781-265718ca43dd</ProjectGuid>
<DockerLaunchBrowser>True</DockerLaunchBrowser> <DockerLaunchBrowser>True</DockerLaunchBrowser>
<DockerServiceUrl>http://localhost:5100</DockerServiceUrl>
<DockerServiceUrl>https://localhost:4100</DockerServiceUrl>
<DockerServiceName>webmvc</DockerServiceName> <DockerServiceName>webmvc</DockerServiceName>
<DockerTargetOS>Linux</DockerTargetOS> <DockerTargetOS>Linux</DockerTargetOS>
<ProjectVersion>2.1</ProjectVersion> <ProjectVersion>2.1</ProjectVersion>


+ 20
- 9
docker-compose.override.yml View File

@ -30,11 +30,11 @@ services:
identity.api: identity.api:
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:80
- SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104
- ASPNETCORE_URLS=http://0.0.0.0:80;https://+:443
- SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104;https://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:4104
- XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always
- ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word} - ConnectionString=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word}
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110.
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100;https://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:4100 #Local: You need to open your local dev-machine firewall at range 5100-5110.
- LocationApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5109 - LocationApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5109
- MarketingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110 - MarketingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110
- BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103 - BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103
@ -45,7 +45,11 @@ services:
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
- OrchestratorType=${ORCHESTRATOR_TYPE} - OrchestratorType=${ORCHESTRATOR_TYPE}
ports: ports:
- "5105:80"
- "5105:80"
- "4105:443"
volumes:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:rw
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:rw
basket.api: basket.api:
environment: environment:
@ -188,7 +192,7 @@ services:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
ports: ports:
- "5200:80"
- "5200:80"
volumes: volumes:
- ./src/ApiGateways/Mobile.Bff.Shopping/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration} - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration}
@ -206,7 +210,7 @@ services:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. - IdentityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
ports: ports:
- "5202:80"
- "5202:80"
volumes: volumes:
- ./src/ApiGateways/Web.Bff.Shopping/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration} - ./src/ApiGateways/Web.Bff.Shopping/apigw:${ESHOP_OCELOT_VOLUME_SPEC:-/app/configuration}
@ -277,7 +281,7 @@ services:
webspa: webspa:
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:80
- ASPNETCORE_URLS=http://+:80;https://+:443
- IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- PurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 - PurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
- MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5203 - MarketingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5203
@ -293,11 +297,15 @@ services:
- SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202 - SignalrHubUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
ports: ports:
- "5104:80" - "5104:80"
- "4104:443"
volumes:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:rw
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:rw
webmvc: webmvc:
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:80
- ASPNETCORE_URLS=http://+:80;https://+:443
- PurchaseUrl=http://webshoppingapigw - PurchaseUrl=http://webshoppingapigw
- IdentityUrl=http://10.0.75.1:5105 # Local Mac: Use http://docker.for.mac.localhost:5105 || Local Windows: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. || #Remote access: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. - IdentityUrl=http://10.0.75.1:5105 # Local Mac: Use http://docker.for.mac.localhost:5105 || Local Windows: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. || #Remote access: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser.
- MarketingUrl=http://webmarketingapigw - MarketingUrl=http://webmarketingapigw
@ -314,4 +322,7 @@ services:
- UseLoadTest=${USE_LOADTEST:-False} - UseLoadTest=${USE_LOADTEST:-False}
ports: ports:
- "5100:80" - "5100:80"
- "4100:443"
volumes:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:rw
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:rw

+ 2
- 2
src/ApiGateways/ApiGw-Base/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-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/


+ 11
- 10
src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj View File

@ -1,15 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Ocelot" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Ocelot" Version="3.0.0" />
</ItemGroup>
</Project> </Project>

+ 2
- 1
src/ApiGateways/ApiGw-Base/Properties/launchSettings.json View File

@ -13,7 +13,8 @@
"launchBrowser": true, "launchBrowser": true,
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"OcelotApiGw": { "OcelotApiGw": {
"commandName": "Project", "commandName": "Project",


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

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator


+ 15
- 14
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj View File

@ -1,20 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
</ItemGroup>
</Project> </Project>

+ 2
- 1
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "api/values", "launchUrl": "api/values",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"PurchaseForMvc": { "PurchaseForMvc": {
"commandName": "Project", "commandName": "Project",


+ 172
- 162
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs View File

@ -19,166 +19,176 @@ using System.Net.Http;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddHttpServices();
}
// 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)
{
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase);
}
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");
});
}
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddMvc();
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.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>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
return services;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services
.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddHttpServices();
//services.AddHttpsRedirection(opts =>
//{
// opts.HttpsPort = 4120;
//});
}
// 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)
{
string pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase);
}
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");
});
}
}
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()
{
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
OnAuthenticationFailed = async ctx =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
},
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
OnTokenValidated = async ctx =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
}
};
});
return services;
}
public static IServiceCollection AddHttpServices(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>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
return services;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
} }

+ 21
- 13
src/ApiGateways/Mobile.Bff.Shopping/aggregator/appsettings.json View File

@ -1,15 +1,23 @@
{ {
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
},
"Kestrel": {
"Certificates": {
"Default": {
"Path": "./synergydev.pfx",
"Password": "RH@ssl2018"
}
}
}
} }

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

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/ApiGateways/Web.Bff.Shopping/aggregator WORKDIR /src/src/ApiGateways/Web.Bff.Shopping/aggregator


+ 2
- 1
src/ApiGateways/Web.Bff.Shopping/aggregator/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "api/values", "launchUrl": "api/values",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"PurchaseForMvc": { "PurchaseForMvc": {
"commandName": "Project", "commandName": "Project",


+ 174
- 165
src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs View File

@ -11,7 +11,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Polly; using Polly;
using Polly.Extensions.Http; using Polly.Extensions.Http;
using Polly.Timeout;
using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.Swagger;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -20,168 +19,178 @@ using System.Net.Http;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddApplicationServices();
}
// 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)
{
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase);
}
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");
});
}
}
public static class ServiceCollectionExtensions
{
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 = "webshoppingagg";
options.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = async ctx =>
{
int i = 0;
},
OnTokenValidated = async ctx =>
{
int i = 0;
}
};
});
return services;
}
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddMvc();
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;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services
.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddApplicationServices();
}
// 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)
{
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase);
}
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");
});
}
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
string 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 = "webshoppingagg";
options.Events = new JwtBearerEvents()
{
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
OnAuthenticationFailed = async ctx =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
},
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
OnTokenValidated = async ctx =>
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
}
};
});
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 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.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>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
return services;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
} }

+ 17
- 15
src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj View File

@ -1,21 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<UserSecretsId>0890cb23-79b5-408d-9aeb-13e6ff218d71</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.4.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.4.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
</ItemGroup>
</Project> </Project>

+ 4
- 4
src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj View File

@ -6,10 +6,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 1
- 1
src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks/Microsoft.AspNetCore.HealthChecks.csproj View File

@ -13,7 +13,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.1.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

+ 3
- 3
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks.AzureStorage/Microsoft.Extensions.HealthChecks.AzureStorage.csproj View File

@ -16,11 +16,11 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.1.0" />
<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.5.0" />
<PackageReference Include="WindowsAzure.Storage" Version="9.1.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.1" />
<PackageReference Include="WindowsAzure.Storage" Version="9.3.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

+ 2
- 2
src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks/Microsoft.Extensions.HealthChecks.csproj View File

@ -9,12 +9,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <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.5.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

+ 1
- 1
src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj View File

@ -6,7 +6,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Polly" Version="6.0.1" /> <PackageReference Include="Polly" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>

+ 30
- 29
src/Services/Basket/Basket.API/Basket.API.csproj View File

@ -1,36 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Content Update="web.config">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Update="web.config">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="StackExchange.Redis.StrongName" Version="1.2.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="StackExchange.Redis.StrongName" Version="1.2.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.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.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.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.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
</Project> </Project>

+ 2
- 2
src/Services/Basket/Basket.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Basket/Basket.API WORKDIR /src/src/Services/Basket/Basket.API


+ 2
- 1
src/Services/Basket/Basket.API/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "swagger", "launchUrl": "swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Microsoft.eShopOnContainers.Services.Basket.API": { "Microsoft.eShopOnContainers.Services.Basket.API": {
"commandName": "Project", "commandName": "Project",


+ 274
- 272
src/Services/Basket/Basket.API/Startup.cs View File

@ -34,281 +34,283 @@ using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Basket.API namespace Microsoft.eShopOnContainers.Services.Basket.API
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
// Add framework services.
services.AddMvc(options =>
{
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
options.Filters.Add(typeof(ValidateModelStateFilter));
}).AddControllersAsServices();
ConfigureAuthService(services);
services.AddHealthChecks(checks =>
{
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);
//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);
configuration.ResolveDns = true;
return ConnectionMultiplexer.Connect(configuration);
});
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);
services.AddSwaggerGen(options =>
{
options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Info
{
Title = "Basket HTTP API",
Version = "v1",
Description = "The Basket 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>()
{
{ "basket", "Basket API" }
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IBasketRepository, RedisBasketRepository>();
services.AddTransient<IIdentityService, IdentityService>();
services.AddOptions();
var container = new ContainerBuilder();
container.Populate(services);
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"];
if (!string.IsNullOrEmpty(pathBase))
{
app.UsePathBase(pathBase);
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
// Add framework services.
services.AddMvc(options =>
{
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
options.Filters.Add(typeof(ValidateModelStateFilter));
})
.AddControllersAsServices()
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1)
;
ConfigureAuthService(services);
services.AddHealthChecks(checks =>
{
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);
//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(sp =>
{
var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true);
configuration.ResolveDns = true;
return ConnectionMultiplexer.Connect(configuration);
});
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);
services.AddSwaggerGen(options =>
{
options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Info
{
Title = "Basket HTTP API",
Version = "v1",
Description = "The Basket 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>()
{
{ "basket", "Basket API" }
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IBasketRepository, RedisBasketRepository>();
services.AddTransient<IIdentityService, IdentityService>();
services.AddOptions();
var container = new ContainerBuilder();
container.Populate(services);
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"];
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.UseCors("CorsPolicy");
ConfigureAuth(app);
app.UseMvcWithDefaultRoute();
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
c.OAuthClientId ("basketswaggerui");
c.OAuthAppName("Basket Swagger UI");
});
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 ConfigureAuthService(IServiceCollection services)
{
// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
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 = "basket";
});
}
protected virtual void ConfigureAuth(IApplicationBuilder app)
{
if (Configuration.GetValue<bool>("UseLoadTest"))
{
app.UseMiddleware<ByPassAuthMiddleware>();
}
app.UseAuthentication();
}
private void RegisterEventBus(IServiceCollection services)
{
var subscriptionClientName = Configuration["SubscriptionClientName"];
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
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,
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>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
services.AddTransient<ProductPriceChangedIntegrationEventHandler>();
services.AddTransient<OrderStartedIntegrationEventHandler>();
}
private void ConfigureEventBus(IApplicationBuilder app)
{
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>();
eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>();
}
}
app.UseStaticFiles();
app.UseCors("CorsPolicy");
ConfigureAuth(app);
app.UseMvcWithDefaultRoute();
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1");
c.OAuthClientId("basketswaggerui");
c.OAuthAppName("Basket Swagger UI");
});
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 ConfigureAuthService(IServiceCollection services)
{
// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
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 = "basket";
});
}
protected virtual void ConfigureAuth(IApplicationBuilder app)
{
if (Configuration.GetValue<bool>("UseLoadTest"))
{
app.UseMiddleware<ByPassAuthMiddleware>();
}
app.UseAuthentication();
}
private void RegisterEventBus(IServiceCollection services)
{
var subscriptionClientName = Configuration["SubscriptionClientName"];
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
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,
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>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
services.AddTransient<ProductPriceChangedIntegrationEventHandler>();
services.AddTransient<OrderStartedIntegrationEventHandler>();
}
private void ConfigureEventBus(IApplicationBuilder app)
{
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>();
eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>();
}
}
} }

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

@ -1,24 +1,24 @@
{ {
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"IdentityUrl": "http://localhost:5105",
"ConnectionString": "127.0.0.1",
"AzureServiceBusEnabled": false,
"SubscriptionClientName": "Basket",
"ApplicationInsights": {
"InstrumentationKey": ""
},
"EventBusRetryCount": 5,
"UseVault": false,
"Vault": {
"Name": "eshop",
"ClientId": "your-clien-id",
"ClientSecret": "your-client-secret"
}
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"IdentityUrl": "https://localhost:4105",
"ConnectionString": "127.0.0.1",
"AzureServiceBusEnabled": false,
"SubscriptionClientName": "Basket",
"ApplicationInsights": {
"InstrumentationKey": ""
},
"EventBusRetryCount": 5,
"UseVault": false,
"Vault": {
"Name": "eshop",
"ClientId": "your-clien-id",
"ClientSecret": "your-client-secret"
}
} }

+ 6
- 6
src/Services/Catalog/Catalog.API/Catalog.API.csproj View File

@ -35,13 +35,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" /> <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.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" /> <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" /> <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>


+ 2
- 2
src/Services/Catalog/Catalog.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Catalog/Catalog.API WORKDIR /src/src/Services/Catalog/Catalog.API


+ 2
- 1
src/Services/Catalog/Catalog.API/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "/swagger", "launchUrl": "/swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Microsoft.eShopOnContainers.Services.Catalog.API": { "Microsoft.eShopOnContainers.Services.Catalog.API": {
"commandName": "Project", "commandName": "Project",


+ 294
- 291
src/Services/Catalog/Catalog.API/Startup.cs View File

@ -32,299 +32,302 @@ using System.Reflection;
namespace Microsoft.eShopOnContainers.Services.Catalog.API namespace Microsoft.eShopOnContainers.Services.Catalog.API
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddAppInsight(Configuration)
.AddCustomMVC(Configuration)
.AddCustomDbContext(Configuration)
.AddCustomOptions(Configuration)
.AddIntegrationServices(Configuration)
.AddEventBus(Configuration)
.AddSwagger();
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);
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddAppInsight(Configuration)
.AddCustomMVC(Configuration)
.AddCustomDbContext(Configuration)
.AddCustomOptions(Configuration)
.AddIntegrationServices(Configuration)
.AddEventBus(Configuration)
.AddSwagger();
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 #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.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 =>
{
var minutes = 1;
if (int.TryParse(configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("CatalogDb", configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
var accountName = configuration.GetValue<string>("AzureStorageAccountName");
var accountKey = configuration.GetValue<string>("AzureStorageAccountKey");
if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey))
{
checks.AddAzureBlobStorageCheck(accountName, accountKey);
}
});
services.AddMvc(options =>
{
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
}).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 =>
{
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);
});
// Changing default behavior when client evaluation occurs to throw.
// Default in EF Core would be to log a warning when client evaluation is performed.
options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
//Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval
});
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 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 =>
{
options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
{
Title = "eShopOnContainers - Catalog HTTP API",
Version = "v1",
Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample",
TermsOfService = "Terms Of Service"
});
});
return services;
}
public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
sp => (DbConnection c) => new IntegrationEventLogService(c));
services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>();
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
{
var settings = sp.GetRequiredService<IOptions<CatalogSettings>>().Value;
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
var serviceBusConnection = new ServiceBusConnectionStringBuilder(settings.EventBusConnection);
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
});
}
else
{
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
{
var settings = sp.GetRequiredService<IOptions<CatalogSettings>>().Value;
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 AddEventBus(this IServiceCollection services, IConfiguration configuration)
{
var subscriptionClientName = configuration["SubscriptionClientName"];
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
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,
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>();
var retryCount = 5;
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
services.AddTransient<OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
services.AddTransient<OrderStatusChangedToPaidIntegrationEventHandler>();
return services;
}
}
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 =>
{
var minutes = 1;
if (int.TryParse(configuration["HealthCheck:Timeout"], out int minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("CatalogDb", configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
var accountName = configuration.GetValue<string>("AzureStorageAccountName");
var accountKey = configuration.GetValue<string>("AzureStorageAccountKey");
if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey))
{
checks.AddAzureBlobStorageCheck(accountName, accountKey);
}
});
services.AddMvc(options =>
{
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
})
.AddControllersAsServices()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
;
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 =>
{
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);
});
// Changing default behavior when client evaluation occurs to throw.
// Default in EF Core would be to log a warning when client evaluation is performed.
options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
//Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval
});
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 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 =>
{
options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
{
Title = "eShopOnContainers - Catalog HTTP API",
Version = "v1",
Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample",
TermsOfService = "Terms Of Service"
});
});
return services;
}
public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
sp => (DbConnection c) => new IntegrationEventLogService(c));
services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>();
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
{
var settings = sp.GetRequiredService<IOptions<CatalogSettings>>().Value;
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
var serviceBusConnection = new ServiceBusConnectionStringBuilder(settings.EventBusConnection);
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
});
}
else
{
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
{
var settings = sp.GetRequiredService<IOptions<CatalogSettings>>().Value;
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 AddEventBus(this IServiceCollection services, IConfiguration configuration)
{
var subscriptionClientName = configuration["SubscriptionClientName"];
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
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,
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>();
var retryCount = 5;
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
});
}
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
services.AddTransient<OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
services.AddTransient<OrderStatusChangedToPaidIntegrationEventHandler>();
return services;
}
}
} }

+ 4
- 2
src/Services/Identity/Identity.API/Dockerfile View File

@ -1,9 +1,10 @@
ARG NODE_IMAGE=node:8.11 ARG NODE_IMAGE=node:8.11
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
EXPOSE 443
FROM microsoft/dotnet:2.1-sdk as dotnet-build
FROM microsoft/dotnet:2.1.401-sdk as dotnet-build
WORKDIR /src WORKDIR /src
FROM ${NODE_IMAGE} as node-build FROM ${NODE_IMAGE} as node-build
@ -16,6 +17,7 @@ FROM dotnet-build as build
WORKDIR /src/src/Services/Identity/Identity.API/wwwroot WORKDIR /src/src/Services/Identity/Identity.API/wwwroot
COPY --from=node-build /web/wwwroot . COPY --from=node-build /web/wwwroot .
WORKDIR /src WORKDIR /src
COPY src/Services/Identity/Identity.API/Setup/eShopOnContainers.pfx /root/.aspnet/https/
COPY . . COPY . .
WORKDIR /src/src/Services/Identity/Identity.API WORKDIR /src/src/Services/Identity/Identity.API
RUN dotnet restore -nowarn:msb3202,nu1503 RUN dotnet restore -nowarn:msb3202,nu1503


+ 62
- 56
src/Services/Identity/Identity.API/Identity.API.csproj View File

@ -1,60 +1,66 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<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.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.3" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.113" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
</ItemGroup>
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
<Exec Command="dotnet bundle" Condition="'$(ASPNETCORE_ENVIRONMENT)'!='Development'" />
</Target>
<ItemGroup>
<DotNetCliToolReference Include="BundlerMinifier.Core" Version="2.7.385" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Certificate\idsrv3test.pfx" />
</ItemGroup>
<ItemGroup>
<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\Microsoft.Extensions.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Extensions\" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Remove="Setup\DotNet Foundation CA.pfx" />
<None Remove="Setup\eShopOnContainers.pfx" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<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.Extensions.Configuration.AzureKeyVault" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.3" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.113" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
</ItemGroup>
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
<Exec Command="dotnet bundle" Condition="'$(ASPNETCORE_ENVIRONMENT)'!='Development'" />
</Target>
<ItemGroup>
<DotNetCliToolReference Include="BundlerMinifier.Core" Version="2.7.385" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Certificate\idsrv3test.pfx" />
</ItemGroup>
<ItemGroup>
<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\Microsoft.Extensions.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Extensions\" />
</ItemGroup>
</Project> </Project>

+ 4
- 3
src/Services/Identity/Identity.API/Properties/launchSettings.json View File

@ -3,8 +3,8 @@
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:54010/",
"sslPort": 0
"applicationUrl": "http://localhost:5105/",
"sslPort": 4105
} }
}, },
"profiles": { "profiles": {
@ -14,7 +14,8 @@
"launchUrl": "http://localhost:55105", "launchUrl": "http://localhost:55105",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"eShopOnContainers.Identity": { "eShopOnContainers.Identity": {
"commandName": "Project", "commandName": "Project",


BIN
src/Services/Identity/Identity.API/Setup/DotNet Foundation CA.pfx View File


BIN
src/Services/Identity/Identity.API/Setup/eShopOnContainers.pfx View File


+ 168
- 154
src/Services/Identity/Identity.API/Startup.cs View File

@ -22,163 +22,177 @@ using System.Reflection;
namespace Microsoft.eShopOnContainers.Services.Identity.API namespace Microsoft.eShopOnContainers.Services.Identity.API
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
// Add framework 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>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<AppSettings>(Configuration);
services.AddMvc();
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
{
services.AddDataProtection(opts =>
{
opts.ApplicationDiscriminator = "eshop.identity";
})
.PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys");
}
services.AddHealthChecks(checks =>
{
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("Identity_Db", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
});
services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();
services.AddTransient<IRedirectService, RedirectService>();
var connectionString = Configuration["ConnectionString"];
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
// Adds IdentityServer
services.AddIdentityServer(x => x.IssuerUri = "null")
.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();
container.Populate(services);
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.AddConsole(Configuration.GetSection("Logging"));
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);
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
// Add framework 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>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<AppSettings>(Configuration);
services
.AddMvc(opts=>
{
opts.SslPort = 4105;
opts.RequireHttpsPermanent = true;
})
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1)
;
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
{
services.AddDataProtection(opts =>
{
opts.ApplicationDiscriminator = "eshop.identity";
})
.PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys");
}
services.AddHealthChecks(checks =>
{
int minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out int minutesParsed))
{
minutes = minutesParsed;
}
checks.AddSqlCheck("Identity_Db", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
});
services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();
services.AddTransient<IRedirectService, RedirectService>();
string connectionString = Configuration["ConnectionString"];
string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
// Adds IdentityServer
services.AddIdentityServer(x => x.IssuerUri = "null")
.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>();
services.AddHttpsRedirection(opts =>
{
opts.HttpsPort = 4105;
});
ContainerBuilder container = new ContainerBuilder();
container.Populate(services);
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.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddAzureWebAppDiagnostics();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
string 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();
// Make work identity server redirections in Edge and lastest versions of browers. WARN: Not valid in a production environment.
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Content-Security-Policy", "script-src 'unsafe-inline'");
await next();
});
app.UseForwardedHeaders();
// Adds IdentityServer
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
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());
}
}
}
app.UseStaticFiles();
// Make work identity server redirections in Edge and lastest versions of browers. WARN: Not valid in a production environment.
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Content-Security-Policy", "script-src 'unsafe-inline'");
await next();
});
app.UseForwardedHeaders();
// Adds IdentityServer
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
private void RegisterAppInsights(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration);
string 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());
}
}
}
} }

+ 31
- 23
src/Services/Identity/Identity.API/appsettings.json View File

@ -1,25 +1,33 @@
{ {
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word;",
"IsClusterEnv": "False",
"MvcClient": "http://localhost:5100",
"SpaClient": "http://localhost:5104",
"XamarinCallback": "http://localhost:5105/xamarincallback",
"UseCustomizationData": false,
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"InstrumentationKey": ""
},
"UseVault": false,
"Vault": {
"Name": "eshop",
"ClientId": "your-clien-id",
"ClientSecret": "your-client-secret"
}
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word;",
"IsClusterEnv": "False",
"MvcClient": "https://localhost:4100",
"SpaClient": "https://localhost:4104",
"XamarinCallback": "https://localhost:4105/xamarincallback",
"UseCustomizationData": false,
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"InstrumentationKey": ""
},
"UseVault": false,
"Vault": {
"Name": "eshop",
"ClientId": "your-clien-id",
"ClientSecret": "your-client-secret"
},
"Kestrel": {
"Certificates": {
"Default": {
"Path": "./Setup/eshopOnContainers.pfx",
"Password": "D0tNet@"
}
}
}
} }

+ 2
- 2
src/Services/Location/Locations.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Location/Locations.API WORKDIR /src/src/Services/Location/Locations.API


+ 29
- 28
src/Services/Location/Locations.API/Locations.API.csproj View File

@ -1,32 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<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.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.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.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.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.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
</Project> </Project>

+ 2
- 1
src/Services/Location/Locations.API/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "api/values", "launchUrl": "api/values",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Locations.API": { "Locations.API": {
"commandName": "Project", "commandName": "Project",


+ 2
- 2
src/Services/Marketing/Marketing.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Marketing/Marketing.API WORKDIR /src/src/Services/Marketing/Marketing.API


+ 50
- 49
src/Services/Marketing/Marketing.API/Marketing.API.csproj View File

@ -1,55 +1,56 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<RootNamespace>Microsoft.eShopOnContainers.Services.Marketing.API</RootNamespace>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<UserSecretsId>aspnet-Marketing.API-20161122013619</UserSecretsId>
<AssemblyName />
<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>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<RootNamespace>Microsoft.eShopOnContainers.Services.Marketing.API</RootNamespace>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<UserSecretsId>aspnet-Marketing.API-20161122013619</UserSecretsId>
<AssemblyName />
<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>
</PropertyGroup>
<ItemGroup>
<Folder Include="Connected Services\" />
<Folder Include="Infrastructure\MarketingMigrations\" />
<Content Include="Pics\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Folder Include="Infrastructure\MarketingMigrations\" />
</ItemGroup>
<ItemGroup>
<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.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.0" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.AzureStorage\Microsoft.Extensions.HealthChecks.AzureStorage.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Connected Services\" />
<Folder Include="Infrastructure\MarketingMigrations\" />
<Content Include="Pics\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Folder Include="Infrastructure\MarketingMigrations\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.1" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="mongocsharpdriver" Version="2.5.0" />
<PackageReference Include="MongoDB.Bson" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver" Version="2.5.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.AzureStorage\Microsoft.Extensions.HealthChecks.AzureStorage.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Pics\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="Pics\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Connected Services" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Connected Services" />
</ItemGroup>
</Project> </Project>

+ 2
- 1
src/Services/Marketing/Marketing.API/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "swagger", "launchUrl": "swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Marketing.API": { "Marketing.API": {
"commandName": "Project", "commandName": "Project",


+ 2
- 2
src/Services/Ordering/Ordering.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Ordering/Ordering.API WORKDIR /src/src/Services/Ordering/Ordering.API


+ 50
- 49
src/Services/Ordering/Ordering.API/Ordering.API.csproj View File

@ -1,56 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<UserSecretsId>aspnet-Ordering.API-20161122013547</UserSecretsId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<UserSecretsId>aspnet-Ordering.API-20161122013547</UserSecretsId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Content Update="web.config;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Update="web.config;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.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\Microsoft.Extensions.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
<ProjectReference Include="..\Ordering.Domain\Ordering.Domain.csproj" />
<ProjectReference Include="..\Ordering.Infrastructure\Ordering.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.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\Microsoft.Extensions.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
<ProjectReference Include="..\Ordering.Domain\Ordering.Domain.csproj" />
<ProjectReference Include="..\Ordering.Infrastructure\Ordering.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.0" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="4.1.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.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="MediatR" Version="4.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
<PackageReference Include="System.Reflection" Version="4.3.0" />
<PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="Polly" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.0" />
<PackageReference Include="MediatR" Version="4.1.0" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="4.1.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<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>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

+ 2
- 1
src/Services/Ordering/Ordering.API/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "/swagger", "launchUrl": "/swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Microsoft.eShopOnContainers.Services.Ordering.API": { "Microsoft.eShopOnContainers.Services.Ordering.API": {
"commandName": "Project", "commandName": "Project",


+ 2
- 2
src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks


+ 25
- 24
src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj View File

@ -1,31 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Compile Remove="wwwroot\**" />
<Content Remove="wwwroot\**" />
<EmbeddedResource Remove="wwwroot\**" />
<None Remove="wwwroot\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="wwwroot\**" />
<Content Remove="wwwroot\**" />
<EmbeddedResource Remove="wwwroot\**" />
<None Remove="wwwroot\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.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.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.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.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
</Project> </Project>

+ 3
- 2
src/Services/Ordering/Ordering.BackgroundTasks/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "api/values", "launchUrl": "api/values",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Ordering.BackgroundTasks": { "Ordering.BackgroundTasks": {
"commandName": "Project", "commandName": "Project",
@ -26,4 +27,4 @@
"applicationUrl": "http://localhost:5162/" "applicationUrl": "http://localhost:5162/"
} }
} }
}
}

+ 3
- 3
src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj View File

@ -9,9 +9,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 2
- 2
src/Services/Ordering/Ordering.SignalrHub/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub


+ 25
- 24
src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj View File

@ -1,31 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Redis" Version="1.0.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.3" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.0.3" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Redis" Version="1.0.3" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
</ItemGroup>
</Project> </Project>

+ 3
- 2
src/Services/Ordering/Ordering.SignalrHub/Properties/launchSettings.json View File

@ -13,7 +13,8 @@
"launchBrowser": true, "launchBrowser": true,
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Ordering.SignalrHub": { "Ordering.SignalrHub": {
"commandName": "Project", "commandName": "Project",
@ -24,4 +25,4 @@
"applicationUrl": "http://localhost:51312/" "applicationUrl": "http://localhost:51312/"
} }
} }
}
}

+ 2
- 2
src/Services/Payment/Payment.API/Dockerfile View File

@ -1,8 +1,8 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Services/Payment/Payment.API WORKDIR /src/src/Services/Payment/Payment.API


+ 24
- 23
src/Services/Payment/Payment.API/Payment.API.csproj View File

@ -1,28 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
</PropertyGroup>
<ItemGroup>
<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.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.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\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.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\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
</Project> </Project>

+ 2
- 1
src/Services/Payment/Payment.API/Properties/launchSettings.json View File

@ -14,7 +14,8 @@
"launchUrl": "api/values", "launchUrl": "api/values",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Payment.API": { "Payment.API": {
"commandName": "Project", "commandName": "Project",


+ 13
- 0
src/Web/WebMVC/Controllers/HomeController.cs View File

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc;
namespace WebMVC.Controllers
{
public class HomeController : Controller
{
public IActionResult Privacy()
{
return View();
}
}
}

+ 4
- 2
src/Web/WebMVC/Dockerfile View File

@ -1,9 +1,10 @@
ARG NODE_IMAGE=node:8.11 ARG NODE_IMAGE=node:8.11
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
EXPOSE 443
FROM microsoft/dotnet:2.1-sdk as dotnet-build
FROM microsoft/dotnet:2.1.401-sdk as dotnet-build
WORKDIR /src WORKDIR /src
FROM ${NODE_IMAGE} as node-build FROM ${NODE_IMAGE} as node-build
@ -16,6 +17,7 @@ FROM dotnet-build as build
WORKDIR /src/src/Web/WebMVC/wwwroot WORKDIR /src/src/Web/WebMVC/wwwroot
COPY --from=node-build /web/wwwroot . COPY --from=node-build /web/wwwroot .
WORKDIR /src WORKDIR /src
COPY Certificates/eShopOnContainers.pfx /root/.aspnet/https/
COPY . . COPY . .
WORKDIR /src/src/Web/WebMVC WORKDIR /src/src/Web/WebMVC
RUN dotnet restore -nowarn:msb3202,nu1503 RUN dotnet restore -nowarn:msb3202,nu1503


+ 11
- 10
src/Web/WebMVC/Properties/launchSettings.json View File

@ -4,7 +4,7 @@
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:5100", "applicationUrl": "http://localhost:5100",
"sslPort": 0
"sslPort": 4100
} }
}, },
"profiles": { "profiles": {
@ -12,15 +12,16 @@
"commandName": "IISExpress", "commandName": "IISExpress",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"Microsoft.eShopOnContainers.WebMVC": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
"Microsoft.eShopOnContainers.WebMVC": {
"commandName": "Project",
"launchUrl": "http://localhost:4001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:4001;http://localhost:5001"
}
} }
} }

+ 5
- 4
src/Web/WebMVC/Services/CatalogService.cs View File

@ -45,11 +45,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
var responseString = await _httpClient.GetStringAsync(uri); var responseString = await _httpClient.GetStringAsync(uri);
var items = new List<SelectListItem>();
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
var items = new List<SelectListItem>
{
new SelectListItem() { Value = null, Text = "All", Selected = true }
};
var brands = JArray.Parse(responseString);
var brands = JArray.Parse(responseString);
foreach (var brand in brands.Children<JObject>()) foreach (var brand in brands.Children<JObject>())
{ {


+ 269
- 249
src/Web/WebMVC/Startup.cs View File

@ -24,258 +24,278 @@ using WebMVC.Services;
namespace Microsoft.eShopOnContainers.WebMVC namespace Microsoft.eShopOnContainers.WebMVC
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the IoC container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAppInsight(Configuration)
.AddHealthChecks(Configuration)
.AddCustomMvc(Configuration)
.AddHttpClientServices(Configuration)
//.AddHttpClientLogging(Configuration) //Opt-in HttpClientLogging config
.AddCustomAuthentication(Configuration);
}
// 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.AddAzureWebAppDiagnostics();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase);
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the IoC container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(opts =>
{
opts.MinimumSameSitePolicy = SameSiteMode.None;
opts.CheckConsentNeeded = context => true;
});
services
.AddAppInsight(Configuration)
.AddHealthChecks(Configuration)
.AddCustomMvc(Configuration)
.AddHttpClientServices(Configuration)
//.AddHttpClientLogging(Configuration) //Opt-in HttpClientLogging config
.AddCustomAuthentication(Configuration);
services.AddHttpsRedirection(options =>
{
options.HttpsPort = 4100;
});
}
// 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.AddAzureWebAppDiagnostics();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseCookiePolicy();
string 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.UseStaticFiles();
if (Configuration.GetValue<bool>("UseLoadTest"))
{
app.UseMiddleware<ByPassAuthMiddleware>();
}
app.UseAuthentication();
var log = loggerFactory.CreateLogger("identity");
WebContextSeed.Seed(app, env, loggerFactory);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Catalog}/{action=Index}/{id?}");
routes.MapRoute(
name: "defaultError",
template: "{controller=Error}/{action=Error}");
});
}
}
static class ServiceCollectionExtensions
{
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 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();
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.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()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
app.UseSession();
app.UseStaticFiles();
if (Configuration.GetValue<bool>("UseLoadTest"))
{
app.UseMiddleware<ByPassAuthMiddleware>();
}
app.UseAuthentication();
ILogger log = loggerFactory.CreateLogger("identity");
WebContextSeed.Seed(app, env, loggerFactory);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Catalog}/{action=Index}/{id?}");
routes.MapRoute(
name: "defaultError",
template: "{controller=Error}/{action=Error}");
});
}
}
static class ServiceCollectionExtensions
{
public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration)
{
services.AddApplicationInsightsTelemetry(configuration);
string 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 AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
{
services.AddHealthChecks(checks =>
{
int minutes = 1;
if (int.TryParse(configuration["HealthCheck:Timeout"], out int 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(opts =>
{
opts.SslPort = 4100;
opts.RequireHttpsPermanent = true;
})
.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)
{
bool useLoadTest = configuration.GetValue<bool>("UseLoadTest");
string identityUrl = configuration.GetValue<string>("IdentityUrl");
string 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");
});
return services;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
} }

+ 22
- 20
src/Web/WebMVC/Views/Campaigns/Details.cshtml View File

@ -1,28 +1,30 @@
@{ @{
ViewData["Title"] = "Campaign details";
@model CampaignItem
ViewData["Title"] = "Campaign details";
var headers = new List<Header>{
new Header { Controller = "Campaigns", Text = "Back to Campaigns" },
new Header { Controller = "Catalog", Text = "Back to catalog" }
};
@model CampaignItem
} }
<section class="esh-campaigns-hero"> <section class="esh-campaigns-hero">
<div class="container">
<img class="esh-campaigns-title" src="~/images/main_banner_text.png" />
</div>
<div class="container">
<img class="esh-campaigns-title" src="~/images/main_banner_text.png" />
</div>
</section> </section>
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Controller = "Campaigns", Text = "Back to Campaigns" } })
<partial name="_Header" model="headers" />
<div class="container"> <div class="container">
<div class="card esh-campaigns-items">
<img class="card-img-top" src="@Model.PictureUri" alt="Card image cap">
<div class="card-block">
<h4 class="card-title">@Model.Name</h4>
<p class="card-text">@Model.Description</p>
<p class="card-text">
<small class="text-muted">
From @Model.From.ToString("MMMM dd, yyyy") until @Model.To.ToString("MMMM dd, yyyy")
</small>
</p>
</div>
</div>
<div class="card esh-campaigns-items">
<img class="card-img-top" src="@Model.PictureUri" alt="Card image cap">
<div class="card-block">
<h4 class="card-title">@Model.Name</h4>
<p class="card-text">@Model.Description</p>
<p class="card-text">
<small class="text-muted">
From @Model.From.ToString("MMMM dd, yyyy") until @Model.To.ToString("MMMM dd, yyyy")
</small>
</p>
</div>
</div>
</div> </div>

+ 60
- 57
src/Web/WebMVC/Views/Campaigns/Index.cshtml View File

@ -1,72 +1,75 @@
@{ @{
ViewData["Title"] = "Campaigns";
@model WebMVC.ViewModels.CampaignViewModel
ViewData["Title"] = "Campaigns";
@model WebMVC.ViewModels.CampaignViewModel
var headers = new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } };
} }
<section class="esh-campaigns-hero"> <section class="esh-campaigns-hero">
<div class="container">
<img class="esh-campaigns-title" src="~/images/main_banner_text.png" />
</div>
<div class="container">
<img class="esh-campaigns-title" src="~/images/main_banner_text.png" />
</div>
</section> </section>
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } })
<partial name="_Header" model="headers" />
<div class="container"> <div class="container">
<br />
<div class="row">
@if (!ViewData.ModelState.IsValid)
{
<div class="alert alert-warning">
@Html.ValidationSummary(false)
</div>
}
<br />
<div class="row">
<div class="col-md-12">
<div class="esh-campaigns-items" style="font-weight: 300;">
UPDATE USER LOCATION
</div>
@if (!ViewData.ModelState.IsValid)
{
<div class="alert alert-warning">
@Html.ValidationSummary(false)
</div>
}
<form class="form-inline" asp-action="CreateNewUserLocation" method="post">
<label class="sr-only" for="longitudeInput">Name</label>
<div class="input-group mb-2 mr-sm-2 mb-sm-0">
<div class="input-group-addon">Lat</div>
<input type="text" class="form-control mb-2 mr-sm-2 mb-sm-0" id="latitudeInput" asp-for="Lat" placeholder="Latitude">
</div>
<div class="col-md-12">
<div class="esh-campaigns-items" style="font-weight: 300;">
UPDATE USER LOCATION
</div>
<div class="input-group mb-2 mr-sm-2 mb-sm-0">
<div class="input-group-addon">Lon</div>
<input type="text" class="form-control mb-2 mr-sm-2 mb-sm-0" id="longitudeInput" asp-for="Lon" placeholder="Longitude">
</div>
<div class="input-group mb-2 mr-sm-2 mb-sm-0 col-md-2">
<input type="submit" value="Update" class="btn esh-campaigns-form-button" />
</div>
</form>
</div>
</div>
<br />
@if (Model != null && Model.CampaignItems !=null && Model.CampaignItems.Any())
{
<div class="card-group esh-campaigns-items row">
@foreach (var catalogItem in Model.CampaignItems)
{
<div class="esh-campaigns-item col-md-4">
@Html.Partial("_campaign", catalogItem)
</div>
}
</div>
<form class="form-inline" asp-action="CreateNewUserLocation" method="post">
<label class="sr-only" for="longitudeInput">Name</label>
@Html.Partial("_pagination", Model.PaginationInfo)
}
else
{
<div class="esh-campaigns-items row">
THERE ARE NO CAMPAIGNS
</div>
}
<div class="input-group mb-2 mr-sm-2 mb-sm-0">
<div class="input-group-addon">Lat</div>
<input type="text" class="form-control mb-2 mr-sm-2 mb-sm-0" id="latitudeInput" asp-for="Lat" placeholder="Latitude">
</div>
<div class="input-group mb-2 mr-sm-2 mb-sm-0">
<div class="input-group-addon">Lon</div>
<input type="text" class="form-control mb-2 mr-sm-2 mb-sm-0" id="longitudeInput" asp-for="Lon" placeholder="Longitude">
</div>
<div class="input-group mb-2 mr-sm-2 mb-sm-0 col-md-2">
<input type="submit" value="Update" class="btn esh-campaigns-form-button" />
</div>
</form>
</div>
</div>
<br />
@if (Model != null && Model.CampaignItems != null && Model.CampaignItems.Any())
{
<div class="card-group esh-campaigns-items row">
@foreach (var catalogItem in Model.CampaignItems)
{
<div class="esh-campaigns-item col-md-4">
@*@Html.Partial("_campaign", catalogItem)*@
<partial name="_campaign" model="catalogItem" />
</div>
}
</div>
@*@Html.Partial("_pagination", Model.PaginationInfo)*@
<partial name="_pagination" model="Model.PaginationInfo" />
}
else
{
<div class="esh-campaigns-items row">
THERE ARE NO CAMPAIGNS
</div>
}
</div> </div>

+ 7
- 7
src/Web/WebMVC/Views/Cart/Index.cshtml View File

@ -5,14 +5,14 @@
@inject IIdentityParser<ApplicationUser> UserManager @inject IIdentityParser<ApplicationUser> UserManager
@{ @{
ViewData["Title"] = "My Cart";
ViewData["Title"] = "My Cart";
var headers = new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } };
} }
<form method="post" id="cartForm"> <form method="post" id="cartForm">
<div class="esh-basket">
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } })
@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })
</div>
<div class="esh-basket">
<partial name="_header" model="headers" />
@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })
</div>
</form> </form>

+ 44
- 44
src/Web/WebMVC/Views/Catalog/Index.cshtml View File

@ -1,57 +1,57 @@
@{ @{
ViewData["Title"] = "Catalog";
@model Microsoft.eShopOnContainers.WebMVC.ViewModels.CatalogViewModels.IndexViewModel
ViewData["Title"] = "Catalog";
@model Microsoft.eShopOnContainers.WebMVC.ViewModels.CatalogViewModels.IndexViewModel
} }
<section class="esh-catalog-hero"> <section class="esh-catalog-hero">
<div class="container">
<img class="esh-catalog-title" src="~/images/main_banner_text.png" />
</div>
<div class="container">
<img class="esh-catalog-title" src="~/images/main_banner_text.png" />
</div>
</section> </section>
<section class="esh-catalog-filters"> <section class="esh-catalog-filters">
<div class="container">
<form asp-action="Index" asp-controller="Catalog" method="post">
<label class="esh-catalog-label" data-title="brand">
<select asp-for="@Model.BrandFilterApplied" asp-items="@Model.Brands" class="esh-catalog-filter"></select>
</label>
<label class="esh-catalog-label" data-title="type">
<select asp-for="@Model.TypesFilterApplied" asp-items="@Model.Types" class="esh-catalog-filter"></select>
</label>
<input class="esh-catalog-send" type="image" src="~/images/arrow-right.svg" />
</form>
</div>
<div class="container">
<form asp-action="Index" asp-controller="Catalog" method="post">
<label class="esh-catalog-label" data-title="brand">
<select asp-for="@Model.BrandFilterApplied" asp-items="@Model.Brands" class="esh-catalog-filter"></select>
</label>
<label class="esh-catalog-label" data-title="type">
<select asp-for="@Model.TypesFilterApplied" asp-items="@Model.Types" class="esh-catalog-filter"></select>
</label>
<input class="esh-catalog-send" type="image" src="~/images/arrow-right.svg" />
</form>
</div>
</section> </section>
<div class="container"> <div class="container">
<div class="row">
<br />
@if(ViewBag.BasketInoperativeMsg != null)
{
<div class="alert alert-warning" role="alert">
&nbsp;@ViewBag.BasketInoperativeMsg
</div>
}
</div>
<div class="row">
<br />
@if (ViewBag.BasketInoperativeMsg != null)
{
<div class="alert alert-warning" role="alert">
&nbsp;@ViewBag.BasketInoperativeMsg
</div>
}
</div>
@if (Model.CatalogItems.Count() > 0)
{
@Html.Partial("_pagination", Model.PaginationInfo)
@if (Model.CatalogItems.Count() > 0)
{
<partial name="_pagination" model="Model.PaginationInfo" />
<div class="esh-catalog-items row">
@foreach (var catalogItem in Model.CatalogItems)
{
<div class="esh-catalog-item col-md-4">
@Html.Partial("_product", catalogItem)
</div>
}
</div>
<div class="esh-catalog-items row">
@foreach (var catalogItem in Model.CatalogItems)
{
<div class="esh-catalog-item col-md-4">
<partial name="_product" , model="catalogItem" />
</div>
}
</div>
@Html.Partial("_pagination", Model.PaginationInfo)
}
else
{
<div class="esh-catalog-items row">
THERE ARE NO RESULTS THAT MATCH YOUR SEARCH
</div>
}
<partial name="_pagination" model="Model.PaginationInfo" />
}
else
{
<div class="esh-catalog-items row">
THERE ARE NO RESULTS THAT MATCH YOUR SEARCH
</div>
}
</div> </div>

+ 6
- 0
src/Web/WebMVC/Views/Home/Privacy.cshtml View File

@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h2>@ViewData["Title"]</h2>
<p>Use this page to detail your site's privacy policy.</p>

+ 93
- 91
src/Web/WebMVC/Views/Order/Create.cshtml View File

@ -3,103 +3,105 @@
@inject IIdentityParser<ApplicationUser> UserManager @inject IIdentityParser<ApplicationUser> UserManager
@{ @{
ViewData["Title"] = "New Order";
ViewData["Title"] = "New Order";
var header = new Header { Controller = "Cart", Text = "Back to cart" };
} }
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Cart", Text = "Back to cart" } })
<partial name="_header" model="new List<Header> { header }" />
<div class="container"> <div class="container">
<form method="post" asp-controller="Order" asp-action="Checkout">
<section class="esh-orders_new-section">
<div class="row">
@foreach (var error in ViewData.ModelState.Values.SelectMany(err => err.Errors)) {
<div class="alert alert-warning" role="alert">
&nbsp;@error.ErrorMessage
</div>
}
</div>
<h4 class="esh-orders_new-title">Shipping address</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Street" class="esh-orders_new-title">Address</label>
<input asp-for="Street" class="form-control form-input" type="text" placeholder="Street"/>
<span asp-validation-for="Street" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="City" class="esh-orders_new-title">City</label>
<input asp-for="City" class="form-control form-input" type="text" placeholder="City"/>
<span asp-validation-for="City" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="State" class="esh-orders_new-title">State</label>
<input asp-for="State" class="form-control form-input" type="text" placeholder="State"/>
<span asp-validation-for="State" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="Country" class="esh-orders_new-title">Country</label>
<input asp-for="Country" class="form-control form-input" type="text" placeholder="Country"/>
<span asp-validation-for="Country" class="alert alert-danger" />
</div>
</div>
</div>
</section>
<section class="esh-orders_new-section">
<h4 class="esh-orders_new-title">Payment method</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardNumber" class="esh-orders_new-title">Card number</label>
<input asp-for="CardNumber" class="form-control form-input" type="text" placeholder="000000000000000"/>
<span asp-validation-for="CardNumber" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardHolderName" class="esh-orders_new-title">Cardholder name</label>
<input asp-for="CardHolderName" class="form-control form-input" type="text" placeholder="Cardholder"/>
<span asp-validation-for="CardHolderName" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardExpirationShort" class="esh-orders_new-title">Expiration date</label>
<input asp-for="CardExpirationShort" class="form-control form-input form-input-medium" type="text" placeholder="MM/YY"/>
<span asp-validation-for="CardExpirationShort" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardSecurityNumber" class="esh-orders_new-title">Security code</label>
<input asp-for="CardSecurityNumber" class="form-control form-input form-input-small" type="text" placeholder="000"/>
<span asp-validation-for="CardSecurityNumber" class="alert alert-danger" />
</div>
</div>
</div>
</section>
<form method="post" asp-controller="Order" asp-action="Checkout">
<section class="esh-orders_new-section">
<div class="row">
@foreach (var error in ViewData.ModelState.Values.SelectMany(err => err.Errors))
{
<div class="alert alert-warning" role="alert">
&nbsp;@error.ErrorMessage
</div>
}
</div>
<h4 class="esh-orders_new-title">Shipping address</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Street" class="esh-orders_new-title">Address</label>
<input asp-for="Street" class="form-control form-input" type="text" placeholder="Street" />
<span asp-validation-for="Street" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="City" class="esh-orders_new-title">City</label>
<input asp-for="City" class="form-control form-input" type="text" placeholder="City" />
<span asp-validation-for="City" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="State" class="esh-orders_new-title">State</label>
<input asp-for="State" class="form-control form-input" type="text" placeholder="State" />
<span asp-validation-for="State" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="Country" class="esh-orders_new-title">Country</label>
<input asp-for="Country" class="form-control form-input" type="text" placeholder="Country" />
<span asp-validation-for="Country" class="alert alert-danger" />
</div>
</div>
</div>
</section>
<section class="esh-orders_new-section">
<h4 class="esh-orders_new-title">Payment method</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardNumber" class="esh-orders_new-title">Card number</label>
<input asp-for="CardNumber" class="form-control form-input" type="text" placeholder="000000000000000" />
<span asp-validation-for="CardNumber" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardHolderName" class="esh-orders_new-title">Cardholder name</label>
<input asp-for="CardHolderName" class="form-control form-input" type="text" placeholder="Cardholder" />
<span asp-validation-for="CardHolderName" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardExpirationShort" class="esh-orders_new-title">Expiration date</label>
<input asp-for="CardExpirationShort" class="form-control form-input form-input-medium" type="text" placeholder="MM/YY" />
<span asp-validation-for="CardExpirationShort" class="alert alert-danger" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="CardSecurityNumber" class="esh-orders_new-title">Security code</label>
<input asp-for="CardSecurityNumber" class="form-control form-input form-input-small" type="text" placeholder="000" />
<span asp-validation-for="CardSecurityNumber" class="alert alert-danger" />
</div>
</div>
</div>
</section>
@await Html.PartialAsync("_OrderItems")
<partial name="_OrderItems" />
<section class="esh-orders_new-section">
<div class="form-group">
<div class="col-md-9">
</div>
<div class="col-md-2">
<input type="submit" value="[ Place Order ]" name="action" class="btn esh-orders_new-placeOrder" />
</div>
</div>
</section>
<input asp-for="ZipCode" type="hidden" />
<input asp-for="RequestId" type="hidden" value="@Guid.NewGuid().ToString()"/>
</form>
<section class="esh-orders_new-section">
<div class="form-group">
<div class="col-md-9">
</div>
<div class="col-md-2">
<input type="submit" value="[ Place Order ]" name="action" class="btn esh-orders_new-placeOrder" />
</div>
</div>
</section>
<input asp-for="ZipCode" type="hidden" />
<input asp-for="RequestId" type="hidden" value="@Guid.NewGuid().ToString()" />
</form>
</div> </div>
@section Scripts { @section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<partial name="_ValidationScriptsPartial" />
} }

+ 71
- 70
src/Web/WebMVC/Views/Order/Detail.cshtml View File

@ -3,88 +3,89 @@
@model Microsoft.eShopOnContainers.WebMVC.ViewModels.Order @model Microsoft.eShopOnContainers.WebMVC.ViewModels.Order
@{ @{
ViewData["Title"] = "Order Detail";
ViewData["Title"] = "Order Detail";
var headers = new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } };
} }
<div class="esh-orders_detail"> <div class="esh-orders_detail">
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } })
<partial name="_Header" model="headers" />
<div class="container">
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-3">Order number</section>
<section class="esh-orders_detail-title col-xs-3">Date</section>
<section class="esh-orders_detail-title col-xs-3">Total</section>
<section class="esh-orders_detail-title col-xs-3">Status</section>
</article>
<div class="container">
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-3">Order number</section>
<section class="esh-orders_detail-title col-xs-3">Date</section>
<section class="esh-orders_detail-title col-xs-3">Total</section>
<section class="esh-orders_detail-title col-xs-3">Status</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-3">@Model.OrderNumber</section>
<section class="esh-orders_detail-item col-xs-3">@Model.Date</section>
<section class="esh-orders_detail-item col-xs-3">$@Model.Total</section>
<section class="esh-orders_detail-title col-xs-3">@Model.Status</section>
</article>
</section>
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-12">Description</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-3">@Model.OrderNumber</section>
<section class="esh-orders_detail-item col-xs-3">@Model.Date</section>
<section class="esh-orders_detail-item col-xs-3">$@Model.Total</section>
<section class="esh-orders_detail-title col-xs-3">@Model.Status</section>
</article>
</section>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.Description</section>
</article>
</section>
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-12">Description</section>
</article>
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-12">Shiping address</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.Description</section>
</article>
</section>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.Street</section>
</article>
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-12">Shiping address</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.City</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.Street</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.Country</section>
</article>
</section>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.City</section>
</article>
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-12">ORDER DETAILS</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-12">@Model.Country</section>
</article>
</section>
@for (int i = 0; i < Model.OrderItems.Count; i++)
{
var item = Model.OrderItems[i];
<article class="esh-orders_detail-items esh-orders_detail-items--border row">
<section class="esh-orders_detail-item col-md-4 hidden-md-down">
<img class="esh-orders_detail-image" src="@item.PictureUrl">
</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-4">@item.ProductName</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">$ @item.UnitPrice.ToString("N2")</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">@item.Units</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-2">$ @Math.Round(item.Units * item.UnitPrice, 2).ToString("N2")</section>
</article>
}
</section>
<section class="esh-orders_detail-section">
<article class="esh-orders_detail-titles row">
<section class="esh-orders_detail-title col-xs-12">ORDER DETAILS</section>
</article>
<section class="esh-orders_detail-section esh-orders_detail-section--right">
<article class="esh-orders_detail-titles esh-basket-titles--clean row">
<section class="esh-orders_detail-title col-xs-9"></section>
<section class="esh-orders_detail-title col-xs-2">TOTAL</section>
</article>
@for (int i = 0; i < Model.OrderItems.Count; i++)
{
var item = Model.OrderItems[i];
<article class="esh-orders_detail-items esh-orders_detail-items--border row">
<section class="esh-orders_detail-item col-md-4 hidden-md-down">
<img class="esh-orders_detail-image" src="@item.PictureUrl">
</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-4">@item.ProductName</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">$ @item.UnitPrice.ToString("N2")</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">@item.Units</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-2">$ @Math.Round(item.Units * item.UnitPrice, 2).ToString("N2")</section>
</article>
}
</section>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-9"></section>
<section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ @Model.Total</section>
</article>
</section>
</div>
<section class="esh-orders_detail-section esh-orders_detail-section--right">
<article class="esh-orders_detail-titles esh-basket-titles--clean row">
<section class="esh-orders_detail-title col-xs-9"></section>
<section class="esh-orders_detail-title col-xs-2">TOTAL</section>
</article>
<article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-9"></section>
<section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ @Model.Total</section>
</article>
</section>
</div>
</div> </div>

+ 38
- 36
src/Web/WebMVC/Views/Order/Index.cshtml View File

@ -3,45 +3,47 @@
@model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order> @model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order>
@{ @{
ViewData["Title"] = "My Orders";
ViewData["Title"] = "My Orders";
var headers = new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Text = " / " },
new Header() { Controller = "OrderManagement", Text = "Orders Management" }
};
} }
<div class="esh-orders"> <div class="esh-orders">
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Text = " / " },
new Header() { Controller = "OrderManagement", Text = "Orders Management" } })
<div class="container">
<article class="esh-orders-titles row">
<section class="esh-orders-title col-xs-2">Order number</section>
<section class="esh-orders-title col-xs-4">Date</section>
<section class="esh-orders-title col-xs-2">Total</section>
<section class="esh-orders-title col-xs-2">Status</section>
<section class="esh-orders-title col-xs-2"></section>
</article>
@if (Model != null && Model.Any())
{
foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-1">
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</section>
<section class="esh-orders-item col-xs-1">
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article>
}
}
</div>
<partial name="_Header" model="headers" />
<div class="container">
<article class="esh-orders-titles row">
<section class="esh-orders-title col-xs-2">Order number</section>
<section class="esh-orders-title col-xs-4">Date</section>
<section class="esh-orders-title col-xs-2">Total</section>
<section class="esh-orders-title col-xs-2">Status</section>
<section class="esh-orders-title col-xs-2"></section>
</article>
@if (Model != null && Model.Any())
{
foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-1">
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</section>
<section class="esh-orders-item col-xs-1">
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article>
}
}
</div>
</div> </div>


+ 33
- 32
src/Web/WebMVC/Views/OrderManagement/Index.cshtml View File

@ -3,41 +3,42 @@
@model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order> @model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order>
@{ @{
ViewData["Title"] = "My Orders";
ViewData["Title"] = "My Orders";
var headers = new List<Header>() {
new Header { Controller = " Catalog", Text="Back to catalog" } };
} }
<div class="esh-orders"> <div class="esh-orders">
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } })
<partial name="_Header" model="headers" />
<div class="container">
<article class="esh-orders-titles row">
<section class="esh-orders-title col-xs-2">Order number</section>
<section class="esh-orders-title col-xs-4">Date</section>
<section class="esh-orders-title col-xs-2">Total</section>
<section class="esh-orders-title col-xs-2">Status</section>
<section class="esh-orders-title col-xs-2"></section>
</article>
<div class="container">
<article class="esh-orders-titles row">
<section class="esh-orders-title col-xs-2">Order number</section>
<section class="esh-orders-title col-xs-4">Date</section>
<section class="esh-orders-title col-xs-2">Total</section>
<section class="esh-orders-title col-xs-2">Status</section>
<section class="esh-orders-title col-xs-2"></section>
</article>
@foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-2">
<form asp-action="OrderProcess" id="orderForm+@item.OrderNumber" method="post">
<input type="hidden" name="orderId" value="@item.OrderNumber" />
<select name="actionCode" asp-items="@item.ActionCodeSelectList"
disabled=@(item.Status != "paid")
onchange="document.getElementById('orderForm+@item.OrderNumber').submit()">
<option value="">&nbsp;&nbsp;Select Action</option>
<option value="">------------------</option>
</select>
</form>
</section>
</article>
}
</div>
@foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-2">
<form asp-action="OrderProcess" id="orderForm+@item.OrderNumber" method="post">
<input type="hidden" name="orderId" value="@item.OrderNumber" />
<select name="actionCode" asp-items="@item.ActionCodeSelectList"
disabled=@(item.Status != "paid")
onchange="document.getElementById('orderForm+@item.OrderNumber').submit()">
<option value="">&nbsp;&nbsp;Select Action</option>
<option value="">------------------</option>
</select>
</form>
</section>
</article>
}
</div>
</div> </div>

+ 41
- 0
src/Web/WebMVC/Views/Shared/_CookieConsentPartial.cshtml View File

@ -0,0 +1,41 @@
@using Microsoft.AspNetCore.Http.Features
@{
var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
var showBanner = !consentFeature?.CanTrack ?? false;
var cookieString = consentFeature?.CreateConsentCookie();
}
@if (showBanner)
{
<nav id="cookieConsent" class="navbar navbar-default navbar-fixed-top" role="alert">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#cookieConsent .navbar-collapse">
<span class="sr-only">Toggle cookie consent banner</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<span class="navbar-brand"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></span>
</div>
<div class="collapse navbar-collapse">
<p class="navbar-text">
Use this space to summarize your privacy and cookie use policy.
</p>
<div class="navbar-right">
<a asp-controller="Home" asp-action="Privacy" class="btn btn-info navbar-btn">Learn More</a>
<button type="button" class="btn btn-default navbar-btn" data-cookie-string="@cookieString">Accept</button>
</div>
</div>
</div>
</nav>
<script>
(function () {
document.querySelector("#cookieConsent button[data-cookie-string]").addEventListener("click", function (el) {
document.cookie = el.target.dataset.cookieString;
document.querySelector("#cookieConsent").classList.add("hidden");
}, false);
})();
</script>
}

+ 1
- 0
src/Web/WebMVC/Views/Shared/_Layout.cshtml View File

@ -49,6 +49,7 @@
</div> </div>
</header> </header>
<partial name="_CookieConsentPartial" />
@RenderBody() @RenderBody()


+ 46
- 48
src/Web/WebMVC/WebMVC.csproj View File

@ -1,52 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<UserSecretsId>aspnet-Microsoft.eShopOnContainers-946ae052-8305-4a99-965b-ec8636ddbae3</UserSecretsId>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Content Include="Setup\images.zip">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Setup\override.css">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="2.6.375" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.3" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Fabric.MSBuild" Version="1.6.5" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.113" />
</ItemGroup>
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
<Exec Command="dotnet bundle" Condition="'$(ASPNETCORE_ENVIRONMENT)'!='Development'" />
</Target>
<ItemGroup>
<DotNetCliToolReference Include="BundlerMinifier.Core" Version="2.7.385" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="ViewModels\CampaignItem.cs" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<UserSecretsId>aspnet-Microsoft.eShopOnContainers-946ae052-8305-4a99-965b-ec8636ddbae3</UserSecretsId>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<Content Include="Setup\images.zip">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Setup\override.css">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="2.8.391" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.4.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Fabric.MSBuild" Version="1.6.7" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.3" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.163" />
</ItemGroup>
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
<Exec Command="dotnet bundle" Condition="'$(ASPNETCORE_ENVIRONMENT)'!='Development'" />
</Target>
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="ViewModels\CampaignItem.cs" />
</ItemGroup>
</Project> </Project>

+ 34
- 25
src/Web/WebMVC/appsettings.json View File

@ -1,27 +1,36 @@
{ {
"CatalogUrl": "http://localhost:5101",
"OrderingUrl": "http://localhost:5102",
"BasketUrl": "http://localhost:5103",
"MarketingUrl": "http://localhost:5110",
"IdentityUrl": "http://localhost:5105",
"CallBackUrl": "http://localhost:5100/",
"LocationsUrl": "http://localhost:5109/",
"IsClusterEnv": "False",
"UseResilientHttp": "True",
"UseLoadTest": false,
"ActivateCampaignDetailFunction": "False",
"UseCustomizationData": false,
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"InstrumentationKey": ""
},
"HttpClientRetryCount": 8,
"HttpClientExceptionsAllowedBeforeBreaking": 7
"AllowedHosts": "*",
"CatalogUrl": "http://localhost:5101",
"OrderingUrl": "http://localhost:5102",
"BasketUrl": "http://localhost:5103",
"MarketingUrl": "http://localhost:5110",
"IdentityUrl": "https://localhost:4105",
"CallBackUrl": "https://localhost:4100/",
"LocationsUrl": "http://localhost:5109/",
"IsClusterEnv": "False",
"UseResilientHttp": "True",
"UseLoadTest": false,
"ActivateCampaignDetailFunction": "False",
"UseCustomizationData": false,
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"InstrumentationKey": ""
},
"HttpClientRetryCount": 8,
"HttpClientExceptionsAllowedBeforeBreaking": 7,
"Kestrel": {
"Certificates": {
"Default": {
"Path": "./synergydev.pfx",
"Password": "RH@ssl2018"
}
}
}
} }

+ 2835
- 2833
src/Web/WebMVC/wwwroot/js/site.js
File diff suppressed because it is too large
View File


+ 6
- 6
src/Web/WebMVC/wwwroot/js/site.min.js
File diff suppressed because it is too large
View File


+ 4
- 2
src/Web/WebSPA/Dockerfile View File

@ -1,9 +1,10 @@
ARG NODE_IMAGE=node:8.11 ARG NODE_IMAGE=node:8.11
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
EXPOSE 443
FROM microsoft/dotnet:2.1-sdk as dotnet-build
FROM microsoft/dotnet:2.1.401-sdk as dotnet-build
WORKDIR /src WORKDIR /src
FROM ${NODE_IMAGE} as node-build FROM ${NODE_IMAGE} as node-build
@ -16,6 +17,7 @@ FROM dotnet-build as publish
WORKDIR /src/src/Web/WebSPA/wwwroot WORKDIR /src/src/Web/WebSPA/wwwroot
COPY --from=node-build /web/wwwroot . COPY --from=node-build /web/wwwroot .
WORKDIR /src WORKDIR /src
COPY /Certificates/eShopOnContainers.pfx /root/.aspnet/https/
COPY . . COPY . .
WORKDIR /src/src/Web/WebSPA WORKDIR /src/src/Web/WebSPA
RUN dotnet publish -c Release -o /app RUN dotnet publish -c Release -o /app


+ 17
- 16
src/Web/WebSPA/Properties/launchSettings.json View File

@ -1,18 +1,19 @@
{ {
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:58018/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
}
}
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:58018/",
"sslPort": 4104
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
},
"use64Bit": true
}
}
} }

BIN
src/Web/WebSPA/Setup/DotNet Foundation CA.pfx View File


BIN
src/Web/WebSPA/Setup/eShopOnContainers.pfx View File


+ 144
- 133
src/Web/WebSPA/Startup.cs View File

@ -17,142 +17,153 @@ using WebSPA.Infrastructure;
namespace eShopConContainers.WebSPA namespace eShopConContainers.WebSPA
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
private IHostingEnvironment _hostingEnv;
public Startup(IHostingEnvironment env)
{
_hostingEnv = env;
var localPath = new Uri(Configuration["ASPNETCORE_URLS"])?.LocalPath ?? "/";
Configuration["BaseUrl"] = localPath;
}
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
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));
});
services.Configure<AppSettings>(Configuration);
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
{
services.AddDataProtection(opts =>
{
opts.ApplicationDiscriminator = "eshop.webspa";
})
.PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys");
}
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
}
// 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, IAntiforgery antiforgery)
{
loggerFactory.AddAzureWebAppDiagnostics();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Configure XSRF middleware, This pattern is for SPA style applications where XSRF token is added on Index page
// load and passed back token on every subsequent async request
// app.Use(async (context, next) =>
// {
// if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase))
// {
// var tokens = antiforgery.GetAndStoreTokens(context);
// context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
// }
// await next.Invoke();
// });
//Seed Data
WebContextSeed.Seed(app, env, loggerFactory);
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase);
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
private readonly IHostingEnvironment _hostingEnv;
public Startup(IHostingEnvironment env)
{
_hostingEnv = env;
string localPath = new Uri(Configuration["ASPNETCORE_URLS"])?.LocalPath ?? "/";
Configuration["BaseUrl"] = localPath;
}
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
services.AddHealthChecks(checks =>
{
int minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out int 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));
});
services.Configure<AppSettings>(Configuration);
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
{
services.AddDataProtection(opts =>
{
opts.ApplicationDiscriminator = "eshop.webspa";
})
.PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys");
}
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
})
.SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
services.AddHttpsRedirection(opts =>
{
opts.HttpsPort = 4104;
});
}
// 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, IAntiforgery antiforgery)
{
loggerFactory.AddAzureWebAppDiagnostics();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
// Configure XSRF middleware, This pattern is for SPA style applications where XSRF token is added on Index page
// load and passed back token on every subsequent async request
// app.Use(async (context, next) =>
// {
// if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase))
// {
// var tokens = antiforgery.GetAndStoreTokens(context);
// context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
// }
// await next.Invoke();
// });
//Seed Data
WebContextSeed.Seed(app, env, loggerFactory);
string 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.Use(async (context, next) =>
{
await next();
// If there's no available file and the request doesn't contain an extension, we're probably trying to access a page.
// Rewrite request to use app root
if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api"))
{
context.Request.Path = "/index.html";
context.Response.StatusCode = 200; // Make sure we update the status code, otherwise it returns 404
await next();
}
});
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
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());
}
}
}
app.Use(async (context, next) =>
{
await next();
// If there's no available file and the request doesn't contain an extension, we're probably trying to access a page.
// Rewrite request to use app root
if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api"))
{
context.Request.Path = "/index.html";
context.Response.StatusCode = 200; // Make sure we update the status code, otherwise it returns 404
await next();
}
});
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
private void RegisterAppInsights(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration);
string 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());
}
}
}
} }

+ 172
- 164
src/Web/WebSPA/WebSPA.csproj View File

@ -1,102 +1,107 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<UserSecretsId>aspnetcorespa-c23d27a4-eb88-4b18-9b77-2a93f3b15119</UserSecretsId>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<TypeScriptCompileOnSaveEnabled>false</TypeScriptCompileOnSaveEnabled>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<GeneratedItemPatterns>wwwroot/dist/**</GeneratedItemPatterns>
<DefaultItemExcludes>$(DefaultItemExcludes);$(GeneratedItemPatterns)</DefaultItemExcludes>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<UserSecretsId>aspnetcorespa-c23d27a4-eb88-4b18-9b77-2a93f3b15119</UserSecretsId>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<TypeScriptCompileOnSaveEnabled>false</TypeScriptCompileOnSaveEnabled>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<GeneratedItemPatterns>wwwroot/dist/**</GeneratedItemPatterns>
<DefaultItemExcludes>$(DefaultItemExcludes);$(GeneratedItemPatterns)</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<Compile Remove="node_modules\**\*;Client\**\*" />
<None Remove="Client\environments\environment.prod.ts" />
<None Remove="Client\environments\environment.ts" />
<None Remove="Client\guid.ts" />
<None Remove="Client\main.ts" />
<None Remove="Client\modules\app.component.ts" />
<None Remove="Client\modules\app.module.ts" />
<None Remove="Client\modules\app.routes.ts" />
<None Remove="Client\modules\app.service.ts" />
<None Remove="Client\modules\basket\basket-status\basket-status.component.ts" />
<None Remove="Client\modules\basket\basket.component.ts" />
<None Remove="Client\modules\basket\basket.module.ts" />
<None Remove="Client\modules\basket\basket.service.ts" />
<None Remove="Client\modules\campaigns\campaigns-detail\campaigns-detail.component.ts" />
<None Remove="Client\modules\campaigns\campaigns.component.ts" />
<None Remove="Client\modules\campaigns\campaigns.module.ts" />
<None Remove="Client\modules\campaigns\campaigns.service.ts" />
<None Remove="Client\modules\catalog\catalog.component.ts" />
<None Remove="Client\modules\catalog\catalog.module.ts" />
<None Remove="Client\modules\catalog\catalog.service.ts" />
<None Remove="Client\modules\orders\orders-detail\orders-detail.component.ts" />
<None Remove="Client\modules\orders\orders-new\orders-new.component.ts" />
<None Remove="Client\modules\orders\orders.component.ts" />
<None Remove="Client\modules\orders\orders.module.ts" />
<None Remove="Client\modules\orders\orders.service.ts" />
<None Remove="Client\modules\shared\components\header\header.ts" />
<None Remove="Client\modules\shared\components\identity\identity.ts" />
<None Remove="Client\modules\shared\components\page-not-found\page-not-found.component.spec.ts" />
<None Remove="Client\modules\shared\components\page-not-found\page-not-found.component.ts" />
<None Remove="Client\modules\shared\components\pager\pager.ts" />
<None Remove="Client\modules\shared\models\basket.model.ts" />
<None Remove="Client\modules\shared\models\basketCheckout.model.ts" />
<None Remove="Client\modules\shared\models\basketItem.model.ts" />
<None Remove="Client\modules\shared\models\campaign.model.ts" />
<None Remove="Client\modules\shared\models\campaignItem.model.ts" />
<None Remove="Client\modules\shared\models\catalog.model.ts" />
<None Remove="Client\modules\shared\models\catalogBrand.model.ts" />
<None Remove="Client\modules\shared\models\catalogItem.model.ts" />
<None Remove="Client\modules\shared\models\catalogType.model.ts" />
<None Remove="Client\modules\shared\models\configuration.model.ts" />
<None Remove="Client\modules\shared\models\identity.model.ts" />
<None Remove="Client\modules\shared\models\order-detail.model.ts" />
<None Remove="Client\modules\shared\models\order.model.ts" />
<None Remove="Client\modules\shared\models\orderItem.model.ts" />
<None Remove="Client\modules\shared\models\pager.model.ts" />
<None Remove="Client\modules\shared\pipes\uppercase.pipe.spec.ts" />
<None Remove="Client\modules\shared\pipes\uppercase.pipe.ts" />
<None Remove="Client\modules\shared\services\basket.wrapper.service.ts" />
<None Remove="Client\modules\shared\services\configuration.service.ts" />
<None Remove="Client\modules\shared\services\data.service.ts" />
<None Remove="Client\modules\shared\services\notification.service.ts" />
<None Remove="Client\modules\shared\services\security.service.ts" />
<None Remove="Client\modules\shared\services\signalr.service.ts" />
<None Remove="Client\modules\shared\services\storage.service.ts" />
<None Remove="Client\modules\shared\shared.module.ts" />
<None Remove="Client\polyfills.ts" />
<None Remove="Client\test.ts" />
<None Remove="Client\typings.d.ts" />
<Content Include="Setup\images.zip">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="appsettings.json;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="web.config;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="wwwroot\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Remove="node_modules\**\*;Client\**\*" />
<None Remove="Client\environments\environment.prod.ts" />
<None Remove="Client\environments\environment.ts" />
<None Remove="Client\guid.ts" />
<None Remove="Client\main.ts" />
<None Remove="Client\modules\app.component.ts" />
<None Remove="Client\modules\app.module.ts" />
<None Remove="Client\modules\app.routes.ts" />
<None Remove="Client\modules\app.service.ts" />
<None Remove="Client\modules\basket\basket-status\basket-status.component.ts" />
<None Remove="Client\modules\basket\basket.component.ts" />
<None Remove="Client\modules\basket\basket.module.ts" />
<None Remove="Client\modules\basket\basket.service.ts" />
<None Remove="Client\modules\campaigns\campaigns-detail\campaigns-detail.component.ts" />
<None Remove="Client\modules\campaigns\campaigns.component.ts" />
<None Remove="Client\modules\campaigns\campaigns.module.ts" />
<None Remove="Client\modules\campaigns\campaigns.service.ts" />
<None Remove="Client\modules\catalog\catalog.component.ts" />
<None Remove="Client\modules\catalog\catalog.module.ts" />
<None Remove="Client\modules\catalog\catalog.service.ts" />
<None Remove="Client\modules\orders\orders-detail\orders-detail.component.ts" />
<None Remove="Client\modules\orders\orders-new\orders-new.component.ts" />
<None Remove="Client\modules\orders\orders.component.ts" />
<None Remove="Client\modules\orders\orders.module.ts" />
<None Remove="Client\modules\orders\orders.service.ts" />
<None Remove="Client\modules\shared\components\header\header.ts" />
<None Remove="Client\modules\shared\components\identity\identity.ts" />
<None Remove="Client\modules\shared\components\page-not-found\page-not-found.component.spec.ts" />
<None Remove="Client\modules\shared\components\page-not-found\page-not-found.component.ts" />
<None Remove="Client\modules\shared\components\pager\pager.ts" />
<None Remove="Client\modules\shared\models\basket.model.ts" />
<None Remove="Client\modules\shared\models\basketCheckout.model.ts" />
<None Remove="Client\modules\shared\models\basketItem.model.ts" />
<None Remove="Client\modules\shared\models\campaign.model.ts" />
<None Remove="Client\modules\shared\models\campaignItem.model.ts" />
<None Remove="Client\modules\shared\models\catalog.model.ts" />
<None Remove="Client\modules\shared\models\catalogBrand.model.ts" />
<None Remove="Client\modules\shared\models\catalogItem.model.ts" />
<None Remove="Client\modules\shared\models\catalogType.model.ts" />
<None Remove="Client\modules\shared\models\configuration.model.ts" />
<None Remove="Client\modules\shared\models\identity.model.ts" />
<None Remove="Client\modules\shared\models\order-detail.model.ts" />
<None Remove="Client\modules\shared\models\order.model.ts" />
<None Remove="Client\modules\shared\models\orderItem.model.ts" />
<None Remove="Client\modules\shared\models\pager.model.ts" />
<None Remove="Client\modules\shared\pipes\uppercase.pipe.spec.ts" />
<None Remove="Client\modules\shared\pipes\uppercase.pipe.ts" />
<None Remove="Client\modules\shared\services\basket.wrapper.service.ts" />
<None Remove="Client\modules\shared\services\configuration.service.ts" />
<None Remove="Client\modules\shared\services\data.service.ts" />
<None Remove="Client\modules\shared\services\notification.service.ts" />
<None Remove="Client\modules\shared\services\security.service.ts" />
<None Remove="Client\modules\shared\services\signalr.service.ts" />
<None Remove="Client\modules\shared\services\storage.service.ts" />
<None Remove="Client\modules\shared\shared.module.ts" />
<None Remove="Client\polyfills.ts" />
<None Remove="Client\test.ts" />
<None Remove="Client\typings.d.ts" />
<None Remove="Setup\DotNet Foundation CA.pfx" />
<None Remove="Setup\eShopOnContainers.pfx" />
<Content Include="Setup\DotNet Foundation CA.pfx" />
<Content Include="Setup\eShopOnContainers.pfx" />
<Content Include="Setup\images.zip">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="appsettings.json;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="web.config;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="wwwroot\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.3" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta9" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.4.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
<!-- workaround for https://github.com/aspnet/websdk/issues/114 -->
<!--
<!-- workaround for https://github.com/aspnet/websdk/issues/114 -->
<!--
<Target Name="AddGeneratedContentItems" BeforeTargets="AssignTargetPaths" DependsOnTargets="PrepareForPublish"> <Target Name="AddGeneratedContentItems" BeforeTargets="AssignTargetPaths" DependsOnTargets="PrepareForPublish">
<ItemGroup> <ItemGroup>
<Content Include="wwwroot/**" CopyToPublishDirectory="PreserveNewest" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);@(Content)" /> <Content Include="wwwroot/**" CopyToPublishDirectory="PreserveNewest" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);@(Content)" />
@ -104,79 +109,82 @@
</Target> </Target>
--> -->
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\assets\" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\assets\" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="Client\environments\environment.prod.ts" />
<TypeScriptCompile Include="Client\environments\environment.ts" />
<TypeScriptCompile Include="Client\guid.ts" />
<TypeScriptCompile Include="Client\main.ts" />
<TypeScriptCompile Include="Client\modules\app.component.ts" />
<TypeScriptCompile Include="Client\modules\app.module.ts" />
<TypeScriptCompile Include="Client\modules\app.routes.ts" />
<TypeScriptCompile Include="Client\modules\app.service.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket-status\basket-status.component.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.component.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.module.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.service.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns-detail\campaigns-detail.component.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.component.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.module.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.service.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.component.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.module.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.service.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders-detail\orders-detail.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders-new\orders-new.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.module.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\header\header.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\identity\identity.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\page-not-found\page-not-found.component.spec.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\page-not-found\page-not-found.component.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\pager\pager.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basket.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basketCheckout.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basketItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\campaign.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\campaignItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalog.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogBrand.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogType.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\configuration.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\identity.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\order-detail.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\order.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\orderItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\pager.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\pipes\uppercase.pipe.spec.ts" />
<TypeScriptCompile Include="Client\modules\shared\pipes\uppercase.pipe.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\basket.wrapper.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\configuration.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\data.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\notification.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\security.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\signalr.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\storage.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\shared.module.ts" />
<TypeScriptCompile Include="Client\polyfills.ts" />
<TypeScriptCompile Include="Client\test.ts" />
<TypeScriptCompile Include="Client\typings.d.ts" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="Client\environments\environment.prod.ts" />
<TypeScriptCompile Include="Client\environments\environment.ts" />
<TypeScriptCompile Include="Client\guid.ts" />
<TypeScriptCompile Include="Client\main.ts" />
<TypeScriptCompile Include="Client\modules\app.component.ts" />
<TypeScriptCompile Include="Client\modules\app.module.ts" />
<TypeScriptCompile Include="Client\modules\app.routes.ts" />
<TypeScriptCompile Include="Client\modules\app.service.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket-status\basket-status.component.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.component.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.module.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.service.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns-detail\campaigns-detail.component.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.component.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.module.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.service.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.component.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.module.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.service.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders-detail\orders-detail.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders-new\orders-new.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.module.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\header\header.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\identity\identity.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\page-not-found\page-not-found.component.spec.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\page-not-found\page-not-found.component.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\pager\pager.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basket.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basketCheckout.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basketItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\campaign.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\campaignItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalog.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogBrand.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogType.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\configuration.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\identity.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\order-detail.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\order.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\orderItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\pager.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\pipes\uppercase.pipe.spec.ts" />
<TypeScriptCompile Include="Client\modules\shared\pipes\uppercase.pipe.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\basket.wrapper.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\configuration.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\data.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\notification.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\security.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\signalr.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\storage.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\shared.module.ts" />
<TypeScriptCompile Include="Client\polyfills.ts" />
<TypeScriptCompile Include="Client\test.ts" />
<TypeScriptCompile Include="Client\typings.d.ts" />
</ItemGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties package-lock_1json__JSONSchema="http://json.schemastore.org/bower" />
</VisualStudio>
</ProjectExtensions>
<ItemGroup>
<Content Update="Setup\DotNet Foundation CA.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="Setup\eShopOnContainers.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project> </Project>

+ 26
- 18
src/Web/WebSPA/appsettings.json View File

@ -1,20 +1,28 @@
{ {
"IdentityUrl": "http://localhost:5105",
"MarketingUrl": "http://localhost:5110",
"CallBackUrl": "http://localhost:5104/",
"PurchaseUrl": "http://localhost:5200",
"UseCustomizationData": true,
"IsClusterEnv": "False",
"ActivateCampaignDetailFunction": true,
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"InstrumentationKey": ""
}
"IdentityUrl": "https://localhost:4105",
"MarketingUrl": "http://localhost:5110",
"CallBackUrl": "https://localhost:4104/",
"PurchaseUrl": "http://localhost:5200",
"UseCustomizationData": true,
"IsClusterEnv": "False",
"ActivateCampaignDetailFunction": true,
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"InstrumentationKey": ""
},
"Kestrel": {
"Certificates": {
"Default": {
"Path": "./Setup/eShopOnContainers.pfx",
"Password": "D0tNet@"
}
}
}
} }

src/Web/WebSPA/package-lock.json → src/Web/WebSPA/npm-shrinkwrap.json View File


+ 3
- 2
src/Web/WebStatus/Dockerfile View File

@ -1,12 +1,13 @@
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime AS base
WORKDIR /app WORKDIR /app
EXPOSE 80 EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
FROM microsoft/dotnet:2.1.401-sdk AS build
WORKDIR /src WORKDIR /src
COPY . . COPY . .
WORKDIR /src/src/Web/WebStatus WORKDIR /src/src/Web/WebStatus
RUN dotnet restore -nowarn:msb3202,nu1503 RUN dotnet restore -nowarn:msb3202,nu1503
COPY src/Web/WebMVC/synergydev.pfx /root/.aspnet/https/
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


+ 2
- 1
src/Web/WebStatus/Properties/launchSettings.json View File

@ -13,7 +13,8 @@
"launchBrowser": true, "launchBrowser": true,
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
}, },
"WebStatus": { "WebStatus": {
"commandName": "Project", "commandName": "Project",


+ 96
- 95
src/Web/WebStatus/Startup.cs View File

@ -1,110 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.ServiceFabric;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
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 WebStatus.Extensions; using WebStatus.Extensions;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.ServiceFabric;
using TimeSpan = System.TimeSpan;
namespace WebStatus namespace WebStatus
{ {
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
services.AddOptions();
// Add framework services.
services.AddHealthChecks(checks =>
{
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
{
minutes = minutesParsed;
}
checks.AddUrlCheckIfNotNull(Configuration["OrderingUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["OrderingBackgroundTasksUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["BasketUrl"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
checks.AddUrlCheckIfNotNull(Configuration["CatalogUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["IdentityUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["LocationsUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["MarketingUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["PaymentUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["mvc"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
checks.AddUrlCheckIfNotNull(Configuration["spa"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
});
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)
{
loggerFactory.AddAzureWebAppDiagnostics();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
app.UsePathBase(pathBase);
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
RegisterAppInsights(services);
services.AddOptions();
// Add framework services.
services.AddHealthChecks(checks =>
{
var minutes = 1;
if (int.TryParse(Configuration["HealthCheck:Timeout"], out int minutesParsed))
{
minutes = minutesParsed;
}
checks.AddUrlCheckIfNotNull(Configuration["OrderingUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["OrderingBackgroundTasksUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["BasketUrl"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
checks.AddUrlCheckIfNotNull(Configuration["CatalogUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["IdentityUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["LocationsUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["MarketingUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["PaymentUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["mvc"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
checks.AddUrlCheckIfNotNull(Configuration["spa"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
});
services
.AddMvc()
.SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1)
;
}
// 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);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
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.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
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());
}
}
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
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());
}
}
}
} }

+ 19
- 18
src/Web/WebStatus/WebStatus.csproj View File

@ -1,22 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.113" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.3</RuntimeFrameworkVersion>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.4.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.7.2" />
<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" Version="2.1.3" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="1.0.113" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>
</Project> </Project>

Loading…
Cancel
Save