Catalog.API gRPC support for one endpoint
This commit is contained in:
parent
e1ace6fe47
commit
7c0e2a1c86
@ -77,7 +77,7 @@ services:
|
|||||||
catalog.api:
|
catalog.api:
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
- ASPNETCORE_URLS=http://0.0.0.0:80;https://0.0.0.0:443;
|
||||||
- ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word}
|
- ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word}
|
||||||
- PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/api/v1/c/catalog/items/[0]/pic/} #Local: You need to open your local dev-machine firewall at range 5100-5110.
|
- PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5202/api/v1/c/catalog/items/[0]/pic/} #Local: You need to open your local dev-machine firewall at range 5100-5110.
|
||||||
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
|
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
|
||||||
@ -91,8 +91,8 @@ services:
|
|||||||
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
|
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
|
||||||
- OrchestratorType=${ORCHESTRATOR_TYPE}
|
- OrchestratorType=${ORCHESTRATOR_TYPE}
|
||||||
ports:
|
ports:
|
||||||
- "5101:80" # Important: In a production environment your should remove the external port (5101) kept here for microservice debugging purposes.
|
- "5101:80"
|
||||||
# The API Gateway redirects and access through the internal port (80).
|
- "9101:443"
|
||||||
|
|
||||||
ordering.api:
|
ordering.api:
|
||||||
environment:
|
environment:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
<DebugType>portable</DebugType>
|
<DebugType>portable</DebugType>
|
||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
<AssemblyName>Catalog.API</AssemblyName>
|
<AssemblyName>Catalog.API</AssemblyName>
|
||||||
@ -32,8 +32,18 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="Proto\catalog.proto" GrpcServices="Server" Generator="MSBuild:Compile" />
|
||||||
|
<Content Include="@(Protobuf)" />
|
||||||
|
<None Remove="@(Protobuf)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Grpc.AspNetCore.Server" Version="0.1.21-pre1" />
|
||||||
|
<PackageReference Include="Google.Protobuf" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Grpc.Tools" Version="1.21.0" PrivateAssets="All" />
|
||||||
|
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="2.2.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
@ -43,18 +53,16 @@
|
|||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="3.0.0-preview6.19304.6" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="3.0.0-dev-00053" />
|
||||||
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" />
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" />
|
||||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.1-dev-00209" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Http" Version="4.2.1" />
|
<PackageReference Include="Serilog.Sinks.Http" Version="4.2.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc2" />
|
||||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@ -63,7 +71,6 @@
|
|||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -13,10 +13,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class PicController : ControllerBase
|
public class PicController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly IHostingEnvironment _env;
|
private readonly IWebHostEnvironment _env;
|
||||||
private readonly CatalogContext _catalogContext;
|
private readonly CatalogContext _catalogContext;
|
||||||
|
|
||||||
public PicController(IHostingEnvironment env,
|
public PicController(IWebHostEnvironment env,
|
||||||
CatalogContext catalogContext)
|
CatalogContext catalogContext)
|
||||||
{
|
{
|
||||||
_env = env;
|
_env = env;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
|
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
EXPOSE 443
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
|
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
COPY scripts scripts/
|
COPY scripts scripts/
|
||||||
@ -28,4 +29,6 @@ FROM build AS publish
|
|||||||
FROM base AS final
|
FROM base AS final
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=publish /app .
|
COPY --from=publish /app .
|
||||||
|
COPY --from=build /src/src/Services/Catalog/Catalog.API/Proto /app/Proto
|
||||||
|
COPY --from=build /src/src/Services/Catalog/Catalog.API/eshop.pfx .
|
||||||
ENTRYPOINT ["dotnet", "Catalog.API.dll"]
|
ENTRYPOINT ["dotnet", "Catalog.API.dll"]
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Polly;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace Catalog.API.Extensions
|
||||||
|
{
|
||||||
|
public static class HostExtensions
|
||||||
|
{
|
||||||
|
public static bool IsInKubernetes(this IHost host)
|
||||||
|
{
|
||||||
|
var cfg = host.Services.GetService<IConfiguration>();
|
||||||
|
var orchestratorType = cfg.GetValue<string>("OrchestratorType");
|
||||||
|
return orchestratorType?.ToUpper() == "K8S";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHost MigrateDbContext<TContext>(this IHost host, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
|
||||||
|
{
|
||||||
|
var underK8s = host.IsInKubernetes();
|
||||||
|
|
||||||
|
using (var scope = host.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var services = scope.ServiceProvider;
|
||||||
|
|
||||||
|
var logger = services.GetRequiredService<ILogger<TContext>>();
|
||||||
|
|
||||||
|
var context = services.GetService<TContext>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name);
|
||||||
|
|
||||||
|
if (underK8s)
|
||||||
|
{
|
||||||
|
InvokeSeeder(seeder, context, services);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var retry = Policy.Handle<SqlException>()
|
||||||
|
.WaitAndRetry(new TimeSpan[]
|
||||||
|
{
|
||||||
|
TimeSpan.FromSeconds(3),
|
||||||
|
TimeSpan.FromSeconds(5),
|
||||||
|
TimeSpan.FromSeconds(8),
|
||||||
|
});
|
||||||
|
|
||||||
|
//if the sql server container is not created on run docker compose this
|
||||||
|
//migration can't fail for network related exception. The retry options for DbContext only
|
||||||
|
//apply to transient exceptions
|
||||||
|
// Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service)
|
||||||
|
retry.Execute(() => InvokeSeeder(seeder, context, services));
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name);
|
||||||
|
if (underK8s)
|
||||||
|
{
|
||||||
|
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InvokeSeeder<TContext>(Action<TContext, IServiceProvider> seeder, TContext context, IServiceProvider services)
|
||||||
|
where TContext : DbContext
|
||||||
|
{
|
||||||
|
context.Database.Migrate();
|
||||||
|
seeder(context, services);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs
Normal file
61
src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CatalogApi;
|
||||||
|
using Grpc.Core;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Catalog.API;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Model;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using static CatalogApi.Catalog;
|
||||||
|
|
||||||
|
namespace Catalog.API.Grpc
|
||||||
|
{
|
||||||
|
public class CatalogService : CatalogBase
|
||||||
|
{
|
||||||
|
private readonly CatalogContext _catalogContext;
|
||||||
|
private readonly CatalogSettings _settings;
|
||||||
|
public CatalogService(CatalogContext dbContext, IOptions<CatalogSettings> settings)
|
||||||
|
{
|
||||||
|
_settings = settings.Value;
|
||||||
|
_catalogContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<CatalogItemResponse> GetItemById(CatalogItemRequest request, ServerCallContext context)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (request.Id <=0)
|
||||||
|
{
|
||||||
|
context.Status = new Status(StatusCode.FailedPrecondition, $"Id must be > 0 (received {request.Id})");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = await _catalogContext.CatalogItems.SingleOrDefaultAsync(ci => ci.Id == request.Id);
|
||||||
|
var baseUri = _settings.PicBaseUrl;
|
||||||
|
var azureStorageEnabled = _settings.AzureStorageEnabled;
|
||||||
|
item.FillProductUrl(baseUri, azureStorageEnabled: azureStorageEnabled);
|
||||||
|
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
return new CatalogItemResponse()
|
||||||
|
{
|
||||||
|
AvailableStock = item.AvailableStock,
|
||||||
|
Description = item.Description,
|
||||||
|
Id = item.Id,
|
||||||
|
MaxStockThreshold = item.MaxStockThreshold,
|
||||||
|
Name = item.Name,
|
||||||
|
OnReorder = item.OnReorder,
|
||||||
|
PictureFileName = item.PictureFileName,
|
||||||
|
PictureUri = item.PictureUri,
|
||||||
|
Price = (double)item.Price,
|
||||||
|
RestockThreshold = item.RestockThreshold
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Status = new Status(StatusCode.NotFound, $"Product with id {request.Id} do not exist");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
public class CatalogContextSeed
|
public class CatalogContextSeed
|
||||||
{
|
{
|
||||||
public async Task SeedAsync(CatalogContext context,IHostingEnvironment env,IOptions<CatalogSettings> settings,ILogger<CatalogContextSeed> logger)
|
public async Task SeedAsync(CatalogContext context,IWebHostEnvironment env,IOptions<CatalogSettings> settings,ILogger<CatalogContextSeed> logger)
|
||||||
{
|
{
|
||||||
var policy = CreatePolicy(logger, nameof(CatalogContextSeed));
|
var policy = CreatePolicy(logger, nameof(CatalogContextSeed));
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
@ -11,10 +12,10 @@ namespace Catalog.API.Infrastructure.Filters
|
|||||||
{
|
{
|
||||||
public class HttpGlobalExceptionFilter : IExceptionFilter
|
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||||
{
|
{
|
||||||
private readonly IHostingEnvironment env;
|
private readonly IWebHostEnvironment env;
|
||||||
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||||
|
|
||||||
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
public HttpGlobalExceptionFilter(IWebHostEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
||||||
{
|
{
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
using Microsoft.AspNetCore;
|
using Autofac.Extensions.DependencyInjection;
|
||||||
|
using Catalog.API.Extensions;
|
||||||
|
using Microsoft.AspNetCore;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||||
{
|
{
|
||||||
@ -26,12 +33,12 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
var host = BuildWebHost(configuration, args);
|
var host = CreateHostBuilder(configuration, args).Build();
|
||||||
|
|
||||||
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
|
Log.Information("Applying migrations ({ApplicationContext})...", AppName);
|
||||||
host.MigrateDbContext<CatalogContext>((context, services) =>
|
host.MigrateDbContext<CatalogContext>((context, services) =>
|
||||||
{
|
{
|
||||||
var env = services.GetService<IHostingEnvironment>();
|
var env = services.GetService<IWebHostEnvironment>();
|
||||||
var settings = services.GetService<IOptions<CatalogSettings>>();
|
var settings = services.GetService<IOptions<CatalogSettings>>();
|
||||||
var logger = services.GetService<ILogger<CatalogContextSeed>>();
|
var logger = services.GetService<ILogger<CatalogContextSeed>>();
|
||||||
|
|
||||||
@ -57,16 +64,37 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
|
||||||
WebHost.CreateDefaultBuilder(args)
|
private static IHostBuilder CreateHostBuilder(IConfiguration configuration, string[] args) =>
|
||||||
.CaptureStartupErrors(false)
|
Host.CreateDefaultBuilder(args)
|
||||||
.UseStartup<Startup>()
|
.ConfigureServices(services => services.AddAutofac())
|
||||||
.UseApplicationInsights()
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.ConfigureWebHostDefaults(builder =>
|
||||||
.UseWebRoot("Pics")
|
{
|
||||||
.UseConfiguration(configuration)
|
builder.CaptureStartupErrors(false)
|
||||||
.UseSerilog()
|
.UseConfiguration(configuration)
|
||||||
.Build();
|
.ConfigureKestrel(options =>
|
||||||
|
{
|
||||||
|
var ports = GetDefinedPorts(configuration);
|
||||||
|
foreach (var port in ports.Distinct())
|
||||||
|
{
|
||||||
|
options.ListenAnyIP(port.portNumber, listenOptions =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Binding to port {port.portNumber} (https is {port.https})");
|
||||||
|
if (port.https)
|
||||||
|
{
|
||||||
|
listenOptions.UseHttps("eshop.pfx");
|
||||||
|
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.UseApplicationInsights()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseWebRoot("Pics")
|
||||||
|
.UseSerilog();
|
||||||
|
});
|
||||||
|
|
||||||
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
@ -83,6 +111,40 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<(int portNumber, bool https)> GetDefinedPorts(IConfiguration config)
|
||||||
|
{
|
||||||
|
const string https = "https://";
|
||||||
|
const string http = "http://";
|
||||||
|
var defport = config.GetValue("ASPNETCORE_HTTPS_PORT", 0);
|
||||||
|
if (defport != 0)
|
||||||
|
{
|
||||||
|
yield return (defport, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var urls = config.GetValue<string>("ASPNETCORE_URLS", null)?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (urls?.Any() == true)
|
||||||
|
{
|
||||||
|
foreach (var urlString in urls)
|
||||||
|
{
|
||||||
|
var uri = urlString.ToLowerInvariant().Trim();
|
||||||
|
var isHttps = uri.StartsWith(https);
|
||||||
|
var isHttp = uri.StartsWith(http);
|
||||||
|
if (!isHttp && !isHttps)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Url {uri} must start with https:// or http://");
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = uri.Substring(isHttps ? https.Length : http.Length);
|
||||||
|
var lastdots = uri.LastIndexOf(':');
|
||||||
|
if (lastdots != -1)
|
||||||
|
{
|
||||||
|
var sport = uri.Substring(lastdots + 1);
|
||||||
|
yield return (int.TryParse(sport, out var nport) ? nport : isHttps ? 443 : 80, isHttps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IConfiguration GetConfiguration()
|
private static IConfiguration GetConfiguration()
|
||||||
{
|
{
|
||||||
var builder = new ConfigurationBuilder()
|
var builder = new ConfigurationBuilder()
|
||||||
@ -103,4 +165,4 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
"launchUrl": "/swagger",
|
"launchUrl": "/swagger",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ConnectionString": "server=localhost,5433;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
|
"ConnectionString": "server=localhost,5433;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
|
||||||
|
"Serilog:LogstashgUrl": "http://locahost:8080",
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
"EventBusConnection": "localhost",
|
"EventBusConnection": "localhost",
|
||||||
"Serilog:SeqServerUrl": "http://locahost:5340",
|
"Serilog:SeqServerUrl": "http://locahost:5340"
|
||||||
"Serilog:LogstashgUrl":"http://locahost:8080",
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.eShopOnContainers.Services.Catalog.API": {
|
"Microsoft.eShopOnContainers.Services.Catalog.API": {
|
||||||
|
36
src/Services/Catalog/Catalog.API/Proto/catalog.proto
Normal file
36
src/Services/Catalog/Catalog.API/Proto/catalog.proto
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package CatalogApi;
|
||||||
|
|
||||||
|
message CatalogItemRequest {
|
||||||
|
int32 id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CatalogItemResponse {
|
||||||
|
int32 id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string description=3;
|
||||||
|
double price=4;
|
||||||
|
string picture_file_name=5;
|
||||||
|
string picture_uri=6;
|
||||||
|
CatalogType catalog_type=8;
|
||||||
|
CatalogBrand catalog_brand=10;
|
||||||
|
int32 available_stock=11;
|
||||||
|
int32 restock_threshold=12;
|
||||||
|
int32 max_stock_threshold=13;
|
||||||
|
bool on_reorder=14;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CatalogBrand {
|
||||||
|
int32 id = 1;
|
||||||
|
string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CatalogType {
|
||||||
|
int32 id = 1;
|
||||||
|
string type = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
service Catalog {
|
||||||
|
rpc GetItemById (CatalogItemRequest) returns (CatalogItemResponse) {}
|
||||||
|
}
|
@ -3,7 +3,6 @@ using Autofac.Extensions.DependencyInjection;
|
|||||||
using global::Catalog.API.Infrastructure.Filters;
|
using global::Catalog.API.Infrastructure.Filters;
|
||||||
using global::Catalog.API.IntegrationEvents;
|
using global::Catalog.API.IntegrationEvents;
|
||||||
using Microsoft.ApplicationInsights.Extensibility;
|
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.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
@ -31,6 +30,8 @@ using System.Reflection;
|
|||||||
using HealthChecks.UI.Client;
|
using HealthChecks.UI.Client;
|
||||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
|
using Catalog.API.Grpc;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||||
{
|
{
|
||||||
@ -43,9 +44,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
public IServiceProvider ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddAppInsight(Configuration)
|
services.AddAppInsight(Configuration)
|
||||||
|
.AddGrpc().Services
|
||||||
.AddCustomMVC(Configuration)
|
.AddCustomMVC(Configuration)
|
||||||
.AddCustomDbContext(Configuration)
|
.AddCustomDbContext(Configuration)
|
||||||
.AddCustomOptions(Configuration)
|
.AddCustomOptions(Configuration)
|
||||||
@ -56,11 +58,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
|
|
||||||
var container = new ContainerBuilder();
|
var container = new ContainerBuilder();
|
||||||
container.Populate(services);
|
container.Populate(services);
|
||||||
return new AutofacServiceProvider(container.Build());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
//Configure logs
|
//Configure logs
|
||||||
|
|
||||||
@ -88,7 +89,18 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
|
|
||||||
app.UseCors("CorsPolicy");
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
app.UseMvcWithDefaultRoute();
|
app.UseRouting();
|
||||||
|
app.UseEndpoints(e =>
|
||||||
|
{
|
||||||
|
e.MapDefaultControllerRoute();
|
||||||
|
e.MapGet("/_proto/", async ctx =>
|
||||||
|
{
|
||||||
|
var data = await File.ReadAllTextAsync(Path.Combine(env.ContentRootPath, "Proto", "catalog.proto"));
|
||||||
|
ctx.Response.ContentType = "text/plain";
|
||||||
|
await ctx.Response.WriteAsync(data);
|
||||||
|
});
|
||||||
|
e.MapGrpcService<CatalogService>();
|
||||||
|
});
|
||||||
|
|
||||||
app.UseSwagger()
|
app.UseSwagger()
|
||||||
.UseSwaggerUI(c =>
|
.UseSwaggerUI(c =>
|
||||||
@ -119,23 +131,17 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
// Enable K8s telemetry initializer
|
// Enable K8s telemetry initializer
|
||||||
services.AddApplicationInsightsKubernetesEnricher();
|
services.AddApplicationInsightsKubernetesEnricher();
|
||||||
}
|
}
|
||||||
if (orchestratorType?.ToUpper() == "SF")
|
|
||||||
{
|
|
||||||
// Enable SF telemetry initializer
|
|
||||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
|
||||||
new FabricTelemetryInitializer());
|
|
||||||
}
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.AddMvc(options =>
|
services.AddMvc(options =>
|
||||||
{
|
{
|
||||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
})
|
})
|
||||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
|
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
|
||||||
.AddControllersAsServices();
|
.AddControllersAsServices();
|
||||||
|
|
||||||
services.AddCors(options =>
|
services.AddCors(options =>
|
||||||
@ -166,7 +172,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
tags: new string[] { "catalogdb" });
|
tags: new string[] { "catalogdb" });
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey))
|
if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey))
|
||||||
{
|
{
|
||||||
hcBuilder
|
hcBuilder
|
||||||
.AddAzureBlobStorage(
|
.AddAzureBlobStorage(
|
||||||
$"DefaultEndpointsProtocol=https;AccountName={accountName};AccountKey={accountKey};EndpointSuffix=core.windows.net",
|
$"DefaultEndpointsProtocol=https;AccountName={accountName};AccountKey={accountKey};EndpointSuffix=core.windows.net",
|
||||||
@ -256,12 +262,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
services.AddSwaggerGen(options =>
|
services.AddSwaggerGen(options =>
|
||||||
{
|
{
|
||||||
options.DescribeAllEnumsAsStrings();
|
options.DescribeAllEnumsAsStrings();
|
||||||
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
options.SwaggerDoc("v1", new OpenApi.Models.OpenApiInfo
|
||||||
{
|
{
|
||||||
Title = "eShopOnContainers - Catalog HTTP API",
|
Title = "eShopOnContainers - Catalog HTTP API",
|
||||||
Version = "v1",
|
Version = "v1",
|
||||||
Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample",
|
Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample"
|
||||||
TermsOfService = "Terms Of Service"
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Debug",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@
|
|||||||
"ApplicationInsights": {
|
"ApplicationInsights": {
|
||||||
"InstrumentationKey": ""
|
"InstrumentationKey": ""
|
||||||
},
|
},
|
||||||
|
"EventBusConnection": "localhost",
|
||||||
"EventBusRetryCount": 5,
|
"EventBusRetryCount": 5,
|
||||||
"UseVault": false,
|
"UseVault": false,
|
||||||
"Vault": {
|
"Vault": {
|
||||||
@ -28,3 +29,4 @@
|
|||||||
"ClientSecret": "your-client-secret"
|
"ClientSecret": "your-client-secret"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
src/Services/Catalog/Catalog.API/eshop.pfx
Normal file
BIN
src/Services/Catalog/Catalog.API/eshop.pfx
Normal file
Binary file not shown.
@ -4,8 +4,15 @@
|
|||||||
<handlers>
|
<handlers>
|
||||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
||||||
</handlers>
|
</handlers>
|
||||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="false" stdoutLogEnabled="false">
|
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="false" stdoutLogEnabled="false" hostingModel="inprocess">
|
||||||
<environmentVariables />
|
<environmentVariables>
|
||||||
|
<environmentVariable name="COMPLUS_ForceENC" value="1" />
|
||||||
|
<environmentVariable name="ConnectionString" value="server=localhost,5433;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word" />
|
||||||
|
<environmentVariable name="Serilog:LogstashgUrl" value="http://locahost:8080" />
|
||||||
|
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
|
||||||
|
<environmentVariable name="EventBusConnection" value="localhost" />
|
||||||
|
<environmentVariable name="Serilog:SeqServerUrl" value="http://locahost:5340" />
|
||||||
|
</environmentVariables>
|
||||||
</aspNetCore>
|
</aspNetCore>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
</configuration>
|
</configuration>
|
Loading…
x
Reference in New Issue
Block a user