21
21
using System . Diagnostics ;
22
22
using System . Diagnostics . CodeAnalysis ;
23
23
using System . Globalization ;
24
+ using System . Net . Http ;
24
25
using System . Net . Security ;
25
26
using System . Net . Sockets ;
26
27
using System . Reflection ;
@@ -78,6 +79,7 @@ public static async Task<int> Main(string[] args)
78
79
var streamsOption = new Option < int > ( new string [ ] { "--streams" } , ( ) => 1 , "Maximum concurrent streams per connection" ) ;
79
80
var enableCertAuthOption = new Option < bool > ( new string [ ] { "--enableCertAuth" } , ( ) => false , "Flag indicating whether client sends a client certificate" ) ;
80
81
var deadlineOption = new Option < int > ( new string [ ] { "--deadline" } , "Duration of deadline in seconds" ) ;
82
+ var winHttpHandlerOption = new Option < bool > ( new string [ ] { "--winhttphandler" } , ( ) => false , "Whether to use WinHttpHandler with Grpc.Net.Client" ) ;
81
83
82
84
var rootCommand = new RootCommand ( ) ;
83
85
rootCommand . AddOption ( urlOption ) ;
@@ -97,6 +99,7 @@ public static async Task<int> Main(string[] args)
97
99
rootCommand . AddOption ( streamsOption ) ;
98
100
rootCommand . AddOption ( enableCertAuthOption ) ;
99
101
rootCommand . AddOption ( deadlineOption ) ;
102
+ rootCommand . AddOption ( winHttpHandlerOption ) ;
100
103
101
104
rootCommand . SetHandler ( async ( InvocationContext context ) =>
102
105
{
@@ -118,6 +121,7 @@ public static async Task<int> Main(string[] args)
118
121
_options . Streams = context . ParseResult . GetValueForOption ( streamsOption ) ;
119
122
_options . EnableCertAuth = context . ParseResult . GetValueForOption ( enableCertAuthOption ) ;
120
123
_options . Deadline = context . ParseResult . GetValueForOption ( deadlineOption ) ;
124
+ _options . WinHttpHandler = context . ParseResult . GetValueForOption ( winHttpHandlerOption ) ;
121
125
122
126
var runtimeVersion = typeof ( object ) . GetTypeInfo ( ) . Assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ? . InformationalVersion ?? "Unknown" ;
123
127
var isServerGC = GCSettings . IsServerGC ;
@@ -159,8 +163,10 @@ public static async Task<int> Main(string[] args)
159
163
return await rootCommand . InvokeAsync ( args ) ;
160
164
}
161
165
166
+ #if NET9_0_OR_GREATER
162
167
[ UnconditionalSuppressMessage ( "AotAnalysis" , "IL3050:RequiresDynamicCode" ,
163
168
Justification = "DependencyInjection only used with safe types." ) ]
169
+ #endif
164
170
private static ILoggerFactory CreateLoggerFactory ( )
165
171
{
166
172
return LoggerFactory . Create ( c =>
@@ -244,7 +250,7 @@ private static async Task StartScenario()
244
250
var text = "Exception from test: " + ex . Message ;
245
251
Log ( text ) ;
246
252
_errorStringBuilder . AppendLine ( ) ;
247
- _errorStringBuilder . Append ( CultureInfo . InvariantCulture , $ "[{ DateTime . Now : hh:mm:ss.fff} ] { text } " ) ;
253
+ _errorStringBuilder . Append ( string . Format ( CultureInfo . InvariantCulture , "[{0 :hh:mm:ss.fff}] {1}" , DateTime . Now , text ) ) ;
248
254
}
249
255
}
250
256
@@ -425,7 +431,9 @@ private static void CreateChannels()
425
431
var initialUri = _options . Url ! ;
426
432
var resolvedUri = initialUri . Authority ;
427
433
434
+ Log ( $ "Framework version: { System . Runtime . InteropServices . RuntimeInformation . FrameworkDescription } ") ;
428
435
Log ( $ "gRPC client type: { _options . GrpcClientType } ") ;
436
+ Log ( $ "WinHttpHandler: { ( _options . GrpcClientType == GrpcClientType . GrpcNetClient ? _options . WinHttpHandler . ToString ( ) : "N/A" ) } ") ;
429
437
Log ( $ "Log level: { _options . LogLevel } ") ;
430
438
Log ( $ "Protocol: '{ _options . Protocol } '") ;
431
439
Log ( $ "Creating channels to '{ resolvedUri } '") ;
@@ -465,43 +473,12 @@ private static ChannelBase CreateChannel(string target)
465
473
var address = useTls ? "https://" : "http://" ;
466
474
address += target ;
467
475
468
- var httpClientHandler = new SocketsHttpHandler ( ) ;
469
- httpClientHandler . UseProxy = false ;
470
- httpClientHandler . AllowAutoRedirect = false ;
471
- if ( _options . EnableCertAuth )
472
- {
473
- var basePath = Path . GetDirectoryName ( AppContext . BaseDirectory ) ;
474
- var certPath = Path . Combine ( basePath ! , "Certs" , "client.pfx" ) ;
475
- var clientCertificates = X509CertificateLoader . LoadPkcs12CollectionFromFile ( certPath , "1111" ) ;
476
- httpClientHandler . SslOptions . ClientCertificates = clientCertificates ;
477
- }
478
-
479
- if ( ! string . IsNullOrEmpty ( _options . UdsFileName ) )
480
- {
481
- var connectionFactory = new UnixDomainSocketConnectionFactory ( new UnixDomainSocketEndPoint ( ResolveUdsPath ( _options . UdsFileName ) ) ) ;
482
- httpClientHandler . ConnectCallback = connectionFactory . ConnectAsync ;
483
- }
484
- else if ( ! string . IsNullOrEmpty ( _options . NamedPipeName ) )
485
- {
486
- var connectionFactory = new NamedPipeConnectionFactory ( _options . NamedPipeName ) ;
487
- httpClientHandler . ConnectCallback = connectionFactory . ConnectAsync ;
488
- }
489
-
490
- httpClientHandler . SslOptions . RemoteCertificateValidationCallback =
491
- ( object sender , X509Certificate ? certificate , X509Chain ? chain , SslPolicyErrors sslPolicyErrors ) => true ;
492
-
493
- HttpMessageHandler httpMessageHandler = httpClientHandler ;
494
-
495
- Version ? versionOverride = null ;
496
- if ( _options . Protocol == "h3" )
497
- {
498
- // Stop gRPC channel from creating TCP socket.
499
- httpClientHandler . ConnectCallback = ( context , cancellationToken ) => throw new InvalidOperationException ( "Should never be called for H3." ) ;
500
-
501
- // Force H3 on all requests.
502
- versionOverride = new Version ( 3 , 0 ) ;
503
- }
476
+ // Force H3 on all requests.
477
+ var versionOverride = _options . Protocol == "h3"
478
+ ? new Version ( 3 , 0 )
479
+ : null ;
504
480
481
+ var httpMessageHandler = CreateMessageHandler ( ) ;
505
482
return GrpcChannel . ForAddress ( address , new GrpcChannelOptions
506
483
{
507
484
HttpHandler = httpMessageHandler ,
@@ -511,6 +488,61 @@ private static ChannelBase CreateChannel(string target)
511
488
}
512
489
}
513
490
491
+ private static HttpMessageHandler CreateMessageHandler ( )
492
+ {
493
+ if ( _options . WinHttpHandler )
494
+ {
495
+ return CreateWinHttpHandler ( ) ;
496
+ }
497
+
498
+ #if NET9_0_OR_GREATER
499
+ var httpClientHandler = new SocketsHttpHandler ( ) ;
500
+ httpClientHandler . UseProxy = false ;
501
+ httpClientHandler . AllowAutoRedirect = false ;
502
+ if ( _options . EnableCertAuth )
503
+ {
504
+ var basePath = Path . GetDirectoryName ( AppContext . BaseDirectory ) ;
505
+ var certPath = Path . Combine ( basePath ! , "Certs" , "client.pfx" ) ;
506
+ var clientCertificates = X509CertificateLoader . LoadPkcs12CollectionFromFile ( certPath , "1111" ) ;
507
+ httpClientHandler . SslOptions . ClientCertificates = clientCertificates ;
508
+ }
509
+
510
+ if ( ! string . IsNullOrEmpty ( _options . UdsFileName ) )
511
+ {
512
+ var connectionFactory = new UnixDomainSocketConnectionFactory ( new UnixDomainSocketEndPoint ( ResolveUdsPath ( _options . UdsFileName ) ) ) ;
513
+ httpClientHandler . ConnectCallback = connectionFactory . ConnectAsync ;
514
+ }
515
+ else if ( ! string . IsNullOrEmpty ( _options . NamedPipeName ) )
516
+ {
517
+ var connectionFactory = new NamedPipeConnectionFactory ( _options . NamedPipeName ) ;
518
+ httpClientHandler . ConnectCallback = connectionFactory . ConnectAsync ;
519
+ }
520
+
521
+ httpClientHandler . SslOptions . RemoteCertificateValidationCallback =
522
+ ( object sender , X509Certificate ? certificate , X509Chain ? chain , SslPolicyErrors sslPolicyErrors ) => true ;
523
+
524
+ if ( _options . Protocol == "h3" )
525
+ {
526
+ // Stop gRPC channel from creating TCP socket.
527
+ httpClientHandler . ConnectCallback = ( context , cancellationToken ) => throw new InvalidOperationException ( "Should never be called for H3." ) ;
528
+ }
529
+
530
+ return httpClientHandler ;
531
+ #else
532
+ return CreateWinHttpHandler ( ) ;
533
+ #endif
534
+ }
535
+
536
+ private static WinHttpHandler CreateWinHttpHandler ( )
537
+ {
538
+ #pragma warning disable CA1416 // Validate platform compatibility
539
+ return new WinHttpHandler
540
+ {
541
+ ServerCertificateValidationCallback = ( sender , certificate , chain , sslPolicyErrors ) => true ,
542
+ } ;
543
+ #pragma warning restore CA1416 // Validate platform compatibility
544
+ }
545
+
514
546
private static string ResolveUdsPath ( string udsFileName ) => Path . Combine ( Path . GetTempPath ( ) , udsFileName ) ;
515
547
516
548
private static SslCredentials GetSslCredentials ( )
0 commit comments