dotnet / aspnetcore Public
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add gRPC JSON transcoding #40242
Add gRPC JSON transcoding #40242
Conversation
f309f02
to
b3c0dab
Compare
...f/Microsoft.AspNetCore.Grpc.Microbenchmarks/Microsoft.AspNetCore.Grpc.Microbenchmarks.csproj
Outdated
Show resolved
Hide resolved
df0a1cb
to
3e5f59e
Compare
...Core.Grpc.HttpApi.IntegrationTests/Microsoft.AspNetCore.Grpc.HttpApi.IntegrationTests.csproj
Outdated
Show resolved
Hide resolved
...Core.Grpc.HttpApi.IntegrationTests/Microsoft.AspNetCore.Grpc.HttpApi.IntegrationTests.csproj
Outdated
Show resolved
Hide resolved
.../test/Microsoft.AspNetCore.Grpc.Swagger.Tests/Microsoft.AspNetCore.Grpc.Swagger.Tests.csproj
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/test/testassets/IntegrationTestsWebsite/IntegrationTestsWebsite.csproj
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/test/testassets/IntegrationTestsWebsite/IntegrationTestsWebsite.csproj
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/perf/Microsoft.AspNetCore.Grpc.Microbenchmarks/DefaultCoreConfig.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/GrpcHttpApiServiceExtensions.cs
Outdated
Show resolved
Hide resolved
...ttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Binding/HttpApiProviderSeviceBinder.cs
Outdated
Show resolved
Hide resolved
...ttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Binding/HttpApiProviderSeviceBinder.cs
Outdated
Show resolved
Hide resolved
...ttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Binding/HttpApiProviderSeviceBinder.cs
Outdated
Show resolved
Hide resolved
...ttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Binding/HttpApiProviderSeviceBinder.cs
Outdated
Show resolved
Hide resolved
...i/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Binding/ReflectionServiceInvokerResolver.cs
Outdated
Show resolved
Hide resolved
...Api/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/CallHandlers/CallHandlerDescriptorInfo.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/GrpcProtocolConstants.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/HttpApiServerCallContext.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/HttpApiServerCallContext.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/HttpContextStreamWriter.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Json/MessageConverter.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Microsoft.AspNetCore.Grpc.HttpApi.csproj
Outdated
Show resolved
Hide resolved
.../test/Microsoft.AspNetCore.Grpc.Swagger.Tests/Microsoft.AspNetCore.Grpc.Swagger.Tests.csproj
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.Swagger/Microsoft.AspNetCore.Grpc.Swagger.csproj
Outdated
Show resolved
Hide resolved
...ttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Binding/HttpApiProviderSeviceBinder.cs
Outdated
Show resolved
Hide resolved
...tpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Binding/HttpApiServiceMethodProvider.cs
Outdated
Show resolved
Hide resolved
|
||
if (serverCallContext.Status.StatusCode != StatusCode.OK) | ||
{ | ||
throw new RpcException(serverCallContext.Status); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a message that can be provided here?
<!-- Workaround lack of Linux MUSL x64 support. --> | ||
<ExcludeFromBuild | ||
Condition=" '$(TargetOsName)' == 'linux-musl' and '$(TargetArchitecture)' == 'x64' ">true</ExcludeFromBuild> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JamesNK I'm not sure of the bug here but the tooling fails to start on Linux MUSL x64.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grpc.Tools has some native components. Might not support architecture?
Do the gRPC integration tests have the same issue? They also use Grpc.Tools.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean by "gRPC integration tests". If that's InteropTests
, then no, they're fine because we don't run or build tests on Linux MUSL x64. Hit the problem here because the folder includes implementation projects and I hadn't got the exclusions in BuildAfterApp.csproj working right. (Yeah, I discovered a problem because something else was busted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put another way, I left this here as defence-in-depth and a reminder.
src/Grpc/HttpApi/src/Shared/Server/DuplexStreamingServerMethodInvoker.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Json/AnyConverter.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Json/AnyConverter.cs
Outdated
Show resolved
Hide resolved
src/Grpc/HttpApi/src/Microsoft.AspNetCore.Grpc.HttpApi/Internal/Json/FieldMaskConverter.cs
Outdated
Show resolved
Hide resolved
{ | ||
if (reader.TokenType == JsonTokenType.String) | ||
{ | ||
return long.Parse(reader.GetString()!, CultureInfo.InvariantCulture); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is support for string numbers really needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a rule in gRPC <-> JSON transcoding. 64 bits don't fit into a JavaScript's 50ish bit number. So send as a string instead.
Not a fan but need to support it.
...Microsoft.AspNetCore.Grpc.JsonTranscoding/Internal/CallHandlers/CallHandlerDescriptorInfo.cs
Outdated
Show resolved
Hide resolved
@@ -50,9 +47,10 @@ public override async Task StreamingOutputCall(StreamingOutputCallRequest reques | |||
|
|||
foreach (var responseParam in request.ResponseParameters) | |||
{ | |||
// TODO(JamesNK): Remove nullable override after Grpc.Core.Api update |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do this now after the 2.40.0 -> 2.43.0 updates in Version.props?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it requires 2.45.0
else | ||
{ | ||
// Consider setting to enable mapping to methods without HttpRule | ||
// AddMethodCore(method, method.FullName, "GET", string.Empty, string.Empty, methodDescriptor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a log when an HttpRule is not found similar to when a MethodDescriptor is not found?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's normal to have a gRPC method that you don't want a RESTful version for. They don't have a HttpRule defined on them by the user.
if (response == null) | ||
{ | ||
// This is consistent with Grpc.Core when a null value is returned | ||
throw new RpcException(new Status(StatusCode.Cancelled, "No message returned from method.")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, did we ever come to a conclusion about grpc/grpc-dotnet#1555?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. Next 1:1 with Jan I'll bring it up again.
{ | ||
if (includeExceptionDetails ?? false) | ||
{ | ||
return message + " " + CommonGrpcProtocolHelpers.ConvertToRpcExceptionMessage(exception); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's wrong with exception.ToString()
? Are we trying to avoid stack traces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
{ | ||
throw new InvalidOperationException("Expected string value for FieldMask."); | ||
} | ||
// TODO: Do we *want* to remove empty entries? Probably okay to treat "" as "no paths", but "foo,,bar"? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we didn't remove empty entries, "" would give a single path and "," would give two? I think removing empty entries probably makes sense, but I don't know the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field mask logic matches what is in the Google.Protobuf serializer. I'll add to the todo that we should follow their lead.
|
||
public override void Write(Utf8JsonWriter writer, TMessage value, JsonSerializerOptions options) | ||
{ | ||
var paths = (IList<string>)value.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove empty entries from paths
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field mask logic matches what is in the Google.Protobuf serializer. I'll add to the todo that we should follow their lead.
|
||
public IDisposable BeginScope<TState>(TState state) | ||
{ | ||
return null!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Soon we won't need this !
! dotnet/runtime#66960
@dougbu There is a project - I set |
Either works. |
1f8ef3e
to
c3174dd
Compare
Moving code from https://github.com/aspnet/AspLabs/tree/main/src/GrpcHttpApi