|
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