Make the ordering API use the commmon services
This commit is contained in:
		
							parent
							
								
									a41560544c
								
							
						
					
					
						commit
						909f08675b
					
				| @ -1,10 +0,0 @@ | |||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers; |  | ||||||
| 
 |  | ||||||
| public class HomeController : Controller |  | ||||||
| { |  | ||||||
|     // GET: /<controller>/ |  | ||||||
|     public IActionResult Index() |  | ||||||
|     { |  | ||||||
|         return new RedirectResult("~/swagger"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -0,0 +1,79 @@ | |||||||
|  | using Microsoft.EntityFrameworkCore.Infrastructure; | ||||||
|  | 
 | ||||||
|  | static class CustomExtensionsMethods | ||||||
|  | { | ||||||
|  |     public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration) | ||||||
|  |     { | ||||||
|  |         var hcBuilder = services.AddHealthChecks(); | ||||||
|  | 
 | ||||||
|  |         hcBuilder | ||||||
|  |             .AddSqlServer(_ => | ||||||
|  |                 configuration.GetRequiredConnectionString("OrderingDB"), | ||||||
|  |                 name: "OrderingDB-check", | ||||||
|  |                 tags: new string[] { "live", "ready" }); | ||||||
|  | 
 | ||||||
|  |         return services; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static IServiceCollection AddDbContexts(this IServiceCollection services, IConfiguration configuration) | ||||||
|  |     { | ||||||
|  |         static void ConfigureSqlOptions(SqlServerDbContextOptionsBuilder 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); | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         services.AddDbContext<OrderingContext>(options => | ||||||
|  |         { | ||||||
|  |             options.UseSqlServer(configuration.GetRequiredConnectionString("OrderingDB"), ConfigureSqlOptions); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         services.AddDbContext<IntegrationEventLogContext>(options => | ||||||
|  |         { | ||||||
|  |             options.UseSqlServer(configuration.GetRequiredConnectionString("OrderingDB"), ConfigureSqlOptions); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         return services; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static IServiceCollection AddCustomIntegrations(this IServiceCollection services, IConfiguration configuration) | ||||||
|  |     { | ||||||
|  |         services.AddTransient<IIdentityService, IdentityService>(); | ||||||
|  |         services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>( | ||||||
|  |             sp => (DbConnection c) => new IntegrationEventLogService(c)); | ||||||
|  | 
 | ||||||
|  |         services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>(); | ||||||
|  | 
 | ||||||
|  |         return services; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static IServiceCollection AddCustomConfiguration(this IServiceCollection services, IConfiguration configuration) | ||||||
|  |     { | ||||||
|  |         services.Configure<OrderingSettings>(configuration); | ||||||
|  |         services.Configure<ApiBehaviorOptions>(options => | ||||||
|  |         { | ||||||
|  |             options.InvalidModelStateResponseFactory = context => | ||||||
|  |             { | ||||||
|  |                 var problemDetails = new ValidationProblemDetails(context.ModelState) | ||||||
|  |                 { | ||||||
|  |                     Instance = context.HttpContext.Request.Path, | ||||||
|  |                     Status = StatusCodes.Status400BadRequest, | ||||||
|  |                     Detail = "Please refer to the errors property for additional details." | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 return new BadRequestObjectResult(problemDetails) | ||||||
|  |                 { | ||||||
|  |                     ContentTypes = { "application/problem+json", "application/problem+xml" } | ||||||
|  |                 }; | ||||||
|  |             }; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         return services; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static string GetRequiredConnectionString(this IConfiguration configuration, string name) => | ||||||
|  |         configuration.GetConnectionString(name) ?? throw new InvalidOperationException($"Configuration missing value for: {(configuration is IConfigurationSection s ? s.Path + ":ConnectionStrings:" + name : "ConnectionStrings:" + name)}"); | ||||||
|  | } | ||||||
| @ -1,77 +1,57 @@ | |||||||
| global using ApiModels = Microsoft.eShopOnContainers.Services.Ordering.API.Application.Models; | global using System; | ||||||
| global using AppCommand = Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | global using System.Collections.Generic; | ||||||
| global using Azure.Core; | global using System.Data.Common; | ||||||
|  | global using System.Data.SqlClient; | ||||||
|  | global using System.IO; | ||||||
|  | global using System.Linq; | ||||||
|  | global using System.Net; | ||||||
|  | global using System.Runtime.Serialization; | ||||||
|  | global using System.Threading; | ||||||
|  | global using System.Threading.Tasks; | ||||||
| global using Azure.Identity; | global using Azure.Identity; | ||||||
| global using Dapper; | global using Dapper; | ||||||
| global using FluentValidation; | global using FluentValidation; | ||||||
| global using Google.Protobuf.Collections; | global using Google.Protobuf.Collections; | ||||||
| global using Grpc.Core; | global using Grpc.Core; | ||||||
| global using HealthChecks.UI.Client; |  | ||||||
| global using MediatR; | global using MediatR; | ||||||
| global using Microsoft.AspNetCore.Authorization; | global using Microsoft.AspNetCore.Authorization; | ||||||
| global using Microsoft.AspNetCore.Builder; | global using Microsoft.AspNetCore.Builder; | ||||||
| global using Microsoft.AspNetCore.Diagnostics.HealthChecks; |  | ||||||
| global using Microsoft.AspNetCore.Hosting; | global using Microsoft.AspNetCore.Hosting; | ||||||
| global using Microsoft.AspNetCore.Http; | global using Microsoft.AspNetCore.Http; | ||||||
| global using Microsoft.AspNetCore.Mvc.Authorization; |  | ||||||
| global using Microsoft.AspNetCore.Mvc.Filters; |  | ||||||
| global using Microsoft.AspNetCore.Mvc; | global using Microsoft.AspNetCore.Mvc; | ||||||
| global using Microsoft.AspNetCore.Server.Kestrel.Core; |  | ||||||
| global using Microsoft.AspNetCore; |  | ||||||
| global using Microsoft.EntityFrameworkCore.Design; |  | ||||||
| global using Microsoft.EntityFrameworkCore; | global using Microsoft.EntityFrameworkCore; | ||||||
|  | global using Microsoft.EntityFrameworkCore.Design; | ||||||
| global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||||
| global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||||
| global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions; | global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions; | ||||||
| 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.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; | global using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; | ||||||
|  | global using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; | ||||||
|  | global using Microsoft.eShopOnContainers.Services.Ordering.API; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Behaviors; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Behaviors; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.DomainEventHandlers; |  | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events; |  | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.EventHandling; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.EventHandling; | ||||||
|  | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Models; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Models; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Validations; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Validations; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers; |  | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Extensions; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Extensions; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults; |  | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Filters; |  | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; |  | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.API; | global using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; | global using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | global using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Domain.Events; | global using Microsoft.eShopOnContainers.Services.Ordering.Domain.Events; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Domain.Exceptions; | global using Microsoft.eShopOnContainers.Services.Ordering.Domain.Exceptions; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork; | global using Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork; | ||||||
|  | global using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | global using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories; | global using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories; | ||||||
| global using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; |  | ||||||
| global using Microsoft.Extensions.Configuration; | global using Microsoft.Extensions.Configuration; | ||||||
| global using Microsoft.Extensions.DependencyInjection; | global using Microsoft.Extensions.DependencyInjection; | ||||||
| global using Microsoft.Extensions.Diagnostics.HealthChecks; |  | ||||||
| global using Microsoft.Extensions.Hosting; |  | ||||||
| global using Microsoft.Extensions.Logging; | global using Microsoft.Extensions.Logging; | ||||||
| global using Microsoft.Extensions.Options; | global using Microsoft.Extensions.Options; | ||||||
| global using Microsoft.OpenApi.Models; |  | ||||||
| global using Polly.Retry; |  | ||||||
| global using Polly; | global using Polly; | ||||||
| global using RabbitMQ.Client; | global using Polly.Retry; | ||||||
| global using Swashbuckle.AspNetCore.SwaggerGen; | global using Swashbuckle.AspNetCore.SwaggerGen; | ||||||
| global using System.Collections.Generic; | global using AppCommand = Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | ||||||
| global using System.Data.Common; | global using ApiModels = Microsoft.eShopOnContainers.Services.Ordering.API.Application.Models; | ||||||
| global using System.Data.SqlClient; |  | ||||||
| global using System.IdentityModel.Tokens.Jwt; |  | ||||||
| global using System.IO; |  | ||||||
| global using System.Linq; |  | ||||||
| global using System.Net; |  | ||||||
| global using System.Reflection; |  | ||||||
| global using System.Runtime.Serialization; |  | ||||||
| global using System.Threading.Tasks; |  | ||||||
| global using System.Threading; |  | ||||||
| global using System; |  | ||||||
|  | |||||||
| @ -1,10 +0,0 @@ | |||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults; |  | ||||||
| 
 |  | ||||||
| public class InternalServerErrorObjectResult : ObjectResult |  | ||||||
| { |  | ||||||
|     public InternalServerErrorObjectResult(object error) |  | ||||||
|         : base(error) |  | ||||||
|     { |  | ||||||
|         StatusCode = StatusCodes.Status500InternalServerError; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,27 +0,0 @@ | |||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Auth; |  | ||||||
| 
 |  | ||||||
| public class AuthorizationHeaderParameterOperationFilter : IOperationFilter |  | ||||||
| { |  | ||||||
|     public void Apply(OpenApiOperation operation, OperationFilterContext context) |  | ||||||
|     { |  | ||||||
|         var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; |  | ||||||
|         var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter); |  | ||||||
|         var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter); |  | ||||||
| 
 |  | ||||||
|         if (isAuthorized && !allowAnonymous) |  | ||||||
|         { |  | ||||||
|             if (operation.Parameters == null) |  | ||||||
|                 operation.Parameters = new List<OpenApiParameter>(); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|             operation.Parameters.Add(new OpenApiParameter |  | ||||||
|             { |  | ||||||
|                 Name = "Authorization", |  | ||||||
|                 In = ParameterLocation.Header, |  | ||||||
|                 Description = "access token", |  | ||||||
|                 Required = true |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,29 +0,0 @@ | |||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Filters; |  | ||||||
| 
 |  | ||||||
| public class AuthorizeCheckOperationFilter : IOperationFilter |  | ||||||
| { |  | ||||||
|     public void Apply(OpenApiOperation operation, OperationFilterContext context) |  | ||||||
|     { |  | ||||||
|         // Check for authorize attribute |  | ||||||
|         var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() || |  | ||||||
|                             context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().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<OpenApiSecurityRequirement> |  | ||||||
|             { |  | ||||||
|                 new() |  | ||||||
|                 { |  | ||||||
|                     [ oAuthScheme ] = new [] { "orderingapi" } |  | ||||||
|                 } |  | ||||||
|             }; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,60 +0,0 @@ | |||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Filters; |  | ||||||
| 
 |  | ||||||
| public class HttpGlobalExceptionFilter : IExceptionFilter |  | ||||||
| { |  | ||||||
|     private readonly IWebHostEnvironment env; |  | ||||||
|     private readonly ILogger<HttpGlobalExceptionFilter> logger; |  | ||||||
| 
 |  | ||||||
|     public HttpGlobalExceptionFilter(IWebHostEnvironment env, ILogger<HttpGlobalExceptionFilter> logger) |  | ||||||
|     { |  | ||||||
|         this.env = env; |  | ||||||
|         this.logger = logger; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void OnException(ExceptionContext context) |  | ||||||
|     { |  | ||||||
|         logger.LogError(new EventId(context.Exception.HResult), |  | ||||||
|             context.Exception, |  | ||||||
|             context.Exception.Message); |  | ||||||
| 
 |  | ||||||
|         if (context.Exception.GetType() == typeof(OrderingDomainException)) |  | ||||||
|         { |  | ||||||
|             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 string[] { context.Exception.Message.ToString() }); |  | ||||||
| 
 |  | ||||||
|             context.Result = new BadRequestObjectResult(problemDetails); |  | ||||||
|             context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             var json = new JsonErrorResponse |  | ||||||
|             { |  | ||||||
|                 Messages = new[] { "An error occur.Try it again." } |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             if (env.IsDevelopment()) |  | ||||||
|             { |  | ||||||
|                 json.DeveloperMessage = context.Exception; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1 |  | ||||||
|             // It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information |  | ||||||
|             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; } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -11,9 +11,6 @@ | |||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Content Update="web.config;"> |  | ||||||
|       <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> |  | ||||||
|     </Content> |  | ||||||
|     <Content Include="Setup\**\*;"> |     <Content Include="Setup\**\*;"> | ||||||
|       <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> |       <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> | ||||||
|     </Content> |     </Content> | ||||||
| @ -35,6 +32,7 @@ | |||||||
|     <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" />    |     <ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" />    | ||||||
|  |     <ProjectReference Include="..\..\Services.Common\Services.Common.csproj" /> | ||||||
|     <ProjectReference Include="..\Ordering.Domain\Ordering.Domain.csproj" /> |     <ProjectReference Include="..\Ordering.Domain\Ordering.Domain.csproj" /> | ||||||
|     <ProjectReference Include="..\Ordering.Infrastructure\Ordering.Infrastructure.csproj" /> |     <ProjectReference Include="..\Ordering.Infrastructure\Ordering.Infrastructure.csproj" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  | |||||||
| @ -1,42 +1,16 @@ | |||||||
| var builder = WebApplication.CreateBuilder(args); | using Services.Common; | ||||||
| 
 | 
 | ||||||
| if (builder.Configuration.GetValue<bool>("UseVault", false)) | var builder = WebApplication.CreateBuilder(args); | ||||||
| { |  | ||||||
|     TokenCredential credential = new ClientSecretCredential( |  | ||||||
|         builder.Configuration["Vault:TenantId"], |  | ||||||
|         builder.Configuration["Vault:ClientId"], |  | ||||||
|         builder.Configuration["Vault:ClientSecret"]); |  | ||||||
|     builder.Configuration.AddAzureKeyVault(new Uri($"https://{builder.Configuration["Vault:Name"]}.vault.azure.net/"), credential); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| builder.WebHost.ConfigureKestrel(options => | builder.AddServiceDefaults(); | ||||||
| { |  | ||||||
|     var httpPort = builder.Configuration.GetValue("PORT", 80); |  | ||||||
|     options.Listen(IPAddress.Any, httpPort, listenOptions => |  | ||||||
|     { |  | ||||||
|         listenOptions.Protocols = HttpProtocols.Http1AndHttp2; |  | ||||||
|     }); |  | ||||||
| 
 | 
 | ||||||
|     var grpcPort = builder.Configuration.GetValue("GRPC_PORT", 5001); | builder.Services.AddGrpc(); | ||||||
|     options.Listen(IPAddress.Any, grpcPort, listenOptions => | builder.Services.AddControllers(); | ||||||
|     { |  | ||||||
|         listenOptions.Protocols = HttpProtocols.Http2; |  | ||||||
|     }); |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| builder.Services.AddGrpc(options => options.EnableDetailedErrors = true); | builder.Services.AddHealthChecks(builder.Configuration); | ||||||
| builder.Services.AddApplicationInsightsTelemetry(builder.Configuration); | builder.Services.AddDbContexts(builder.Configuration); | ||||||
| builder.Services.AddApplicationInsightsKubernetesEnricher(); | builder.Services.AddCustomIntegrations(builder.Configuration); | ||||||
| builder.Services | builder.Services.AddCustomConfiguration(builder.Configuration); | ||||||
|     .AddCustomMvc() |  | ||||||
|     .AddHealthChecks(builder.Configuration) |  | ||||||
|     .AddCustomDbContext(builder.Configuration) |  | ||||||
|     .AddCustomSwagger(builder.Configuration) |  | ||||||
|     .AddCustomAuthentication(builder.Configuration) |  | ||||||
|     .AddCustomAuthorization(builder.Configuration) |  | ||||||
|     .AddCustomIntegrations(builder.Configuration) |  | ||||||
|     .AddCustomConfiguration(builder.Configuration) |  | ||||||
|     .AddEventBus(builder.Configuration); |  | ||||||
| 
 | 
 | ||||||
| var services = builder.Services; | var services = builder.Services; | ||||||
| 
 | 
 | ||||||
| @ -55,9 +29,7 @@ services.AddSingleton<IValidator<CreateOrderCommand>, CreateOrderCommandValidato | |||||||
| services.AddSingleton<IValidator<IdentifiedCommand<CreateOrderCommand, bool>>, IdentifiedCommandValidator>(); | services.AddSingleton<IValidator<IdentifiedCommand<CreateOrderCommand, bool>>, IdentifiedCommandValidator>(); | ||||||
| services.AddSingleton<IValidator<ShipOrderCommand>, ShipOrderCommandValidator>(); | services.AddSingleton<IValidator<ShipOrderCommand>, ShipOrderCommandValidator>(); | ||||||
| 
 | 
 | ||||||
| var queriesConnectionString = builder.Configuration["ConnectionString"]; | services.AddScoped<IOrderQueries>(sp => new OrderQueries(builder.Configuration.GetConnectionString("OrderingDB"))); | ||||||
| 
 |  | ||||||
| services.AddScoped<IOrderQueries>(sp => new OrderQueries(queriesConnectionString)); |  | ||||||
| services.AddScoped<IBuyerRepository, BuyerRepository>(); | services.AddScoped<IBuyerRepository, BuyerRepository>(); | ||||||
| services.AddScoped<IOrderRepository, OrderRepository>(); | services.AddScoped<IOrderRepository, OrderRepository>(); | ||||||
| services.AddScoped<IRequestManager, RequestManager>(); | services.AddScoped<IRequestManager, RequestManager>(); | ||||||
| @ -71,55 +43,27 @@ services.AddSingleton<IIntegrationEventHandler<OrderStockRejectedIntegrationEven | |||||||
| services.AddSingleton<IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>, UserCheckoutAcceptedIntegrationEventHandler>(); | services.AddSingleton<IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>, UserCheckoutAcceptedIntegrationEventHandler>(); | ||||||
| 
 | 
 | ||||||
| var app = builder.Build(); | var app = builder.Build(); | ||||||
| if (!app.Environment.IsDevelopment()) | 
 | ||||||
|  | if (!await app.CheckHealthAsync()) | ||||||
| { | { | ||||||
|     app.UseExceptionHandler("/Home/Error"); |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var pathBase = app.Configuration["PATH_BASE"]; | app.UseServiceDefaults(); | ||||||
| if (!string.IsNullOrEmpty(pathBase)) |  | ||||||
| { |  | ||||||
|     app.UsePathBase(pathBase); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| app.UseSwagger().UseSwaggerUI(c => | app.MapGet("/", () => Results.Redirect("/swagger")); | ||||||
| { |  | ||||||
|    c.SwaggerEndpoint($"{(!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty)}/swagger/v1/swagger.json", "Ordering.API V1"); |  | ||||||
|    c.OAuthClientId("orderingswaggerui"); |  | ||||||
|    c.OAuthAppName("Ordering Swagger UI"); |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| app.UseRouting(); |  | ||||||
| app.UseCors("CorsPolicy"); |  | ||||||
| app.UseAuthentication(); |  | ||||||
| app.UseAuthorization(); |  | ||||||
| app.MapGrpcService<OrderingService>(); | app.MapGrpcService<OrderingService>(); | ||||||
| app.MapDefaultControllerRoute(); |  | ||||||
| app.MapControllers(); | app.MapControllers(); | ||||||
| app.MapGet("/_proto/", async ctx => | 
 | ||||||
| { | var eventBus = app.Services.GetRequiredService<IEventBus>(); | ||||||
|     ctx.Response.ContentType = "text/plain"; | 
 | ||||||
|     using var fs = new FileStream(Path.Combine(app.Environment.ContentRootPath, "Proto", "basket.proto"), FileMode.Open, FileAccess.Read); | eventBus.Subscribe<UserCheckoutAcceptedIntegrationEvent, IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>>(); | ||||||
|     using var sr = new StreamReader(fs); | eventBus.Subscribe<GracePeriodConfirmedIntegrationEvent, IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent>>(); | ||||||
|     while (!sr.EndOfStream) | eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>>(); | ||||||
|     { | eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>(); | ||||||
|         var line = await sr.ReadLineAsync(); | eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>(); | ||||||
|         if (line != "/* >>" || line != "<< */") | eventBus.Subscribe<OrderPaymentSucceededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSucceededIntegrationEvent>>(); | ||||||
|         { |  | ||||||
|             await ctx.Response.WriteAsync(line); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| }); |  | ||||||
| app.MapHealthChecks("/hc", new HealthCheckOptions() |  | ||||||
| { |  | ||||||
|     Predicate = _ => true, |  | ||||||
|     ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse |  | ||||||
| }); |  | ||||||
| app.MapHealthChecks("/liveness", new HealthCheckOptions |  | ||||||
| { |  | ||||||
|     Predicate = r => r.Name.Contains("self") |  | ||||||
| }); |  | ||||||
| ConfigureEventBus(app); |  | ||||||
| 
 | 
 | ||||||
| using (var scope = app.Services.CreateScope()) | using (var scope = app.Services.CreateScope()) | ||||||
| { | { | ||||||
| @ -135,284 +79,3 @@ using (var scope = app.Services.CreateScope()) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| await app.RunAsync(); | await app.RunAsync(); | ||||||
| 
 |  | ||||||
| void ConfigureEventBus(IApplicationBuilder app) |  | ||||||
| { |  | ||||||
|     var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); |  | ||||||
| 
 |  | ||||||
|     eventBus.Subscribe<UserCheckoutAcceptedIntegrationEvent, IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>>(); |  | ||||||
|     eventBus.Subscribe<GracePeriodConfirmedIntegrationEvent, IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent>>(); |  | ||||||
|     eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>>(); |  | ||||||
|     eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>(); |  | ||||||
|     eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>(); |  | ||||||
|     eventBus.Subscribe<OrderPaymentSucceededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSucceededIntegrationEvent>>(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static class CustomExtensionsMethods |  | ||||||
| { |  | ||||||
|     public static IServiceCollection AddCustomMvc(this IServiceCollection services) |  | ||||||
|     { |  | ||||||
|         // Add framework services. |  | ||||||
|         services.AddControllers(options => |  | ||||||
|         { |  | ||||||
|             options.Filters.Add(typeof(HttpGlobalExceptionFilter)); |  | ||||||
|         }) |  | ||||||
|             // Added for functional tests |  | ||||||
|             .AddApplicationPart(typeof(OrdersController).Assembly) |  | ||||||
|             .AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true); |  | ||||||
| 
 |  | ||||||
|         services.AddCors(options => |  | ||||||
|         { |  | ||||||
|             options.AddPolicy("CorsPolicy", |  | ||||||
|                 builder => builder |  | ||||||
|                 .SetIsOriginAllowed((host) => true) |  | ||||||
|                 .AllowAnyMethod() |  | ||||||
|                 .AllowAnyHeader() |  | ||||||
|                 .AllowCredentials()); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         return services; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration) |  | ||||||
|     { |  | ||||||
|         var hcBuilder = services.AddHealthChecks(); |  | ||||||
| 
 |  | ||||||
|         hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy()); |  | ||||||
| 
 |  | ||||||
|         hcBuilder |  | ||||||
|             .AddSqlServer( |  | ||||||
|                 configuration["ConnectionString"], |  | ||||||
|                 name: "OrderingDB-check", |  | ||||||
|                 tags: new string[] { "orderingdb" }); |  | ||||||
| 
 |  | ||||||
|         if (configuration.GetValue<bool>("AzureServiceBusEnabled")) |  | ||||||
|         { |  | ||||||
|             hcBuilder |  | ||||||
|                 .AddAzureServiceBusTopic( |  | ||||||
|                     configuration["EventBusConnection"], |  | ||||||
|                     topicName: "eshop_event_bus", |  | ||||||
|                     name: "ordering-servicebus-check", |  | ||||||
|                     tags: new string[] { "servicebus" }); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             hcBuilder |  | ||||||
|                 .AddRabbitMQ( |  | ||||||
|                     $"amqp://{configuration["EventBusConnection"]}", |  | ||||||
|                     name: "ordering-rabbitmqbus-check", |  | ||||||
|                     tags: new string[] { "rabbitmqbus" }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return services; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) |  | ||||||
|     { |  | ||||||
|         services.AddDbContext<OrderingContext>(options => |  | ||||||
|         { |  | ||||||
|             options.UseSqlServer(configuration["ConnectionString"], |  | ||||||
|                 sqlServerOptionsAction: sqlOptions => |  | ||||||
|                 { |  | ||||||
|                     sqlOptions.MigrationsAssembly(typeof(Program).GetTypeInfo().Assembly.GetName().Name); |  | ||||||
|                     sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); |  | ||||||
|                 }); |  | ||||||
|         }, |  | ||||||
|                     ServiceLifetime.Scoped  //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request) |  | ||||||
|                 ); |  | ||||||
| 
 |  | ||||||
|         services.AddDbContext<IntegrationEventLogContext>(options => |  | ||||||
|         { |  | ||||||
|             options.UseSqlServer(configuration["ConnectionString"], |  | ||||||
|                                     sqlServerOptionsAction: sqlOptions => |  | ||||||
|                                     { |  | ||||||
|                                         sqlOptions.MigrationsAssembly(typeof(Program).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 AddCustomSwagger(this IServiceCollection services, IConfiguration configuration) |  | ||||||
|     { |  | ||||||
|         return services.AddSwaggerGen(options => |  | ||||||
|         { |  | ||||||
|             options.SwaggerDoc("v1", new OpenApiInfo |  | ||||||
|             { |  | ||||||
|                 Title = "eShopOnContainers - Ordering HTTP API", |  | ||||||
|                 Version = "v1", |  | ||||||
|                 Description = "The Ordering Service HTTP API" |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             var identityUrl = configuration.GetSection("Identity")["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<string, string>() |  | ||||||
|                         { |  | ||||||
|                             { "orders", "Ordering API" } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             options.OperationFilter<AuthorizeCheckOperationFilter>(); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static IServiceCollection AddCustomIntegrations(this IServiceCollection services, IConfiguration configuration) |  | ||||||
|     { |  | ||||||
|         services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); |  | ||||||
|         services.AddTransient<IIdentityService, IdentityService>(); |  | ||||||
|         services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>( |  | ||||||
|             sp => (DbConnection c) => new IntegrationEventLogService(c)); |  | ||||||
| 
 |  | ||||||
|         services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>(); |  | ||||||
| 
 |  | ||||||
|         if (configuration.GetValue<bool>("AzureServiceBusEnabled")) |  | ||||||
|         { |  | ||||||
|             services.AddSingleton<IServiceBusPersisterConnection>(sp => |  | ||||||
|             { |  | ||||||
|                 var serviceBusConnectionString = configuration["EventBusConnection"]; |  | ||||||
| 
 |  | ||||||
|                 var subscriptionClientName = configuration["SubscriptionClientName"]; |  | ||||||
| 
 |  | ||||||
|                 return new DefaultServiceBusPersisterConnection(serviceBusConnectionString); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             services.AddSingleton<IRabbitMQPersistentConnection>(sp => |  | ||||||
|             { |  | ||||||
|                 var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>(); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|                 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 AddCustomConfiguration(this IServiceCollection services, IConfiguration configuration) |  | ||||||
|     { |  | ||||||
|         services.Configure<OrderingSettings>(configuration); |  | ||||||
|         services.Configure<ApiBehaviorOptions>(options => |  | ||||||
|         { |  | ||||||
|             options.InvalidModelStateResponseFactory = context => |  | ||||||
|             { |  | ||||||
|                 var problemDetails = new ValidationProblemDetails(context.ModelState) |  | ||||||
|                 { |  | ||||||
|                     Instance = context.HttpContext.Request.Path, |  | ||||||
|                     Status = StatusCodes.Status400BadRequest, |  | ||||||
|                     Detail = "Please refer to the errors property for additional details." |  | ||||||
|                 }; |  | ||||||
| 
 |  | ||||||
|                 return new BadRequestObjectResult(problemDetails) |  | ||||||
|                 { |  | ||||||
|                     ContentTypes = { "application/problem+json", "application/problem+xml" } |  | ||||||
|                 }; |  | ||||||
|             }; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         return services; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) |  | ||||||
|     { |  | ||||||
|         if (configuration.GetValue<bool>("AzureServiceBusEnabled")) |  | ||||||
|         { |  | ||||||
|             services.AddSingleton<IEventBus, EventBusServiceBus>(sp => |  | ||||||
|             { |  | ||||||
|                 var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); |  | ||||||
|                 var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); |  | ||||||
|                 var eventBusSubscriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |  | ||||||
|                 string subscriptionName = configuration["SubscriptionClientName"]; |  | ||||||
| 
 |  | ||||||
|                 return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubscriptionsManager, sp, subscriptionName); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp => |  | ||||||
|             { |  | ||||||
|                 var subscriptionClientName = configuration["SubscriptionClientName"]; |  | ||||||
|                 var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>(); |  | ||||||
|                 var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>(); |  | ||||||
|                 var eventBusSubscriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |  | ||||||
| 
 |  | ||||||
|                 if (!int.TryParse(configuration["EventBusRetryCount"], out var retryCount)) |  | ||||||
|                 { |  | ||||||
|                     retryCount = 5; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, sp, eventBusSubscriptionsManager, subscriptionClientName, retryCount); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); |  | ||||||
| 
 |  | ||||||
|         return services; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) |  | ||||||
|     { |  | ||||||
|         // prevent from mapping "sub" claim to nameidentifier. |  | ||||||
|         JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); |  | ||||||
| 
 |  | ||||||
|         var identityUrl = configuration.GetValue<string>("IdentityUrl"); |  | ||||||
| 
 |  | ||||||
|         services.AddAuthentication("Bearer").AddJwtBearer(options => |  | ||||||
|         { |  | ||||||
|             options.Authority = identityUrl; |  | ||||||
|             options.RequireHttpsMetadata = false; |  | ||||||
|             options.Audience = "orders"; |  | ||||||
|             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", "orders"); |  | ||||||
|             }); |  | ||||||
|         }); |  | ||||||
|         return services; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -1,25 +1,9 @@ | |||||||
| { | { | ||||||
|   "iisSettings": { |  | ||||||
|     "windowsAuthentication": false, |  | ||||||
|     "anonymousAuthentication": true, |  | ||||||
|     "iisExpress": { |  | ||||||
|       "applicationUrl": "http://localhost:55102/", |  | ||||||
|       "sslPort": 0 |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   "profiles": { |   "profiles": { | ||||||
|     "IIS Express": { |     "Ordering.API": { | ||||||
|       "commandName": "IISExpress", |  | ||||||
|       "launchBrowser": true, |  | ||||||
|       "launchUrl": "/swagger", |  | ||||||
|       "environmentVariables": { |  | ||||||
|         "ASPNETCORE_ENVIRONMENT": "Development" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "Microsoft.eShopOnContainers.Services.Ordering.API": { |  | ||||||
|       "commandName": "Project", |       "commandName": "Project", | ||||||
|       "launchBrowser": true, |       "launchBrowser": true, | ||||||
|       "launchUrl": "http://localhost:55102/", |       "applicationUrl": "http://localhost:5228/", | ||||||
|       "environmentVariables": { |       "environmentVariables": { | ||||||
|         "ASPNETCORE_ENVIRONMENT": "Development" |         "ASPNETCORE_ENVIRONMENT": "Development" | ||||||
|       } |       } | ||||||
|  | |||||||
| @ -1,24 +1,43 @@ | |||||||
| { | { | ||||||
|   "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;TrustServerCertificate=true", |   "Logging": { | ||||||
|   "Identity": { |     "LogLevel": { | ||||||
|     "Url": "http://localhost:5105", |       "Default": "Information", | ||||||
|     "ExternalUrl": "http://localhost:5105", |       "Microsoft.AspNetCore": "Warning" | ||||||
|     "Audience": "orders" |     } | ||||||
|   }, |   }, | ||||||
|   "UseCustomizationData": false, |   "OpenApi": { | ||||||
|   "AzureServiceBusEnabled": false, |     "Endpoint": { | ||||||
|  |       "Name": "Ordering.API V1" | ||||||
|  |     }, | ||||||
|  |     "Document": { | ||||||
|  |       "Description": "The Ordering Service HTTP API", | ||||||
|  |       "Title": "eShopOnContainers - Ordering HTTP API", | ||||||
|  |       "Version": "v1" | ||||||
|  |     }, | ||||||
|  |     "Auth": { | ||||||
|  |       "ClientId": "orderingswaggerui", | ||||||
|  |       "AppName": "Ordering Swagger UI" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "ConnectionStrings": { | ||||||
|  |     "EventBus": "localhost" | ||||||
|  |   }, | ||||||
|  |   "EventBus": { | ||||||
|     "SubscriptionClientName": "Ordering", |     "SubscriptionClientName": "Ordering", | ||||||
|   "GracePeriodTime": "1", |     "RetryCount": 5 | ||||||
|   "CheckUpdateTime": "30000", |   }, | ||||||
|   "ApplicationInsights": { |   "ApplicationInsights": { | ||||||
|     "InstrumentationKey": "" |     "InstrumentationKey": "" | ||||||
|   }, |   }, | ||||||
|   "EventBusRetryCount": 5, |   "Identity": { | ||||||
|   "EventBusConnection": "localhost", |     "Url": "http://localhost:5105", | ||||||
|   "UseVault": false, |     "ExternalUrl": "http://localhost:5105", | ||||||
|   "Vault": { |     "Audience": "orders", | ||||||
|     "Name": "eshop", |     "Scopes": { | ||||||
|     "ClientId": "your-client-id", |       "orders": "Ordering API" | ||||||
|     "ClientSecret": "your-client-secret" |  | ||||||
|     } |     } | ||||||
|  |   }, | ||||||
|  |   "UseCustomizationData": false, | ||||||
|  |   "GracePeriodTime": "1", | ||||||
|  |   "CheckUpdateTime": "30000" | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,14 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> |  | ||||||
| <configuration> |  | ||||||
|   <!-- |  | ||||||
|     Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380 |  | ||||||
|   --> |  | ||||||
|   <system.webServer> |  | ||||||
|     <handlers> |  | ||||||
|       <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> |  | ||||||
|     </handlers> |  | ||||||
|     <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"> |  | ||||||
|       <environmentVariables /> |  | ||||||
|     </aspNetCore> |  | ||||||
|   </system.webServer> |  | ||||||
| </configuration> |  | ||||||
| @ -9,18 +9,6 @@ public class OrderingScenarioBase | |||||||
|     { |     { | ||||||
|         public TestServer CreateServer() |         public TestServer CreateServer() | ||||||
|         { |         { | ||||||
|             Services.MigrateDbContext<OrderingContext>((context, services) => |  | ||||||
|             { |  | ||||||
|                 var env = services.GetService<IWebHostEnvironment>(); |  | ||||||
|                 var settings = services.GetService<IOptions<OrderingSettings>>(); |  | ||||||
|                 var logger = services.GetService<ILogger<OrderingContextSeed>>(); |  | ||||||
| 
 |  | ||||||
|                 new OrderingContextSeed() |  | ||||||
|                     .SeedAsync(context, env, settings, logger) |  | ||||||
|                     .Wait(); |  | ||||||
|             }) |  | ||||||
|             .MigrateDbContext<IntegrationEventLogContext>((_, __) => { }); |  | ||||||
| 
 |  | ||||||
|             return Server; |             return Server; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ namespace Ordering.FunctionalTests | |||||||
|             var response = await server.CreateClient() |             var response = await server.CreateClient() | ||||||
|                 .PutAsync(Put.CancelOrder, content); |                 .PutAsync(Put.CancelOrder, content); | ||||||
| 
 | 
 | ||||||
|  |             var s = await response.Content.ReadAsStringAsync(); | ||||||
|             Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); |             Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,9 @@ | |||||||
| { | { | ||||||
|  |   "ConnectionStrings": { | ||||||
|  |     "OrderingDb": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;Encrypt=False;TrustServerCertificate=true", | ||||||
|  |     "EventBus": "localhost" | ||||||
|  |   }, | ||||||
|   "CheckUpdateTime": "30000", |   "CheckUpdateTime": "30000", | ||||||
|   "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;Encrypt=False;TrustServerCertificate=true", |  | ||||||
|   "EventBusConnection": "localhost", |   "EventBusConnection": "localhost", | ||||||
|   "ExternalCatalogBaseUrl": "http://localhost:5101", |   "ExternalCatalogBaseUrl": "http://localhost:5101", | ||||||
|   "GracePeriodTime": "1", |   "GracePeriodTime": "1", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user