What version of protobuf and what language are you using?
Version: master
Language: C#
What operating system (Linux, Windows, ...) and version?
Windows 10.
What runtime / compiler are you using (e.g., python version or gcc version)
protoc from 3.10.1 on Windows
What did you do?
Proto file test.proto:
syntax = "proto3";
import "extensions.proto";
message TestMessage {}
Proto file extensions.proto:
syntax = "proto3";
import "google/protobuf/descriptor.proto";
extend google.protobuf.MethodOptions {
string method_ext = 1234567;
}
Generate code:
protoc.exe -I. -Ipath/to/tools test.proto extensions.proto --csharp_out=.
C# code:
using System;
class Program
{
static void Main(string[] args)
{
var descriptor = TestMessage.Descriptor;
Console.WriteLine(descriptor);
}
}
What did you expect to see
The descriptor.
What did you see instead?
The following exception - full paths removed for simplicity.
Unhandled exception. System.TypeInitializationException: The type initializer for 'TestReflection' threw an exception.
---> System.ArgumentNullException: Value cannot be null. (Parameter 'extension')
at Google.Protobuf.ProtoPreconditions.CheckNotNull[T](T value, String name) in ProtoPreconditions.cs:line 57
at Google.Protobuf.ExtensionRegistry.Add(Extension extension) in ExtensionRegistry.cs:line 80
at Google.Protobuf.ExtensionRegistry.AddRange(IEnumerable`1 extensions) in ExtensionRegistry.cs:line 94
at Google.Protobuf.Reflection.FileDescriptor.AddAllExtensions(FileDescriptor[] dependencies, GeneratedClrTypeInfo generatedInfo, ExtensionRegistry registry) in FileDescriptor.cs:line 447
at Google.Protobuf.Reflection.FileDescriptor.FromGeneratedCode(Byte[] descriptorData, FileDescriptor[] dependencies, GeneratedClrTypeInfo generatedCodeInfo) in FileDescriptor.cs:line 422
at TestReflection..cctor() in Test.cs:line 27
--- End of inner exception stack trace ---
at TestReflection.get_Descriptor() in Test.cs:line 18
at TestMessage.get_Descriptor() in Test.cs:line 45
at Program.Main(String[] args) in Program.cs:line 7
Okay, the problem is that ExtensionsReflection.Descriptor.Extensions.UnorderedExtensions[0] is a FieldDescriptor (method_ext) but it has a null Extension property. Looking into why that is.
I've regenerated with the HEAD generator, and the problem goes away. So this is mostly a case of working out what to do with old generated code. We should probably just ignore extensions with an Extension property of null.
@jskeet I have the same problem, how to fix this?
I'm using dotnet core 3.0
[16:46:34 ERR] Error when executing service method 'GetUser'.
System.ArgumentNullException: Value cannot be null. (Parameter 'value')
at Google.Protobuf.ProtoPreconditions.CheckNotNull[T](T value, String name)
at MultiNetworkServices.WebApi.Services.UserReplay.set_Phone(String value) in /app/MultiNetworkServices.WebApi/obj/Release/netcoreapp3.0/UserInformation.cs:line 243
at MultiNetworkServices.WebApi.Services.UserInformationService.GetUser(UserRequest request, ServerCallContext context) in /app/MultiNetworkServices.WebApi/Services/UserInformationService.cs:line 32
at Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler`3.HandleCallAsyncCore(HttpContext httpContext, HttpContextServerCallContext serverCallContext)
at Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler`3.HandleCallAsyncCore(HttpContext httpContext, HttpContextServerCallContext serverCallContext)
at Grpc.AspNetCore.Server.Internal.CallHandlers.ServerCallHandlerBase`3.<HandleCallAsync>g__AwaitHandleCall|17_0(HttpContextServerCallContext serverCallContext, Method`2 method, Task handleCall)
[16:46:34 INF] Executed endpoint 'gRPC - /User.UserInformation/GetUser'
[16:46:34 INF] HTTP POST /User.UserInformation/GetUser responded 200 in 21.0825 ms
[16:46:34 INF] Request finished in 21.392400000000002ms 200 application/grpc
@AlanBurlison: I don't believe that's the same problem. It looks like you're trying to set the Phone property to a null value when it doesn't support that.
@jskeet it's null from database, the .proto file have a:
proto
message UserReplay {
string name = 1;
string email = 2;
string phone = 3;
}
@alexsandro-xpt: Right, that's an app issue then. You need to decide what you want to do with a null value, given that it can't be represented directly in your proto. That's not at all what this issue is about, I'm afraid.
@jskeet Are you told me the C# gRPC can't work with null properts message and then I should decide like that?
````csharp
var userReplay = new UserReplay();
if (!string.IsNullOrWhiteSpace(bridge.UserAccount.Data?.Name))
{
userReplay.Name = bridge.UserAccount.Data.Name;
}
if (!string.IsNullOrWhiteSpace(bridge.UserAccount.Data?.Email))
{
userReplay.Email = bridge.UserAccount.Data.Email;
}
if (!string.IsNullOrWhiteSpace(bridge.UserAccount.Data?.Phone))
{
userReplay.Phone = bridge.UserAccount.Data.Phone;
}
return userReplay;
````
I can't do that?
csharp
return new UserReplay
{
Name = bridge.UserAccount.Data?.Name,
Email = bridge.UserAccount.Data?.Email,
Phone = bridge.UserAccount.Data?.Phone
};
@ObsidianMinor
@alexsandro-xpt: This isn't a gRPC restriction, it's a protobuf restriction - and a natural one that comes from protobuf treating an unset string field as an empty string.
If you need to tell the difference between null and empty, use the StringValue message. But if you're happy enough using empty strings, you don't need long-winded code - just use the null coalescing ?? operator:
csharp
return new UserReplay
{
Name = bridge.UserAccount.Data?.Name ?? "",
Email = bridge.UserAccount.Data?.Email ?? "",
Phone = bridge.UserAccount.Data?.Phone ?? ""
};
Again, all of this is entirely separate from the topic of this issue, which is to do with fetching descriptors. I suggest if you have further questions about null handling in protobuf, you ask on Stack Overflow.
Most helpful comment
@alexsandro-xpt: This isn't a gRPC restriction, it's a protobuf restriction - and a natural one that comes from protobuf treating an unset string field as an empty string.
If you need to tell the difference between null and empty, use the
StringValuemessage. But if you're happy enough using empty strings, you don't need long-winded code - just use the null coalescing ?? operator:Again, all of this is entirely separate from the topic of this issue, which is to do with fetching descriptors. I suggest if you have further questions about null handling in protobuf, you ask on Stack Overflow.