mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-05-07 14:52:09 +08:00
- Fix problem load assemblies in test cli
- Add Test pipeline to ci-cd
This commit is contained in:
parent
6a410a7b05
commit
97ab953975
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@ -21,4 +21,6 @@ jobs:
|
|||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build -c Release --no-restore
|
run: dotnet build -c Release --no-restore
|
||||||
|
- name: Test
|
||||||
|
run: dotnet test -c Release --no-restore
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,8 @@ public static class Extensions
|
|||||||
bool.TryParse(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER"), out var inContainer) &&
|
bool.TryParse(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER"), out var inContainer) &&
|
||||||
inContainer;
|
inContainer;
|
||||||
|
|
||||||
public static IServiceCollection AddCustomMassTransit(this IServiceCollection services, Assembly assembly,
|
public static IServiceCollection AddCustomMassTransit(this IServiceCollection services,
|
||||||
IWebHostEnvironment env)
|
IWebHostEnvironment env, Assembly assembly)
|
||||||
{
|
{
|
||||||
services.AddOptions<RabbitMqOptions>()
|
services.AddOptions<RabbitMqOptions>()
|
||||||
.BindConfiguration(nameof(RabbitMqOptions))
|
.BindConfiguration(nameof(RabbitMqOptions))
|
||||||
@ -29,22 +29,22 @@ public static class Extensions
|
|||||||
{
|
{
|
||||||
services.AddMassTransitTestHarness(configure =>
|
services.AddMassTransitTestHarness(configure =>
|
||||||
{
|
{
|
||||||
SetupMasstransitConfigurations(services, assembly, configure);
|
SetupMasstransitConfigurations(services, configure, assembly);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
services.AddMassTransit(configure =>
|
services.AddMassTransit(configure =>
|
||||||
{
|
{
|
||||||
SetupMasstransitConfigurations(services, assembly, configure);
|
SetupMasstransitConfigurations(services, configure, assembly);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetupMasstransitConfigurations(IServiceCollection services, Assembly assembly,
|
private static void SetupMasstransitConfigurations(IServiceCollection services,
|
||||||
IBusRegistrationConfigurator configure)
|
IBusRegistrationConfigurator configure, Assembly assembly)
|
||||||
{
|
{
|
||||||
configure.AddConsumers(assembly);
|
configure.AddConsumers(assembly);
|
||||||
|
|
||||||
@ -60,38 +60,44 @@ public static class Extensions
|
|||||||
h.Password(rabbitMqOptions?.Password);
|
h.Password(rabbitMqOptions?.Password);
|
||||||
});
|
});
|
||||||
|
|
||||||
var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
|
|
||||||
|
var integrationEventRootAssemblies = Assembly.GetAssembly(typeof(IIntegrationEvent));
|
||||||
|
|
||||||
|
var types = integrationEventRootAssemblies?.GetTypes()
|
||||||
.Where(x => x.IsAssignableTo(typeof(IIntegrationEvent))
|
.Where(x => x.IsAssignableTo(typeof(IIntegrationEvent))
|
||||||
&& !x.IsInterface
|
&& !x.IsInterface
|
||||||
&& !x.IsAbstract
|
&& !x.IsAbstract
|
||||||
&& !x.IsGenericType);
|
&& !x.IsGenericType)?.ToList();
|
||||||
|
|
||||||
foreach (var type in types)
|
if (types != null && types.Any())
|
||||||
{
|
{
|
||||||
var consumers = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
|
foreach (var type in types)
|
||||||
.Where(x => x.IsAssignableTo(typeof(IConsumer<>).MakeGenericType(type))).ToList();
|
{
|
||||||
|
var consumers = assembly?.GetTypes()
|
||||||
|
.Where(x => x.IsAssignableTo(typeof(IConsumer<>).MakeGenericType(type))).ToList();
|
||||||
|
|
||||||
if (consumers.Any())
|
if (consumers != null && consumers.Any())
|
||||||
configurator.ReceiveEndpoint(
|
configurator.ReceiveEndpoint(
|
||||||
string.IsNullOrEmpty(rabbitMqOptions.ExchangeName)
|
string.IsNullOrEmpty(rabbitMqOptions.ExchangeName)
|
||||||
? type.Name.Underscore()
|
? type.Name.Underscore()
|
||||||
: $"{rabbitMqOptions.ExchangeName}_{type.Name.Underscore()}", e =>
|
: $"{rabbitMqOptions.ExchangeName}_{type.Name.Underscore()}", e =>
|
||||||
{
|
|
||||||
e.UseConsumeFilter(typeof(ConsumeFilter<>), context); //generic filter
|
|
||||||
|
|
||||||
foreach (var consumer in consumers)
|
|
||||||
{
|
{
|
||||||
configurator.ConfigureEndpoints(context, x => x.Exclude(consumer));
|
e.UseConsumeFilter(typeof(ConsumeFilter<>), context); //generic filter
|
||||||
var methodInfo = typeof(DependencyInjectionReceiveEndpointExtensions)
|
|
||||||
.GetMethods()
|
|
||||||
.Where(x => x.GetParameters()
|
|
||||||
.Any(p => p.ParameterType == typeof(IServiceProvider)))
|
|
||||||
.FirstOrDefault(x => x.Name == "Consumer" && x.IsGenericMethod);
|
|
||||||
|
|
||||||
var generic = methodInfo?.MakeGenericMethod(consumer);
|
foreach (var consumer in consumers)
|
||||||
generic?.Invoke(e, new object[] {e, context, null});
|
{
|
||||||
}
|
configurator.ConfigureEndpoints(context, x => x.Exclude(consumer));
|
||||||
});
|
var methodInfo = typeof(DependencyInjectionReceiveEndpointExtensions)
|
||||||
|
.GetMethods()
|
||||||
|
.Where(x => x.GetParameters()
|
||||||
|
.Any(p => p.ParameterType == typeof(IServiceProvider)))
|
||||||
|
.FirstOrDefault(x => x.Name == "Consumer" && x.IsGenericMethod);
|
||||||
|
|
||||||
|
var generic = methodInfo?.MakeGenericMethod(consumer);
|
||||||
|
generic?.Invoke(e, new object[] { e, context, null });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||||
|
|
||||||
namespace BuildingBlocks.Utils;
|
namespace BuildingBlocks.Utils;
|
||||||
|
|
||||||
@ -36,4 +37,49 @@ public static class TypeProvider
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IReadOnlyList<Assembly> GetReferencedAssemblies(Assembly? rootAssembly)
|
||||||
|
{
|
||||||
|
var visited = new HashSet<string>();
|
||||||
|
var queue = new Queue<Assembly?>();
|
||||||
|
var listResult = new List<Assembly>();
|
||||||
|
|
||||||
|
var root = rootAssembly ?? Assembly.GetEntryAssembly();
|
||||||
|
queue.Enqueue(root);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var asm = queue.Dequeue();
|
||||||
|
|
||||||
|
if (asm == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
listResult.Add(asm);
|
||||||
|
|
||||||
|
foreach (var reference in asm.GetReferencedAssemblies())
|
||||||
|
{
|
||||||
|
if (!visited.Contains(reference.FullName))
|
||||||
|
{
|
||||||
|
// Load will add assembly into the application domain of the caller. loading assemblies explicitly to AppDomain, because assemblies are loaded lazily
|
||||||
|
// https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load
|
||||||
|
queue.Enqueue(Assembly.Load(reference));
|
||||||
|
visited.Add(reference.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (queue.Count > 0);
|
||||||
|
|
||||||
|
return listResult.Distinct().ToList().AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IReadOnlyList<Assembly> GetApplicationPartAssemblies(Assembly rootAssembly)
|
||||||
|
{
|
||||||
|
var rootNamespace = rootAssembly.GetName().Name!.Split('.').First();
|
||||||
|
var list = rootAssembly!.GetCustomAttributes<ApplicationPartAttribute>()
|
||||||
|
.Where(x => x.AssemblyName.StartsWith(rootNamespace, StringComparison.InvariantCulture))
|
||||||
|
.Select(name => Assembly.Load(name.AssemblyName))
|
||||||
|
.Distinct();
|
||||||
|
|
||||||
|
return list.ToList().AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using System.Reflection;
|
||||||
|
using BuildingBlocks.Utils;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Scrutor;
|
using Scrutor;
|
||||||
@ -10,10 +12,19 @@ public static class MinimalApiExtensions
|
|||||||
|
|
||||||
public static IServiceCollection AddMinimalEndpoints(
|
public static IServiceCollection AddMinimalEndpoints(
|
||||||
this WebApplicationBuilder applicationBuilder,
|
this WebApplicationBuilder applicationBuilder,
|
||||||
ServiceLifetime lifetime = ServiceLifetime.Scoped)
|
ServiceLifetime lifetime = ServiceLifetime.Scoped,
|
||||||
|
params Assembly[] assemblies)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
var scanAssemblies = assemblies.Any()
|
||||||
|
? assemblies
|
||||||
|
: TypeProvider.GetReferencedAssemblies(Assembly.GetCallingAssembly())
|
||||||
|
.Concat(TypeProvider.GetApplicationPartAssemblies(Assembly.GetCallingAssembly()))
|
||||||
|
.Distinct()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
applicationBuilder.Services.Scan(scan => scan
|
applicationBuilder.Services.Scan(scan => scan
|
||||||
.FromAssemblies(AppDomain.CurrentDomain.GetAssemblies())
|
.FromAssemblies(scanAssemblies)
|
||||||
.AddClasses(classes => classes.AssignableTo(typeof(IMinimalEndpoint)))
|
.AddClasses(classes => classes.AssignableTo(typeof(IMinimalEndpoint)))
|
||||||
.UsingRegistrationStrategy(RegistrationStrategy.Append)
|
.UsingRegistrationStrategy(RegistrationStrategy.Append)
|
||||||
.As<IMinimalEndpoint>()
|
.As<IMinimalEndpoint>()
|
||||||
|
|||||||
@ -72,7 +72,7 @@ public static class InfrastructureExtensions
|
|||||||
builder.Services.AddCustomProblemDetails();
|
builder.Services.AddCustomProblemDetails();
|
||||||
builder.Services.AddCustomMapster(typeof(BookingRoot).Assembly);
|
builder.Services.AddCustomMapster(typeof(BookingRoot).Assembly);
|
||||||
builder.Services.AddCustomHealthCheck();
|
builder.Services.AddCustomHealthCheck();
|
||||||
builder.Services.AddCustomMassTransit(typeof(BookingRoot).Assembly, env);
|
builder.Services.AddCustomMassTransit(env, typeof(BookingRoot).Assembly);
|
||||||
builder.Services.AddCustomOpenTelemetry();
|
builder.Services.AddCustomOpenTelemetry();
|
||||||
builder.Services.AddTransient<AuthHeaderHandler>();
|
builder.Services.AddTransient<AuthHeaderHandler>();
|
||||||
|
|
||||||
|
|||||||
@ -78,7 +78,7 @@ public static class InfrastructureExtensions
|
|||||||
builder.Services.AddValidatorsFromAssembly(typeof(FlightRoot).Assembly);
|
builder.Services.AddValidatorsFromAssembly(typeof(FlightRoot).Assembly);
|
||||||
builder.Services.AddCustomMapster(typeof(FlightRoot).Assembly);
|
builder.Services.AddCustomMapster(typeof(FlightRoot).Assembly);
|
||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
builder.Services.AddCustomMassTransit(typeof(FlightRoot).Assembly, env);
|
builder.Services.AddCustomMassTransit(env, typeof(FlightRoot).Assembly);
|
||||||
builder.Services.AddCustomOpenTelemetry();
|
builder.Services.AddCustomOpenTelemetry();
|
||||||
builder.Services.AddCustomHealthCheck();
|
builder.Services.AddCustomHealthCheck();
|
||||||
|
|
||||||
|
|||||||
@ -68,7 +68,7 @@ public static class InfrastructureExtensions
|
|||||||
builder.Services.AddCustomMapster(typeof(IdentityRoot).Assembly);
|
builder.Services.AddCustomMapster(typeof(IdentityRoot).Assembly);
|
||||||
builder.Services.AddCustomHealthCheck();
|
builder.Services.AddCustomHealthCheck();
|
||||||
|
|
||||||
builder.Services.AddCustomMassTransit(typeof(IdentityRoot).Assembly, env);
|
builder.Services.AddCustomMassTransit(env, typeof(IdentityRoot).Assembly);
|
||||||
builder.Services.AddCustomOpenTelemetry();
|
builder.Services.AddCustomOpenTelemetry();
|
||||||
|
|
||||||
SnowFlakIdGenerator.Configure(4);
|
SnowFlakIdGenerator.Configure(4);
|
||||||
|
|||||||
@ -73,7 +73,7 @@ public static class InfrastructureExtensions
|
|||||||
builder.Services.AddCustomMapster(typeof(PassengerRoot).Assembly);
|
builder.Services.AddCustomMapster(typeof(PassengerRoot).Assembly);
|
||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
builder.Services.AddCustomHealthCheck();
|
builder.Services.AddCustomHealthCheck();
|
||||||
builder.Services.AddCustomMassTransit(typeof(PassengerRoot).Assembly, env);
|
builder.Services.AddCustomMassTransit(env, typeof(PassengerRoot).Assembly);
|
||||||
builder.Services.AddCustomOpenTelemetry();
|
builder.Services.AddCustomOpenTelemetry();
|
||||||
builder.Services.AddGrpc(options =>
|
builder.Services.AddGrpc(options =>
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user