checkpoint
This commit is contained in:
parent
facc8d7851
commit
e19fad2baa
@ -24,8 +24,8 @@ public static class CqrsBuilderExtensions
|
||||
configure?.Invoke(options);
|
||||
builder.Configuration.SetConfiguration(options);
|
||||
|
||||
// Try to find and call the generated AddGrpcFromConfiguration method
|
||||
var addGrpcMethod = FindExtensionMethod("AddGrpcFromConfiguration");
|
||||
// Try to find and call the generated AddGrpcFromConfiguration method for service registration
|
||||
var addGrpcMethod = FindExtensionMethod("AddGrpcFromConfiguration", typeof(IServiceCollection));
|
||||
if (addGrpcMethod != null)
|
||||
{
|
||||
addGrpcMethod.Invoke(null, new object[] { builder.Services });
|
||||
@ -36,10 +36,21 @@ public static class CqrsBuilderExtensions
|
||||
Console.WriteLine("Make sure your project has source generators enabled and references Svrnty.CQRS.Grpc.Generators.");
|
||||
}
|
||||
|
||||
// Register mapping callback for automatic endpoint mapping
|
||||
builder.Configuration.AddMappingCallback(app =>
|
||||
{
|
||||
// Find the generated MapGrpcFromConfiguration method
|
||||
var mapGrpcMethod = FindExtensionMethod("MapGrpcFromConfiguration", typeof(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder));
|
||||
if (mapGrpcMethod != null)
|
||||
{
|
||||
mapGrpcMethod.Invoke(null, new object[] { app });
|
||||
}
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static MethodInfo? FindExtensionMethod(string methodName)
|
||||
private static MethodInfo? FindExtensionMethod(string methodName, Type parameterType)
|
||||
{
|
||||
// Search through all loaded assemblies for the extension method
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
@ -54,7 +65,7 @@ public static class CqrsBuilderExtensions
|
||||
var method = type.GetMethod(methodName,
|
||||
BindingFlags.Static | BindingFlags.Public,
|
||||
null,
|
||||
new[] { typeof(IServiceCollection) },
|
||||
new[] { parameterType },
|
||||
null);
|
||||
|
||||
if (method != null)
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Svrnty.CQRS.Configuration;
|
||||
|
||||
namespace Svrnty.CQRS.MinimalApi;
|
||||
@ -20,6 +23,71 @@ public static class CqrsBuilderExtensions
|
||||
var options = new MinimalApiCqrsOptions();
|
||||
configure?.Invoke(options);
|
||||
builder.Configuration.SetConfiguration(options);
|
||||
|
||||
// Register mapping callback for automatic endpoint mapping
|
||||
builder.Configuration.AddMappingCallback(app =>
|
||||
{
|
||||
if (app is not WebApplication webApp)
|
||||
return;
|
||||
|
||||
var config = webApp.Services.GetService(typeof(CqrsConfiguration)) as CqrsConfiguration;
|
||||
var minimalApiOptions = config?.GetConfiguration<MinimalApiCqrsOptions>();
|
||||
|
||||
if (minimalApiOptions == null)
|
||||
return;
|
||||
|
||||
// Map commands if enabled
|
||||
if (minimalApiOptions.MapCommands)
|
||||
{
|
||||
webApp.MapSvrntyCommands(minimalApiOptions.CommandRoutePrefix);
|
||||
}
|
||||
|
||||
// Map queries if enabled
|
||||
if (minimalApiOptions.MapQueries)
|
||||
{
|
||||
webApp.MapSvrntyQueries(minimalApiOptions.QueryRoutePrefix);
|
||||
}
|
||||
|
||||
// Map dynamic queries if enabled (automatically included)
|
||||
if (minimalApiOptions.MapDynamicQueries)
|
||||
{
|
||||
// Try to find the DynamicQuery.MinimalApi assembly and call MapSvrntyDynamicQueries
|
||||
try
|
||||
{
|
||||
// Force load the assembly by looking for a known type from it
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var dynamicQueryAssembly = assemblies.FirstOrDefault(a => a.GetName().Name == "Svrnty.CQRS.DynamicQuery.MinimalApi");
|
||||
|
||||
if (dynamicQueryAssembly == null)
|
||||
{
|
||||
// Try to load it by finding the type
|
||||
var extensionType = Type.GetType("Svrnty.CQRS.DynamicQuery.MinimalApi.EndpointRouteBuilderExtensions, Svrnty.CQRS.DynamicQuery.MinimalApi");
|
||||
if (extensionType != null)
|
||||
{
|
||||
dynamicQueryAssembly = extensionType.Assembly;
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamicQueryAssembly != null)
|
||||
{
|
||||
var extensionType = dynamicQueryAssembly.GetType("Svrnty.CQRS.DynamicQuery.MinimalApi.EndpointRouteBuilderExtensions");
|
||||
if (extensionType != null)
|
||||
{
|
||||
var mapMethod = extensionType.GetMethod("MapSvrntyDynamicQueries", BindingFlags.Public | BindingFlags.Static);
|
||||
if (mapMethod != null)
|
||||
{
|
||||
mapMethod.Invoke(null, new object[] { webApp, minimalApiOptions.DynamicQueryRoutePrefix });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Warning: Could not map dynamic queries: {ex.Message}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,101 +1,21 @@
|
||||
#nullable enable
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Svrnty.CQRS.Configuration;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Svrnty.CQRS.MinimalApi;
|
||||
|
||||
public static class WebApplicationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps Svrnty CQRS endpoints based on configuration (supports both gRPC and MinimalApi)
|
||||
/// Maps all configured CQRS endpoints (gRPC, MinimalApi, and Dynamic Queries).
|
||||
/// This method is framework-agnostic and executes mapping callbacks registered by extension packages.
|
||||
/// </summary>
|
||||
public static WebApplication UseSvrntyCqrs(this WebApplication app)
|
||||
{
|
||||
var config = app.Services.GetService<CqrsConfiguration>();
|
||||
|
||||
// Handle gRPC configuration if available
|
||||
// Note: GrpcCqrsOptions type is from Svrnty.CQRS.Grpc package
|
||||
var grpcOptionsType = Type.GetType("Svrnty.CQRS.Grpc.GrpcCqrsOptions, Svrnty.CQRS.Grpc");
|
||||
if (grpcOptionsType != null && config != null)
|
||||
{
|
||||
var getConfigMethod = typeof(CqrsConfiguration).GetMethod("GetConfiguration")!.MakeGenericMethod(grpcOptionsType);
|
||||
var grpcOptions = getConfigMethod.Invoke(config, null);
|
||||
|
||||
if (grpcOptions != null)
|
||||
{
|
||||
// Try to find and call MapGrpcFromConfiguration extension method via reflection
|
||||
// This is generated by the source generator in consumer projects
|
||||
var grpcMethod = FindExtensionMethod("MapGrpcFromConfiguration");
|
||||
if (grpcMethod != null)
|
||||
{
|
||||
grpcMethod.Invoke(null, new object[] { app });
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: MapGrpcFromConfiguration not found. gRPC endpoints were not mapped.");
|
||||
Console.WriteLine("Make sure your project references Svrnty.CQRS.Grpc and has source generators enabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle MinimalApi configuration if available
|
||||
var minimalApiOptions = config?.GetConfiguration<MinimalApiCqrsOptions>();
|
||||
if (minimalApiOptions != null)
|
||||
{
|
||||
if (minimalApiOptions.MapCommands)
|
||||
{
|
||||
app.MapSvrntyCommands(minimalApiOptions.CommandRoutePrefix);
|
||||
}
|
||||
|
||||
if (minimalApiOptions.MapQueries)
|
||||
{
|
||||
app.MapSvrntyQueries(minimalApiOptions.QueryRoutePrefix);
|
||||
}
|
||||
|
||||
// TODO: Add dynamic query mapping when available
|
||||
// if (minimalApiOptions.MapDynamicQueries)
|
||||
// {
|
||||
// app.MapSvrntyDynamicQueries(minimalApiOptions.DynamicQueryRoutePrefix);
|
||||
// }
|
||||
}
|
||||
|
||||
var config = app.Services.GetRequiredService<CqrsConfiguration>();
|
||||
config.ExecuteMappingCallbacks(app);
|
||||
return app;
|
||||
}
|
||||
|
||||
private static MethodInfo? FindExtensionMethod(string methodName)
|
||||
{
|
||||
// Search through all loaded assemblies for the extension method
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
try
|
||||
{
|
||||
var types = assembly.GetTypes()
|
||||
.Where(t => t.IsClass && t.IsSealed && !t.IsGenericType && t.IsPublic);
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var method = type.GetMethod(methodName,
|
||||
BindingFlags.Static | BindingFlags.Public,
|
||||
null,
|
||||
new[] { typeof(IEndpointRouteBuilder) },
|
||||
null);
|
||||
|
||||
if (method != null)
|
||||
return method;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Skip assemblies that can't be inspected
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ namespace Svrnty.CQRS.Configuration;
|
||||
public class CqrsConfiguration
|
||||
{
|
||||
private readonly Dictionary<Type, object> _configurations = new();
|
||||
private readonly List<Action<object>> _mappingCallbacks = new();
|
||||
|
||||
/// <summary>
|
||||
/// Sets a configuration object for a specific type
|
||||
@ -35,4 +36,27 @@ public class CqrsConfiguration
|
||||
{
|
||||
return _configurations.ContainsKey(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a callback to be executed during endpoint mapping.
|
||||
/// Used by extension packages to register their endpoint mapping logic.
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback that accepts an application builder (typically WebApplication)</param>
|
||||
public void AddMappingCallback(Action<object> callback)
|
||||
{
|
||||
_mappingCallbacks.Add(callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes all registered mapping callbacks.
|
||||
/// Called by UseSvrntyCqrs() to map endpoints from all configured packages.
|
||||
/// </summary>
|
||||
/// <param name="app">The application builder (typically WebApplication)</param>
|
||||
public void ExecuteMappingCallbacks(object app)
|
||||
{
|
||||
foreach (var callback in _mappingCallbacks)
|
||||
{
|
||||
callback(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ using Svrnty.CQRS.Grpc;
|
||||
using Svrnty.Sample;
|
||||
using Svrnty.CQRS.MinimalApi;
|
||||
using Svrnty.CQRS.DynamicQuery;
|
||||
using Svrnty.CQRS.DynamicQuery.MinimalApi;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@ -39,7 +38,9 @@ builder.Services.AddSvrntyCqrs(cqrs =>
|
||||
});
|
||||
|
||||
// Enable MinimalApi endpoints
|
||||
cqrs.AddMinimalApi();
|
||||
cqrs.AddMinimalApi(configure =>
|
||||
{
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
@ -47,12 +48,9 @@ builder.Services.AddSwaggerGen();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Map all configured CQRS endpoints (gRPC and MinimalApi)
|
||||
// Map all configured CQRS endpoints (gRPC, MinimalApi, and Dynamic Queries)
|
||||
app.UseSvrntyCqrs();
|
||||
|
||||
// Map dynamic queries manually for now
|
||||
app.MapSvrntyDynamicQueries();
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user