From 03b7e089f4f82c903202e62a324afff9bb3761e0 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Thu, 3 Sep 2020 15:45:39 +1200 Subject: [PATCH] Protobuf scalar default values and ByteString detail --- aspnetcore/grpc/protobuf.md | 47 +++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/aspnetcore/grpc/protobuf.md b/aspnetcore/grpc/protobuf.md index c0a081b90893..c48da6f36f67 100644 --- a/aspnetcore/grpc/protobuf.md +++ b/aspnetcore/grpc/protobuf.md @@ -69,6 +69,10 @@ Protobuf supports a range of native scalar value types. The following table list | `string` | `string` | | `bytes` | `ByteString` | +Scalar values always have a default value and can't be set to `null`. This constraint includes `string` and `ByteString` which are C# classes. `string` defaults to an empty string value and `ByteString` defaults to an empty bytes value. Attempting to set them to `null` throws an error. + +[Nullable wrapper types](#nullable-types) can be used to support null values. + ### Dates and times The native scalar types don't provide for date and time values, equivalent to .NET's , , and . These types can be specified by using some of Protobuf's *Well-Known Types* extensions. These extensions provide code generation and runtime support for complex field types across the supported platforms. @@ -129,19 +133,42 @@ message Person { } ``` -Protobuf uses .NET nullable types, for example, `int?`, for the generated message property. +`wrappers.proto` types aren't exposed in generated properties. Protobuf automatically maps them to appropriate .NET nullable types in C# messages. For example, a `google.protobuf.Int32Value` field generates an `int?` property. Reference type properties like `string` and `ByteString` are unchanged except `null` can be assigned to them without error. The following table shows the complete list of wrapper types with their equivalent C# type: -| C# type | Well-Known Type wrapper | -| --------- | ----------------------------- | -| `bool?` | `google.protobuf.BoolValue` | -| `double?` | `google.protobuf.DoubleValue` | -| `float?` | `google.protobuf.FloatValue` | -| `int?` | `google.protobuf.Int32Value` | -| `long?` | `google.protobuf.Int64Value` | -| `uint?` | `google.protobuf.UInt32Value` | -| `ulong?` | `google.protobuf.UInt64Value` | +| C# type | Well-Known Type wrapper | +| ------------ | ----------------------------- | +| `bool?` | `google.protobuf.BoolValue` | +| `double?` | `google.protobuf.DoubleValue` | +| `float?` | `google.protobuf.FloatValue` | +| `int?` | `google.protobuf.Int32Value` | +| `long?` | `google.protobuf.Int64Value` | +| `uint?` | `google.protobuf.UInt32Value` | +| `ulong?` | `google.protobuf.UInt64Value` | +| `string` | `google.protobuf.StringValue` | +| `ByteString` | `google.protobuf.BytesValue` | + +### Bytes + +Binary payloads are supported in Protobuf with the `bytes` scalar value type. A generated property in C# uses `ByteString` as the property type. + +Use `ByteString.CopyFrom(byte[] data)` to create a new instance from a byte array: + +```csharp +var data = await File.ReadAllBytesAsync(path); + +var payload = new PayloadResponse(); +payload.Data = ByteString.CopyFrom(data); +``` + +`ByteString` data is accessed directly using `ByteString.Span` or `ByteString.Memory`. Or call `ByteString.ToByteArray()` to convert an instance back into a byte array: + +```csharp +var payload = await client.GetPayload(new PayloadRequest()); + +await File.WriteAllBytesAsync(path, payload.Data.ToByteArray()); +``` ### Decimals