From e250a881cb89a52b371feafb5f69a7c7edbfca19 Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Thu, 21 Mar 2019 13:11:18 +0000 Subject: [PATCH 01/13] Add hubprefix to options --- .../ServiceOptions.cs | 15 ++-- .../Constants.cs | 3 + .../Endpoints/IServiceEndpointOptions.cs | 1 + .../Endpoints/ServiceEndpoint.cs | 7 +- .../Endpoints/ServiceEndpointManagerBase.cs | 3 +- .../RestApiProvider.cs | 16 +++- .../RestHubLifetimeManager.cs | 2 +- .../ServiceManager.cs | 2 +- .../ServiceManagerOptions.cs | 5 ++ .../DefaultServiceEndpointGenerator.cs | 32 +++++--- .../ServiceEndpointProvider.cs | 2 +- src/Microsoft.Azure.SignalR/ServiceOptions.cs | 5 ++ .../ServiceOptionsSetup.cs | 32 ++++++-- .../RunAzureSignalRTests.cs | 41 ++++++++++ .../UnitTests/RestApiProviderFacts.cs | 5 +- .../UnitTests/ServiceManagerFacts.cs | 14 +++- .../NegotiateHandlerFacts.cs | 69 +++++++++++++++++ .../ServiceEndpointProviderFacts.cs | 75 +++++++++++++++++++ 18 files changed, 296 insertions(+), 33 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs index 1efc1ec1b..61172d381 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs @@ -25,6 +25,11 @@ public class ServiceOptions : IServiceEndpointOptions /// public int ConnectionCount { get; set; } = 5; + /// + /// Gets or sets the prefix to apply to each hub name + /// + public string HubPrefix{ get; set; } + /// /// Gets or sets the func to generate claims from . /// The claims will be included in the auto-generated token for clients. @@ -47,7 +52,7 @@ public ServiceOptions() for (int i = 0; i < count; i++) { var setting = ConfigurationManager.ConnectionStrings[i]; - var (isDefault, endpoint) = GetEndpoint(setting.Name, () => setting.ConnectionString); + var (isDefault, endpoint) = GetEndpoint(setting.Name, this.HubPrefix, () => setting.ConnectionString); if (endpoint != null) { if (isDefault) @@ -64,7 +69,7 @@ public ServiceOptions() // Fallback to use AppSettings foreach(var key in ConfigurationManager.AppSettings.AllKeys) { - var (isDefault, endpoint) = GetEndpoint(key, () => ConfigurationManager.AppSettings[key]); + var (isDefault, endpoint) = GetEndpoint(key, this.HubPrefix, () => ConfigurationManager.AppSettings[key]); if (endpoint != null) { if (isDefault) @@ -81,16 +86,16 @@ public ServiceOptions() Endpoints = endpoints.ToArray(); } - private static (bool isDefault, ServiceEndpoint endpoint) GetEndpoint(string key, Func valueGetter) + private static (bool isDefault, ServiceEndpoint endpoint) GetEndpoint(string key, string hubPrefix, Func valueGetter) { if (key == Constants.ConnectionStringDefaultKey && !string.IsNullOrEmpty(valueGetter())) { - return (true, new ServiceEndpoint(valueGetter())); + return (true, new ServiceEndpoint(valueGetter(), hubPrefix: hubPrefix)); } if (key.StartsWith(Constants.ConnectionStringKeyPrefix) && !string.IsNullOrEmpty(valueGetter())) { - return (false, new ServiceEndpoint(key, valueGetter())); + return (false, new ServiceEndpoint(key, valueGetter(), hubPrefix)); } return (false, null); diff --git a/src/Microsoft.Azure.SignalR.Common/Constants.cs b/src/Microsoft.Azure.SignalR.Common/Constants.cs index 6348fd371..c9785deda 100644 --- a/src/Microsoft.Azure.SignalR.Common/Constants.cs +++ b/src/Microsoft.Azure.SignalR.Common/Constants.cs @@ -8,12 +8,15 @@ namespace Microsoft.Azure.SignalR internal static class Constants { public const string ConnectionStringDefaultKey = "Azure:SignalR:ConnectionString"; + public const string HubPrefixDefaultKey = "Azure:SignalR:HubPrefix"; public static readonly string ConnectionStringSecondaryKey = $"ConnectionStrings:{ConnectionStringDefaultKey}"; public static readonly string ConnectionStringKeyPrefix = $"{ConnectionStringDefaultKey}:"; + public static readonly string HubPrefixDefaultKeyPrefix = $"{HubPrefixDefaultKey}:"; + public static readonly string ConnectionStringSecondaryKeyPrefix = $"{ConnectionStringSecondaryKey}:"; // Default access token lifetime diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs index 38c6c4160..827d04143 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs @@ -6,6 +6,7 @@ namespace Microsoft.Azure.SignalR internal interface IServiceEndpointOptions { ServiceEndpoint[] Endpoints { get; } + string HubPrefix { get; } string ConnectionString { get; } } } diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs index a5209f594..be9501989 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs @@ -28,9 +28,11 @@ public class ServiceEndpoint internal int? Port { get; } + internal string HubPrefix { get; set; } + internal IServiceConnectionContainer Connection { get; set; } - public ServiceEndpoint(string key, string connectionString) : this(connectionString) + public ServiceEndpoint(string key, string connectionString, string hubPrefix = "") : this(connectionString, hubPrefix: hubPrefix) { if (!string.IsNullOrEmpty(key)) { @@ -38,7 +40,7 @@ public ServiceEndpoint(string key, string connectionString) : this(connectionStr } } - public ServiceEndpoint(string connectionString, EndpointType type = EndpointType.Primary, string name = "") + public ServiceEndpoint(string connectionString, EndpointType type = EndpointType.Primary, string name = "", string hubPrefix = "") { // The provider is responsible to check if the connection string is empty and throw correct error message if (!string.IsNullOrEmpty(connectionString)) @@ -49,6 +51,7 @@ public ServiceEndpoint(string connectionString, EndpointType type = EndpointType EndpointType = type; ConnectionString = connectionString; Name = name; + HubPrefix = hubPrefix; } public override string ToString() diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs index 879a63d3a..ec0e03bf5 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs @@ -75,13 +75,14 @@ private static IEnumerable GetEndpoints(IServiceEndpointOptions // TODO: Better way if Endpoints already contains ConnectionString one? if (!string.IsNullOrEmpty(connectionString)) { - yield return new ServiceEndpoint(options.ConnectionString); + yield return new ServiceEndpoint(options.ConnectionString, hubPrefix: options.HubPrefix); } if (endpoints != null) { foreach (var endpoint in endpoints) { + endpoint.HubPrefix = options.HubPrefix; yield return endpoint; } } diff --git a/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs b/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs index d6352a5c1..cad3d62a4 100644 --- a/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs +++ b/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs @@ -10,18 +10,28 @@ internal class RestApiProvider private readonly RestApiAccessTokenGenerator _restApiAccessTokenGenerator; private readonly string _baseEndpoint; private readonly string _hubName; + private readonly string _hubPrefix; private readonly string _requestPrefix; private readonly string _audiencePrefix; private readonly int? _port; - public RestApiProvider(string connectionString, string hubName) + public RestApiProvider(string connectionString, string hubName, string hubPrefix) { string accessKey; (_baseEndpoint, accessKey, _, _port) = ConnectionStringParser.Parse(connectionString); _hubName = hubName; + _hubPrefix = hubPrefix; _restApiAccessTokenGenerator = new RestApiAccessTokenGenerator(accessKey); - _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_hubName}"; - _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_hubName}"; + if (string.IsNullOrEmpty(_hubPrefix)) + { + _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_hubName}"; + _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_hubName}"; + } + else + { + _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_hubPrefix}_{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_hubPrefix}_{_hubName}"; + _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_hubPrefix}_{_hubName}"; + } } public RestApiEndpoint GetBroadcastEndpoint(TimeSpan? lifetime = null) diff --git a/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs b/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs index 4e2b55022..c1a254911 100644 --- a/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs +++ b/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs @@ -23,7 +23,7 @@ internal class RestHubLifetimeManager : HubLifetimeManager, IHubLifetimeMan public RestHubLifetimeManager(ServiceManagerOptions serviceManagerOptions, string hubName) { - _restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, hubName); + _restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, serviceManagerOptions.HubPrefix, hubName); } public override Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) diff --git a/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs b/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs index 4a35c638f..beae9a85a 100644 --- a/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs +++ b/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs @@ -26,7 +26,7 @@ internal class ServiceManager : IServiceManager internal ServiceManager(ServiceManagerOptions serviceManagerOptions) { _serviceManagerOptions = serviceManagerOptions; - _endpoint = new ServiceEndpoint(_serviceManagerOptions.ConnectionString, EndpointType.Secondary); + _endpoint = new ServiceEndpoint(_serviceManagerOptions.ConnectionString, EndpointType.Secondary, hubPrefix: _serviceManagerOptions.HubPrefix); _endpointProvider = new ServiceEndpointProvider(_endpoint); } diff --git a/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs b/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs index 096fca0af..fb3b498ac 100644 --- a/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs +++ b/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs @@ -21,6 +21,11 @@ public class ServiceManagerOptions /// public string ConnectionString { get; set; } = null; + /// + /// Gets or sets the prefix to apply to each hub name + /// + public string HubPrefix { get; set; } + internal void ValidateOptions() { ValidateConnectionString(); diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs index aba1a7b2f..6d6ab5a2d 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs @@ -17,18 +17,22 @@ internal sealed class DefaultServiceEndpointGenerator : IServiceEndpointGenerato public string Version { get; } + public string HubPrefix { get; } + public int? Port { get; } - public DefaultServiceEndpointGenerator(string endpoint, string accessKey, string version, int? port) + public DefaultServiceEndpointGenerator(string endpoint, string accessKey, string version, int? port, string hubPrefix) { Endpoint = endpoint; AccessKey = accessKey; Version = version; Port = port; + HubPrefix = hubPrefix; } public string GetClientAudience(string hubName) => - InternalGetAudience(ClientPath, hubName); + InternalGetAudience(ClientPath, hubName, HubPrefix); + public string GetClientEndpoint(string hubName, string originalPath, string queryString) { @@ -46,21 +50,27 @@ public string GetClientEndpoint(string hubName, string originalPath, string quer queryBuilder.Append("&").Append(queryString); } - return $"{InternalGetEndpoint(ClientPath, hubName)}{queryBuilder}"; + return $"{InternalGetEndpoint(ClientPath, hubName, HubPrefix)}{queryBuilder}"; } public string GetServerAudience(string hubName) => - InternalGetAudience(ServerPath, hubName); + InternalGetAudience(ServerPath, hubName, HubPrefix); public string GetServerEndpoint(string hubName) => - InternalGetEndpoint(ServerPath, hubName); + InternalGetEndpoint(ServerPath, hubName, HubPrefix); - private string InternalGetEndpoint(string path, string hubName) => - Port.HasValue ? - $"{Endpoint}:{Port}/{path}/?hub={hubName.ToLower()}" : - $"{Endpoint}/{path}/?hub={hubName.ToLower()}"; + private string InternalGetEndpoint(string path, string hubName, string hubPrefix) + { + var prefixedHubName = string.IsNullOrEmpty(hubPrefix) ? hubName.ToLower() : $"{hubPrefix.ToLower()}_{hubName.ToLower()}"; + return Port.HasValue ? + $"{Endpoint}:{Port}/{path}/?hub={prefixedHubName}" : + $"{Endpoint}/{path}/?hub={prefixedHubName}"; + } - private string InternalGetAudience(string path, string hubName) => - $"{Endpoint}/{path}/?hub={hubName.ToLower()}"; + private string InternalGetAudience(string path, string hubName, string hubPrefix) + { + var prefixedHubName = string.IsNullOrEmpty(hubPrefix) ? hubName.ToLower() : $"{hubPrefix.ToLower()}_{hubName.ToLower()}"; + return $"{Endpoint}/{path}/?hub={prefixedHubName}"; + } } } diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs index b4f261561..0b5526515 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs @@ -35,7 +35,7 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) var port = endpoint.Port; var version = endpoint.Version; - _generator = new DefaultServiceEndpointGenerator(_endpoint, _accessKey, version, port); + _generator = new DefaultServiceEndpointGenerator(_endpoint, _accessKey, version, port, endpoint.HubPrefix); } public string GenerateClientAccessToken(string hubName, IEnumerable claims = null, TimeSpan? lifetime = null, string requestId = null) diff --git a/src/Microsoft.Azure.SignalR/ServiceOptions.cs b/src/Microsoft.Azure.SignalR/ServiceOptions.cs index 40f16f6d9..fade6ef4e 100644 --- a/src/Microsoft.Azure.SignalR/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR/ServiceOptions.cs @@ -23,6 +23,11 @@ public class ServiceOptions : IServiceEndpointOptions /// public int ConnectionCount { get; set; } = 5; + /// + /// Gets or sets the prefix to apply to each hub name + /// + public string HubPrefix { get; set; } + /// /// Gets or sets the func to generate claims from . /// The claims will be included in the auto-generated token for clients. diff --git a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs index af954afe8..6d8bd54dc 100644 --- a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs +++ b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs @@ -10,31 +10,53 @@ namespace Microsoft.Azure.SignalR { internal class ServiceOptionsSetup : IConfigureOptions { + private readonly string _hubPrefix; private readonly string _connectionString; private readonly ServiceEndpoint[] _endpoints; public ServiceOptionsSetup(IConfiguration configuration) { - var (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringDefaultKey, Constants.ConnectionStringKeyPrefix); + _hubPrefix = GetHubPrefix(configuration); + + var (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringDefaultKey, Constants.ConnectionStringKeyPrefix, _hubPrefix); // Fallback to ConnectionStrings:Azure:SignalR:ConnectionString format when the default one is not available if (endpoints.Count == 0) { - (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringSecondaryKey, Constants.ConnectionStringSecondaryKeyPrefix); + (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringSecondaryKey, Constants.ConnectionStringSecondaryKeyPrefix, _hubPrefix); } _connectionString = connectionString; _endpoints = endpoints.ToArray(); } + private string GetHubPrefix(IConfiguration configuration) + { + foreach (var pair in configuration.AsEnumerable()) + { + var key = pair.Key; + if (key == Constants.HubPrefixDefaultKey && !string.IsNullOrEmpty(pair.Value)) + { + return pair.Value; + } + + if (key.StartsWith(Constants.HubPrefixDefaultKeyPrefix) && !string.IsNullOrEmpty(pair.Value)) + { + return pair.Value; + } + } + return string.Empty; + } + public void Configure(ServiceOptions options) { // The default setup of ServiceOptions options.ConnectionString = _connectionString; options.Endpoints = _endpoints; + options.HubPrefix = _hubPrefix; } - private static (string, List) GetEndpoint(IConfiguration configuration, string defaultKey, string keyPrefix) + private static (string, List) GetEndpoint(IConfiguration configuration, string defaultKey, string keyPrefix, string hubPrefix) { var endpoints = new List(); string connectionString = null; @@ -44,12 +66,12 @@ private static (string, List) GetEndpoint(IConfiguration config if (key == defaultKey && !string.IsNullOrEmpty(pair.Value)) { connectionString = pair.Value; - endpoints.Add(new ServiceEndpoint(pair.Value)); + endpoints.Add(new ServiceEndpoint(pair.Value, hubPrefix: hubPrefix)); } if (key.StartsWith(keyPrefix) && !string.IsNullOrEmpty(pair.Value)) { - endpoints.Add(new ServiceEndpoint(key, pair.Value)); + endpoints.Add(new ServiceEndpoint(key, pair.Value, hubPrefix)); } } diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs index 656e09475..86dbd90e6 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs @@ -33,6 +33,7 @@ public class RunAzureSignalRTests : VerifiableLoggedTest private const string ConnectionString2 = "Endpoint=http://localhost2;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;"; private const string ConnectionString3 = "Endpoint=http://localhost3;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;"; private const string ConnectionString4 = "Endpoint=http://localhost4;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;"; + private const string HubPrefix = "testprefix"; private const string AppName = "AzureSignalRTest"; public RunAzureSignalRTests(ITestOutputHelper output) : base(output) @@ -185,6 +186,44 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettings() } } + [Fact] + public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncludingHubPrefix() + { + // Prepare the configuration + using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) + using (new AppSettingsConfigScope(ConnectionString, ConnectionString2)) + { + var hubConfig = Utility.GetTestHubConfig(loggerFactory); + using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, options => + { + options.HubPrefix = HubPrefix; + options.Endpoints = new ServiceEndpoint[] + { + new ServiceEndpoint(ConnectionString2, EndpointType.Secondary), + new ServiceEndpoint(ConnectionString3), + new ServiceEndpoint(ConnectionString4) + }; + }))) + { + var options = hubConfig.Resolver.Resolve>(); + + Assert.Equal(ConnectionString, options.Value.ConnectionString); + Assert.Equal(HubPrefix, options.Value.HubPrefix); + + Assert.Equal(3, options.Value.Endpoints.Length); + + var manager = hubConfig.Resolver.Resolve(); + var endpoints = manager.GetAvailableEndpoints().ToArray(); + Assert.Equal(4, endpoints.Length); + + Assert.Equal(HubPrefix, endpoints[0].HubPrefix); + Assert.Equal(HubPrefix, endpoints[1].HubPrefix); + Assert.Equal(HubPrefix, endpoints[2].HubPrefix); + Assert.Equal(HubPrefix, endpoints[3].HubPrefix); + } + } + } + [Fact] public async Task TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsAndCustomRouter() { @@ -280,10 +319,12 @@ public void TestRunAzureSignalRWithOptions() { o.ConnectionString = ConnectionString; o.ConnectionCount = -1; + o.HubPrefix = HubPrefix; }))) { var options = hubConfig.Resolver.Resolve>(); Assert.Equal(ConnectionString, options.Value.ConnectionString); + Assert.Equal(HubPrefix, options.Value.HubPrefix); Assert.Equal(-1, options.Value.ConnectionCount); } } diff --git a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs index 0f4451571..3d91b6015 100644 --- a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs +++ b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs @@ -14,11 +14,12 @@ public class RestApiProviderFacts private static readonly string _connectionString = $"Endpoint={_endpoint};AccessKey={_accessKey};Version=1.0;"; private const string _hubName = "signalrbench"; + private const string _hubPrefix = "prefix"; private const string _userId = "UserA"; private const string _groupName = "GroupA"; - private static readonly string _commonEndpoint = $"{_endpoint}/api/v1/hubs/{_hubName}"; + private static readonly string _commonEndpoint = $"{_endpoint}/api/v1/hubs/{_hubPrefix}_{_hubName}"; - private static readonly RestApiProvider _restApiProvider = new RestApiProvider(_connectionString, _hubName); + private static readonly RestApiProvider _restApiProvider = new RestApiProvider(_connectionString, _hubName, _hubPrefix); [Theory] [MemberData(nameof(GetTestData))] diff --git a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs index 22566cea7..718132204 100644 --- a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs +++ b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs @@ -15,12 +15,15 @@ public class ServiceManagerFacts private const string AccessKey = "nOu3jXsHnsO5urMumc87M9skQbUWuQ+PE5IvSUEic8w="; private const string HubName = "signalrBench"; private const string UserId = "UserA"; + private const string _hubPrefix = "hubPrefix"; private static readonly string _clientEndpoint = $"{Endpoint}/client/?hub={HubName.ToLower()}"; + private static readonly string _clientEndpointWithHubPrefix = $"{Endpoint}/client/?hub={_hubPrefix.ToLower()}_{HubName.ToLower()}"; private static readonly string _testConnectionString = $"Endpoint={Endpoint};AccessKey={AccessKey};Version=1.0;"; private static readonly TimeSpan _tokenLifeTime = TimeSpan.FromSeconds(99); private static readonly ServiceManagerOptions _serviceManagerOptions = new ServiceManagerOptions { - ConnectionString = _testConnectionString + ConnectionString = _testConnectionString, + }; private static readonly ServiceManager _serviceManager = new ServiceManager(_serviceManagerOptions); private static readonly Claim[] _defaultClaims = new Claim[] { new Claim("type1", "val1") }; @@ -67,5 +70,14 @@ internal void GenerateClientEndpointTest() Assert.Equal(_clientEndpoint, clientEndpoint); } + + [Fact] + internal void GenerateClientEndpointWithHubPrefixTest() + { + var manager = new ServiceManager(new ServiceManagerOptions() { ConnectionString = _testConnectionString, HubPrefix = _hubPrefix }); + var clientEndpoint = manager.GetClientEndpoint(HubName); + + Assert.Equal(_clientEndpointWithHubPrefix, clientEndpoint); + } } } diff --git a/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs b/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs index 4ebe973ae..6626f08ba 100644 --- a/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs +++ b/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs @@ -104,6 +104,37 @@ public void GenerateNegotiateResponseWithPathAndQuery(string path, string queryS Assert.EndsWith($"?hub=chat&{expectedQueryString}", negotiateResponse.Url); } + [Theory] + [InlineData("", "?hub=chat")] + [InlineData("hubPrefix", "?hub=hubprefix_chat")] + public void GenerateNegotiateResponseWithHubPrefix(string hubPrefix, string expectedResponse) + { + var config = new ConfigurationBuilder().Build(); + var serviceProvider = new ServiceCollection().AddSignalR() + .AddAzureSignalR(o => + { + o.ConnectionString = DefaultConnectionString; + o.HubPrefix = hubPrefix; + }) + .Services + .AddLogging() + .AddSingleton(config) + .BuildServiceProvider(); + + var requestFeature = new HttpRequestFeature + { + }; + var features = new FeatureCollection(); + features.Set(requestFeature); + var httpContext = new DefaultHttpContext(features); + + var handler = serviceProvider.GetRequiredService(); + var negotiateResponse = handler.Process(httpContext, "chat"); + + Assert.NotNull(negotiateResponse); + Assert.EndsWith(expectedResponse, negotiateResponse.Url); + } + [Theory] [InlineData(typeof(ConnectionIdUserIdProvider), ServiceHubConnectionContext.ConnectionIdUnavailableError)] [InlineData(typeof(ConnectionAbortedTokenUserIdProvider), ServiceHubConnectionContext.ConnectionAbortedUnavailableError)] @@ -130,6 +161,44 @@ public void CustomUserIdProviderAccessUnavailablePropertyThrowsException(Type ty Assert.Equal(errorMessage, exception.Message); } + [Fact] + public void TestNegotiateHandlerWithMultipleEndpointsAndCustomerRouterAndHubPrefix() + { + var config = new ConfigurationBuilder().Build(); + var router = new TestCustomRouter(ConnectionString3); + var serviceProvider = new ServiceCollection().AddSignalR() + .AddAzureSignalR(o => + { + o.HubPrefix = "testprefix"; + o.Endpoints = new ServiceEndpoint[] + { + new ServiceEndpoint(ConnectionString2), + new ServiceEndpoint(ConnectionString3), + new ServiceEndpoint(ConnectionString4), + }; + }) + .Services + .AddLogging() + .AddSingleton(router) + .AddSingleton(config) + .BuildServiceProvider(); + + var requestFeature = new HttpRequestFeature + { + Path = "/user/path/negotiate/", + }; + + var features = new FeatureCollection(); + features.Set(requestFeature); + var httpContext = new DefaultHttpContext(features); + + var handler = serviceProvider.GetRequiredService(); + var negotiateResponse = handler.Process(httpContext, "chat"); + + Assert.NotNull(negotiateResponse); + Assert.Equal($"http://localhost3/client/?hub=testprefix_chat&asrs.op=%2Fuser%2Fpath", negotiateResponse.Url); + } + [Fact] public void TestNegotiateHandlerWithMultipleEndpointsAndCustomRouter() { diff --git a/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs b/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs index b6f4a9ee4..ea3c1257e 100644 --- a/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs +++ b/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs @@ -14,6 +14,7 @@ public class ServiceEndpointProviderFacts private const string Endpoint = "https://myendpoint"; private const string AccessKey = "nOu3jXsHnsO5urMumc87M9skQbUWuQ+PE5IvSUEic8w="; private static readonly string HubName = nameof(TestHub).ToLower(); + private static readonly string HubPrefix = "testprefix"; private static readonly string ConnectionStringWithoutVersion = $"Endpoint={Endpoint};AccessKey={AccessKey};"; @@ -30,6 +31,13 @@ public class ServiceEndpointProviderFacts new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version)) }; + private static readonly ServiceEndpointProvider[] EndpointProviderArrayWithPrefix = +{ + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithoutVersion, hubPrefix: HubPrefix)), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithPreviewVersion, hubPrefix: HubPrefix)), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version, hubPrefix: HubPrefix)) + }; + private static readonly (string path, string queryString, string expectedQuery)[] PathAndQueryArray = { ("", "", ""), @@ -50,6 +58,14 @@ from provider in EndpointProviderArray from t in PathAndQueryArray select new object[] { provider, t.path, t.queryString, t.expectedQuery} ; + public static IEnumerable DefaultEndpointProvidersWithPathPlusPrefix => + from provider in EndpointProviderArrayWithPrefix + from t in PathAndQueryArray + select new object[] { provider, t.path, t.queryString, t.expectedQuery }; + + public static IEnumerable DefaultEndpointProvidersPlusPrefix => + EndpointProviderArrayWithPrefix.Select(provider => new object[] { provider }); + [Theory] [MemberData(nameof(DefaultEndpointProviders))] internal void GetServerEndpoint(IServiceEndpointProvider provider) @@ -68,6 +84,24 @@ internal void GetClientEndpoint(IServiceEndpointProvider provider, string path, Assert.Equal(expected, actual); } + [Theory] + [MemberData(nameof(DefaultEndpointProvidersPlusPrefix))] + internal void GetServerEndpointWithHubPrefix(IServiceEndpointProvider provider) + { + var expected = $"{Endpoint}/server/?hub={HubPrefix}_{HubName}"; + var actual = provider.GetServerEndpoint(nameof(TestHub)); + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(DefaultEndpointProvidersWithPathPlusPrefix))] + internal void GetClientEndpointWithHubPrefix(IServiceEndpointProvider provider, string path, string queryString, string expectedQueryString) + { + var expected = $"{Endpoint}/client/?hub={HubPrefix}_{HubName}{expectedQueryString}"; + var actual = provider.GetClientEndpoint(HubName, path, queryString); + Assert.Equal(expected, actual); + } + [Fact] internal void GenerateMutlipleAccessTokenShouldBeUnique() { @@ -107,6 +141,28 @@ internal void GenerateServerAccessToken(IServiceEndpointProvider provider) Assert.Equal(expectedTokenString, tokenString); } + [Theory] + [MemberData(nameof(DefaultEndpointProvidersPlusPrefix))] + internal void GenerateServerAccessTokenWithPrefix(IServiceEndpointProvider provider) + { + const string userId = "UserA"; + var tokenString = provider.GenerateServerAccessToken(nameof(TestHub), userId, requestId: string.Empty); + var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); + + var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/server/?hub={HubPrefix}_{HubName}", + new[] + { + new Claim(ClaimTypes.NameIdentifier, userId) + }, + token.ValidTo, + token.ValidFrom, + token.ValidFrom, + AccessKey, + string.Empty); + + Assert.Equal(expectedTokenString, tokenString); + } + [Theory] [MemberData(nameof(DefaultEndpointProviders))] internal void GenerateClientAccessToken(IServiceEndpointProvider provider) @@ -124,6 +180,25 @@ internal void GenerateClientAccessToken(IServiceEndpointProvider provider) requestId); Assert.Equal(expectedTokenString, tokenString); + } + + [Theory] + [MemberData(nameof(DefaultEndpointProvidersPlusPrefix))] + internal void GenerateClientAccessTokenWithPrefix(IServiceEndpointProvider provider) + { + var requestId = Guid.NewGuid().ToString(); + var tokenString = provider.GenerateClientAccessToken(HubName, requestId: requestId); + var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); + + var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/client/?hub={HubPrefix}_{HubName}", + null, + token.ValidTo, + token.ValidFrom, + token.ValidFrom, + AccessKey, + requestId); + + Assert.Equal(expectedTokenString, tokenString); } } } From c90c34c0143e544cf691b356d9dc7bfd7d0c33aa Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Thu, 21 Mar 2019 15:15:37 +0000 Subject: [PATCH 02/13] Fix merge issues --- .../Endpoints/ServiceEndpointManagerBase.cs | 6 ------ .../Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs | 7 ++++--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs index 46eaf06bf..1a6ad8f15 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs @@ -72,12 +72,6 @@ private static IEnumerable GetEndpoints(IServiceEndpointOptions // ConnectionString can be set by custom Configure // Return both the one from ConnectionString and from Endpoints - // TODO: Better way if Endpoints already contains ConnectionString one? - if (!string.IsNullOrEmpty(connectionString)) - { - yield return new ServiceEndpoint(options.ConnectionString, hubPrefix: options.HubPrefix); - } - // when the one from connectionString is not included in Endpoints var connectionStringIncluded = false; if (endpoints != null) diff --git a/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs b/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs index ac16fef8b..a58337b97 100644 --- a/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs +++ b/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs @@ -166,7 +166,7 @@ public void CustomUserIdProviderAccessUnavailablePropertyThrowsException(Type ty public void TestNegotiateHandlerWithMultipleEndpointsAndCustomerRouterAndHubPrefix() { var config = new ConfigurationBuilder().Build(); - var router = new TestCustomRouter(ConnectionString3); + var router = new TestCustomRouter(); var serviceProvider = new ServiceCollection().AddSignalR() .AddAzureSignalR(o => { @@ -174,7 +174,7 @@ public void TestNegotiateHandlerWithMultipleEndpointsAndCustomerRouterAndHubPref o.Endpoints = new ServiceEndpoint[] { new ServiceEndpoint(ConnectionString2), - new ServiceEndpoint(ConnectionString3), + new ServiceEndpoint(ConnectionString3, name: "chosen"), new ServiceEndpoint(ConnectionString4), }; }) @@ -187,6 +187,7 @@ public void TestNegotiateHandlerWithMultipleEndpointsAndCustomerRouterAndHubPref var requestFeature = new HttpRequestFeature { Path = "/user/path/negotiate/", + QueryString = "?endpoint=chosen" }; var features = new FeatureCollection(); @@ -197,7 +198,7 @@ public void TestNegotiateHandlerWithMultipleEndpointsAndCustomerRouterAndHubPref var negotiateResponse = handler.Process(httpContext, "chat"); Assert.NotNull(negotiateResponse); - Assert.Equal($"http://localhost3/client/?hub=testprefix_chat&asrs.op=%2Fuser%2Fpath", negotiateResponse.Url); + Assert.Equal($"http://localhost3/client/?hub=testprefix_chat&asrs.op=%2Fuser%2Fpath&endpoint=chosen", negotiateResponse.Url); } [Fact] From c9df065c8e96f7bc7aceeebf99cc1aabdbe8315e Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Thu, 21 Mar 2019 15:19:21 +0000 Subject: [PATCH 03/13] Fix merge issue --- .../Endpoints/ServiceEndpointManagerBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs index 1a6ad8f15..cf5ba13be 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs @@ -90,7 +90,7 @@ private static IEnumerable GetEndpoints(IServiceEndpointOptions if (!string.IsNullOrEmpty(connectionString) && !connectionStringIncluded) { - yield return new ServiceEndpoint(options.ConnectionString); + yield return new ServiceEndpoint(options.ConnectionString, hubPrefix: options.HubPrefix); } } From 010c8fadc347b33395d58479c4a963b75021ff1f Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Tue, 2 Apr 2019 07:47:08 +0100 Subject: [PATCH 04/13] ASP.NET include hubprefix on endpoint provider --- .../ServiceEndpointProvider.cs | 10 ++++-- .../ServiceEndpointProviderTests.cs | 34 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs index fb6ce6037..7e380acd2 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs @@ -21,6 +21,7 @@ internal class ServiceEndpointProvider : IServiceEndpointProvider private readonly string _endpoint; private readonly string _accessKey; + private readonly string _hubPrefix; private readonly int? _port; private readonly TimeSpan _accessTokenLifetime; @@ -37,6 +38,7 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) // Version is ignored for aspnet signalr case _endpoint = endpoint.Endpoint; _accessKey = endpoint.AccessKey; + _hubPrefix = endpoint.HubPrefix; _port = endpoint.Port; } @@ -57,7 +59,8 @@ public string GenerateServerAccessToken(string hubName, string userId, TimeSpan? }; } - var audience = $"{_endpoint}/{ServerPath}/?hub={hubName.ToLower()}"; + var prefixedHubName = string.IsNullOrEmpty(_hubPrefix) ? hubName.ToLower() : $"{_hubPrefix.ToLower()}_{hubName.ToLower()}"; + var audience = $"{_endpoint}/{ServerPath}/?hub={prefixedHubName.ToLower()}"; return AuthenticationHelper.GenerateAccessToken(_accessKey, audience, claims, lifetime ?? _accessTokenLifetime, requestId); } @@ -95,9 +98,10 @@ public string GetClientEndpoint(string hubName = null, string originalPath = nul public string GetServerEndpoint(string hubName) { + var prefixedHubName = string.IsNullOrEmpty(_hubPrefix) ? hubName.ToLower() : $"{_hubPrefix.ToLower()}_{hubName.ToLower()}"; return _port.HasValue ? - $"{_endpoint}:{_port}/{ServerPath}/?hub={hubName.ToLower()}" : - $"{_endpoint}/{ServerPath}/?hub={hubName.ToLower()}"; + $"{_endpoint}:{_port}/{ServerPath}/?hub={prefixedHubName.ToLower()}" : + $"{_endpoint}/{ServerPath}/?hub={prefixedHubName.ToLower()}"; } } } diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs index 09d2b4c07..dc89764e0 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs @@ -80,6 +80,27 @@ public void TestGenerateServerAccessToken(string connectionString, string expect Assert.Equal("user1", principal.FindFirst(ClaimTypes.NameIdentifier).Value); } + [Theory] + [InlineData("Endpoint=http://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;Port=8080;Version=1.0", "http://localhost/aspnetserver/?hub=prefix_hub1")] + [InlineData("Endpoint=http://localhost/;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;Port=8080;Version=1.0", "http://localhost/aspnetserver/?hub=prefix_hub1")] + [InlineData("Endpoint=https://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;", "https://localhost/aspnetserver/?hub=prefix_hub1")] + public void TestGenerateServerAccessTokenWIthPrefix(string connectionString, string expectedAudience) + { + var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString, hubPrefix: "prefix")); + + var clientToken = provider.GenerateServerAccessToken("hub1", "user1"); + + var handler = new JwtSecurityTokenHandler(); + var principal = handler.ValidateToken(clientToken, new TokenValidationParameters + { + ValidateIssuer = false, + IssuerSigningKey = SecurityKey, + ValidAudience = expectedAudience + }, out var token); + + Assert.Equal("user1", principal.FindFirst(ClaimTypes.NameIdentifier).Value); + } + [Theory] [InlineData("Endpoint=http://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;Port=8080;Version=1.0", "http://localhost:8080/aspnetserver/?hub=hub1")] [InlineData("Endpoint=http://localhost/;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;Port=8080;Version=1.0", "http://localhost:8080/aspnetserver/?hub=hub1")] @@ -93,6 +114,19 @@ public void TestGenerateServerEndpoint(string connectionString, string expectedE Assert.Equal(expectedEndpoint, clientEndpoint); } + [Theory] + [InlineData("Endpoint=http://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;Port=8080;Version=1.0", "http://localhost:8080/aspnetserver/?hub=prefix_hub1")] + [InlineData("Endpoint=http://localhost/;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;Port=8080;Version=1.0", "http://localhost:8080/aspnetserver/?hub=prefix_hub1")] + [InlineData("Endpoint=https://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;", "https://localhost/aspnetserver/?hub=prefix_hub1")] + public void TestGenerateServerEndpointWithPrefix(string connectionString, string expectedEndpoint) + { + var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString, hubPrefix: "prefix")); + + var clientEndpoint = provider.GetServerEndpoint("hub1"); + + Assert.Equal(expectedEndpoint, clientEndpoint); + } + [Fact] public void GenerateMutlipleAccessTokenShouldBeUnique() { From 5d13383c61a0936e70ed0d8d706ff13928470d62 Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Tue, 2 Apr 2019 09:32:12 +0100 Subject: [PATCH 05/13] Rename HubPrefix to ApplicationName --- .../ServiceEndpointProvider.cs | 8 +++---- .../OwinExtensions.cs | 15 ++++++++++++- .../ServiceOptions.cs | 12 +++++----- .../Constants.cs | 4 ++-- .../Endpoints/IServiceEndpointOptions.cs | 2 +- .../Endpoints/ServiceEndpoint.cs | 8 +++---- .../Endpoints/ServiceEndpointManagerBase.cs | 4 ++-- .../RestApiProvider.cs | 12 +++++----- .../RestHubLifetimeManager.cs | 2 +- .../ServiceManager.cs | 2 +- .../ServiceManagerOptions.cs | 4 ++-- .../DefaultServiceEndpointGenerator.cs | 22 +++++++++---------- .../ServiceEndpointProvider.cs | 2 +- src/Microsoft.Azure.SignalR/ServiceOptions.cs | 2 +- .../ServiceOptionsSetup.cs | 22 +++++++++---------- .../RunAzureSignalRTests.cs | 21 +++++++++--------- .../ServiceEndpointProviderTests.cs | 4 ++-- .../UnitTests/RestApiProviderFacts.cs | 6 ++--- .../UnitTests/ServiceManagerFacts.cs | 10 ++++----- .../NegotiateHandlerFacts.cs | 10 ++++----- .../ServiceEndpointProviderFacts.cs | 20 ++++++++--------- 21 files changed, 103 insertions(+), 89 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs index 7e380acd2..9e309ceaa 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs @@ -21,7 +21,7 @@ internal class ServiceEndpointProvider : IServiceEndpointProvider private readonly string _endpoint; private readonly string _accessKey; - private readonly string _hubPrefix; + private readonly string _appName; private readonly int? _port; private readonly TimeSpan _accessTokenLifetime; @@ -38,7 +38,7 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) // Version is ignored for aspnet signalr case _endpoint = endpoint.Endpoint; _accessKey = endpoint.AccessKey; - _hubPrefix = endpoint.HubPrefix; + _appName = endpoint.ApplicationName; _port = endpoint.Port; } @@ -59,7 +59,7 @@ public string GenerateServerAccessToken(string hubName, string userId, TimeSpan? }; } - var prefixedHubName = string.IsNullOrEmpty(_hubPrefix) ? hubName.ToLower() : $"{_hubPrefix.ToLower()}_{hubName.ToLower()}"; + var prefixedHubName = string.IsNullOrEmpty(_appName) ? hubName.ToLower() : $"{_appName.ToLower()}_{hubName.ToLower()}"; var audience = $"{_endpoint}/{ServerPath}/?hub={prefixedHubName.ToLower()}"; return AuthenticationHelper.GenerateAccessToken(_accessKey, audience, claims, lifetime ?? _accessTokenLifetime, requestId); @@ -98,7 +98,7 @@ public string GetClientEndpoint(string hubName = null, string originalPath = nul public string GetServerEndpoint(string hubName) { - var prefixedHubName = string.IsNullOrEmpty(_hubPrefix) ? hubName.ToLower() : $"{_hubPrefix.ToLower()}_{hubName.ToLower()}"; + var prefixedHubName = string.IsNullOrEmpty(_appName) ? hubName.ToLower() : $"{_appName.ToLower()}_{hubName.ToLower()}"; return _port.HasValue ? $"{_endpoint}:{_port}/{ServerPath}/?hub={prefixedHubName.ToLower()}" : $"{_endpoint}/{ServerPath}/?hub={prefixedHubName.ToLower()}"; diff --git a/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs b/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs index 0e3a57342..a8c5c8631 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs @@ -144,7 +144,11 @@ public static void RunAzureSignalR(this IAppBuilder builder, string applicationN /// The hub configuration . public static void RunAzureSignalR(this IAppBuilder builder, string applicationName, string connectionString, HubConfiguration configuration) { - RunAzureSignalR(builder, applicationName, configuration, s => s.ConnectionString = connectionString); + RunAzureSignalR(builder, applicationName, configuration, s => + { + s.ConnectionString = connectionString; + s.ApplicationName = applicationName; + }); } @@ -181,6 +185,15 @@ private static void RunAzureSignalRCore(IAppBuilder builder, string applicationN throw new ArgumentException(nameof(applicationName), "Empty application name is not allowed."); } + if (!string.IsNullOrEmpty(options.ApplicationName) && + !options.ApplicationName.Equals(applicationName, StringComparison.InvariantCultureIgnoreCase)) + { + throw new ArgumentException(nameof(applicationName), "Options application name (if supplied) must be the same as application name."); + } + + //Options ApplicationName must be the same as the applicationName passed in. + options.ApplicationName = applicationName; + if (configuration == null) { // Keep the same as SignalR's exception diff --git a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs index 61172d381..b91e23fde 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs @@ -28,7 +28,7 @@ public class ServiceOptions : IServiceEndpointOptions /// /// Gets or sets the prefix to apply to each hub name /// - public string HubPrefix{ get; set; } + public string ApplicationName{ get; set; } /// /// Gets or sets the func to generate claims from . @@ -52,7 +52,7 @@ public ServiceOptions() for (int i = 0; i < count; i++) { var setting = ConfigurationManager.ConnectionStrings[i]; - var (isDefault, endpoint) = GetEndpoint(setting.Name, this.HubPrefix, () => setting.ConnectionString); + var (isDefault, endpoint) = GetEndpoint(setting.Name, this.ApplicationName, () => setting.ConnectionString); if (endpoint != null) { if (isDefault) @@ -69,7 +69,7 @@ public ServiceOptions() // Fallback to use AppSettings foreach(var key in ConfigurationManager.AppSettings.AllKeys) { - var (isDefault, endpoint) = GetEndpoint(key, this.HubPrefix, () => ConfigurationManager.AppSettings[key]); + var (isDefault, endpoint) = GetEndpoint(key, this.ApplicationName, () => ConfigurationManager.AppSettings[key]); if (endpoint != null) { if (isDefault) @@ -86,16 +86,16 @@ public ServiceOptions() Endpoints = endpoints.ToArray(); } - private static (bool isDefault, ServiceEndpoint endpoint) GetEndpoint(string key, string hubPrefix, Func valueGetter) + private static (bool isDefault, ServiceEndpoint endpoint) GetEndpoint(string key, string appName, Func valueGetter) { if (key == Constants.ConnectionStringDefaultKey && !string.IsNullOrEmpty(valueGetter())) { - return (true, new ServiceEndpoint(valueGetter(), hubPrefix: hubPrefix)); + return (true, new ServiceEndpoint(valueGetter(), applicationName: appName)); } if (key.StartsWith(Constants.ConnectionStringKeyPrefix) && !string.IsNullOrEmpty(valueGetter())) { - return (false, new ServiceEndpoint(key, valueGetter(), hubPrefix)); + return (false, new ServiceEndpoint(key, valueGetter(), appName)); } return (false, null); diff --git a/src/Microsoft.Azure.SignalR.Common/Constants.cs b/src/Microsoft.Azure.SignalR.Common/Constants.cs index c9785deda..2a715b700 100644 --- a/src/Microsoft.Azure.SignalR.Common/Constants.cs +++ b/src/Microsoft.Azure.SignalR.Common/Constants.cs @@ -8,14 +8,14 @@ namespace Microsoft.Azure.SignalR internal static class Constants { public const string ConnectionStringDefaultKey = "Azure:SignalR:ConnectionString"; - public const string HubPrefixDefaultKey = "Azure:SignalR:HubPrefix"; + public const string ApplicationNameDefaultKey = "Azure:SignalR:ApplicationName"; public static readonly string ConnectionStringSecondaryKey = $"ConnectionStrings:{ConnectionStringDefaultKey}"; public static readonly string ConnectionStringKeyPrefix = $"{ConnectionStringDefaultKey}:"; - public static readonly string HubPrefixDefaultKeyPrefix = $"{HubPrefixDefaultKey}:"; + public static readonly string ApplicationNameDefaultKeyPrefix = $"{ApplicationNameDefaultKey}:"; public static readonly string ConnectionStringSecondaryKeyPrefix = $"{ConnectionStringSecondaryKey}:"; diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs index 827d04143..a881e9ea2 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/IServiceEndpointOptions.cs @@ -6,7 +6,7 @@ namespace Microsoft.Azure.SignalR internal interface IServiceEndpointOptions { ServiceEndpoint[] Endpoints { get; } - string HubPrefix { get; } + string ApplicationName { get; } string ConnectionString { get; } } } diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs index be9501989..c7c9d7b3c 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs @@ -28,11 +28,11 @@ public class ServiceEndpoint internal int? Port { get; } - internal string HubPrefix { get; set; } + internal string ApplicationName { get; set; } internal IServiceConnectionContainer Connection { get; set; } - public ServiceEndpoint(string key, string connectionString, string hubPrefix = "") : this(connectionString, hubPrefix: hubPrefix) + public ServiceEndpoint(string key, string connectionString, string applicationName = "") : this(connectionString, applicationName: applicationName) { if (!string.IsNullOrEmpty(key)) { @@ -40,7 +40,7 @@ public ServiceEndpoint(string key, string connectionString, string hubPrefix = " } } - public ServiceEndpoint(string connectionString, EndpointType type = EndpointType.Primary, string name = "", string hubPrefix = "") + public ServiceEndpoint(string connectionString, EndpointType type = EndpointType.Primary, string name = "", string applicationName = "") { // The provider is responsible to check if the connection string is empty and throw correct error message if (!string.IsNullOrEmpty(connectionString)) @@ -51,7 +51,7 @@ public ServiceEndpoint(string connectionString, EndpointType type = EndpointType EndpointType = type; ConnectionString = connectionString; Name = name; - HubPrefix = hubPrefix; + ApplicationName = applicationName; } public override string ToString() diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs index cf5ba13be..a9166f259 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs @@ -78,7 +78,7 @@ private static IEnumerable GetEndpoints(IServiceEndpointOptions { foreach (var endpoint in endpoints) { - endpoint.HubPrefix = options.HubPrefix; + endpoint.ApplicationName = options.ApplicationName; if (endpoint.ConnectionString == connectionString) { connectionStringIncluded = true; @@ -90,7 +90,7 @@ private static IEnumerable GetEndpoints(IServiceEndpointOptions if (!string.IsNullOrEmpty(connectionString) && !connectionStringIncluded) { - yield return new ServiceEndpoint(options.ConnectionString, hubPrefix: options.HubPrefix); + yield return new ServiceEndpoint(options.ConnectionString, applicationName: options.ApplicationName); } } diff --git a/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs b/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs index cad3d62a4..22f598f2b 100644 --- a/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs +++ b/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs @@ -10,27 +10,27 @@ internal class RestApiProvider private readonly RestApiAccessTokenGenerator _restApiAccessTokenGenerator; private readonly string _baseEndpoint; private readonly string _hubName; - private readonly string _hubPrefix; + private readonly string _appName; private readonly string _requestPrefix; private readonly string _audiencePrefix; private readonly int? _port; - public RestApiProvider(string connectionString, string hubName, string hubPrefix) + public RestApiProvider(string connectionString, string hubName, string appName) { string accessKey; (_baseEndpoint, accessKey, _, _port) = ConnectionStringParser.Parse(connectionString); _hubName = hubName; - _hubPrefix = hubPrefix; + _appName = appName.ToLower(); _restApiAccessTokenGenerator = new RestApiAccessTokenGenerator(accessKey); - if (string.IsNullOrEmpty(_hubPrefix)) + if (string.IsNullOrEmpty(_appName)) { _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_hubName}"; _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_hubName}"; } else { - _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_hubPrefix}_{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_hubPrefix}_{_hubName}"; - _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_hubPrefix}_{_hubName}"; + _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_appName}_{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_appName}_{_hubName}"; + _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_appName}_{_hubName}"; } } diff --git a/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs b/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs index c1a254911..c9097408d 100644 --- a/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs +++ b/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs @@ -23,7 +23,7 @@ internal class RestHubLifetimeManager : HubLifetimeManager, IHubLifetimeMan public RestHubLifetimeManager(ServiceManagerOptions serviceManagerOptions, string hubName) { - _restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, serviceManagerOptions.HubPrefix, hubName); + _restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, serviceManagerOptions.ApplicationName, hubName); } public override Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) diff --git a/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs b/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs index beae9a85a..0c0017ce7 100644 --- a/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs +++ b/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs @@ -26,7 +26,7 @@ internal class ServiceManager : IServiceManager internal ServiceManager(ServiceManagerOptions serviceManagerOptions) { _serviceManagerOptions = serviceManagerOptions; - _endpoint = new ServiceEndpoint(_serviceManagerOptions.ConnectionString, EndpointType.Secondary, hubPrefix: _serviceManagerOptions.HubPrefix); + _endpoint = new ServiceEndpoint(_serviceManagerOptions.ConnectionString, EndpointType.Secondary, applicationName: _serviceManagerOptions.ApplicationName); _endpointProvider = new ServiceEndpointProvider(_endpoint); } diff --git a/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs b/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs index fb3b498ac..26a5aefde 100644 --- a/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs +++ b/src/Microsoft.Azure.SignalR.Management/ServiceManagerOptions.cs @@ -22,9 +22,9 @@ public class ServiceManagerOptions public string ConnectionString { get; set; } = null; /// - /// Gets or sets the prefix to apply to each hub name + /// Gets or sets the ApplicationName which will be prefixed to each hub name /// - public string HubPrefix { get; set; } + public string ApplicationName { get; set; } internal void ValidateOptions() { diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs index 6d6ab5a2d..40a5d9216 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs @@ -17,21 +17,21 @@ internal sealed class DefaultServiceEndpointGenerator : IServiceEndpointGenerato public string Version { get; } - public string HubPrefix { get; } + public string ApplicationName { get; } public int? Port { get; } - public DefaultServiceEndpointGenerator(string endpoint, string accessKey, string version, int? port, string hubPrefix) + public DefaultServiceEndpointGenerator(string endpoint, string accessKey, string version, int? port, string applicationName) { Endpoint = endpoint; AccessKey = accessKey; Version = version; Port = port; - HubPrefix = hubPrefix; + ApplicationName = applicationName; } public string GetClientAudience(string hubName) => - InternalGetAudience(ClientPath, hubName, HubPrefix); + InternalGetAudience(ClientPath, hubName, ApplicationName); public string GetClientEndpoint(string hubName, string originalPath, string queryString) @@ -50,26 +50,26 @@ public string GetClientEndpoint(string hubName, string originalPath, string quer queryBuilder.Append("&").Append(queryString); } - return $"{InternalGetEndpoint(ClientPath, hubName, HubPrefix)}{queryBuilder}"; + return $"{InternalGetEndpoint(ClientPath, hubName, ApplicationName)}{queryBuilder}"; } public string GetServerAudience(string hubName) => - InternalGetAudience(ServerPath, hubName, HubPrefix); + InternalGetAudience(ServerPath, hubName, ApplicationName); public string GetServerEndpoint(string hubName) => - InternalGetEndpoint(ServerPath, hubName, HubPrefix); + InternalGetEndpoint(ServerPath, hubName, ApplicationName); - private string InternalGetEndpoint(string path, string hubName, string hubPrefix) + private string InternalGetEndpoint(string path, string hubName, string applicationName) { - var prefixedHubName = string.IsNullOrEmpty(hubPrefix) ? hubName.ToLower() : $"{hubPrefix.ToLower()}_{hubName.ToLower()}"; + var prefixedHubName = string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}"; return Port.HasValue ? $"{Endpoint}:{Port}/{path}/?hub={prefixedHubName}" : $"{Endpoint}/{path}/?hub={prefixedHubName}"; } - private string InternalGetAudience(string path, string hubName, string hubPrefix) + private string InternalGetAudience(string path, string hubName, string applicationName) { - var prefixedHubName = string.IsNullOrEmpty(hubPrefix) ? hubName.ToLower() : $"{hubPrefix.ToLower()}_{hubName.ToLower()}"; + var prefixedHubName = string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}"; return $"{Endpoint}/{path}/?hub={prefixedHubName}"; } } diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs index 0b5526515..613c1644d 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs @@ -35,7 +35,7 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) var port = endpoint.Port; var version = endpoint.Version; - _generator = new DefaultServiceEndpointGenerator(_endpoint, _accessKey, version, port, endpoint.HubPrefix); + _generator = new DefaultServiceEndpointGenerator(_endpoint, _accessKey, version, port, endpoint.ApplicationName); } public string GenerateClientAccessToken(string hubName, IEnumerable claims = null, TimeSpan? lifetime = null, string requestId = null) diff --git a/src/Microsoft.Azure.SignalR/ServiceOptions.cs b/src/Microsoft.Azure.SignalR/ServiceOptions.cs index fade6ef4e..0842113ff 100644 --- a/src/Microsoft.Azure.SignalR/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR/ServiceOptions.cs @@ -26,7 +26,7 @@ public class ServiceOptions : IServiceEndpointOptions /// /// Gets or sets the prefix to apply to each hub name /// - public string HubPrefix { get; set; } + public string ApplicationName { get; set; } /// /// Gets or sets the func to generate claims from . diff --git a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs index 6d8bd54dc..566e430ec 100644 --- a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs +++ b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs @@ -10,37 +10,37 @@ namespace Microsoft.Azure.SignalR { internal class ServiceOptionsSetup : IConfigureOptions { - private readonly string _hubPrefix; + private readonly string _appName; private readonly string _connectionString; private readonly ServiceEndpoint[] _endpoints; public ServiceOptionsSetup(IConfiguration configuration) { - _hubPrefix = GetHubPrefix(configuration); + _appName = GetAppName(configuration); - var (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringDefaultKey, Constants.ConnectionStringKeyPrefix, _hubPrefix); + var (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringDefaultKey, Constants.ConnectionStringKeyPrefix, _appName); // Fallback to ConnectionStrings:Azure:SignalR:ConnectionString format when the default one is not available if (endpoints.Count == 0) { - (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringSecondaryKey, Constants.ConnectionStringSecondaryKeyPrefix, _hubPrefix); + (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringSecondaryKey, Constants.ConnectionStringSecondaryKeyPrefix, _appName); } _connectionString = connectionString; _endpoints = endpoints.ToArray(); } - private string GetHubPrefix(IConfiguration configuration) + private string GetAppName(IConfiguration configuration) { foreach (var pair in configuration.AsEnumerable()) { var key = pair.Key; - if (key == Constants.HubPrefixDefaultKey && !string.IsNullOrEmpty(pair.Value)) + if (key == Constants.ApplicationNameDefaultKey && !string.IsNullOrEmpty(pair.Value)) { return pair.Value; } - if (key.StartsWith(Constants.HubPrefixDefaultKeyPrefix) && !string.IsNullOrEmpty(pair.Value)) + if (key.StartsWith(Constants.ApplicationNameDefaultKeyPrefix) && !string.IsNullOrEmpty(pair.Value)) { return pair.Value; } @@ -53,10 +53,10 @@ public void Configure(ServiceOptions options) // The default setup of ServiceOptions options.ConnectionString = _connectionString; options.Endpoints = _endpoints; - options.HubPrefix = _hubPrefix; + options.ApplicationName = _appName; } - private static (string, List) GetEndpoint(IConfiguration configuration, string defaultKey, string keyPrefix, string hubPrefix) + private static (string, List) GetEndpoint(IConfiguration configuration, string defaultKey, string keyPrefix, string applicationName) { var endpoints = new List(); string connectionString = null; @@ -66,12 +66,12 @@ private static (string, List) GetEndpoint(IConfiguration config if (key == defaultKey && !string.IsNullOrEmpty(pair.Value)) { connectionString = pair.Value; - endpoints.Add(new ServiceEndpoint(pair.Value, hubPrefix: hubPrefix)); + endpoints.Add(new ServiceEndpoint(pair.Value, applicationName: applicationName)); } if (key.StartsWith(keyPrefix) && !string.IsNullOrEmpty(pair.Value)) { - endpoints.Add(new ServiceEndpoint(key, pair.Value, hubPrefix)); + endpoints.Add(new ServiceEndpoint(key, pair.Value, applicationName)); } } diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs index c19594115..1831572ef 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs @@ -33,7 +33,6 @@ public class RunAzureSignalRTests : VerifiableLoggedTest private const string ConnectionString2 = "Endpoint=http://localhost2;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;"; private const string ConnectionString3 = "Endpoint=http://localhost3;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;"; private const string ConnectionString4 = "Endpoint=http://localhost4;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;"; - private const string HubPrefix = "testprefix"; private const string AppName = "AzureSignalRTest"; public RunAzureSignalRTests(ITestOutputHelper output) : base(output) @@ -187,8 +186,9 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettings() } [Fact] - public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncludingHubPrefix() + public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncludingOptionsAppName() { + const string optionsAppName = AppName; // Prepare the configuration using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) using (new AppSettingsConfigScope(ConnectionString, ConnectionString2)) @@ -196,7 +196,7 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var hubConfig = Utility.GetTestHubConfig(loggerFactory); using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, options => { - options.HubPrefix = HubPrefix; + options.ApplicationName = optionsAppName; options.Endpoints = new ServiceEndpoint[] { new ServiceEndpoint(ConnectionString2, EndpointType.Secondary), @@ -208,7 +208,7 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var options = hubConfig.Resolver.Resolve>(); Assert.Equal(ConnectionString, options.Value.ConnectionString); - Assert.Equal(HubPrefix, options.Value.HubPrefix); + Assert.Equal(optionsAppName, options.Value.ApplicationName); Assert.Equal(3, options.Value.Endpoints.Length); @@ -216,10 +216,10 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var endpoints = manager.GetAvailableEndpoints().ToArray(); Assert.Equal(4, endpoints.Length); - Assert.Equal(HubPrefix, endpoints[0].HubPrefix); - Assert.Equal(HubPrefix, endpoints[1].HubPrefix); - Assert.Equal(HubPrefix, endpoints[2].HubPrefix); - Assert.Equal(HubPrefix, endpoints[3].HubPrefix); + Assert.Equal(optionsAppName, endpoints[0].ApplicationName); + Assert.Equal(optionsAppName, endpoints[1].ApplicationName); + Assert.Equal(optionsAppName, endpoints[2].ApplicationName); + Assert.Equal(optionsAppName, endpoints[3].ApplicationName); } } } @@ -322,6 +322,7 @@ public async Task TestRunAzureSignalRWithDefaultRouterNegotiateWithFallback() [Fact] public void TestRunAzureSignalRWithOptions() { + const string optionsAppName = AppName; using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) { var hubConfig = Utility.GetTestHubConfig(loggerFactory); @@ -329,12 +330,12 @@ public void TestRunAzureSignalRWithOptions() { o.ConnectionString = ConnectionString; o.ConnectionCount = -1; - o.HubPrefix = HubPrefix; + o.ApplicationName = optionsAppName; }))) { var options = hubConfig.Resolver.Resolve>(); Assert.Equal(ConnectionString, options.Value.ConnectionString); - Assert.Equal(HubPrefix, options.Value.HubPrefix); + Assert.Equal(optionsAppName, options.Value.ApplicationName); Assert.Equal(-1, options.Value.ConnectionCount); } } diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs index dc89764e0..d0b722155 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs @@ -86,7 +86,7 @@ public void TestGenerateServerAccessToken(string connectionString, string expect [InlineData("Endpoint=https://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;", "https://localhost/aspnetserver/?hub=prefix_hub1")] public void TestGenerateServerAccessTokenWIthPrefix(string connectionString, string expectedAudience) { - var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString, hubPrefix: "prefix")); + var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString, applicationName: "prefix")); var clientToken = provider.GenerateServerAccessToken("hub1", "user1"); @@ -120,7 +120,7 @@ public void TestGenerateServerEndpoint(string connectionString, string expectedE [InlineData("Endpoint=https://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;", "https://localhost/aspnetserver/?hub=prefix_hub1")] public void TestGenerateServerEndpointWithPrefix(string connectionString, string expectedEndpoint) { - var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString, hubPrefix: "prefix")); + var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString, applicationName: "prefix")); var clientEndpoint = provider.GetServerEndpoint("hub1"); diff --git a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs index 3d91b6015..1430c6fa8 100644 --- a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs +++ b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/RestApiProviderFacts.cs @@ -14,12 +14,12 @@ public class RestApiProviderFacts private static readonly string _connectionString = $"Endpoint={_endpoint};AccessKey={_accessKey};Version=1.0;"; private const string _hubName = "signalrbench"; - private const string _hubPrefix = "prefix"; + private const string _appName = "appName"; private const string _userId = "UserA"; private const string _groupName = "GroupA"; - private static readonly string _commonEndpoint = $"{_endpoint}/api/v1/hubs/{_hubPrefix}_{_hubName}"; + private static readonly string _commonEndpoint = $"{_endpoint}/api/v1/hubs/{_appName.ToLower()}_{_hubName}"; - private static readonly RestApiProvider _restApiProvider = new RestApiProvider(_connectionString, _hubName, _hubPrefix); + private static readonly RestApiProvider _restApiProvider = new RestApiProvider(_connectionString, _hubName, _appName); [Theory] [MemberData(nameof(GetTestData))] diff --git a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs index 718132204..41b12b203 100644 --- a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs +++ b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs @@ -15,9 +15,9 @@ public class ServiceManagerFacts private const string AccessKey = "nOu3jXsHnsO5urMumc87M9skQbUWuQ+PE5IvSUEic8w="; private const string HubName = "signalrBench"; private const string UserId = "UserA"; - private const string _hubPrefix = "hubPrefix"; + private const string _appName = "appName"; private static readonly string _clientEndpoint = $"{Endpoint}/client/?hub={HubName.ToLower()}"; - private static readonly string _clientEndpointWithHubPrefix = $"{Endpoint}/client/?hub={_hubPrefix.ToLower()}_{HubName.ToLower()}"; + private static readonly string _clientEndpointWithAppName = $"{Endpoint}/client/?hub={_appName.ToLower()}_{HubName.ToLower()}"; private static readonly string _testConnectionString = $"Endpoint={Endpoint};AccessKey={AccessKey};Version=1.0;"; private static readonly TimeSpan _tokenLifeTime = TimeSpan.FromSeconds(99); private static readonly ServiceManagerOptions _serviceManagerOptions = new ServiceManagerOptions @@ -72,12 +72,12 @@ internal void GenerateClientEndpointTest() } [Fact] - internal void GenerateClientEndpointWithHubPrefixTest() + internal void GenerateClientEndpointWithAppNameTest() { - var manager = new ServiceManager(new ServiceManagerOptions() { ConnectionString = _testConnectionString, HubPrefix = _hubPrefix }); + var manager = new ServiceManager(new ServiceManagerOptions() { ConnectionString = _testConnectionString, ApplicationName = _appName }); var clientEndpoint = manager.GetClientEndpoint(HubName); - Assert.Equal(_clientEndpointWithHubPrefix, clientEndpoint); + Assert.Equal(_clientEndpointWithAppName, clientEndpoint); } } } diff --git a/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs b/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs index a58337b97..43b8fe6da 100644 --- a/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs +++ b/test/Microsoft.Azure.SignalR.Tests/NegotiateHandlerFacts.cs @@ -107,15 +107,15 @@ public void GenerateNegotiateResponseWithPathAndQuery(string path, string queryS [Theory] [InlineData("", "?hub=chat")] - [InlineData("hubPrefix", "?hub=hubprefix_chat")] - public void GenerateNegotiateResponseWithHubPrefix(string hubPrefix, string expectedResponse) + [InlineData("appName", "?hub=appname_chat")] + public void GenerateNegotiateResponseWithAppName(string appName, string expectedResponse) { var config = new ConfigurationBuilder().Build(); var serviceProvider = new ServiceCollection().AddSignalR() .AddAzureSignalR(o => { o.ConnectionString = DefaultConnectionString; - o.HubPrefix = hubPrefix; + o.ApplicationName = appName; }) .Services .AddLogging() @@ -163,14 +163,14 @@ public void CustomUserIdProviderAccessUnavailablePropertyThrowsException(Type ty } [Fact] - public void TestNegotiateHandlerWithMultipleEndpointsAndCustomerRouterAndHubPrefix() + public void TestNegotiateHandlerWithMultipleEndpointsAndCustomerRouterAndAppName() { var config = new ConfigurationBuilder().Build(); var router = new TestCustomRouter(); var serviceProvider = new ServiceCollection().AddSignalR() .AddAzureSignalR(o => { - o.HubPrefix = "testprefix"; + o.ApplicationName = "testprefix"; o.Endpoints = new ServiceEndpoint[] { new ServiceEndpoint(ConnectionString2), diff --git a/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs b/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs index ea3c1257e..7c0e37473 100644 --- a/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs +++ b/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs @@ -14,7 +14,7 @@ public class ServiceEndpointProviderFacts private const string Endpoint = "https://myendpoint"; private const string AccessKey = "nOu3jXsHnsO5urMumc87M9skQbUWuQ+PE5IvSUEic8w="; private static readonly string HubName = nameof(TestHub).ToLower(); - private static readonly string HubPrefix = "testprefix"; + private static readonly string AppName = "testapp"; private static readonly string ConnectionStringWithoutVersion = $"Endpoint={Endpoint};AccessKey={AccessKey};"; @@ -33,9 +33,9 @@ public class ServiceEndpointProviderFacts private static readonly ServiceEndpointProvider[] EndpointProviderArrayWithPrefix = { - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithoutVersion, hubPrefix: HubPrefix)), - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithPreviewVersion, hubPrefix: HubPrefix)), - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version, hubPrefix: HubPrefix)) + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithoutVersion, applicationName: AppName)), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithPreviewVersion, applicationName: AppName)), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version, applicationName: AppName)) }; private static readonly (string path, string queryString, string expectedQuery)[] PathAndQueryArray = @@ -86,18 +86,18 @@ internal void GetClientEndpoint(IServiceEndpointProvider provider, string path, [Theory] [MemberData(nameof(DefaultEndpointProvidersPlusPrefix))] - internal void GetServerEndpointWithHubPrefix(IServiceEndpointProvider provider) + internal void GetServerEndpointWithAppName(IServiceEndpointProvider provider) { - var expected = $"{Endpoint}/server/?hub={HubPrefix}_{HubName}"; + var expected = $"{Endpoint}/server/?hub={AppName}_{HubName}"; var actual = provider.GetServerEndpoint(nameof(TestHub)); Assert.Equal(expected, actual); } [Theory] [MemberData(nameof(DefaultEndpointProvidersWithPathPlusPrefix))] - internal void GetClientEndpointWithHubPrefix(IServiceEndpointProvider provider, string path, string queryString, string expectedQueryString) + internal void GetClientEndpointWithAppName(IServiceEndpointProvider provider, string path, string queryString, string expectedQueryString) { - var expected = $"{Endpoint}/client/?hub={HubPrefix}_{HubName}{expectedQueryString}"; + var expected = $"{Endpoint}/client/?hub={AppName}_{HubName}{expectedQueryString}"; var actual = provider.GetClientEndpoint(HubName, path, queryString); Assert.Equal(expected, actual); } @@ -149,7 +149,7 @@ internal void GenerateServerAccessTokenWithPrefix(IServiceEndpointProvider provi var tokenString = provider.GenerateServerAccessToken(nameof(TestHub), userId, requestId: string.Empty); var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); - var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/server/?hub={HubPrefix}_{HubName}", + var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/server/?hub={AppName}_{HubName}", new[] { new Claim(ClaimTypes.NameIdentifier, userId) @@ -190,7 +190,7 @@ internal void GenerateClientAccessTokenWithPrefix(IServiceEndpointProvider provi var tokenString = provider.GenerateClientAccessToken(HubName, requestId: requestId); var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); - var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/client/?hub={HubPrefix}_{HubName}", + var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/client/?hub={AppName}_{HubName}", null, token.ValidTo, token.ValidFrom, From 286ed7e0b7755ad7cabcdfc2398b4e86a5b86768 Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Tue, 2 Apr 2019 09:57:50 +0100 Subject: [PATCH 06/13] Add extra tests for ASP.NET ApplicationName Options handling --- .../RunAzureSignalRTests.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs index 1831572ef..821f90f3b 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs @@ -74,6 +74,25 @@ public void TestRunAzureSignalRWithAppNameEqualToHubNameThrows() } } + [Fact] + public void TestRunAzureSignalRWithOptionsAppNameDifferentToParamterThrows() + { + const string optionsAppName = "thisiswrong"; + // Prepare the configuration + using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) + { + var ex = Assert.Throws(() => + WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, options => + { + options.ConnectionString = ConnectionString2; + options.ApplicationName = optionsAppName; + })) + ); + + Assert.EndsWith("Options application name (if supplied) must be the same as application name.", ex.Message); + } + } + [Fact] public void TestRunAzureSignalRWithoutConnectionString() { @@ -114,6 +133,20 @@ public void TestRunAzureSignalRWithConnectionString() } } + [Fact] + public void TestRunAzureSignalRWiillUseApplicationNameInOptionsEvenIfNotExplictlySet() + { + using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) + { + var hubConfig = Utility.GetTestHubConfig(loggerFactory); + using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, ConnectionString, hubConfig))) + { + var options = hubConfig.Resolver.Resolve>(); + Assert.Equal(AppName, options.Value.ApplicationName); + } + } + } + [Fact] public void TestRunAzureSignalRWithAppSettings() { From 86913b09e346dab8e165d3e87c4720c906a8decc Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Tue, 2 Apr 2019 10:25:35 +0100 Subject: [PATCH 07/13] Change handling of PRefix for ASP.NET --- .../OwinExtensions.cs | 18 ++++----- .../ServiceOptions.cs | 9 ++++- .../RunAzureSignalRTests.cs | 37 ++++++++----------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs b/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs index a8c5c8631..f682f9ae9 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs @@ -144,11 +144,7 @@ public static void RunAzureSignalR(this IAppBuilder builder, string applicationN /// The hub configuration . public static void RunAzureSignalR(this IAppBuilder builder, string applicationName, string connectionString, HubConfiguration configuration) { - RunAzureSignalR(builder, applicationName, configuration, s => - { - s.ConnectionString = connectionString; - s.ApplicationName = applicationName; - }); + RunAzureSignalR(builder, applicationName, configuration, s => s.ConnectionString = connectionString); } @@ -185,14 +181,14 @@ private static void RunAzureSignalRCore(IAppBuilder builder, string applicationN throw new ArgumentException(nameof(applicationName), "Empty application name is not allowed."); } - if (!string.IsNullOrEmpty(options.ApplicationName) && - !options.ApplicationName.Equals(applicationName, StringComparison.InvariantCultureIgnoreCase)) + if (options.UseHubNamePrefix) { - throw new ArgumentException(nameof(applicationName), "Options application name (if supplied) must be the same as application name."); + options.ApplicationName = applicationName; + } + else + { + options.ApplicationName = ""; } - - //Options ApplicationName must be the same as the applicationName passed in. - options.ApplicationName = applicationName; if (configuration == null) { diff --git a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs index b91e23fde..d3fe8fb82 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs @@ -26,9 +26,14 @@ public class ServiceOptions : IServiceEndpointOptions public int ConnectionCount { get; set; } = 5; /// - /// Gets or sets the prefix to apply to each hub name + /// Gets applicationName, which will be used as a prefix to apply to each hub name /// - public string ApplicationName{ get; set; } + public string ApplicationName{ get; internal set; } + + /// + /// Gets or sets whether the hub name wiull be prefixed with the ApplicationName + /// + public bool UseHubNamePrefix { get; set; } /// /// Gets or sets the func to generate claims from . diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs index 821f90f3b..81095b8ca 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs @@ -74,25 +74,6 @@ public void TestRunAzureSignalRWithAppNameEqualToHubNameThrows() } } - [Fact] - public void TestRunAzureSignalRWithOptionsAppNameDifferentToParamterThrows() - { - const string optionsAppName = "thisiswrong"; - // Prepare the configuration - using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) - { - var ex = Assert.Throws(() => - WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, options => - { - options.ConnectionString = ConnectionString2; - options.ApplicationName = optionsAppName; - })) - ); - - Assert.EndsWith("Options application name (if supplied) must be the same as application name.", ex.Message); - } - } - [Fact] public void TestRunAzureSignalRWithoutConnectionString() { @@ -134,12 +115,12 @@ public void TestRunAzureSignalRWithConnectionString() } [Fact] - public void TestRunAzureSignalRWiillUseApplicationNameInOptionsEvenIfNotExplictlySet() + public void TestRunAzureSignalRWiillUseApplicationNameInOptionsWhenUseHubPrefixIsTrue() { using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) { var hubConfig = Utility.GetTestHubConfig(loggerFactory); - using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, ConnectionString, hubConfig))) + using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, opts => { opts.ConnectionString = ConnectionString; opts.UseHubNamePrefix = true; }))) { var options = hubConfig.Resolver.Resolve>(); Assert.Equal(AppName, options.Value.ApplicationName); @@ -147,6 +128,20 @@ public void TestRunAzureSignalRWiillUseApplicationNameInOptionsEvenIfNotExplictl } } + [Fact] + public void TestRunAzureSignalRWiillNotUseApplicationNameInOptionsWhenUseHubPrefixIsFalse() + { + using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) + { + var hubConfig = Utility.GetTestHubConfig(loggerFactory); + using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, opts => { opts.ConnectionString = ConnectionString; opts.UseHubNamePrefix = false; }))) + { + var options = hubConfig.Resolver.Resolve>(); + Assert.True(string.IsNullOrEmpty(options.Value.ApplicationName)); + } + } + } + [Fact] public void TestRunAzureSignalRWithAppSettings() { From afd7bfdf95a18c567a39b3a90421be1f5af995b7 Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Tue, 2 Apr 2019 10:34:05 +0100 Subject: [PATCH 08/13] Fix broken tests --- .../RunAzureSignalRTests.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs index 81095b8ca..1c3afcc00 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs @@ -216,7 +216,6 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettings() [Fact] public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncludingOptionsAppName() { - const string optionsAppName = AppName; // Prepare the configuration using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) using (new AppSettingsConfigScope(ConnectionString, ConnectionString2)) @@ -224,7 +223,7 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var hubConfig = Utility.GetTestHubConfig(loggerFactory); using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, options => { - options.ApplicationName = optionsAppName; + options.UseHubNamePrefix = true; options.Endpoints = new ServiceEndpoint[] { new ServiceEndpoint(ConnectionString2, EndpointType.Secondary), @@ -236,7 +235,7 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var options = hubConfig.Resolver.Resolve>(); Assert.Equal(ConnectionString, options.Value.ConnectionString); - Assert.Equal(optionsAppName, options.Value.ApplicationName); + Assert.Equal(AppName, options.Value.ApplicationName); Assert.Equal(3, options.Value.Endpoints.Length); @@ -244,10 +243,10 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var endpoints = manager.GetAvailableEndpoints().ToArray(); Assert.Equal(4, endpoints.Length); - Assert.Equal(optionsAppName, endpoints[0].ApplicationName); - Assert.Equal(optionsAppName, endpoints[1].ApplicationName); - Assert.Equal(optionsAppName, endpoints[2].ApplicationName); - Assert.Equal(optionsAppName, endpoints[3].ApplicationName); + Assert.Equal(AppName, endpoints[0].ApplicationName); + Assert.Equal(AppName, endpoints[1].ApplicationName); + Assert.Equal(AppName, endpoints[2].ApplicationName); + Assert.Equal(AppName, endpoints[3].ApplicationName); } } } @@ -350,7 +349,6 @@ public async Task TestRunAzureSignalRWithDefaultRouterNegotiateWithFallback() [Fact] public void TestRunAzureSignalRWithOptions() { - const string optionsAppName = AppName; using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) { var hubConfig = Utility.GetTestHubConfig(loggerFactory); @@ -358,12 +356,10 @@ public void TestRunAzureSignalRWithOptions() { o.ConnectionString = ConnectionString; o.ConnectionCount = -1; - o.ApplicationName = optionsAppName; }))) { var options = hubConfig.Resolver.Resolve>(); Assert.Equal(ConnectionString, options.Value.ConnectionString); - Assert.Equal(optionsAppName, options.Value.ApplicationName); Assert.Equal(-1, options.Value.ConnectionCount); } } From bf052a2872a1d0560d11c4651690d41aee287db3 Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Wed, 3 Apr 2019 18:54:36 +0100 Subject: [PATCH 09/13] Refector to remove ApplicationName from ServiceEndpoint --- .../ServiceEndpointManager.cs | 4 +- .../ServiceEndpointProvider.cs | 4 +- .../ServiceOptions.cs | 4 +- .../Endpoints/ServiceEndpoint.cs | 7 +- .../Endpoints/ServiceEndpointManagerBase.cs | 3 +- .../ServiceManager.cs | 4 +- .../DefaultServiceEndpointGenerator.cs | 21 +- .../IServiceEndpointGenerator.cs | 8 +- .../ServiceEndpointManager.cs | 4 +- .../ServiceEndpointProvider.cs | 47 ++-- .../ServiceOptionsSetup.cs | 4 +- .../RunAzureSignalRTests.cs | 8 +- .../ServiceEndpointProviderTests.cs | 14 +- .../ServiceEndpointProviderFacts.cs | 220 +++++++++--------- 14 files changed, 181 insertions(+), 171 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointManager.cs b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointManager.cs index 50fb71bae..b9d124d2c 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointManager.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointManager.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.SignalR.AspNet internal class ServiceEndpointManager : ServiceEndpointManagerBase { private readonly TimeSpan? _ttl; + private readonly ServiceOptions _options; public ServiceEndpointManager(ServiceOptions options, ILoggerFactory loggerFactory) : base(options, @@ -20,6 +21,7 @@ public ServiceEndpointManager(ServiceOptions options, ILoggerFactory loggerFacto } _ttl = options.AccessTokenLifetime; + _options = options; } public override IServiceEndpointProvider GetEndpointProvider(ServiceEndpoint endpoint) @@ -29,7 +31,7 @@ public override IServiceEndpointProvider GetEndpointProvider(ServiceEndpoint end return null; } - return new ServiceEndpointProvider(endpoint, _ttl); + return new ServiceEndpointProvider(endpoint, _options, _ttl); } } } diff --git a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs index 9e309ceaa..8c8763d7d 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs @@ -25,7 +25,7 @@ internal class ServiceEndpointProvider : IServiceEndpointProvider private readonly int? _port; private readonly TimeSpan _accessTokenLifetime; - public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) + public ServiceEndpointProvider(ServiceEndpoint endpoint, ServiceOptions options, TimeSpan? ttl = null) { var connectionString = endpoint.ConnectionString; if (string.IsNullOrEmpty(connectionString)) @@ -38,7 +38,7 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) // Version is ignored for aspnet signalr case _endpoint = endpoint.Endpoint; _accessKey = endpoint.AccessKey; - _appName = endpoint.ApplicationName; + _appName = options.ApplicationName; _port = endpoint.Port; } diff --git a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs index d3fe8fb82..de59c1539 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs @@ -95,12 +95,12 @@ private static (bool isDefault, ServiceEndpoint endpoint) GetEndpoint(string key { if (key == Constants.ConnectionStringDefaultKey && !string.IsNullOrEmpty(valueGetter())) { - return (true, new ServiceEndpoint(valueGetter(), applicationName: appName)); + return (true, new ServiceEndpoint(valueGetter())); } if (key.StartsWith(Constants.ConnectionStringKeyPrefix) && !string.IsNullOrEmpty(valueGetter())) { - return (false, new ServiceEndpoint(key, valueGetter(), appName)); + return (false, new ServiceEndpoint(key, valueGetter())); } return (false, null); diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs index c7c9d7b3c..a5209f594 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpoint.cs @@ -28,11 +28,9 @@ public class ServiceEndpoint internal int? Port { get; } - internal string ApplicationName { get; set; } - internal IServiceConnectionContainer Connection { get; set; } - public ServiceEndpoint(string key, string connectionString, string applicationName = "") : this(connectionString, applicationName: applicationName) + public ServiceEndpoint(string key, string connectionString) : this(connectionString) { if (!string.IsNullOrEmpty(key)) { @@ -40,7 +38,7 @@ public ServiceEndpoint(string key, string connectionString, string applicationNa } } - public ServiceEndpoint(string connectionString, EndpointType type = EndpointType.Primary, string name = "", string applicationName = "") + public ServiceEndpoint(string connectionString, EndpointType type = EndpointType.Primary, string name = "") { // The provider is responsible to check if the connection string is empty and throw correct error message if (!string.IsNullOrEmpty(connectionString)) @@ -51,7 +49,6 @@ public ServiceEndpoint(string connectionString, EndpointType type = EndpointType EndpointType = type; ConnectionString = connectionString; Name = name; - ApplicationName = applicationName; } public override string ToString() diff --git a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs index a9166f259..d324ec85f 100644 --- a/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs +++ b/src/Microsoft.Azure.SignalR.Common/Endpoints/ServiceEndpointManagerBase.cs @@ -78,7 +78,6 @@ private static IEnumerable GetEndpoints(IServiceEndpointOptions { foreach (var endpoint in endpoints) { - endpoint.ApplicationName = options.ApplicationName; if (endpoint.ConnectionString == connectionString) { connectionStringIncluded = true; @@ -90,7 +89,7 @@ private static IEnumerable GetEndpoints(IServiceEndpointOptions if (!string.IsNullOrEmpty(connectionString) && !connectionStringIncluded) { - yield return new ServiceEndpoint(options.ConnectionString, applicationName: options.ApplicationName); + yield return new ServiceEndpoint(options.ConnectionString); } } diff --git a/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs b/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs index 0c0017ce7..7c4e35df9 100644 --- a/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs +++ b/src/Microsoft.Azure.SignalR.Management/ServiceManager.cs @@ -26,8 +26,8 @@ internal class ServiceManager : IServiceManager internal ServiceManager(ServiceManagerOptions serviceManagerOptions) { _serviceManagerOptions = serviceManagerOptions; - _endpoint = new ServiceEndpoint(_serviceManagerOptions.ConnectionString, EndpointType.Secondary, applicationName: _serviceManagerOptions.ApplicationName); - _endpointProvider = new ServiceEndpointProvider(_endpoint); + _endpoint = new ServiceEndpoint(_serviceManagerOptions.ConnectionString, EndpointType.Secondary); + _endpointProvider = new ServiceEndpointProvider(_endpoint, appName: _serviceManagerOptions.ApplicationName); } public async Task CreateHubContextAsync(string hubName, ILoggerFactory loggerFactory = null, CancellationToken cancellationToken = default) diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs index 40a5d9216..7e3fc400f 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs @@ -17,24 +17,21 @@ internal sealed class DefaultServiceEndpointGenerator : IServiceEndpointGenerato public string Version { get; } - public string ApplicationName { get; } - public int? Port { get; } - public DefaultServiceEndpointGenerator(string endpoint, string accessKey, string version, int? port, string applicationName) + public DefaultServiceEndpointGenerator(string endpoint, string accessKey, string version, int? port) { Endpoint = endpoint; AccessKey = accessKey; Version = version; Port = port; - ApplicationName = applicationName; } - public string GetClientAudience(string hubName) => - InternalGetAudience(ClientPath, hubName, ApplicationName); + public string GetClientAudience(string hubName, string applicationName) => + InternalGetAudience(ClientPath, hubName, applicationName); - public string GetClientEndpoint(string hubName, string originalPath, string queryString) + public string GetClientEndpoint(string hubName, string applicationName, string originalPath, string queryString) { var queryBuilder = new StringBuilder(); if (!string.IsNullOrEmpty(originalPath)) @@ -50,14 +47,14 @@ public string GetClientEndpoint(string hubName, string originalPath, string quer queryBuilder.Append("&").Append(queryString); } - return $"{InternalGetEndpoint(ClientPath, hubName, ApplicationName)}{queryBuilder}"; + return $"{InternalGetEndpoint(ClientPath, hubName, applicationName)}{queryBuilder}"; } - public string GetServerAudience(string hubName) => - InternalGetAudience(ServerPath, hubName, ApplicationName); + public string GetServerAudience(string hubName, string applicationName) => + InternalGetAudience(ServerPath, hubName, applicationName); - public string GetServerEndpoint(string hubName) => - InternalGetEndpoint(ServerPath, hubName, ApplicationName); + public string GetServerEndpoint(string hubName, string applicationName) => + InternalGetEndpoint(ServerPath, hubName, applicationName); private string InternalGetEndpoint(string path, string hubName, string applicationName) { diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/IServiceEndpointGenerator.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/IServiceEndpointGenerator.cs index d5f326bf7..ddb775383 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/IServiceEndpointGenerator.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/IServiceEndpointGenerator.cs @@ -5,9 +5,9 @@ namespace Microsoft.Azure.SignalR { internal interface IServiceEndpointGenerator { - string GetClientAudience(string hubName); - string GetClientEndpoint(string hubName, string originalPath, string queryString); - string GetServerAudience(string hubName); - string GetServerEndpoint(string hubName); + string GetClientAudience(string hubName, string applicationName); + string GetClientEndpoint(string hubName, string applicationName, string originalPath, string queryString); + string GetServerAudience(string hubName, string applicationName); + string GetServerEndpoint(string hubName, string applicationName); } } diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointManager.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointManager.cs index 6b4142fa5..3020788ef 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointManager.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointManager.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.SignalR { internal class ServiceEndpointManager : ServiceEndpointManagerBase { + private readonly IOptions _options; private readonly TimeSpan? _ttl; public ServiceEndpointManager(IOptions options, ILoggerFactory loggerFactory) : @@ -20,6 +21,7 @@ public ServiceEndpointManager(IOptions options, ILoggerFactory l throw new ArgumentException(ServiceEndpointProvider.ConnectionStringNotFound); } + _options = options; _ttl = options.Value?.AccessTokenLifetime; } @@ -30,7 +32,7 @@ public override IServiceEndpointProvider GetEndpointProvider(ServiceEndpoint end return null; } - return new ServiceEndpointProvider(endpoint, _ttl); + return new ServiceEndpointProvider(endpoint, serviceOptions: _options, ttl: _ttl); } } } diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs index 613c1644d..8fae98b92 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/ServiceEndpointProvider.cs @@ -1,14 +1,15 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Security.Claims; - -namespace Microsoft.Azure.SignalR -{ - internal class ServiceEndpointProvider : IServiceEndpointProvider - { + +namespace Microsoft.Azure.SignalR +{ + internal class ServiceEndpointProvider : IServiceEndpointProvider + { internal static readonly string ConnectionStringNotFound = "No connection string was specified. " + $"Please specify a configuration entry for {Constants.ConnectionStringDefaultKey}, " + @@ -16,10 +17,12 @@ internal class ServiceEndpointProvider : IServiceEndpointProvider private readonly string _endpoint; private readonly string _accessKey; + private readonly IOptions _serviceOptions; + private readonly string _appName; private readonly TimeSpan _accessTokenLifetime; private readonly IServiceEndpointGenerator _generator; - public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) + public ServiceEndpointProvider(ServiceEndpoint endpoint, string appName = "", IOptions serviceOptions = null, TimeSpan? ttl = null) { var connectionString = endpoint.ConnectionString; if (string.IsNullOrEmpty(connectionString)) @@ -31,11 +34,21 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null) _endpoint = endpoint.Endpoint; _accessKey = endpoint.AccessKey; + _serviceOptions = serviceOptions; + _appName = appName; var port = endpoint.Port; var version = endpoint.Version; - _generator = new DefaultServiceEndpointGenerator(_endpoint, _accessKey, version, port, endpoint.ApplicationName); + _generator = new DefaultServiceEndpointGenerator(_endpoint, _accessKey, version, port); + } + + internal string ApplicationName + { + get + { + return _serviceOptions != null ? _serviceOptions.Value.ApplicationName : _appName; + } } public string GenerateClientAccessToken(string hubName, IEnumerable claims = null, TimeSpan? lifetime = null, string requestId = null) @@ -45,7 +58,7 @@ public string GenerateClientAccessToken(string hubName, IEnumerable claim throw new ArgumentNullException(nameof(hubName)); } - var audience = _generator.GetClientAudience(hubName); + var audience = _generator.GetClientAudience(hubName, ApplicationName); return AuthenticationHelper.GenerateAccessToken(_accessKey, audience, claims, lifetime ?? _accessTokenLifetime, requestId); } @@ -57,7 +70,7 @@ public string GenerateServerAccessToken(string hubName, string userId, TimeSpan? throw new ArgumentNullException(nameof(hubName)); } - var audience = _generator.GetServerAudience(hubName); + var audience = _generator.GetServerAudience(hubName, ApplicationName); var claims = userId != null ? new[] {new Claim(ClaimTypes.NameIdentifier, userId)} : null; return AuthenticationHelper.GenerateAccessToken(_accessKey, audience, claims, lifetime ?? _accessTokenLifetime, requestId); @@ -70,7 +83,7 @@ public string GetClientEndpoint(string hubName, string originalPath, string quer throw new ArgumentNullException(nameof(hubName)); } - return _generator.GetClientEndpoint(hubName, originalPath, queryString); + return _generator.GetClientEndpoint(hubName, ApplicationName, originalPath, queryString); } public string GetServerEndpoint(string hubName) @@ -80,7 +93,7 @@ public string GetServerEndpoint(string hubName) throw new ArgumentNullException(nameof(hubName)); } - return _generator.GetServerEndpoint(hubName); - } - } -} + return _generator.GetServerEndpoint(hubName, ApplicationName); + } + } +} diff --git a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs index 566e430ec..71a5014cc 100644 --- a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs +++ b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs @@ -66,12 +66,12 @@ private static (string, List) GetEndpoint(IConfiguration config if (key == defaultKey && !string.IsNullOrEmpty(pair.Value)) { connectionString = pair.Value; - endpoints.Add(new ServiceEndpoint(pair.Value, applicationName: applicationName)); + endpoints.Add(new ServiceEndpoint(pair.Value)); } if (key.StartsWith(keyPrefix) && !string.IsNullOrEmpty(pair.Value)) { - endpoints.Add(new ServiceEndpoint(key, pair.Value, applicationName)); + endpoints.Add(new ServiceEndpoint(key, pair.Value)); } } diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs index 1c3afcc00..5f025c422 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs @@ -243,10 +243,10 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var endpoints = manager.GetAvailableEndpoints().ToArray(); Assert.Equal(4, endpoints.Length); - Assert.Equal(AppName, endpoints[0].ApplicationName); - Assert.Equal(AppName, endpoints[1].ApplicationName); - Assert.Equal(AppName, endpoints[2].ApplicationName); - Assert.Equal(AppName, endpoints[3].ApplicationName); + //Assert.Equal(AppName, endpoints[0].ApplicationName); + //Assert.Equal(AppName, endpoints[1].ApplicationName); + //Assert.Equal(AppName, endpoints[2].ApplicationName); + //Assert.Equal(AppName, endpoints[3].ApplicationName); } } } diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs index d0b722155..4ac5c4514 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/ServiceEndpointProviderTests.cs @@ -25,7 +25,7 @@ public class ServiceEndpointProviderTests [InlineData("Endpoint=https://localhost;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;", "https://localhost/aspnetclient")] public void TestGenerateClientAccessToken(string connectionString, string expectedAudience) { - var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString)); + var provider = new ServiceEndpointProvider(new ServiceEndpoint(connectionString), new ServiceOptions() { }); var clientToken = provider.GenerateClientAccessToken(null, new Claim[] { @@ -52,7 +52,7 @@ public void TestGenerateClientAccessToken(string connectionString, string expect [InlineData("Endpoint=https://abc.com;AccessKey=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;", "orig(); for (int i = 0; i < count; i++) diff --git a/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs b/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs index 7c0e37473..ddaea3d4b 100644 --- a/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs +++ b/test/Microsoft.Azure.SignalR.Tests/ServiceEndpointProviderFacts.cs @@ -1,61 +1,61 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; -using Xunit; - -namespace Microsoft.Azure.SignalR.Tests -{ - public class ServiceEndpointProviderFacts - { - private const string Endpoint = "https://myendpoint"; - private const string AccessKey = "nOu3jXsHnsO5urMumc87M9skQbUWuQ+PE5IvSUEic8w="; - private static readonly string HubName = nameof(TestHub).ToLower(); +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Xunit; + +namespace Microsoft.Azure.SignalR.Tests +{ + public class ServiceEndpointProviderFacts + { + private const string Endpoint = "https://myendpoint"; + private const string AccessKey = "nOu3jXsHnsO5urMumc87M9skQbUWuQ+PE5IvSUEic8w="; + private static readonly string HubName = nameof(TestHub).ToLower(); private static readonly string AppName = "testapp"; - - private static readonly string ConnectionStringWithoutVersion = - $"Endpoint={Endpoint};AccessKey={AccessKey};"; - - private static readonly string ConnectionStringWithPreviewVersion = - $"Endpoint={Endpoint};AccessKey={AccessKey};Version=1.0-preview"; - - private static readonly string ConnectionStringWithV1Version = $"Endpoint={Endpoint};AccessKey={AccessKey};Version=1.0"; - - private static readonly ServiceEndpointProvider[] EndpointProviderArray = - { - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithoutVersion)), - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithPreviewVersion)), - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version)) + + private static readonly string ConnectionStringWithoutVersion = + $"Endpoint={Endpoint};AccessKey={AccessKey};"; + + private static readonly string ConnectionStringWithPreviewVersion = + $"Endpoint={Endpoint};AccessKey={AccessKey};Version=1.0-preview"; + + private static readonly string ConnectionStringWithV1Version = $"Endpoint={Endpoint};AccessKey={AccessKey};Version=1.0"; + + private static readonly ServiceEndpointProvider[] EndpointProviderArray = + { + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithoutVersion)), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithPreviewVersion)), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version)) }; private static readonly ServiceEndpointProvider[] EndpointProviderArrayWithPrefix = { - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithoutVersion, applicationName: AppName)), - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithPreviewVersion, applicationName: AppName)), - new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version, applicationName: AppName)) + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithoutVersion), AppName), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithPreviewVersion), AppName), + new ServiceEndpointProvider(new ServiceEndpoint(ConnectionStringWithV1Version), AppName) }; - private static readonly (string path, string queryString, string expectedQuery)[] PathAndQueryArray = - { - ("", "", ""), + private static readonly (string path, string queryString, string expectedQuery)[] PathAndQueryArray = + { + ("", "", ""), (null, "", ""), ("/user/path", "", $"&{Constants.QueryParameter.OriginalPath}=%2Fuser%2Fpath"), ("", "customKey=customValue", "&customKey=customValue"), ("/user/path", "customKey=customValue", $"&{Constants.QueryParameter.OriginalPath}=%2Fuser%2Fpath&customKey=customValue") - }; - - public static IEnumerable DefaultEndpointProviders => - EndpointProviderArray.Select(provider => new object[] {provider}); - - public static IEnumerable PathAndQueries => - PathAndQueryArray.Select(t => new object[] {t.path, t.queryString, t.expectedQuery}); - - public static IEnumerable DefaultEndpointProvidersWithPath => - from provider in EndpointProviderArray - from t in PathAndQueryArray + }; + + public static IEnumerable DefaultEndpointProviders => + EndpointProviderArray.Select(provider => new object[] {provider}); + + public static IEnumerable PathAndQueries => + PathAndQueryArray.Select(t => new object[] {t.path, t.queryString, t.expectedQuery}); + + public static IEnumerable DefaultEndpointProvidersWithPath => + from provider in EndpointProviderArray + from t in PathAndQueryArray select new object[] { provider, t.path, t.queryString, t.expectedQuery} ; public static IEnumerable DefaultEndpointProvidersWithPathPlusPrefix => @@ -67,23 +67,23 @@ from t in PathAndQueryArray EndpointProviderArrayWithPrefix.Select(provider => new object[] { provider }); [Theory] - [MemberData(nameof(DefaultEndpointProviders))] - internal void GetServerEndpoint(IServiceEndpointProvider provider) - { - var expected = $"{Endpoint}/server/?hub={HubName}"; - var actual = provider.GetServerEndpoint(nameof(TestHub)); - Assert.Equal(expected, actual); - } - - [Theory] - [MemberData(nameof(DefaultEndpointProvidersWithPath))] - internal void GetClientEndpoint(IServiceEndpointProvider provider, string path, string queryString, string expectedQueryString) - { - var expected = $"{Endpoint}/client/?hub={HubName}{expectedQueryString}"; - var actual = provider.GetClientEndpoint(HubName, path, queryString); - Assert.Equal(expected, actual); - } - + [MemberData(nameof(DefaultEndpointProviders))] + internal void GetServerEndpoint(IServiceEndpointProvider provider) + { + var expected = $"{Endpoint}/server/?hub={HubName}"; + var actual = provider.GetServerEndpoint(nameof(TestHub)); + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(DefaultEndpointProvidersWithPath))] + internal void GetClientEndpoint(IServiceEndpointProvider provider, string path, string queryString, string expectedQueryString) + { + var expected = $"{Endpoint}/client/?hub={HubName}{expectedQueryString}"; + var actual = provider.GetClientEndpoint(HubName, path, queryString); + Assert.Equal(expected, actual); + } + [Theory] [MemberData(nameof(DefaultEndpointProvidersPlusPrefix))] internal void GetServerEndpointWithAppName(IServiceEndpointProvider provider) @@ -102,7 +102,7 @@ internal void GetClientEndpointWithAppName(IServiceEndpointProvider provider, st Assert.Equal(expected, actual); } - [Fact] + [Fact] internal void GenerateMutlipleAccessTokenShouldBeUnique() { var count = 1000; @@ -117,30 +117,30 @@ internal void GenerateMutlipleAccessTokenShouldBeUnique() var distinct = tokens.Distinct(); Assert.Equal(tokens.Count, distinct.Count()); - } - - [Theory] - [MemberData(nameof(DefaultEndpointProviders))] - internal void GenerateServerAccessToken(IServiceEndpointProvider provider) - { - const string userId = "UserA"; - var tokenString = provider.GenerateServerAccessToken(nameof(TestHub), userId, requestId: string.Empty); - var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); - - var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/server/?hub={HubName}", - new[] - { - new Claim(ClaimTypes.NameIdentifier, userId) - }, - token.ValidTo, - token.ValidFrom, - token.ValidFrom, - AccessKey, - string.Empty); - - Assert.Equal(expectedTokenString, tokenString); - } - + } + + [Theory] + [MemberData(nameof(DefaultEndpointProviders))] + internal void GenerateServerAccessToken(IServiceEndpointProvider provider) + { + const string userId = "UserA"; + var tokenString = provider.GenerateServerAccessToken(nameof(TestHub), userId, requestId: string.Empty); + var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); + + var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/server/?hub={HubName}", + new[] + { + new Claim(ClaimTypes.NameIdentifier, userId) + }, + token.ValidTo, + token.ValidFrom, + token.ValidFrom, + AccessKey, + string.Empty); + + Assert.Equal(expectedTokenString, tokenString); + } + [Theory] [MemberData(nameof(DefaultEndpointProvidersPlusPrefix))] internal void GenerateServerAccessTokenWithPrefix(IServiceEndpointProvider provider) @@ -162,24 +162,24 @@ internal void GenerateServerAccessTokenWithPrefix(IServiceEndpointProvider provi Assert.Equal(expectedTokenString, tokenString); } - - [Theory] - [MemberData(nameof(DefaultEndpointProviders))] - internal void GenerateClientAccessToken(IServiceEndpointProvider provider) - { - var requestId = Guid.NewGuid().ToString(); - var tokenString = provider.GenerateClientAccessToken(HubName, requestId: requestId); - var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); - - var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/client/?hub={HubName}", - null, - token.ValidTo, - token.ValidFrom, - token.ValidFrom, - AccessKey, - requestId); - - Assert.Equal(expectedTokenString, tokenString); + + [Theory] + [MemberData(nameof(DefaultEndpointProviders))] + internal void GenerateClientAccessToken(IServiceEndpointProvider provider) + { + var requestId = Guid.NewGuid().ToString(); + var tokenString = provider.GenerateClientAccessToken(HubName, requestId: requestId); + var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); + + var expectedTokenString = JwtTokenHelper.GenerateJwtBearer($"{Endpoint}/client/?hub={HubName}", + null, + token.ValidTo, + token.ValidFrom, + token.ValidFrom, + AccessKey, + requestId); + + Assert.Equal(expectedTokenString, tokenString); } [Theory] @@ -199,6 +199,6 @@ internal void GenerateClientAccessTokenWithPrefix(IServiceEndpointProvider provi requestId); Assert.Equal(expectedTokenString, tokenString); - } - } -} + } + } +} From 473fffd4be7d92cb0b8635f94786ad8604728726 Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Wed, 3 Apr 2019 19:18:29 +0100 Subject: [PATCH 10/13] Feedback from PR --- .../ServiceEndpointProvider.cs | 4 ++-- .../ServiceOptions.cs | 3 ++- .../DefaultServiceEndpointGenerator.cs | 13 +++++++----- .../ServiceOptionsSetup.cs | 20 +------------------ 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs index 8c8763d7d..2c2453410 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs @@ -100,8 +100,8 @@ public string GetServerEndpoint(string hubName) { var prefixedHubName = string.IsNullOrEmpty(_appName) ? hubName.ToLower() : $"{_appName.ToLower()}_{hubName.ToLower()}"; return _port.HasValue ? - $"{_endpoint}:{_port}/{ServerPath}/?hub={prefixedHubName.ToLower()}" : - $"{_endpoint}/{ServerPath}/?hub={prefixedHubName.ToLower()}"; + $"{_endpoint}:{_port}/{ServerPath}/?hub={prefixedHubName}" : + $"{_endpoint}/{ServerPath}/?hub={prefixedHubName}"; } } } diff --git a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs index de59c1539..1d51dbde2 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs @@ -28,7 +28,8 @@ public class ServiceOptions : IServiceEndpointOptions /// /// Gets applicationName, which will be used as a prefix to apply to each hub name /// - public string ApplicationName{ get; internal set; } + internal string ApplicationName{ get; set; } + string IServiceEndpointOptions.ApplicationName => ApplicationName; /// /// Gets or sets whether the hub name wiull be prefixed with the ApplicationName diff --git a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs index 7e3fc400f..adaba65ad 100644 --- a/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs +++ b/src/Microsoft.Azure.SignalR/EndpointProvider/DefaultServiceEndpointGenerator.cs @@ -56,18 +56,21 @@ public string GetServerAudience(string hubName, string applicationName) => public string GetServerEndpoint(string hubName, string applicationName) => InternalGetEndpoint(ServerPath, hubName, applicationName); + private string GetPrefixedHubName(string applicationName, string hubName) + { + return string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}"; + } + private string InternalGetEndpoint(string path, string hubName, string applicationName) { - var prefixedHubName = string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}"; return Port.HasValue ? - $"{Endpoint}:{Port}/{path}/?hub={prefixedHubName}" : - $"{Endpoint}/{path}/?hub={prefixedHubName}"; + $"{Endpoint}:{Port}/{path}/?hub={GetPrefixedHubName(applicationName, hubName)}" : + $"{Endpoint}/{path}/?hub={GetPrefixedHubName(applicationName, hubName)}"; } private string InternalGetAudience(string path, string hubName, string applicationName) { - var prefixedHubName = string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}"; - return $"{Endpoint}/{path}/?hub={prefixedHubName}"; + return $"{Endpoint}/{path}/?hub={GetPrefixedHubName(applicationName, hubName)}"; } } } diff --git a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs index 71a5014cc..4a52dcd95 100644 --- a/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs +++ b/src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs @@ -16,7 +16,7 @@ internal class ServiceOptionsSetup : IConfigureOptions public ServiceOptionsSetup(IConfiguration configuration) { - _appName = GetAppName(configuration); + _appName = configuration[Constants.ApplicationNameDefaultKeyPrefix]; var (connectionString, endpoints) = GetEndpoint(configuration, Constants.ConnectionStringDefaultKey, Constants.ConnectionStringKeyPrefix, _appName); @@ -30,24 +30,6 @@ public ServiceOptionsSetup(IConfiguration configuration) _endpoints = endpoints.ToArray(); } - private string GetAppName(IConfiguration configuration) - { - foreach (var pair in configuration.AsEnumerable()) - { - var key = pair.Key; - if (key == Constants.ApplicationNameDefaultKey && !string.IsNullOrEmpty(pair.Value)) - { - return pair.Value; - } - - if (key.StartsWith(Constants.ApplicationNameDefaultKeyPrefix) && !string.IsNullOrEmpty(pair.Value)) - { - return pair.Value; - } - } - return string.Empty; - } - public void Configure(ServiceOptions options) { // The default setup of ServiceOptions From 1bfa3b1aa7a2c33a49fbce12abdb076c51eee488 Mon Sep 17 00:00:00 2001 From: Steve Rash Date: Thu, 4 Apr 2019 08:29:25 +0100 Subject: [PATCH 11/13] More PR feedback --- .../ServiceEndpointProvider.cs | 13 ++++++----- .../OwinExtensions.cs | 9 +------- .../ServiceOptions.cs | 5 ----- .../RestApiProvider.cs | 19 +++++++--------- .../RunAzureSignalRTests.cs | 22 +------------------ 5 files changed, 18 insertions(+), 50 deletions(-) diff --git a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs index 2c2453410..4ca752a8d 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs @@ -42,6 +42,11 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, ServiceOptions options, _port = endpoint.Port; } + private string GetPrefixedHubName(string applicationName, string hubName) + { + return string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}"; + } + public string GenerateClientAccessToken(string hubName = null, IEnumerable claims = null, TimeSpan? lifetime = null, string requestId = null) { var audience = $"{_endpoint}/{ClientPath}"; @@ -59,8 +64,7 @@ public string GenerateServerAccessToken(string hubName, string userId, TimeSpan? }; } - var prefixedHubName = string.IsNullOrEmpty(_appName) ? hubName.ToLower() : $"{_appName.ToLower()}_{hubName.ToLower()}"; - var audience = $"{_endpoint}/{ServerPath}/?hub={prefixedHubName.ToLower()}"; + var audience = $"{_endpoint}/{ServerPath}/?hub={GetPrefixedHubName(_appName, hubName)}"; return AuthenticationHelper.GenerateAccessToken(_accessKey, audience, claims, lifetime ?? _accessTokenLifetime, requestId); } @@ -98,10 +102,9 @@ public string GetClientEndpoint(string hubName = null, string originalPath = nul public string GetServerEndpoint(string hubName) { - var prefixedHubName = string.IsNullOrEmpty(_appName) ? hubName.ToLower() : $"{_appName.ToLower()}_{hubName.ToLower()}"; return _port.HasValue ? - $"{_endpoint}:{_port}/{ServerPath}/?hub={prefixedHubName}" : - $"{_endpoint}/{ServerPath}/?hub={prefixedHubName}"; + $"{_endpoint}:{_port}/{ServerPath}/?hub={GetPrefixedHubName(_appName, hubName)}" : + $"{_endpoint}/{ServerPath}/?hub={GetPrefixedHubName(_appName, hubName)}"; } } } diff --git a/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs b/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs index f682f9ae9..9552457e3 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs @@ -181,14 +181,7 @@ private static void RunAzureSignalRCore(IAppBuilder builder, string applicationN throw new ArgumentException(nameof(applicationName), "Empty application name is not allowed."); } - if (options.UseHubNamePrefix) - { - options.ApplicationName = applicationName; - } - else - { - options.ApplicationName = ""; - } + options.ApplicationName = applicationName; if (configuration == null) { diff --git a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs index 1d51dbde2..a48731fec 100644 --- a/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs +++ b/src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs @@ -31,11 +31,6 @@ public class ServiceOptions : IServiceEndpointOptions internal string ApplicationName{ get; set; } string IServiceEndpointOptions.ApplicationName => ApplicationName; - /// - /// Gets or sets whether the hub name wiull be prefixed with the ApplicationName - /// - public bool UseHubNamePrefix { get; set; } - /// /// Gets or sets the func to generate claims from . /// The claims will be included in the auto-generated token for clients. diff --git a/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs b/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs index 22f598f2b..828fdfe3e 100644 --- a/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs +++ b/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs @@ -20,18 +20,15 @@ public RestApiProvider(string connectionString, string hubName, string appName) string accessKey; (_baseEndpoint, accessKey, _, _port) = ConnectionStringParser.Parse(connectionString); _hubName = hubName; - _appName = appName.ToLower(); + _appName = appName; _restApiAccessTokenGenerator = new RestApiAccessTokenGenerator(accessKey); - if (string.IsNullOrEmpty(_appName)) - { - _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_hubName}"; - _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_hubName}"; - } - else - { - _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_appName}_{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_appName}_{_hubName}"; - _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_appName}_{_hubName}"; - } + _requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{GetPrefixedHubName(_appName, _hubName)}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{GetPrefixedHubName(_appName, _hubName)}"; + _audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{GetPrefixedHubName(_appName, _hubName)}"; + } + + private string GetPrefixedHubName(string applicationName, string hubName) + { + return string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}"; } public RestApiEndpoint GetBroadcastEndpoint(TimeSpan? lifetime = null) diff --git a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs index 5f025c422..df6728096 100644 --- a/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs +++ b/test/Microsoft.Azure.SignalR.AspNet.Tests/RunAzureSignalRTests.cs @@ -120,7 +120,7 @@ public void TestRunAzureSignalRWiillUseApplicationNameInOptionsWhenUseHubPrefixI using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) { var hubConfig = Utility.GetTestHubConfig(loggerFactory); - using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, opts => { opts.ConnectionString = ConnectionString; opts.UseHubNamePrefix = true; }))) + using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, opts => { opts.ConnectionString = ConnectionString; }))) { var options = hubConfig.Resolver.Resolve>(); Assert.Equal(AppName, options.Value.ApplicationName); @@ -128,20 +128,6 @@ public void TestRunAzureSignalRWiillUseApplicationNameInOptionsWhenUseHubPrefixI } } - [Fact] - public void TestRunAzureSignalRWiillNotUseApplicationNameInOptionsWhenUseHubPrefixIsFalse() - { - using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) - { - var hubConfig = Utility.GetTestHubConfig(loggerFactory); - using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, opts => { opts.ConnectionString = ConnectionString; opts.UseHubNamePrefix = false; }))) - { - var options = hubConfig.Resolver.Resolve>(); - Assert.True(string.IsNullOrEmpty(options.Value.ApplicationName)); - } - } - } - [Fact] public void TestRunAzureSignalRWithAppSettings() { @@ -223,7 +209,6 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var hubConfig = Utility.GetTestHubConfig(loggerFactory); using (WebApp.Start(ServiceUrl, app => app.RunAzureSignalR(AppName, hubConfig, options => { - options.UseHubNamePrefix = true; options.Endpoints = new ServiceEndpoint[] { new ServiceEndpoint(ConnectionString2, EndpointType.Secondary), @@ -242,11 +227,6 @@ public void TestRunAzureSignalRWithMultipleAppSettingsAndCustomSettingsIncluding var manager = hubConfig.Resolver.Resolve(); var endpoints = manager.GetAvailableEndpoints().ToArray(); Assert.Equal(4, endpoints.Length); - - //Assert.Equal(AppName, endpoints[0].ApplicationName); - //Assert.Equal(AppName, endpoints[1].ApplicationName); - //Assert.Equal(AppName, endpoints[2].ApplicationName); - //Assert.Equal(AppName, endpoints[3].ApplicationName); } } } From d6eb2bd54f84710982ebc5a5a3c9d46232c0b58d Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Mon, 8 Apr 2019 13:19:17 +0800 Subject: [PATCH 12/13] apply ApplicationName in other tests --- .../E2ETest/ServiceHubContextE2EFacts.cs | 50 +++++----- .../UnitTests/ServiceManagerFacts.cs | 97 +++++++------------ 2 files changed, 62 insertions(+), 85 deletions(-) diff --git a/test/Microsoft.Azure.SignalR.Management.Tests/E2ETest/ServiceHubContextE2EFacts.cs b/test/Microsoft.Azure.SignalR.Management.Tests/E2ETest/ServiceHubContextE2EFacts.cs index 7cda0cd65..0844174d7 100644 --- a/test/Microsoft.Azure.SignalR.Management.Tests/E2ETest/ServiceHubContextE2EFacts.cs +++ b/test/Microsoft.Azure.SignalR.Management.Tests/E2ETest/ServiceHubContextE2EFacts.cs @@ -26,19 +26,24 @@ public class ServiceHubContextE2EFacts : VerifiableLoggedTest private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(1); private static readonly string[] _userNames = GetTestStringList("User", ClientConnectionCount); private static readonly string[] _groupNames = GetTestStringList("Group", GroupCount); + private static readonly ServiceTransportType[] _serviceTransportType = new ServiceTransportType[] { ServiceTransportType.Transient, ServiceTransportType.Persistent }; + private static readonly string[] _appNames = new string[] { "appName", "", null }; public ServiceHubContextE2EFacts(ITestOutputHelper output) : base(output) { } + public static IEnumerable TestData => from serviceTransportType in _serviceTransportType + from appName in _appNames + select new object[] { serviceTransportType, appName }; + [ConditionalTheory] [SkipIfConnectionStringNotPresent] - [InlineData(ServiceTransportType.Transient)] - [InlineData(ServiceTransportType.Persistent)] - internal async Task BroadcastTest(ServiceTransportType serviceTransportType) + [MemberData(nameof(TestData))] + internal async Task BroadcastTest(ServiceTransportType serviceTransportType, string appName) { var receivedMessageDict = new ConcurrentDictionary(); - var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType); + var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType, appName); try { await RunTestCore(clientEndpoint, clientAccessTokens, () => serviceHubContext.Clients.All.SendAsync(MethodName, Message), ClientConnectionCount, receivedMessageDict); @@ -51,12 +56,11 @@ internal async Task BroadcastTest(ServiceTransportType serviceTransportType) [ConditionalTheory] [SkipIfConnectionStringNotPresent] - [InlineData(ServiceTransportType.Transient)] - [InlineData(ServiceTransportType.Persistent)] - internal async Task SendToUserTest(ServiceTransportType serviceTransportType) + [MemberData(nameof(TestData))] + internal async Task SendToUserTest(ServiceTransportType serviceTransportType, string appName) { var receivedMessageDict = new ConcurrentDictionary(); - var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType); + var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType, appName); try { await RunTestCore(clientEndpoint, clientAccessTokens, () => serviceHubContext.Clients.User(_userNames[0]).SendAsync(MethodName, Message), 1, receivedMessageDict); @@ -69,12 +73,11 @@ internal async Task SendToUserTest(ServiceTransportType serviceTransportType) [ConditionalTheory] [SkipIfConnectionStringNotPresent] - [InlineData(ServiceTransportType.Transient)] - [InlineData(ServiceTransportType.Persistent)] - internal async Task SendToUsersTest(ServiceTransportType serviceTransportType) + [MemberData(nameof(TestData))] + internal async Task SendToUsersTest(ServiceTransportType serviceTransportType, string appName) { var receivedMessageDict = new ConcurrentDictionary(); - var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType); + var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType, appName); try { await RunTestCore(clientEndpoint, clientAccessTokens, () => serviceHubContext.Clients.Users(_userNames).SendAsync(MethodName, Message), ClientConnectionCount, receivedMessageDict); @@ -87,12 +90,11 @@ internal async Task SendToUsersTest(ServiceTransportType serviceTransportType) [ConditionalTheory] [SkipIfConnectionStringNotPresent] - [InlineData(ServiceTransportType.Transient)] - [InlineData(ServiceTransportType.Persistent)] - internal async Task SendToGroupTest(ServiceTransportType serviceTransportType) + [MemberData(nameof(TestData))] + internal async Task SendToGroupTest(ServiceTransportType serviceTransportType, string appName) { var receivedMessageDict = new ConcurrentDictionary(); - var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType); + var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType, appName); try { Func sendTaskFunc = () => serviceHubContext.Clients.Group(_groupNames[0]).SendAsync(MethodName, Message); @@ -106,12 +108,11 @@ internal async Task SendToGroupTest(ServiceTransportType serviceTransportType) [ConditionalTheory] [SkipIfConnectionStringNotPresent] - [InlineData(ServiceTransportType.Transient)] - [InlineData(ServiceTransportType.Persistent)] - internal async Task SendToGroupsTest(ServiceTransportType serviceTransportType) + [MemberData(nameof(TestData))] + internal async Task SendToGroupsTest(ServiceTransportType serviceTransportType, string appName) { var receivedMessageDict = new ConcurrentDictionary(); - var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType); + var (clientEndpoint, clientAccessTokens, serviceHubContext) = await InitAsync(serviceTransportType, appName); try { Func sendTaskFunc = () => serviceHubContext.Clients.Groups(_groupNames).SendAsync(MethodName, Message); @@ -160,12 +161,12 @@ private static string[] GetTestStringList(string prefix, int count) select $"{prefix}{i}").ToArray(); } - private async Task<(string ClientEndpoint, IEnumerable ClientAccessTokens, IServiceHubContext ServiceHubContext)> InitAsync(ServiceTransportType serviceTransportType) + private async Task<(string ClientEndpoint, IEnumerable ClientAccessTokens, IServiceHubContext ServiceHubContext)> InitAsync(ServiceTransportType serviceTransportType, string appName) { using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug)) { - var serviceManager = GenerateServiceManager(TestConfiguration.Instance.ConnectionString, serviceTransportType); + var serviceManager = GenerateServiceManager(TestConfiguration.Instance.ConnectionString, serviceTransportType, appName); var serviceHubContext = await serviceManager.CreateHubContextAsync(HubName, loggerFactory); var clientEndpoint = serviceManager.GetClientEndpoint(HubName); @@ -202,12 +203,13 @@ private static void ListenOnMessage(IList connections, Concurrent } } - private static IServiceManager GenerateServiceManager(string connectionString, ServiceTransportType serviceTransportType = ServiceTransportType.Transient) + private static IServiceManager GenerateServiceManager(string connectionString, ServiceTransportType serviceTransportType = ServiceTransportType.Transient, string appName = null) { var serviceManagerOptions = new ServiceManagerOptions { ConnectionString = connectionString, - ServiceTransportType = serviceTransportType + ServiceTransportType = serviceTransportType, + ApplicationName = appName }; return new ServiceManager(serviceManagerOptions); diff --git a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs index 0f62d5bcf..7d47780b5 100644 --- a/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs +++ b/test/Microsoft.Azure.SignalR.Management.Tests/UnitTests/ServiceManagerFacts.cs @@ -18,88 +18,53 @@ public class ServiceManagerFacts private const string AccessKey = "nOu3jXsHnsO5urMumc87M9skQbUWuQ+PE5IvSUEic8w="; private const string HubName = "signalrBench"; private const string UserId = "UserA"; - private static readonly string _clientEndpoint = $"{Endpoint}/client/?hub={HubName.ToLower()}"; - private static readonly string _clientEndpointWithAppName = $"{Endpoint}/client/?hub={_appName.ToLower()}_{HubName.ToLower()}"; private static readonly string _testConnectionString = $"Endpoint={Endpoint};AccessKey={AccessKey};Version=1.0;"; private static readonly TimeSpan _tokenLifeTime = TimeSpan.FromSeconds(99); - private static readonly ServiceManagerOptions _serviceManagerOptions = new ServiceManagerOptions - { - ConnectionString = _testConnectionString, - - }; - private static readonly ServiceManager _serviceManager = new ServiceManager(_serviceManagerOptions); private static readonly Claim[] _defaultClaims = new Claim[] { new Claim("type1", "val1") }; + private static readonly ServiceTransportType[] _serviceTransportTypes = new ServiceTransportType[] { ServiceTransportType.Transient, ServiceTransportType.Persistent }; + private static readonly bool[] _useLoggerFatories = new bool[] { false, true }; + private static readonly string[] _appNames = new string[] { "appName", "", null }; + private static readonly string[] _userIds = new string[] { UserId, null }; + private static readonly IEnumerable _claimLists = new Claim[][] { _defaultClaims, null }; - private static readonly ServiceTransportType[] _serviceTransportTypes = new ServiceTransportType[] - { - ServiceTransportType.Transient, - ServiceTransportType.Persistent - }; - - private static readonly bool[] _useLoggerFatories = new bool[] - { - false, - true - }; - - private static readonly string[] _appNames = new string[] - { - "appName", - "", - null - }; + public static IEnumerable TestServiceManagerOptionData => from transport in _serviceTransportTypes + from useLoggerFactory in _useLoggerFatories + from appName in _appNames + select new object[] { transport, useLoggerFactory, appName }; - public static readonly IEnumerable TestGenerateAccessTokenData = new object[][] - { - new object[] - { - null, - null - }, - new object[] - { - UserId, - null - }, - new object[] - { - null, - _defaultClaims - }, - new object[] - { - UserId, - _defaultClaims - } - }; + public static IEnumerable TestGenerateClientEndpointData => from appName in _appNames + select new object[] { appName, GetExpectedClientEndpoint(appName) }; - public static IEnumerable TestServiceOptionData => from transport in _serviceTransportTypes - from useLoggerFactory in _useLoggerFatories - from appName in _appNames - select new object[] { transport, useLoggerFactory, appName}; + public static IEnumerable TestGenerateAccessTokenData => from userId in _userIds + from claims in _claimLists + from appName in _appNames + select new object[] { userId, claims, appName }; [Theory] [MemberData(nameof(TestGenerateAccessTokenData))] - internal void GenerateClientAccessTokenTest(string userId, Claim[] claims) + internal void GenerateClientAccessTokenTest(string userId, Claim[] claims, string appName) { - var tokenString = _serviceManager.GenerateClientAccessToken(HubName, userId, claims, _tokenLifeTime); + var manager = new ServiceManager(new ServiceManagerOptions() { ConnectionString = _testConnectionString, ApplicationName = appName }); + var tokenString = manager.GenerateClientAccessToken(HubName, userId, claims, _tokenLifeTime); var token = JwtTokenHelper.JwtHandler.ReadJwtToken(tokenString); - string expectedToken = JwtTokenHelper.GenerateExpectedAccessToken(token, _clientEndpoint, AccessKey, claims); + string expectedToken = JwtTokenHelper.GenerateExpectedAccessToken(token, GetExpectedClientEndpoint(appName), AccessKey, claims); Assert.Equal(expectedToken, tokenString); } - [Fact] - internal void GenerateClientEndpointTest() + [Theory] + [MemberData(nameof(TestGenerateClientEndpointData))] + internal void GenerateClientEndpointTest(string appName, string expectedClientEndpoint) { - var clientEndpoint = _serviceManager.GetClientEndpoint(HubName); + var manager = new ServiceManager(new ServiceManagerOptions() { ConnectionString = _testConnectionString, ApplicationName = appName }); + var clientEndpoint = manager.GetClientEndpoint(HubName); - Assert.Equal(_clientEndpoint, clientEndpoint); + Assert.Equal(expectedClientEndpoint, clientEndpoint); } [Theory] - [MemberData(nameof(TestServiceOptionData))] + [MemberData(nameof(TestServiceManagerOptionData))] internal async Task CreateServiceHubContextTest(ServiceTransportType serviceTransportType, bool useLoggerFacory, string appName) { var serviceManager = new ServiceManager(new ServiceManagerOptions @@ -116,5 +81,15 @@ internal async Task CreateServiceHubContextTest(ServiceTransportType serviceTran var hubContext = await serviceManager.CreateHubContextAsync(HubName, loggerFactory); } } + + private static string GetExpectedClientEndpoint(string appName = null) + { + if (string.IsNullOrEmpty(appName)) + { + return $"{Endpoint}/client/?hub={HubName.ToLower()}"; + } + + return $"{Endpoint}/client/?hub={appName.ToLower()}_{HubName.ToLower()}"; + } } } From 64afefbc8ec12c1ec445643fb5ef5112e80406f6 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Mon, 8 Apr 2019 15:27:56 +0800 Subject: [PATCH 13/13] fix bug: parameters order --- .../RestHubLifetimeManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs b/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs index c9097408d..776522174 100644 --- a/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs +++ b/src/Microsoft.Azure.SignalR.Management/RestHubLifetimeManager.cs @@ -23,7 +23,7 @@ internal class RestHubLifetimeManager : HubLifetimeManager, IHubLifetimeMan public RestHubLifetimeManager(ServiceManagerOptions serviceManagerOptions, string hubName) { - _restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, serviceManagerOptions.ApplicationName, hubName); + _restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, hubName, serviceManagerOptions.ApplicationName); } public override Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default)