You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 23:29:57