diff --git a/src/Services/Ordering/Ordering.API/appsettings.json b/src/Services/Ordering/Ordering.API/appsettings.json index 3f54fb3ce..7c110dc0c 100644 --- a/src/Services/Ordering/Ordering.API/appsettings.json +++ b/src/Services/Ordering/Ordering.API/appsettings.json @@ -5,6 +5,7 @@ "Microsoft.AspNetCore": "Warning" } }, + "AllowedHosts": "*", "OpenApi": { "Endpoint": { "Name": "Ordering.API V1" diff --git a/src/Services/Webhooks/Webhooks.API/Controllers/HomeController.cs b/src/Services/Webhooks/Webhooks.API/Controllers/HomeController.cs deleted file mode 100644 index 2a7951ec3..000000000 --- a/src/Services/Webhooks/Webhooks.API/Controllers/HomeController.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Webhooks.API.Controllers; - -public class HomeController : Controller -{ - // GET: // - public IActionResult Index() - { - return new RedirectResult("~/swagger"); - } - -} diff --git a/src/Services/Webhooks/Webhooks.API/CustomExtensionMethods.cs b/src/Services/Webhooks/Webhooks.API/CustomExtensionMethods.cs new file mode 100644 index 000000000..2a2f5df06 --- /dev/null +++ b/src/Services/Webhooks/Webhooks.API/CustomExtensionMethods.cs @@ -0,0 +1,47 @@ +internal static class CustomExtensionMethods +{ + public static IServiceCollection AddDbContexts(this IServiceCollection services, IConfiguration configuration) + { + services.AddDbContext(options => + { + options.UseSqlServer(configuration.GetRequiredConnectionString("WebHooksDb"), + sqlServerOptionsAction: sqlOptions => + { + sqlOptions.MigrationsAssembly(typeof(Program).Assembly.FullName); + + //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency + sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + }); + }); + + return services; + } + + public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration) + { + var hcBuilder = services.AddHealthChecks(); + + hcBuilder + .AddSqlServer(_ => + configuration.GetRequiredConnectionString("WebHooksDb"), + name: "WebhooksApiDb-check", + tags: new string[] { "ready", "live" }); + + return services; + } + + public static IServiceCollection AddHttpClientServices(this IServiceCollection services) + { + // Add http client services + services.AddHttpClient("GrantClient") + .SetHandlerLifetime(TimeSpan.FromMinutes(5)); + + return services; + } + + public static IServiceCollection AddIntegrationServices(this IServiceCollection services) + { + return services.AddTransient>( + sp => (DbConnection c) => new IntegrationEventLogService(c)); + } +} diff --git a/src/Services/Webhooks/Webhooks.API/GlobalUsings.cs b/src/Services/Webhooks/Webhooks.API/GlobalUsings.cs index 133a01cb1..2ef5c1bd7 100644 --- a/src/Services/Webhooks/Webhooks.API/GlobalUsings.cs +++ b/src/Services/Webhooks/Webhooks.API/GlobalUsings.cs @@ -1,46 +1,28 @@ -global using HealthChecks.UI.Client; -global using Microsoft.AspNetCore.Authentication.JwtBearer; +global using System; +global using System.Collections.Generic; +global using System.ComponentModel.DataAnnotations; +global using System.Data.Common; +global using System.Linq; +global using System.Net; +global using System.Net.Http; +global using System.Text; +global using System.Text.Json; +global using System.Threading.Tasks; global using Microsoft.AspNetCore.Authorization; global using Microsoft.AspNetCore.Builder; -global using Microsoft.AspNetCore.Diagnostics.HealthChecks; global using Microsoft.AspNetCore.Hosting; global using Microsoft.AspNetCore.Http; -global using Microsoft.AspNetCore.Mvc.Filters; global using Microsoft.AspNetCore.Mvc; -global using Microsoft.AspNetCore; -global using Microsoft.EntityFrameworkCore.Design; global using Microsoft.EntityFrameworkCore; +global using Microsoft.EntityFrameworkCore.Design; global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; -global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; -global using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; -global using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; global using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; -global using Microsoft.Extensions.Diagnostics.HealthChecks; -global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; -global using Microsoft.OpenApi.Models; -global using RabbitMQ.Client; -global using Swashbuckle.AspNetCore.SwaggerGen; -global using System.Collections.Generic; -global using System.ComponentModel.DataAnnotations; -global using System.Data.Common; -global using System.IdentityModel.Tokens.Jwt; -global using System.Linq; -global using System.Net.Http; -global using System.Net; -global using System.Reflection; -global using System.Text.Json; -global using System.Text; -global using System.Threading.Tasks; -global using System.Threading; -global using System; -global using Webhooks.API.Exceptions; -global using Webhooks.API.Infrastructure.ActionResult; +global using Services.Common; global using Webhooks.API.Infrastructure; global using Webhooks.API.IntegrationEvents; global using Webhooks.API.Model; global using Webhooks.API.Services; -global using Webhooks.API; diff --git a/src/Services/Webhooks/Webhooks.API/Infrastructure/ActionResult/InternalServerErrorObjectResult.cs b/src/Services/Webhooks/Webhooks.API/Infrastructure/ActionResult/InternalServerErrorObjectResult.cs deleted file mode 100644 index d71e8b55f..000000000 --- a/src/Services/Webhooks/Webhooks.API/Infrastructure/ActionResult/InternalServerErrorObjectResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Webhooks.API.Infrastructure.ActionResult; - -class InternalServerErrorObjectResult : ObjectResult -{ - public InternalServerErrorObjectResult(object error) : base(error) - { - StatusCode = StatusCodes.Status500InternalServerError; - } -} diff --git a/src/Services/Webhooks/Webhooks.API/Infrastructure/AuthorizeCheckOperationFilter.cs b/src/Services/Webhooks/Webhooks.API/Infrastructure/AuthorizeCheckOperationFilter.cs deleted file mode 100644 index 13b0fcbdb..000000000 --- a/src/Services/Webhooks/Webhooks.API/Infrastructure/AuthorizeCheckOperationFilter.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Webhooks.API.Infrastructure; - -public class AuthorizeCheckOperationFilter : IOperationFilter -{ - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - // Check for authorize attribute - var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || - context.MethodInfo.GetCustomAttributes(true).OfType().Any(); - - if (!hasAuthorize) return; - - operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); - operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); - - var oAuthScheme = new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } - }; - - operation.Security = new List - { - new() - { - [ oAuthScheme ] = new [] { "webhooksapi" } - } - }; - } -} diff --git a/src/Services/Webhooks/Webhooks.API/Infrastructure/HttpGlobalExceptionFilter.cs b/src/Services/Webhooks/Webhooks.API/Infrastructure/HttpGlobalExceptionFilter.cs deleted file mode 100644 index 58e2e1656..000000000 --- a/src/Services/Webhooks/Webhooks.API/Infrastructure/HttpGlobalExceptionFilter.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace Webhooks.API.Infrastructure; - -public class HttpGlobalExceptionFilter : IExceptionFilter -{ - private readonly IWebHostEnvironment _env; - private readonly ILogger _logger; - - public HttpGlobalExceptionFilter(IWebHostEnvironment env, ILogger logger) - { - _env = env; - _logger = logger; - } - - public void OnException(ExceptionContext context) - { - _logger.LogError(new EventId(context.Exception.HResult), - context.Exception, - context.Exception.Message); - - if (context.Exception.GetType() == typeof(WebhooksDomainException)) - { - var problemDetails = new ValidationProblemDetails() - { - Instance = context.HttpContext.Request.Path, - Status = StatusCodes.Status400BadRequest, - Detail = "Please refer to the errors property for additional details." - }; - - problemDetails.Errors.Add("DomainValidations", new[] { context.Exception.Message }); - - context.Result = new BadRequestObjectResult(problemDetails); - context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; - } - else - { - var json = new JsonErrorResponse - { - Messages = new[] { "An error occurred." } - }; - - if (_env.IsDevelopment()) - { - json.DeveloperMessage = context.Exception; - } - - context.Result = new InternalServerErrorObjectResult(json); - context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - } - context.ExceptionHandled = true; - } - - private class JsonErrorResponse - { - public string[] Messages { get; set; } - - public object DeveloperMessage { get; set; } - } -} diff --git a/src/Services/Webhooks/Webhooks.API/Program.cs b/src/Services/Webhooks/Webhooks.API/Program.cs index bc5d6c29f..ccebe59bb 100644 --- a/src/Services/Webhooks/Webhooks.API/Program.cs +++ b/src/Services/Webhooks/Webhooks.API/Program.cs @@ -1,20 +1,41 @@ -// TODO: Don't do this twice... -var host = CreateWebHostBuilder(args).Build(); -host.Services.MigrateDbContext((_, __) => { }); -host.Run(); - - -IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .ConfigureAppConfiguration((builderContext, config) => - { - config.AddEnvironmentVariables(); - }) - .ConfigureLogging((hostingContext, builder) => - { - builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); - builder.AddConsole(); - builder.AddDebug(); - builder.AddAzureWebAppDiagnostics(); - }); +var builder = WebApplication.CreateBuilder(args); + +builder.AddServiceDefaults(); + +builder.Services.AddControllers(); +builder.Services.AddDbContexts(builder.Configuration); +builder.Services.AddHealthChecks(builder.Configuration); +builder.Services.AddHttpClientServices(); +builder.Services.AddIntegrationServices(); + +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); + +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); + +var app = builder.Build(); + +if (!await app.CheckHealthAsync()) +{ + return; +} + +app.UseServiceDefaults(); + +app.MapGet("/", () => Results.Redirect("/swagger")); +app.MapControllers(); + + +var eventBus = app.Services.GetRequiredService(); + +eventBus.Subscribe(); +eventBus.Subscribe(); +eventBus.Subscribe(); + +app.Services.MigrateDbContext((_, __) => { }); + +await app.RunAsync(); diff --git a/src/Services/Webhooks/Webhooks.API/Properties/launchSettings.json b/src/Services/Webhooks/Webhooks.API/Properties/launchSettings.json index 533291599..859a2ae16 100644 --- a/src/Services/Webhooks/Webhooks.API/Properties/launchSettings.json +++ b/src/Services/Webhooks/Webhooks.API/Properties/launchSettings.json @@ -1,27 +1,12 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:62486", - "sslPort": 0 - } - }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "Webhooks.API": { "commandName": "Project", "launchBrowser": true, + "applicationUrl": "http://localhost:5222", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:5000" + } }, "Docker": { "commandName": "Docker", diff --git a/src/Services/Webhooks/Webhooks.API/Startup.cs b/src/Services/Webhooks/Webhooks.API/Startup.cs deleted file mode 100644 index c79ea4b2e..000000000 --- a/src/Services/Webhooks/Webhooks.API/Startup.cs +++ /dev/null @@ -1,318 +0,0 @@ -namespace Webhooks.API; -public class Startup -{ - public IConfiguration Configuration { get; } - - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IServiceProvider ConfigureServices(IServiceCollection services) - { - services - .AddAppInsight(Configuration) - .AddCustomRouting(Configuration) - .AddCustomDbContext(Configuration) - .AddSwagger(Configuration) - .AddCustomHealthCheck(Configuration) - .AddHttpClientServices(Configuration) - .AddIntegrationServices(Configuration) - .AddEventBus(Configuration) - .AddCustomAuthentication(Configuration) - .AddSingleton() - .AddTransient() - .AddTransient() - .AddTransient() - .AddTransient(); - return services.BuildServiceProvider(); - } - - public void Configure(IApplicationBuilder app, ILogger logger) - { - var pathBase = Configuration["PATH_BASE"]; - - if (!string.IsNullOrEmpty(pathBase)) - { - logger.LogDebug("Using PATH BASE '{PathBase}'", pathBase); - app.UsePathBase(pathBase); - } - - app.UseRouting(); - app.UseCors("CorsPolicy"); - ConfigureAuth(app); - - app.UseEndpoints(endpoints => - { - endpoints.MapDefaultControllerRoute(); - endpoints.MapControllers(); - endpoints.MapHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - endpoints.MapHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - }); - - app.UseSwagger() - .UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{(!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty)}/swagger/v1/swagger.json", "Webhooks.API V1"); - c.OAuthClientId("webhooksswaggerui"); - c.OAuthAppName("WebHooks Service Swagger UI"); - }); - - ConfigureEventBus(app); - } - - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - app.UseAuthentication(); - app.UseAuthorization(); - } - - protected virtual void ConfigureEventBus(IApplicationBuilder app) - { - var eventBus = app.ApplicationServices.GetRequiredService(); - eventBus.Subscribe(); - eventBus.Subscribe(); - eventBus.Subscribe(); - } -} - -internal static class CustomExtensionMethods -{ - public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) - { - services.AddApplicationInsightsTelemetry(configuration); - services.AddApplicationInsightsKubernetesEnricher(); - - return services; - } - - public static IServiceCollection AddCustomRouting(this IServiceCollection services, IConfiguration configuration) - { - services.AddControllers(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }); - - services.AddCors(options => - { - options.AddPolicy("CorsPolicy", - builder => builder - .SetIsOriginAllowed((host) => true) - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials()); - }); - - return services; - } - - public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) - { - services.AddEntityFrameworkSqlServer() - .AddDbContext(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); - }); - }); - - return services; - } - - public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration) - { - services.AddSwaggerGen(options => - { - options.SwaggerDoc("v1", new OpenApiInfo - { - Title = "eShopOnContainers - Webhooks HTTP API", - Version = "v1", - Description = "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint" - }); - - var identityUrl = configuration.GetSection("Identity").GetValue("ExternalUrl"); - options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme - { - Type = SecuritySchemeType.OAuth2, - Flows = new OpenApiOAuthFlows() - { - Implicit = new OpenApiOAuthFlow() - { - AuthorizationUrl = new Uri($"{identityUrl}/connect/authorize"), - TokenUrl = new Uri($"{identityUrl}/connect/token"), - Scopes = new Dictionary() - { - { "webhooks", "Webhooks API" } - } - } - } - }); - - options.OperationFilter(); - }); - - return services; - } - public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) - { - if (configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var serviceBusPersisterConnection = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubscriptionManager = sp.GetRequiredService(); - string subscriptionName = configuration["SubscriptionClientName"]; - - return new EventBusServiceBus(serviceBusPersisterConnection, logger, - eventBusSubscriptionManager, sp, subscriptionName); - }); - - } - else - { - services.AddSingleton(sp => - { - var subscriptionClientName = configuration["SubscriptionClientName"]; - var rabbitMQPersistentConnection = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubscriptionManager = sp.GetRequiredService(); - - var retryCount = 5; - if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) - { - retryCount = int.Parse(configuration["EventBusRetryCount"]); - } - - return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, sp, eventBusSubscriptionManager, subscriptionClientName, retryCount); - }); - } - - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - return services; - } - - public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) - { - var hcBuilder = services.AddHealthChecks(); - - hcBuilder - .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddSqlServer( - configuration["ConnectionString"], - name: "WebhooksApiDb-check", - tags: new string[] { "webhooksdb" }); - - return services; - } - - public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddSingleton(); - services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan); - //add http client services - services.AddHttpClient("GrantClient") - .SetHandlerLifetime(TimeSpan.FromMinutes(5)); - return services; - } - - public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddTransient>( - sp => (DbConnection c) => new IntegrationEventLogService(c)); - - if (configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var subscriptionClientName = configuration["SubscriptionClientName"]; - return new DefaultServiceBusPersisterConnection(configuration["EventBusConnection"]); - }); - } - else - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - - var factory = new ConnectionFactory() - { - HostName = configuration["EventBusConnection"], - DispatchConsumersAsync = true - }; - - 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 AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) - { - // prevent from mapping "sub" claim to nameidentifier. - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); - - var identityUrl = configuration.GetValue("IdentityUrl"); - - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - - }).AddJwtBearer(options => - { - options.Authority = identityUrl; - options.RequireHttpsMetadata = false; - options.Audience = "webhooks"; - options.TokenValidationParameters.ValidateAudience = false; - }); - - return services; - } - - - public static IServiceCollection AddCustomAuthorization(this IServiceCollection services, IConfiguration configuration) - { - services.AddAuthorization(options => - { - options.AddPolicy("ApiScope", policy => - { - policy.RequireAuthenticatedUser(); - policy.RequireClaim("scope", "webhooks"); - }); - }); - return services; - } -} diff --git a/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj b/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj index 4357a1520..979154074 100644 --- a/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj +++ b/src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj @@ -2,33 +2,17 @@ net7.0 - InProcess Linux - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; - false - true - - - - - - - - - - - - - + diff --git a/src/Services/Webhooks/Webhooks.API/appsettings.Development.json b/src/Services/Webhooks/Webhooks.API/appsettings.Development.json index f4f8f9d26..37de2515b 100644 --- a/src/Services/Webhooks/Webhooks.API/appsettings.Development.json +++ b/src/Services/Webhooks/Webhooks.API/appsettings.Development.json @@ -6,5 +6,7 @@ "Microsoft": "Information" } }, - "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word;TrustServerCertificate=true" + "ConnectionStrings": { + "WebHooksDb": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word;TrustServerCertificate=true" + } } diff --git a/src/Services/Webhooks/Webhooks.API/appsettings.json b/src/Services/Webhooks/Webhooks.API/appsettings.json index 200ea4c96..470c0839a 100644 --- a/src/Services/Webhooks/Webhooks.API/appsettings.json +++ b/src/Services/Webhooks/Webhooks.API/appsettings.json @@ -1,10 +1,44 @@ { "Logging": { "LogLevel": { - "Default": "Warning" + "Default": "Information", + "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", - "SubscriptionClientName": "Webhooks", - "EventBusRetryCount": 5 + "OpenApi": { + "Endpoint": { + "Name": "Webhooks.API V1" + }, + "Document": { + "Description": "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint", + "Title": "eShopOnContainers - Webhooks HTTP API", + "Version": "v1" + }, + "Auth": { + "ClientId": "webhooksswaggerui", + "AppName": "WebHooks Service Swagger UI" + } + }, + "ConnectionStrings": { + "EventBus": "localhost" + }, + "EventBus": { + "SubscriptionClientName": "Webhooks", + "RetryCount": 5 + }, + "ApplicationInsights": { + "InstrumentationKey": "" + }, + "Identity": { + "Url": "http://localhost:5105", + "ExternalUrl": "http://localhost:5105", + "Audience": "webhooks", + "Scopes": { + "webhooks": "Webhooks API" + } + }, + "UseCustomizationData": false, + "GracePeriodTime": "1", + "CheckUpdateTime": "30000" }