grpc-dotnet
grpc-dotnet copied to clipboard
troubles using grpc-web client from .net framework
im running this on Win10 21H2 (Build 19044.1415) and trying to make a call from the .net framework to my .net 6 greeter service
Server
using web.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddGrpc();
var app = builder.Build();
app.UseGrpcWeb();
// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client.");
app.Run();
client project
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net48;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.19.1" />
<PackageReference Include="Grpc.Net.Client" Version="2.41.0" />
<PackageReference Include="Grpc.Net.Client.Web" Version="2.41.0" />
<PackageReference Include="Grpc.Tools" Version="2.42.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework) == 'net48'" >
<PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Client" Link="Proto\greet.proto" />
</ItemGroup>
</Project>
client code
using Grpc.Net.Client;
using Greet;
using Grpc.Net.Client.Web;
var version =
#if NET48
"net48";
#else
"net6.0";
#endif
var handler = new GrpcWebHandler(new HttpClientHandler());
var options = new GrpcChannelOptions {HttpHandler = handler};
var channel = GrpcChannel.ForAddress("http://localhost:5001", options);
var client = new Greeter.GreeterClient(channel);
var result = await client.SayHelloAsync(new HelloRequest { Name = version });
Console.WriteLine(result.Message);
which works fine with net6
dotnet run --framework net6.0
Hello net6.0
but fails on .net framework 4.8
dotnet run --framework net48
Unhandled Exception: Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: An error occurred while sending the request. WebException: The server committed a protocol violation. Section=ResponseStatusLine", DebugException="System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The server committed a protocol violation. Section=ResponseStatusLine
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
...
any hint would be highly appreciated
Running into the same problem, was about to create an issue as well.
I have a repro available here , using a net48 client with a net5.0 server using a server-side streaming call, observing the same error that @Bonuspunkt reported.
Some additional notes:
- When running the client as
netcoreapp3.1, I get a different error message:
Unhandled exception. Grpc.Core.RpcException: Status(StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: An error occurred while sending the request. IOException: The response ended prematurely.", DebugException="System.Net.Http.HttpRequestException: An error occurred while sending the request.
- On the server, I get the following debug messages (same for
net48andnetcoreapp3.1clients):
dbug: Microsoft.AspNetCore.Server.Kestrel[39]
Connection id "0HMEESG5T174T" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel[1]
Connection id "0HMEESG5T174T" started.
dbug: Microsoft.AspNetCore.Server.Kestrel[29]
Connection id "0HMEESG5T174T": HTTP/2 connection error.
Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2ConnectionErrorException: HTTP/2 connection error (PROTOCOL_ERROR): Invalid HTTP/2 connection preface.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2Connection.ParsePreface(ReadOnlySequence`1& buffer, SequencePosition& consumed, SequencePosition& examined)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2Connection.TryReadPrefaceAsync()
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2Connection.ProcessRequestsAsync[TContext](IHttpApplication`1 application)
dbug: Microsoft.AspNetCore.Server.Kestrel[36]
Connection id "0HMEESG5T174T" is closed. The last processed stream ID was 0.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
Connection id "0HMEESG5T174T" received FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel[2]
Connection id "0HMEESG5T174T" stopped.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
Connection id "0HMEESG5T174T" sending FIN because: "The Socket transport's send loop completed gracefully."
@ThorstenReichert Have you tried verifying that the port number and protocol used in the client match up with the port/protocol that the gRPC service is running on?
@Bonuspunkt Can you share a repro project?
.NET Framework only supports HTTP/1.1 (unless WinHttpHandler is configured). That's fine, because gRPC-Web works over HTTP/1.1. An ASP.NET Core gRPC project is configured by default to HTTP/2 only. This is most likely your problem
You're both sending non-TLS requests (i.e. the address is http and not https). That means the .NET Framework client is sending HTTP/1.1 to a server that expects HTTP/2.
To fix this, you must either use TLS and allow HTTP/1.1 and 2 (TLS allows negotiation between the client and server of which to use) or have a separate HTTP/1.1 only http port.
I think it would be worth having troubleshooting docs for this situation.
@captainsafia https://github.com/Bonuspunkt/PoC_gRPC-Web
@JamesNK thank you, that has been the issue
https://github.com/Bonuspunkt/PoC_gRPC-Web/commit/2f1013c66a484ffb7023d03bd0f681831e909587
issue can be closed
@JamesNK indeed, changing the appsettings json from
{ "Kestrel": { "EndpointDefaults": { "Protocols": "Http2" }}}
to
{ "Kestrel": { "EndpointDefaults": { "Protocols": "Http1AndHttp2" }}}
solved the issue for me, thanks a lot!
it's useful
worked for me
Docs that discuss this: https://learn.microsoft.com/en-us/aspnet/core/grpc/grpcweb?view=aspnetcore-6.0#http-protocol