All checks were successful
Publish NuGets / build (release) Successful in 37s
When AddGrpcFromConfiguration method is not found via reflection, logs detailed diagnostics to help identify the root cause: - Entry assembly name and total type count - All Grpc-related types with their IsClass/IsSealed/IsPublic flags - Whether the target method exists on each type - ReflectionTypeLoadException details if type loading fails Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
137 lines
4.8 KiB
C#
137 lines
4.8 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Svrnty.CQRS.Configuration;
|
|
|
|
namespace Svrnty.CQRS.Grpc;
|
|
|
|
/// <summary>
|
|
/// Extension methods for CqrsBuilder to add gRPC support
|
|
/// </summary>
|
|
public static class CqrsBuilderExtensions
|
|
{
|
|
/// <summary>
|
|
/// Adds gRPC support to the CQRS pipeline
|
|
/// </summary>
|
|
/// <param name="builder">The CQRS builder</param>
|
|
/// <param name="configure">Optional configuration for gRPC endpoints</param>
|
|
/// <returns>The CQRS builder for method chaining</returns>
|
|
public static CqrsBuilder AddGrpc(this CqrsBuilder builder, Action<GrpcCqrsOptions>? configure = null)
|
|
{
|
|
var options = new GrpcCqrsOptions();
|
|
configure?.Invoke(options);
|
|
builder.Configuration.SetConfiguration(options);
|
|
|
|
// 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 });
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Warning: AddGrpcFromConfiguration not found. gRPC services were not registered.");
|
|
Console.WriteLine("Make sure your project has source generators enabled and references Svrnty.CQRS.Grpc.Generators.");
|
|
DiagnoseGeneratedCode();
|
|
}
|
|
|
|
// 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 void DiagnoseGeneratedCode()
|
|
{
|
|
var entryAsm = Assembly.GetEntryAssembly();
|
|
if (entryAsm == null)
|
|
{
|
|
Console.WriteLine("Diagnostic: Entry assembly is null");
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine($"Diagnostic: Entry assembly = {entryAsm.GetName().Name}");
|
|
|
|
try
|
|
{
|
|
var allTypes = entryAsm.GetTypes();
|
|
Console.WriteLine($"Diagnostic: Total types in entry assembly = {allTypes.Length}");
|
|
|
|
var grpcTypes = allTypes
|
|
.Where(t => t.FullName?.Contains("Grpc") == true)
|
|
.ToList();
|
|
|
|
if (grpcTypes.Any())
|
|
{
|
|
Console.WriteLine("Diagnostic: Found Grpc-related types:");
|
|
foreach (var t in grpcTypes)
|
|
{
|
|
Console.WriteLine($" - {t.FullName} (IsClass={t.IsClass}, IsSealed={t.IsSealed}, IsPublic={t.IsPublic})");
|
|
|
|
// Check for our target method
|
|
var method = t.GetMethod("AddGrpcFromConfiguration", BindingFlags.Static | BindingFlags.Public);
|
|
if (method != null)
|
|
Console.WriteLine($" -> HAS AddGrpcFromConfiguration method!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Diagnostic: No Grpc-related types found. Source generator did NOT run.");
|
|
}
|
|
}
|
|
catch (ReflectionTypeLoadException ex)
|
|
{
|
|
Console.WriteLine($"Diagnostic: ReflectionTypeLoadException - {ex.Message}");
|
|
foreach (var le in ex.LoaderExceptions)
|
|
{
|
|
if (le != null)
|
|
Console.WriteLine($" LoaderException: {le.Message}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Diagnostic: Exception - {ex.GetType().Name}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private static MethodInfo? FindExtensionMethod(string methodName, Type parameterType)
|
|
{
|
|
// 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[] { parameterType },
|
|
null);
|
|
|
|
if (method != null)
|
|
return method;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Skip assemblies that can't be inspected
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|