Adding various language enhancements, removing unused/duplicated extension
This commit is contained in:
parent
981507dccb
commit
303c958e43
@ -22,7 +22,7 @@
|
||||
|
||||
operation.Security = new List<OpenApiSecurityRequirement>
|
||||
{
|
||||
new OpenApiSecurityRequirement
|
||||
new()
|
||||
{
|
||||
[ oAuthScheme ] = new [] { "Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator" }
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
operation.Security = new List<OpenApiSecurityRequirement>
|
||||
{
|
||||
new OpenApiSecurityRequirement
|
||||
new()
|
||||
{
|
||||
[ oAuthScheme ] = new[] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" }
|
||||
}
|
||||
|
@ -34,8 +34,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
_persistentConnection.TryConnect();
|
||||
}
|
||||
|
||||
using (var channel = _persistentConnection.CreateModel())
|
||||
{
|
||||
using var channel = _persistentConnection.CreateModel();
|
||||
channel.QueueUnbind(queue: _queueName,
|
||||
exchange: BROKER_NAME,
|
||||
routingKey: eventName);
|
||||
@ -46,7 +45,6 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
_consumerChannel.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Publish(IntegrationEvent @event)
|
||||
{
|
||||
@ -66,8 +64,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
|
||||
_logger.LogTrace("Creating RabbitMQ channel to publish event: {EventId} ({EventName})", @event.Id, eventName);
|
||||
|
||||
using (var channel = _persistentConnection.CreateModel())
|
||||
{
|
||||
using var channel = _persistentConnection.CreateModel();
|
||||
_logger.LogTrace("Declaring RabbitMQ exchange to publish event: {EventId}", @event.Id);
|
||||
|
||||
channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct");
|
||||
@ -92,7 +89,6 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
body: body);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void SubscribeDynamic<TH>(string eventName)
|
||||
where TH : IDynamicIntegrationEventHandler
|
||||
@ -244,15 +240,13 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
|
||||
if (_subsManager.HasSubscriptionsForEvent(eventName))
|
||||
{
|
||||
using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME))
|
||||
{
|
||||
using var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME);
|
||||
var subscriptions = _subsManager.GetHandlersForEvent(eventName);
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
if (subscription.IsDynamic)
|
||||
{
|
||||
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
||||
if (handler == null) continue;
|
||||
if (scope.ResolveOptional(subscription.HandlerType) is not IDynamicIntegrationEventHandler handler) continue;
|
||||
using dynamic eventData = JsonDocument.Parse(message);
|
||||
await Task.Yield();
|
||||
await handler.Handle(eventData);
|
||||
@ -262,7 +256,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
var handler = scope.ResolveOptional(subscription.HandlerType);
|
||||
if (handler == null) continue;
|
||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||
var integrationEvent = JsonSerializer.Deserialize(message, eventType, new JsonSerializerOptions() { PropertyNameCaseInsensitive= true});
|
||||
var integrationEvent = JsonSerializer.Deserialize(message, eventType, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
|
||||
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||
|
||||
await Task.Yield();
|
||||
@ -270,7 +264,6 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No subscription for RabbitMQ event: {EventName}", eventName);
|
||||
|
@ -155,15 +155,13 @@ public class EventBusServiceBus : IEventBus, IDisposable
|
||||
var processed = false;
|
||||
if (_subsManager.HasSubscriptionsForEvent(eventName))
|
||||
{
|
||||
using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME))
|
||||
{
|
||||
var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME);
|
||||
var subscriptions = _subsManager.GetHandlersForEvent(eventName);
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
if (subscription.IsDynamic)
|
||||
{
|
||||
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
||||
if (handler == null) continue;
|
||||
if (scope.ResolveOptional(subscription.HandlerType) is not IDynamicIntegrationEventHandler handler) continue;
|
||||
|
||||
using dynamic eventData = JsonDocument.Parse(message);
|
||||
await handler.Handle(eventData);
|
||||
@ -180,7 +178,6 @@ public class EventBusServiceBus : IEventBus, IDisposable
|
||||
}
|
||||
}
|
||||
processed = true;
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
|
@ -15,11 +15,9 @@ public class ResilientTransaction
|
||||
var strategy = _context.Database.CreateExecutionStrategy();
|
||||
await strategy.ExecuteAsync(async () =>
|
||||
{
|
||||
using (var transaction = _context.Database.BeginTransaction())
|
||||
{
|
||||
using var transaction = _context.Database.BeginTransaction();
|
||||
await action();
|
||||
transaction.Commit();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||
{
|
||||
var underK8s = webHost.IsInKubernetes();
|
||||
|
||||
using (var scope = webHost.Services.CreateScope())
|
||||
{
|
||||
using var scope = webHost.Services.CreateScope();
|
||||
var services = scope.ServiceProvider;
|
||||
var logger = services.GetRequiredService<ILogger<TContext>>();
|
||||
var context = services.GetService<TContext>();
|
||||
@ -64,7 +63,6 @@ namespace Microsoft.AspNetCore.Hosting
|
||||
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return webHost;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||
|
||||
operation.Security = new List<OpenApiSecurityRequirement>
|
||||
{
|
||||
new OpenApiSecurityRequirement
|
||||
new()
|
||||
{
|
||||
[ oAuthScheme ] = new [] { "basketapi" }
|
||||
}
|
||||
|
@ -6,33 +6,28 @@ public class BasketScenarios
|
||||
[Fact]
|
||||
public async Task Post_basket_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var content = new StringContent(BuildBasket(), UTF8Encoding.UTF8, "application/json");
|
||||
var response = await server.CreateClient()
|
||||
.PostAsync(Post.Basket, content);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_basket_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.GetBasket(1));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Send_Checkout_basket_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var contentBasket = new StringContent(BuildBasket(), UTF8Encoding.UTF8, "application/json");
|
||||
|
||||
await server.CreateClient()
|
||||
@ -45,7 +40,6 @@ public class BasketScenarios
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
string BuildBasket()
|
||||
{
|
||||
|
@ -9,8 +9,7 @@ namespace Basket.FunctionalTests
|
||||
[Fact]
|
||||
public async Task UpdateBasket_return_and_add_basket()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var redis = server.Host.Services.GetRequiredService<ConnectionMultiplexer>();
|
||||
|
||||
var redisBasketRepository = BuildBasketRepository(redis);
|
||||
@ -23,7 +22,6 @@ namespace Basket.FunctionalTests
|
||||
|
||||
Assert.NotNull(basket);
|
||||
Assert.Single(basket.Items);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -32,8 +30,7 @@ namespace Basket.FunctionalTests
|
||||
public async Task Delete_Basket_return_null()
|
||||
{
|
||||
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var redis = server.Host.Services.GetRequiredService<ConnectionMultiplexer>();
|
||||
|
||||
var redisBasketRepository = BuildBasketRepository(redis);
|
||||
@ -51,7 +48,6 @@ namespace Basket.FunctionalTests
|
||||
Assert.True(deleteResult);
|
||||
Assert.Null(result);
|
||||
}
|
||||
}
|
||||
|
||||
RedisBasketRepository BuildBasketRepository(ConnectionMultiplexer connMux)
|
||||
{
|
||||
|
@ -47,40 +47,18 @@ public class PicController : ControllerBase
|
||||
|
||||
private string GetImageMimeTypeFromImageFileExtension(string extension)
|
||||
{
|
||||
string mimetype;
|
||||
|
||||
switch (extension)
|
||||
string mimetype = extension switch
|
||||
{
|
||||
case ".png":
|
||||
mimetype = "image/png";
|
||||
break;
|
||||
case ".gif":
|
||||
mimetype = "image/gif";
|
||||
break;
|
||||
case ".jpg":
|
||||
case ".jpeg":
|
||||
mimetype = "image/jpeg";
|
||||
break;
|
||||
case ".bmp":
|
||||
mimetype = "image/bmp";
|
||||
break;
|
||||
case ".tiff":
|
||||
mimetype = "image/tiff";
|
||||
break;
|
||||
case ".wmf":
|
||||
mimetype = "image/wmf";
|
||||
break;
|
||||
case ".jp2":
|
||||
mimetype = "image/jp2";
|
||||
break;
|
||||
case ".svg":
|
||||
mimetype = "image/svg+xml";
|
||||
break;
|
||||
default:
|
||||
mimetype = "application/octet-stream";
|
||||
break;
|
||||
}
|
||||
|
||||
".png" => "image/png",
|
||||
".gif" => "image/gif",
|
||||
".jpg" or ".jpeg" => "image/jpeg",
|
||||
".bmp" => "image/bmp",
|
||||
".tiff" => "image/tiff",
|
||||
".wmf" => "image/wmf",
|
||||
".jp2" => "image/jp2",
|
||||
".svg" => "image/svg+xml",
|
||||
_ => "application/octet-stream",
|
||||
};
|
||||
return mimetype;
|
||||
}
|
||||
}
|
||||
|
@ -1,122 +0,0 @@
|
||||
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;
|
||||
}
|
||||
|
||||
public static IWebHost MigrateDbContext<TContext>(this IWebHost 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);
|
||||
}
|
||||
}
|
@ -13,8 +13,7 @@ public static class WebHostExtensions
|
||||
{
|
||||
var underK8s = host.IsInKubernetes();
|
||||
|
||||
using (var scope = host.Services.CreateScope())
|
||||
{
|
||||
using var scope = host.Services.CreateScope();
|
||||
var services = scope.ServiceProvider;
|
||||
|
||||
var logger = services.GetRequiredService<ILogger<TContext>>();
|
||||
@ -56,7 +55,6 @@ public static class WebHostExtensions
|
||||
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
@ -92,11 +92,11 @@ public class CatalogContextSeed
|
||||
{
|
||||
return new List<CatalogBrand>()
|
||||
{
|
||||
new CatalogBrand() { Brand = "Azure"},
|
||||
new CatalogBrand() { Brand = ".NET" },
|
||||
new CatalogBrand() { Brand = "Visual Studio" },
|
||||
new CatalogBrand() { Brand = "SQL Server" },
|
||||
new CatalogBrand() { Brand = "Other" }
|
||||
new() { Brand = "Azure"},
|
||||
new() { Brand = ".NET" },
|
||||
new() { Brand = "Visual Studio" },
|
||||
new() { Brand = "SQL Server" },
|
||||
new() { Brand = "Other" }
|
||||
};
|
||||
}
|
||||
|
||||
@ -147,10 +147,10 @@ public class CatalogContextSeed
|
||||
{
|
||||
return new List<CatalogType>()
|
||||
{
|
||||
new CatalogType() { Type = "Mug"},
|
||||
new CatalogType() { Type = "T-Shirt" },
|
||||
new CatalogType() { Type = "Sheet" },
|
||||
new CatalogType() { Type = "USB Memory Stick" }
|
||||
new() { Type = "Mug"},
|
||||
new() { Type = "T-Shirt" },
|
||||
new() { Type = "Sheet" },
|
||||
new() { Type = "USB Memory Stick" }
|
||||
};
|
||||
}
|
||||
|
||||
@ -297,18 +297,18 @@ public class CatalogContextSeed
|
||||
{
|
||||
return new List<CatalogItem>()
|
||||
{
|
||||
new CatalogItem { CatalogTypeId = 2, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Bot Black Hoodie", Name = ".NET Bot Black Hoodie", Price = 19.5M, PictureFileName = "1.png" },
|
||||
new CatalogItem { CatalogTypeId = 1, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureFileName = "2.png" },
|
||||
new CatalogItem { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureFileName = "3.png" },
|
||||
new CatalogItem { CatalogTypeId = 2, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Foundation T-shirt", Name = ".NET Foundation T-shirt", Price = 12, PictureFileName = "4.png" },
|
||||
new CatalogItem { CatalogTypeId = 3, CatalogBrandId = 5, AvailableStock = 100, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureFileName = "5.png" },
|
||||
new CatalogItem { CatalogTypeId = 2, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Blue Hoodie", Name = ".NET Blue Hoodie", Price = 12, PictureFileName = "6.png" },
|
||||
new CatalogItem { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureFileName = "7.png" },
|
||||
new CatalogItem { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Kudu Purple Hoodie", Name = "Kudu Purple Hoodie", Price = 8.5M, PictureFileName = "8.png" },
|
||||
new CatalogItem { CatalogTypeId = 1, CatalogBrandId = 5, AvailableStock = 100, Description = "Cup<T> White Mug", Name = "Cup<T> White Mug", Price = 12, PictureFileName = "9.png" },
|
||||
new CatalogItem { CatalogTypeId = 3, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureFileName = "10.png" },
|
||||
new CatalogItem { CatalogTypeId = 3, CatalogBrandId = 2, AvailableStock = 100, Description = "Cup<T> Sheet", Name = "Cup<T> Sheet", Price = 8.5M, PictureFileName = "11.png" },
|
||||
new CatalogItem { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Prism White TShirt", Name = "Prism White TShirt", Price = 12, PictureFileName = "12.png" },
|
||||
new() { CatalogTypeId = 2, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Bot Black Hoodie", Name = ".NET Bot Black Hoodie", Price = 19.5M, PictureFileName = "1.png" },
|
||||
new() { CatalogTypeId = 1, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureFileName = "2.png" },
|
||||
new() { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureFileName = "3.png" },
|
||||
new() { CatalogTypeId = 2, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Foundation T-shirt", Name = ".NET Foundation T-shirt", Price = 12, PictureFileName = "4.png" },
|
||||
new() { CatalogTypeId = 3, CatalogBrandId = 5, AvailableStock = 100, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureFileName = "5.png" },
|
||||
new() { CatalogTypeId = 2, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Blue Hoodie", Name = ".NET Blue Hoodie", Price = 12, PictureFileName = "6.png" },
|
||||
new() { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureFileName = "7.png" },
|
||||
new() { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Kudu Purple Hoodie", Name = "Kudu Purple Hoodie", Price = 8.5M, PictureFileName = "8.png" },
|
||||
new() { CatalogTypeId = 1, CatalogBrandId = 5, AvailableStock = 100, Description = "Cup<T> White Mug", Name = "Cup<T> White Mug", Price = 12, PictureFileName = "9.png" },
|
||||
new() { CatalogTypeId = 3, CatalogBrandId = 2, AvailableStock = 100, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureFileName = "10.png" },
|
||||
new() { CatalogTypeId = 3, CatalogBrandId = 2, AvailableStock = 100, Description = "Cup<T> Sheet", Name = "Cup<T> Sheet", Price = 8.5M, PictureFileName = "11.png" },
|
||||
new() { CatalogTypeId = 2, CatalogBrandId = 5, AvailableStock = 100, Description = "Prism White TShirt", Name = "Prism White TShirt", Price = 12, PictureFileName = "12.png" },
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,135 +6,113 @@ public class CatalogScenarios
|
||||
[Fact]
|
||||
public async Task Get_get_all_catalogitems_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Items());
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_catalogitem_by_id_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.ItemById(1));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_catalogitem_by_id_and_response_bad_request_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.ItemById(int.MinValue));
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_catalogitem_by_id_and_response_not_found_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.ItemById(int.MaxValue));
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_catalogitem_by_name_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.ItemByName(".NET"));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_paginated_catalogitem_by_name_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
const bool paginated = true;
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.ItemByName(".NET", paginated));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_paginated_catalog_items_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
const bool paginated = true;
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Items(paginated));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_filtered_catalog_items_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Filtered(1, 1));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_get_paginated_filtered_catalog_items_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
const bool paginated = true;
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Filtered(1, 1, paginated));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_catalog_types_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Types);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_catalog_brands_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Brands);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
global using Catalog.API.Extensions;
|
||||
global using Microsoft.AspNetCore.Hosting;
|
||||
global using Microsoft.AspNetCore.Hosting;
|
||||
global using Microsoft.AspNetCore.TestHost;
|
||||
global using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||
global using Microsoft.eShopOnContainers.Services.Catalog.API.Extensions;
|
||||
global using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||
global using Microsoft.eShopOnContainers.Services.Catalog.API;
|
||||
global using Microsoft.Extensions.Configuration;
|
||||
|
@ -25,12 +25,10 @@ public class CatalogControllerTest
|
||||
.UseInMemoryDatabase(databaseName: "in-memory")
|
||||
.Options;
|
||||
|
||||
using (var dbContext = new CatalogContext(_dbOptions))
|
||||
{
|
||||
using var dbContext = new CatalogContext(_dbOptions);
|
||||
dbContext.AddRange(GetFakeCatalog());
|
||||
dbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_catalog_items_success()
|
||||
@ -66,7 +64,7 @@ public class CatalogControllerTest
|
||||
{
|
||||
return new List<CatalogItem>()
|
||||
{
|
||||
new CatalogItem()
|
||||
new()
|
||||
{
|
||||
Id = 1,
|
||||
Name = "fakeItemA",
|
||||
@ -74,7 +72,7 @@ public class CatalogControllerTest
|
||||
CatalogBrandId = 1,
|
||||
PictureFileName = "fakeItemA.png"
|
||||
},
|
||||
new CatalogItem()
|
||||
new()
|
||||
{
|
||||
Id = 2,
|
||||
Name = "fakeItemB",
|
||||
@ -82,7 +80,7 @@ public class CatalogControllerTest
|
||||
CatalogBrandId = 1,
|
||||
PictureFileName = "fakeItemB.png"
|
||||
},
|
||||
new CatalogItem()
|
||||
new()
|
||||
{
|
||||
Id = 3,
|
||||
Name = "fakeItemC",
|
||||
@ -90,7 +88,7 @@ public class CatalogControllerTest
|
||||
CatalogBrandId = 1,
|
||||
PictureFileName = "fakeItemC.png"
|
||||
},
|
||||
new CatalogItem()
|
||||
new()
|
||||
{
|
||||
Id = 4,
|
||||
Name = "fakeItemD",
|
||||
@ -98,7 +96,7 @@ public class CatalogControllerTest
|
||||
CatalogBrandId = 1,
|
||||
PictureFileName = "fakeItemD.png"
|
||||
},
|
||||
new CatalogItem()
|
||||
new()
|
||||
{
|
||||
Id = 5,
|
||||
Name = "fakeItemE",
|
||||
@ -106,7 +104,7 @@ public class CatalogControllerTest
|
||||
CatalogBrandId = 1,
|
||||
PictureFileName = "fakeItemE.png"
|
||||
},
|
||||
new CatalogItem()
|
||||
new()
|
||||
{
|
||||
Id = 6,
|
||||
Name = "fakeItemF",
|
||||
@ -120,7 +118,7 @@ public class CatalogControllerTest
|
||||
|
||||
public class TestCatalogSettings : IOptionsSnapshot<CatalogSettings>
|
||||
{
|
||||
public CatalogSettings Value => new CatalogSettings
|
||||
public CatalogSettings Value => new()
|
||||
{
|
||||
PicBaseUrl = "http://image-server.com/",
|
||||
AzureStorageEnabled = true
|
||||
|
@ -12,17 +12,14 @@
|
||||
* real environment the certificate should be created and stored in a secure way, which is out
|
||||
* of the scope of this project.
|
||||
**********************************************************************************************/
|
||||
using (var stream = assembly.GetManifestResourceStream("Identity.API.Certificate.idsrv3test.pfx"))
|
||||
{
|
||||
using var stream = assembly.GetManifestResourceStream("Identity.API.Certificate.idsrv3test.pfx");
|
||||
return new X509Certificate2(ReadStream(stream), "idsrv3test");
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] ReadStream(Stream input)
|
||||
{
|
||||
byte[] buffer = new byte[16 * 1024];
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
using MemoryStream ms = new MemoryStream();
|
||||
int read;
|
||||
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
@ -31,5 +28,4 @@
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -191,8 +191,7 @@
|
||||
string imagePath = Path.Combine(webroot, "images");
|
||||
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
|
||||
|
||||
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
|
||||
{
|
||||
using ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read);
|
||||
foreach (ZipArchiveEntry entry in zip.Entries)
|
||||
{
|
||||
if (imageFiles.Contains(entry.Name))
|
||||
@ -210,7 +209,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "EXCEPTION ERROR: {Message}", ex.Message); ;
|
||||
|
@ -13,8 +13,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||
{
|
||||
var underK8s = webHost.IsInKubernetes();
|
||||
|
||||
using (var scope = webHost.Services.CreateScope())
|
||||
{
|
||||
using var scope = webHost.Services.CreateScope();
|
||||
var services = scope.ServiceProvider;
|
||||
var logger = services.GetRequiredService<ILogger<TContext>>();
|
||||
var context = services.GetService<TContext>();
|
||||
@ -56,7 +55,6 @@ namespace Microsoft.AspNetCore.Hosting
|
||||
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return webHost;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class TransactionBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequ
|
||||
{
|
||||
Guid transactionId;
|
||||
|
||||
using (var transaction = await _dbContext.BeginTransactionAsync())
|
||||
using var transaction = await _dbContext.BeginTransactionAsync();
|
||||
using (LogContext.PushProperty("TransactionContext", transaction.TransactionId))
|
||||
{
|
||||
_logger.LogInformation("----- Begin transaction {TransactionId} for {CommandName} ({@Command})", transaction.TransactionId, typeName, request);
|
||||
|
@ -13,8 +13,7 @@ public class OrderQueries
|
||||
|
||||
public async Task<Order> GetOrderAsync(int id)
|
||||
{
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
using var connection = new SqlConnection(_connectionString);
|
||||
connection.Open();
|
||||
|
||||
var result = await connection.QueryAsync<dynamic>(
|
||||
@ -34,12 +33,10 @@ public class OrderQueries
|
||||
|
||||
return MapOrderItems(result);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<OrderSummary>> GetOrdersFromUserAsync(Guid userId)
|
||||
{
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
using var connection = new SqlConnection(_connectionString);
|
||||
connection.Open();
|
||||
|
||||
return await connection.QueryAsync<OrderSummary>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status], SUM(oi.units*oi.unitprice) as total
|
||||
@ -51,17 +48,14 @@ public class OrderQueries
|
||||
GROUP BY o.[Id], o.[OrderDate], os.[Name]
|
||||
ORDER BY o.[Id]", new { userId });
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<CardType>> GetCardTypesAsync()
|
||||
{
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
using var connection = new SqlConnection(_connectionString);
|
||||
connection.Open();
|
||||
|
||||
return await connection.QueryAsync<CardType>("SELECT * FROM ordering.cardtypes");
|
||||
}
|
||||
}
|
||||
|
||||
private Order MapOrderItems(dynamic result)
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||
|
||||
operation.Security = new List<OpenApiSecurityRequirement>
|
||||
{
|
||||
new OpenApiSecurityRequirement
|
||||
new()
|
||||
{
|
||||
[ oAuthScheme ] = new [] { "orderingapi" }
|
||||
}
|
||||
|
@ -63,8 +63,7 @@ namespace Ordering.BackgroundTasks.Services
|
||||
{
|
||||
IEnumerable<int> orderIds = new List<int>();
|
||||
|
||||
using (var conn = new SqlConnection(_settings.ConnectionString))
|
||||
{
|
||||
using var conn = new SqlConnection(_settings.ConnectionString);
|
||||
try
|
||||
{
|
||||
conn.Open();
|
||||
@ -79,7 +78,6 @@ namespace Ordering.BackgroundTasks.Services
|
||||
_logger.LogCritical(exception, "FATAL ERROR: Database connections could not be opened: {Message}", exception.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return orderIds;
|
||||
}
|
||||
|
@ -14,40 +14,34 @@ namespace Ordering.FunctionalTests
|
||||
[Fact]
|
||||
public async Task Get_get_all_stored_orders_and_response_ok_status_code()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Orders);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Cancel_order_no_order_created_bad_request_response()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
|
||||
var response = await server.CreateIdempotentClient()
|
||||
.PutAsync(Put.CancelOrder, content);
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Ship_order_no_order_created_bad_request_response()
|
||||
{
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
using var server = CreateServer();
|
||||
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
|
||||
var response = await server.CreateIdempotentClient()
|
||||
.PutAsync(Put.ShipOrder, content);
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
string BuildOrder()
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||
|
||||
operation.Security = new List<OpenApiSecurityRequirement>
|
||||
{
|
||||
new OpenApiSecurityRequirement
|
||||
new()
|
||||
{
|
||||
[ oAuthScheme ] = new [] { "webhooksapi" }
|
||||
}
|
||||
|
@ -11,9 +11,8 @@ public class IntegrationEventsScenarios
|
||||
decimal priceModification = 0.15M;
|
||||
string userId = "JohnId";
|
||||
|
||||
using (var catalogServer = new CatalogScenariosBase().CreateServer())
|
||||
using (var basketServer = new BasketScenariosBase().CreateServer())
|
||||
{
|
||||
using var catalogServer = new CatalogScenariosBase().CreateServer();
|
||||
using var basketServer = new BasketScenariosBase().CreateServer();
|
||||
var catalogClient = catalogServer.CreateClient();
|
||||
var basketClient = basketServer.CreateClient();
|
||||
|
||||
@ -51,7 +50,6 @@ public class IntegrationEventsScenarios
|
||||
Assert.Equal(oldPrice, itemUpdated.OldUnitPrice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<BasketItem> GetUpdatedBasketItem(decimal newPrice, int productId, string userId, HttpClient basketClient)
|
||||
{
|
||||
|
@ -5,9 +5,8 @@ public class OrderingScenarios : OrderingScenariosBase
|
||||
[Fact]
|
||||
public async Task Cancel_basket_and_check_order_status_cancelled()
|
||||
{
|
||||
using (var orderServer = new OrderingScenariosBase().CreateServer())
|
||||
using (var basketServer = new BasketScenariosBase().CreateServer())
|
||||
{
|
||||
using var orderServer = new OrderingScenariosBase().CreateServer();
|
||||
using var basketServer = new BasketScenariosBase().CreateServer();
|
||||
// Expected data
|
||||
var cityExpected = $"city-{Guid.NewGuid()}";
|
||||
var orderStatusExpected = "cancelled";
|
||||
@ -34,7 +33,6 @@ public class OrderingScenarios : OrderingScenariosBase
|
||||
// THEN check status
|
||||
Assert.Equal(orderStatusExpected, order.Status);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<Order> TryGetOrder(string orderNumber, HttpClient orderClient)
|
||||
{
|
||||
|
@ -56,8 +56,7 @@ public class WebContextSeed
|
||||
string imagePath = Path.Combine(webroot, "images");
|
||||
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
|
||||
|
||||
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
|
||||
{
|
||||
using ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read);
|
||||
foreach (ZipArchiveEntry entry in zip.Entries)
|
||||
{
|
||||
if (imageFiles.Contains(entry.Name))
|
||||
@ -75,7 +74,6 @@ public class WebContextSeed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Error(ex, "EXCEPTION ERROR: {Message}", ex.Message);
|
||||
|
@ -39,8 +39,7 @@ public class WebContextSeed
|
||||
}
|
||||
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
|
||||
|
||||
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
|
||||
{
|
||||
using ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read);
|
||||
foreach (ZipArchiveEntry entry in zip.Entries)
|
||||
{
|
||||
if (!imageFiles.Contains(entry.Name))
|
||||
@ -58,7 +57,6 @@ public class WebContextSeed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.LogError(ex, "ERROR in GetPreconfiguredImages: {Message}", ex.Message);
|
||||
|
Loading…
x
Reference in New Issue
Block a user