仅Release模式下gRPC服务反射映射报错问题求助
问题描述
在Program.cs中实现反射扫描并自动映射gRPC服务的逻辑后,Debug模式运行正常,但Release模式抛出参数异常,提示泛型参数不符合约束。
反射映射代码
ScanAndMapGrpcServices(app); static void ScanAndMapGrpcServices(WebApplication app) { var currentAssembly = Assembly.GetExecutingAssembly(); var allTypes = currentAssembly.GetTypes().Concat( currentAssembly .GetReferencedAssemblies() .SelectMany(assemblyName => Assembly.Load(assemblyName).GetTypes())) .Where(type => type.Namespace == "<my namespace>" && !type.IsInterface && !type.IsAbstract); Console.WriteLine(allTypes.Count()); foreach (var type in allTypes) { var method = typeof(GrpcEndpointRouteBuilderExtensions).GetMethod("MapGrpcService")?.MakeGenericMethod([type]); object? invokedBuilder = method?.Invoke(app, [app]); if (invokedBuilder is GrpcServiceEndpointConventionBuilder builder) { _ = builder.RequireCors(); } } }
报错信息
System.ArgumentException: 'GenericArguments[0], 'BlazorSchool.BLServer.Services.ReadTutorialService+<RequestTreeData>d__2', on 'Microsoft.AspNetCore.Builder.GrpcServiceEndpointConventionBuilder MapGrpcService[TService](Microsoft.AspNetCore.Routing.IEndpointRouteBuilder)' violates the constraint of type 'TService'.'
涉事gRPC服务代码
public class ReadTutorialService(MyContext myContext, IConfiguration configuration) : ReadTutorialPageData.ReadTutorialPageDataBase { public override async Task<TreeDataResponse> RequestTreeData(TreeDataRequest request, ServerCallContext context) { // 业务逻辑实现 } }
排查线索
Debug和Release模式下,allTypes.Count()返回值均为22,排除程序集裁剪导致类型缺失的可能。
问题原因
报错中的ReadTutorialService+<RequestTreeData>d__2是编译器为异步方法RequestTreeData自动生成的状态机嵌套类,属于编译阶段创建的辅助类型,并非用户定义的gRPC服务类。
在Release模式下,编译器对这类状态机类的命名空间处理与Debug模式不同:Debug模式下状态机类的命名空间不会匹配用户指定的命名空间,而Release模式下它会继承外层类的命名空间,导致被你的过滤条件type.Namespace == "<my namespace>"选中。
而MapGrpcService<TService>要求TService必须继承自gRPC自动生成的服务基类(如示例中的ReadTutorialPageDataBase),但状态机类并不满足这一约束,因此抛出参数异常。
解决方案
修改反射过滤条件,排除编译器自动生成的类型,以下是几种可行的优化方向:
方案1:排除嵌套类+编译器生成类型
直接过滤掉嵌套类和带编译器生成标记的类型:
.Where(type => type.Namespace == "<my namespace>" && !type.IsInterface && !type.IsAbstract && !type.IsNested && !Attribute.IsDefined(type, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)));
方案2:精准匹配gRPC服务基类
通过判断类型是否继承自gRPC生成的服务基类(通常命名以Base结尾)来过滤:
.Where(type => type.Namespace == "<my namespace>" && !type.IsInterface && !type.IsAbstract && type.BaseType != null && type.BaseType.Name.EndsWith("Base"));
内容的提问来源于stack exchange,提问作者Red Wei
相关产品推荐
相关产品推荐

