internal MultiEndpointServiceConnectionContainer(
            string hub,
            Func <HubServiceEndpoint, IServiceConnectionContainer> generator,
            IServiceEndpointManager endpointManager,
            IMessageRouter router,
            ILoggerFactory loggerFactory)
        {
            if (generator == null)
            {
                throw new ArgumentNullException(nameof(generator));
            }

            _logger = loggerFactory?.CreateLogger <MultiEndpointServiceConnectionContainer>() ?? throw new ArgumentNullException(nameof(loggerFactory));

            // provides a copy to the endpoint per container
            _endpoints = endpointManager.GetEndpoints(hub);

            if (_endpoints.Count == 1)
            {
                _inner = generator(_endpoints[0]);
            }
            else
            {
                // router is required when endpoints > 1
                _router = router ?? throw new ArgumentNullException(nameof(router));
                ConnectionContainers = _endpoints.ToDictionary(s => (ServiceEndpoint)s, s => generator(s));
            }
        }
예제 #2
0
        public async Task <NegotiationResponse> NegotiateAsync(string hubName, HttpContext httpContext = null, string userId = null, IEnumerable <Claim> claims = null, TimeSpan?lifetime = null, bool isDiagnosticClient = false, CancellationToken cancellationToken = default)
        {
            try
            {
                if (cancellationToken == default && httpContext != null)
                {
                    cancellationToken = httpContext.RequestAborted;
                }

                var candidateEndpoints = _serviceEndpointManager.GetEndpoints(hubName);
                var selectedEndpoint   = _router.GetNegotiateEndpoint(httpContext, candidateEndpoints);
                var provider           = _serviceEndpointManager.GetEndpointProvider(selectedEndpoint);

                Func <IEnumerable <Claim> > claimProvider = null;
                if (claims != null)
                {
                    claimProvider = () => claims;
                }
                var claimsWithUserId = ClaimsUtility.BuildJwtClaims(httpContext?.User, userId: userId, claimProvider, isDiagnosticClient: isDiagnosticClient);

                var tokenTask = provider.GenerateClientAccessTokenAsync(hubName, claimsWithUserId, lifetime);
                await tokenTask.OrTimeout(cancellationToken, Timeout, GeneratingTokenTaskDescription);

                return(new NegotiationResponse
                {
                    Url = provider.GetClientEndpoint(hubName, null, null),
                    AccessToken = tokenTask.Result
                });
            }
            catch (Exception e)
            {
                throw new AzureSignalRException(ErrorMsg, e);
            }
        }
예제 #3
0
 private async Task CheckEndpointHealthAsync()
 {
     await Task.WhenAll(_serviceEndpointManager.GetEndpoints(_hubName).Select(async endpoint =>
     {
         var retry     = 0;
         var isHealthy = false;
         bool needRetry;
         do
         {
             try
             {
                 using var client = _clientFactory.Create(endpoint);
                 isHealthy        = await client.IsServiceHealthy(default);
예제 #4
0
        public async Task <NegotiationResponse> NegotiateAsync(string hubName, NegotiationOptions negotiationOptions, CancellationToken cancellationToken = default)
        {
            negotiationOptions ??= NegotiationOptions.Default;
            var httpContext          = negotiationOptions.HttpContext;
            var userId               = negotiationOptions.UserId;
            var claims               = negotiationOptions.Claims;
            var isDiagnosticClient   = negotiationOptions.IsDiagnosticClient;
            var enableDetailedErrors = negotiationOptions.EnableDetailedErrors;
            var lifetime             = negotiationOptions.TokenLifetime;

            try
            {
                if (cancellationToken == default && httpContext != null)
                {
                    cancellationToken = httpContext.RequestAborted;
                }

                var candidateEndpoints = _serviceEndpointManager.GetEndpoints(hubName);
                var selectedEndpoint   = _router.GetNegotiateEndpoint(httpContext, candidateEndpoints);
                var provider           = _serviceEndpointManager.GetEndpointProvider(selectedEndpoint);

                Func <IEnumerable <Claim> > claimProvider = null;
                if (claims != null)
                {
                    claimProvider = () => claims;
                }
                var claimsWithUserId = ClaimsUtility.BuildJwtClaims(httpContext?.User, userId: userId, claimProvider, enableDetailedErrors: enableDetailedErrors, isDiagnosticClient: isDiagnosticClient);

                var tokenTask = provider.GenerateClientAccessTokenAsync(hubName, claimsWithUserId, lifetime);
                await tokenTask.OrTimeout(cancellationToken, Timeout, GeneratingTokenTaskDescription);

                return(new NegotiationResponse
                {
                    Url = provider.GetClientEndpoint(hubName, null, null),
                    AccessToken = tokenTask.Result
                });
            }
            catch (Exception e) when(e is OperationCanceledException || e is TimeoutException)
            {
                throw new AzureSignalRException(ErrorMsg, e);
            }
        }
예제 #5
0
        public NegotiationResponse Process(HttpContext context, string hubName)
        {
            var claims       = BuildClaims(context);
            var request      = context.Request;
            var originalPath = GetOriginalPath(request.Path);
            var provider     = _endpointManager.GetEndpointProvider(_router.GetNegotiateEndpoint(context, _endpointManager.GetEndpoints(hubName)));

            if (provider == null)
            {
                return(null);
            }

            var queryString = GetQueryString(request.QueryString.HasValue ? request.QueryString.Value.Substring(1) : null);

            return(new NegotiationResponse
            {
                Url = provider.GetClientEndpoint(hubName, originalPath, queryString),
                AccessToken = provider.GenerateClientAccessToken(hubName, claims),
                // Need to set this even though it's technically protocol violation https://github.com/aspnet/SignalR/issues/2133
                AvailableTransports = new List <AvailableTransport>()
            });
        }
 IEnumerable <ServiceEndpoint> IInternalServiceHubContext.GetServiceEndpoints() => _endpointManager.GetEndpoints(_hubName);