Issue when using GrpcClient with HttpClientFactory on .NET 6

See original GitHub issue

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)

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
JamesNKcommented, Nov 11, 2021

Great.

Thanks for the feedback. I’ve improved the doc some more: https://github.com/dotnet/AspNetCore.Docs/pull/23857

0reactions
thangchungcommented, 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 👍

Read more comments on GitHub >

github_iconTop Results From Across the Web

gRPC client factory integration in .NET
Learn how to create gRPC clients using the client factory. ... gRPC integration with HttpClientFactory offers a centralized way to create ...
Read more >
A Deep Dive into Working with gRPC in .NET 6
AspNetCore.Server.ClientFactory: This package supports the integration of HTTPClientFactory for gRPC .NET clients in ASP.NET Core applications.
Read more >
c# - is it possible to instance as singleton a http client with ...
The performance heavy task seems to be the re-creation of gRPC channels, which use the HttpClientMessageHandler type.
Read more >
ASP.NET Core 6: Here is the best way to pass a JWT in ...
NET 6 allows you to attach a delegate (which can be asynchronous) to a gRPC type client which allows you to automatically manipulate...
Read more >
Using HttpClientFactory in ASP.NET Core Applications
Let's learn how to use HttpClientFactory in .NET Core applications. Also, we will learn how to use Named and Typed client instances.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found