robcao opened a new issue, #45451: URL: https://github.com/apache/arrow/issues/45451
### Describe the enhancement requested # Request I would like the `FlightClient` to support standard integration with the `Grpc.Net.ClientFactory` library. # Background It is standard in .NET web applications to manage gRPC clients using the [Grpc.Net.ClientFactory](https://learn.microsoft.com/en-us/aspnet/core/grpc/clientfactory?view=aspnetcore-9.0), particularly when using the ASP.NET Core framework. Currently the `FlightClient` does not work out of the box with the `Grpc.Net.ClientFactory` library. This is because the `FlightClient` is a thin abstraction over the raw .NET gRPC client, and does not have all of the same constructors as the raw gRPC client. Specifically, the `Grpc.Net.ClientFactory` expects a constructor that accepts a `CallInvoker`. Steps to reproduce: Update the `Apache.Arrow.Flight.Tests` package with the following library: `dotnet add package Grpc.Net.ClientFactory`. Add the following test class, which attempts to instantiate a `FlightClient` instance using the `Grpc.Net.ClientFactory` library, and view the test fails with the following error. ```csharp using System; using Apache.Arrow.Flight.Client; using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Apache.Arrow.Flight.Tests { public class GrpcNetClientFactoryTests { [Fact] public void CanResolve_FlightClient_UsingGrpcClientFactory() { IServiceCollection services = new ServiceCollection(); services.AddGrpcClient<FlightClient>(grpc => grpc.Address = new("http://localhost:50051")) .ConfigureChannel(channel => channel.UnsafeUseInsecureChannelCallCredentials = true); IServiceProvider provider = services.BuildServiceProvider(); provider.GetRequiredService<FlightClient>(); } } } ``` ``` System.InvalidOperationException A suitable constructor for type 'Apache.Arrow.Flight.Client.FlightClient' could not be located. Ensure the type is concrete and all parameters of a public constructor are either registered as services or passed as arguments. Also ensure no extraneous arguments are provided. at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable`1[]& matchingParameterMap) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateFactoryInternal(Type instanceType, Type[] argumentTypes, ParameterExpression& provider, ParameterExpression& argumentArray, Expression& factoryExpressionBody) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateFactory(Type instanceType, Type[] argumentTypes) at Grpc.Net.ClientFactory.Internal.DefaultClientActivator`1.<>c.<.cctor>b__9_0() at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory) at Grpc.Net.ClientFactory.Internal.DefaultClientActivator`1.get_Activator() at Grpc.Net.ClientFactory.Internal.DefaultClientActivator`1.CreateClient(CallInvoker callInvoker) at Grpc.Net.ClientFactory.Internal.DefaultGrpcClientFactory.CreateClient[TClient](String name) at Microsoft.Extensions.DependencyInjection.GrpcClientServiceExtensions.<>c__DisplayClass7_0`1.<AddGrpcHttpClient>b__0(IServiceProvider s) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, 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.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Apache.Arrow.Flight.Tests.GrpcNetClientFactoryTests.CanResolve_FlightClient_UsingGrpcClientFactory() in C:\Sourcecode\arrow\csharp\test\Apache.Arrow.Flight.Tests\GrpcNetClientFactoryTests.cs:line 24 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) ``` # Proposed Solution This can be achieved by adding another constructor to the `FlightClient` like below. I would be happy to open a pull request for this (along with test coverage) if this proposal is accepted. ```csharp public FlightClient(CallInvoker callInvoker) { _client = new FlightService.FlightServiceClient(callInvoker); } ``` ### Component(s) C# -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@arrow.apache.org.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org