Skip to content
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

Issue when using GrpcClient with HttpClientFactory on .NET 6 #1478

Closed
thangchung opened this issue Nov 10, 2021 · 5 comments · Fixed by dotnet/AspNetCore.Docs#23857
Closed
Labels
bug Something isn't working

Comments

@thangchung
Copy link

What version of gRPC and what language are you using?

<PackageReference Include="Grpc.AspNetCore" Version="2.40.0" />

What operating system (Linux, Windows,...) and version?

Windows 11

What runtime / compiler are you using (e.g. .NET Core SDK version dotnet --info)

.NET 6.0.100

What did you do?

I just followed the guidance from MS docs to create the client and server using gRPC. The server part runs fine without errors.
But the client whenever I add the code below

builder.Services
    .AddGrpcClient<Auditor.AuditorClient>("Auditor", o =>
    {
        o.Address = new Uri("https://localhost:5006");
    })
    .ConfigureHttpClient(client => /* <=== This will cause the exception */
    {
    })
    .EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);

What did you expect to see?

I expect the client part should run fine with the ConfigureHttpClient function in-place

What did you see instead?

The exception

System.InvalidOperationException: The ConfigureHttpClient method is not supported when creating gRPC clients. Unable to create client with name 'Auditor'.
   at Grpc.Net.ClientFactory.Internal.DefaultGrpcClientFactory.CreateClient[TClient](String name)
   at SalePayment.StateMachines.OrderStateMachine..ctor(GrpcClientFactory grpcClientFactory) in D:\github\northwind-dotnet\SalePayment\StateMachines\OrderStateMachine.cs:line 12
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at MassTransit.ExtensionsDependencyInjectionIntegration.Registration.DependencyInjectionContainerRegistrar.<>c__5`2.<MassTransit.Registration.IContainerRegistrar.RegisterSagaStateMachine>b__5_0(IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
@thangchung thangchung added the bug Something isn't working label Nov 10, 2021
@adityamandaleeka
Copy link

@thangchung Can you point to which doc you're using?

The error you're seeing is expected because GrpcClient doesn't use HttpClient (and therefore you can't use ConfigureHttpClient).

If you can share what you're trying to do with the ConfigureHttpClient, we might be able to help provide an alternate way to accomplish that.

@thangchung
Copy link
Author

@adityamandaleeka I followed the guidance to add the support HTTP/3 for gPRC, the server part is okay, I can run it. But the gRPC client whenever I configure with ConfigureHttpClient to set

httpClient.DefaultRequestVersion = HttpVersion.Version30;
httpClient.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;

Then it did not allow me to do that, always throw the exception above. It's strange.

The blog for setting it up at https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/#grpc-with-http-3

@JamesNK
Copy link
Member

JamesNK commented Nov 11, 2021

You can set those properties using a DelegatingHandler. I wrote some docs here: #1478

Instead of configuring the channel to use the delegating handler, you'll configure client factory to use it.

@thangchung
Copy link
Author

thangchung commented Nov 11, 2021

Hi @JamesNK and @adityamandaleeka ,

I would like to confirm that after following the docs that you wrote, then it works. But with some of the changes so that I put it here for someone who has got the issue just like me

gRPC Server

We have set up the server with some lines of codes as

using System.Net;
using AuditCenter.Services;
using Microsoft.AspNetCore.Server.Kestrel.Core;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();
builder.WebHost.ConfigureKestrel((context, options) =>
{
    options.Listen(IPAddress.Any, 5001, listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http3;
        listenOptions.UseHttps();
    });
});

var app = builder.Build();

app.UseHttpLogging();

// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>();
app.MapGrpcService<AuditService>();
app.MapGet("/",
    () =>
        "AuditService is ready to serve you!!! What do you want from me?");

app.Run();

And after the run, it should run at https://localhost:5001. And we might need to trust the server using dotnet dev-certs https --trust

gRPC Client

The client should follow some steps:

  • Step 1: Open up the client.csproj, and add
<ItemGroup>
    <RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />
</ItemGroup>

The docs for it can be found at https://docs.microsoft.com/en-us/dotnet/core/extensions/httpclient-http3#using-httpclient

  • Step 2: Adding some code for configuration like you mentioned
public class Http3Handler : DelegatingHandler
{
    public Http3Handler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;
        return base.SendAsync(request, cancellationToken);
    }
}

And configure for gRPC Client

builder.Services
    .AddGrpcClient<Auditor.AuditorClient>("Auditor", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(options =>
    {
        options.HttpHandler = new Http3Handler(new HttpClientHandler());
    })
    .EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);

And now we can run it perfectly.

Thank you again for the guidance and shed the light on it @JamesNK 👍

@JamesNK
Copy link
Member

JamesNK commented Nov 11, 2021

Great.

Thanks for the feedback. I've improved the doc some more: dotnet/AspNetCore.Docs#23857

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants