设置Access=Internal后无法访问自动生成的Protobuf类
场景描述
我要做一个NuGet包,对外提供封装后的gRPC客户端(由my.proto定义),不想暴露自动生成的gRPC客户端类,所以在.csproj中做了如下配置:
<ItemGroup> <Protobuf Include="Grpc/Protos/my.proto" GrpcServices="Client" Access="Internal" /> </ItemGroup>
proto文件的命名空间为MyProject.Grpc.Protos,生成的服务和消息类存放在obj/Debug/net6.0/Grpc/Protos/目录下,类的访问修饰符确实是internal,符合预期。但项目内尝试引用自动生成的客户端时:
MyProject.Grpc.Protos.Search.SearchClient _client;
却报错:
Cannot resolve symbol 'Protos'
按道理项目内的internal类应该能被访问,这是哪里出了问题?
原因分析
问题核心在于**Access="Internal"不仅修改了类的访问修饰符,还会让生成代码的命名空间被隐式标记为internal,且Grpc.Tools默认不会将这些internal的生成代码主动纳入项目的编译可见范围**。
当设置Access="Public"时,工具会自动让编译器识别obj目录下的生成代码,完整命名空间可以正常解析;但切换到Internal模式后,编译器默认不会主动扫描这些internal的生成代码,导致无法通过完整命名空间找到对应的类型。
解决方案
1. 手动将生成代码纳入编译范围
在.csproj中添加编译项,让编译器明确包含生成的代码文件:
<ItemGroup> <!-- 适配所有配置和目标框架的路径 --> <Compile Include="obj/$(Configuration)/$(TargetFramework)/Grpc/Protos/**/*.cs" /> </ItemGroup>
这样编译器会主动扫描指定目录下的生成代码,就能正常识别internal命名空间下的类型。
2. 使用using指令简化引用
在自定义封装类的代码文件顶部添加命名空间引用:
using MyProject.Grpc.Protos;
之后直接用短命名引用客户端类:
Search.SearchClient _client;
这种方式能绕过编译器对完整命名空间解析的限制,因为using指令会直接导入目标命名空间,即使它是internal的。
3. 更新Grpc.Tools版本
部分旧版本的Grpc.Tools对Access="Internal"的实现存在bug,导致生成代码的可见性异常。尝试将Grpc.Tools更新到最新稳定版本:
<PackageReference Include="Grpc.Tools" Version="2.59.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference>
内容的提问来源于stack exchange,提问作者mnj

