private ResolverFactory GetResolverFactory(GrpcChannelOptions options) { // Special case http and https schemes. These schemes don't use a dynamic resolver. An http/https // address is always just one address and that is enabled using the static resolver. // // Even with just one address we still want to use the load balancing infrastructure. This enables // the connectivity APIs on channel like GrpcChannel.State and GrpcChannel.WaitForStateChanged. if (IsHttpOrHttpsAddress()) { return(new StaticResolverFactory(uri => new[] { new BalancerAddress(Address.Host, Address.Port) })); } var factories = options.ResolveService <IEnumerable <ResolverFactory> >(Array.Empty <ResolverFactory>()); factories = factories.Union(ResolverFactory.KnownLoadResolverFactories); foreach (var factory in factories) { if (string.Equals(factory.Name, Address.Scheme, StringComparison.OrdinalIgnoreCase)) { return(factory); } } throw new InvalidOperationException($"No address resolver configured for the scheme '{Address.Scheme}'."); }
private LoadBalancerFactory[] ResolveLoadBalancerFactories(GrpcChannelOptions channelOptions) { var serviceFactories = channelOptions.ResolveService <IEnumerable <LoadBalancerFactory>?>(defaultValue: null); if (serviceFactories != null) { return(serviceFactories.Union(LoadBalancerFactory.KnownLoadBalancerFactories).ToArray()); } return(LoadBalancerFactory.KnownLoadBalancerFactories); }
internal GrpcChannel(Uri address, GrpcChannelOptions channelOptions) : base(address.Authority) { _lock = new object(); _methodInfoCache = new ConcurrentDictionary <IMethod, GrpcMethodInfo>(); // Dispose the HTTP client/handler if... // 1. No client/handler was specified and so the channel created the client itself // 2. User has specified a client/handler and set DisposeHttpClient to true _shouldDisposeHttpClient = (channelOptions.HttpClient == null && channelOptions.HttpHandler == null) || channelOptions.DisposeHttpClient; Address = address; LoggerFactory = channelOptions.LoggerFactory ?? channelOptions.ResolveService <ILoggerFactory>(NullLoggerFactory.Instance); RandomGenerator = channelOptions.ResolveService <IRandomGenerator>(new RandomGenerator()); HttpHandlerType = CalculateHandlerType(channelOptions); #if SUPPORT_LOAD_BALANCING InitialReconnectBackoff = channelOptions.InitialReconnectBackoff; MaxReconnectBackoff = channelOptions.MaxReconnectBackoff; var resolverFactory = GetResolverFactory(channelOptions); ResolveCredentials(channelOptions, out _isSecure, out _callCredentials); SubchannelTransportFactory = channelOptions.ResolveService <ISubchannelTransportFactory>(new SubChannelTransportFactory(this)); if (!IsHttpOrHttpsAddress() || channelOptions.ServiceConfig?.LoadBalancingConfigs.Count > 0) { ValidateHttpHandlerSupportsConnectivity(); } var defaultPort = IsSecure ? 443 : 80; var resolver = resolverFactory.Create(new ResolverOptions(Address, defaultPort, LoggerFactory, channelOptions)); ConnectionManager = new ConnectionManager( resolver, channelOptions.DisableResolverServiceConfig, LoggerFactory, channelOptions.ResolveService <IBackoffPolicyFactory>(new ExponentialBackoffPolicyFactory(RandomGenerator, InitialReconnectBackoff, MaxReconnectBackoff)), SubchannelTransportFactory, ResolveLoadBalancerFactories(channelOptions)); ConnectionManager.ConfigureBalancer(c => new ChildHandlerLoadBalancer( c, channelOptions.ServiceConfig, ConnectionManager)); #else if (string.IsNullOrEmpty(address.Host)) { throw new ArgumentException($"Address '{address.OriginalString}' doesn't have a host. Address should include a scheme, host, and optional port. For example, 'https://localhost:5001'."); } ResolveCredentials(channelOptions, out _isSecure, out _callCredentials); #endif HttpInvoker = channelOptions.HttpClient ?? CreateInternalHttpInvoker(channelOptions.HttpHandler); SendMaxMessageSize = channelOptions.MaxSendMessageSize; ReceiveMaxMessageSize = channelOptions.MaxReceiveMessageSize; MaxRetryAttempts = channelOptions.MaxRetryAttempts; MaxRetryBufferSize = channelOptions.MaxRetryBufferSize; MaxRetryBufferPerCallSize = channelOptions.MaxRetryBufferPerCallSize; CompressionProviders = ResolveCompressionProviders(channelOptions.CompressionProviders); MessageAcceptEncoding = GrpcProtocolHelpers.GetMessageAcceptEncoding(CompressionProviders); Logger = LoggerFactory.CreateLogger <GrpcChannel>(); ThrowOperationCanceledOnCancellation = channelOptions.ThrowOperationCanceledOnCancellation; UnsafeUseInsecureChannelCallCredentials = channelOptions.UnsafeUseInsecureChannelCallCredentials; _createMethodInfoFunc = CreateMethodInfo; ActiveCalls = new HashSet <IDisposable>(); if (channelOptions.ServiceConfig is { } serviceConfig) { RetryThrottling = serviceConfig.RetryThrottling != null?CreateChannelRetryThrottling(serviceConfig.RetryThrottling) : null; _serviceConfigMethods = CreateServiceConfigMethods(serviceConfig); } // Non-HTTP addresses (e.g. dns:///custom-hostname) usually specify a path instead of an authority. // Only log about a path being present if HTTP or HTTPS. if (!string.IsNullOrEmpty(Address.PathAndQuery) && Address.PathAndQuery != "/" && (Address.Scheme == Uri.UriSchemeHttps || Address.Scheme == Uri.UriSchemeHttp)) { Log.AddressPathUnused(Logger, Address.OriginalString); } }