| 
26 | 26 | using Microsoft.Extensions.Logging.Testing;  | 
27 | 27 | using NUnit.Framework;  | 
28 | 28 | using Grpc.Net.Client.Internal;  | 
 | 29 | +using System.Net;  | 
29 | 30 | #if SUPPORT_LOAD_BALANCING  | 
30 | 31 | using Grpc.Net.Client.Balancer;  | 
31 | 32 | using Grpc.Net.Client.Balancer.Internal;  | 
@@ -401,6 +402,87 @@ public async Task Dispose_CalledWhileActiveCalls_ActiveCallsDisposed()  | 
401 | 402 |         Assert.AreEqual(0, channel.ActiveCalls.Count);  | 
402 | 403 |     }  | 
403 | 404 | 
 
  | 
 | 405 | +    [TestCase(null)]  | 
 | 406 | +    [TestCase(false)]  | 
 | 407 | +    public void HttpHandler_HttpClientHandlerOverNativeOnAndroid_ThrowError(bool useDelegatingHandlers)  | 
 | 408 | +    {  | 
 | 409 | +        // Arrange  | 
 | 410 | +        AppContext.SetSwitch("System.Net.Http.UseNativeHttpHandler", true);  | 
 | 411 | +          | 
 | 412 | +        try  | 
 | 413 | +        {  | 
 | 414 | +            var services = new ServiceCollection();  | 
 | 415 | +            services.AddSingleton<IOperatingSystem>(new TestOperatingSystem { IsAndroid = true });  | 
 | 416 | + | 
 | 417 | +            HttpMessageHandler handler = new HttpClientHandler();  | 
 | 418 | +            if (useDelegatingHandlers)  | 
 | 419 | +            {  | 
 | 420 | +                handler = new TestDelegatingHandler(handler);  | 
 | 421 | +            }  | 
 | 422 | + | 
 | 423 | +            var ex = Assert.Throws<InvalidOperationException>(() =>  | 
 | 424 | +            {  | 
 | 425 | +                GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions  | 
 | 426 | +                {  | 
 | 427 | +                    HttpHandler = handler,  | 
 | 428 | +                    ServiceProvider = services.BuildServiceProvider()  | 
 | 429 | +                });  | 
 | 430 | +            });  | 
 | 431 | + | 
 | 432 | +            Assert.AreEqual(ex!.Message, "The channel configuration isn't valid on Android devices. " +  | 
 | 433 | +                "The channel is configured to use HttpClientHandler and Android's native HTTP/2 library. " +  | 
 | 434 | +                "gRPC isn't fully supported by Android's native HTTP/2 library and it can cause runtime errors. " +  | 
 | 435 | +                "To fix this problem, either configure the channel to use SocketsHttpHandler, or add " +  | 
 | 436 | +                "<UseNativeHttpHandler>false</UseNativeHttpHandler> to the app's project file. " +  | 
 | 437 | +                "For more information, see https://aka.ms/aspnet/grpc/android.");  | 
 | 438 | +        }  | 
 | 439 | +        finally  | 
 | 440 | +        {  | 
 | 441 | +            // Reset switch for other tests.  | 
 | 442 | +            AppContext.SetSwitch("System.Net.Http.UseNativeHttpHandler", false);  | 
 | 443 | +        }  | 
 | 444 | +    }  | 
 | 445 | + | 
 | 446 | +    private class TestDelegatingHandler : DelegatingHandler  | 
 | 447 | +    {  | 
 | 448 | +        public TestDelegatingHandler(HttpMessageHandler innerHandler) : base(innerHandler)  | 
 | 449 | +        {  | 
 | 450 | +        }  | 
 | 451 | +    }  | 
 | 452 | + | 
 | 453 | +    [Test]  | 
 | 454 | +    [TestCase(null)]  | 
 | 455 | +    [TestCase(false)]  | 
 | 456 | +    public void HttpHandler_HttpClientHandlerOverSocketsOnAndroid_Success(bool? isNativeHttpHandler)  | 
 | 457 | +    {  | 
 | 458 | +        // Arrange  | 
 | 459 | +        if (isNativeHttpHandler != null)  | 
 | 460 | +        {  | 
 | 461 | +            AppContext.SetSwitch("System.Net.Http.UseNativeHttpHandler", isNativeHttpHandler.Value);  | 
 | 462 | +        }  | 
 | 463 | + | 
 | 464 | +        var services = new ServiceCollection();  | 
 | 465 | +        services.AddSingleton<IOperatingSystem>(new TestOperatingSystem { IsAndroid = true });  | 
 | 466 | + | 
 | 467 | +        var handler = new HttpClientHandler();  | 
 | 468 | + | 
 | 469 | +        // Act  | 
 | 470 | +        var channel = GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions  | 
 | 471 | +        {  | 
 | 472 | +            HttpHandler = handler,  | 
 | 473 | +            ServiceProvider = services.BuildServiceProvider()  | 
 | 474 | +        });  | 
 | 475 | + | 
 | 476 | +        // Assert  | 
 | 477 | +        Assert.IsTrue(channel.OperatingSystem.IsAndroid);  | 
 | 478 | +    }  | 
 | 479 | + | 
 | 480 | +    private class TestOperatingSystem : IOperatingSystem  | 
 | 481 | +    {  | 
 | 482 | +        public bool IsBrowser { get; set; }  | 
 | 483 | +        public bool IsAndroid { get; set; }  | 
 | 484 | +    }  | 
 | 485 | + | 
404 | 486 | #if SUPPORT_LOAD_BALANCING  | 
405 | 487 |     [Test]  | 
406 | 488 |     public void Resolver_SocketHttpHandlerWithConnectCallback_Error()  | 
 | 
0 commit comments