Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 62 additions & 9 deletions src/Microsoft.Azure.SignalR/ServiceOptionsSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,56 @@ public void Configure(ServiceOptions options)
options.ConnectionString = configuration.ConnectionString;
options.Endpoints = configuration.Endpoints;
options.ApplicationName = configuration.AppName;
options.ServerStickyMode = configuration.StickyMode;

var configurableOption = configuration.configurableOptions;
if (configurableOption != null)
{
options.ServerStickyMode = GetConfiguredEnum(configurableOption.ServerStickyMode, options.ServerStickyMode);
options.InitialHubServerConnectionCount = configurableOption.InitialHubServerConnectionCount ?? options.InitialHubServerConnectionCount;
options.MaxHubServerConnectionCount = configurableOption.MaxHubServerConnectionCount ?? options.MaxHubServerConnectionCount;
options.AccessTokenAlgorithm = GetConfiguredEnum(configurableOption.AccessTokenAlgorithm, options.AccessTokenAlgorithm);

options.AccessTokenLifetime = GetConfiguredTimeSpanFromSeconds(configurableOption.AccessTokenLifetimeInSeconds, options.AccessTokenLifetime);
options.ServiceScaleTimeout = GetConfiguredTimeSpanFromSeconds(configurableOption.ServiceScaleTimeoutInSeconds, options.ServiceScaleTimeout);
options.MaxPollIntervalInSeconds = configurableOption.MaxPollIntervalInSeconds ?? options.MaxPollIntervalInSeconds;

if (configurableOption.GracefulShutdown != null)
{
var shutdownOptions = new GracefulShutdownOptions();
shutdownOptions.Mode = GetConfiguredEnum(configurableOption.GracefulShutdown.Mode, shutdownOptions.Mode);
shutdownOptions.Timeout = GetConfiguredTimeSpanFromSeconds(configurableOption.GracefulShutdown.TimeoutInSeconds, shutdownOptions.Timeout);
options.GracefulShutdown = shutdownOptions;
}
}
}

public IChangeToken GetChangeToken()
{
return _configuration.GetReloadToken();
}

private (string AppName, string ConnectionString, ServerStickyMode StickyMode, ServiceEndpoint[] Endpoints) ParseConfiguration()
private TimeSpan GetConfiguredTimeSpanFromSeconds(int? seconds, TimeSpan defaultValue)
{
// For backward compatability, first read from prefix
var appName = _configuration[Constants.Keys.ApplicationNameDefaultKeyPrefix] ?? _configuration[Constants.Keys.ApplicationNameDefaultKey];
var stickyMode = ServerStickyMode.Disabled;
var mode = _configuration[Constants.Keys.ServerStickyModeDefaultKey];
if (!string.IsNullOrEmpty(mode))
return seconds == null ? defaultValue : TimeSpan.FromSeconds(seconds.Value);
}

private T GetConfiguredEnum<T>(string value, T defaultValue) where T : struct
{
if (Enum.TryParse<T>(value, true, out var result))
{
Enum.TryParse(mode, true, out stickyMode);
return result;
}

return defaultValue;
}

private (string AppName, string ConnectionString, ServiceEndpoint[] Endpoints, ConfigurableServiceOptions configurableOptions) ParseConfiguration()
{
var options = _configuration.GetSection(Constants.Keys.AzureSignalRSectionKey).Get<ConfigurableServiceOptions>();

// For backward compatability, first read from prefix
var appName = _configuration[Constants.Keys.ApplicationNameDefaultKeyPrefix] ?? _configuration[Constants.Keys.ApplicationNameDefaultKey];

// Fallback to ConnectionStrings:Azure:SignalR:ConnectionString format when the default one is not available
var connectionString = _configuration[Constants.Keys.ConnectionStringDefaultKey] ?? _configuration[Constants.Keys.ConnectionStringSecondaryKey];

Expand All @@ -56,7 +87,29 @@ public IChangeToken GetChangeToken()
endpoints = _configuration.GetEndpoints(Constants.Keys.ConnectionStringSecondaryKey).ToArray();
}

return (appName, connectionString, stickyMode, endpoints);
return (appName, connectionString, endpoints, options);
}

private record class ConfigurableGracefulShutdownOptions(
string Mode,
int? TimeoutInSeconds
)
{
public ConfigurableGracefulShutdownOptions() : this(null, null) { }
}

private record class ConfigurableServiceOptions(
string ServerStickyMode,
int? InitialHubServerConnectionCount,
int? MaxHubServerConnectionCount,
string AccessTokenAlgorithm,
int? AccessTokenLifetimeInSeconds,
int? ServiceScaleTimeoutInSeconds,
int? MaxPollIntervalInSeconds,
ConfigurableGracefulShutdownOptions GracefulShutdown
)
{
public ConfigurableServiceOptions() : this(null, null, null, null, null, null, null, null) { }
}
}
}
45 changes: 44 additions & 1 deletion test/Microsoft.Azure.SignalR.Tests/AddAzureSignalRFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,49 @@ public void AddAzureWithDiagnosticClientRuleProvider()
}
}

[Fact]
public void AddAzureOptionsFromConfiguration()
{
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
{
var services = new ServiceCollection();
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
{"Azure:SignalR:ConnectionString", DefaultValue},
{"Azure:SignalR:ServerStickyMode", "preferred" },
{"Azure:SignalR:ApplicationName:", "ABC" },
{"Azure:SignalR:InitialHubServerConnectionCount", "1" },
{"Azure:SignalR:MaxHubServerConnectionCount", "2" },
{"Azure:SignalR:AccessTokenLifetimeInSeconds", "1" },
{"Azure:SignalR:ServiceScaleTimeoutInSeconds", "2" },
{"Azure:SignalR:MaxPollIntervalInSeconds", "3" },
{"Azure:SignalR:GracefulShutdown:Mode", "WaitForClientsClose" },
{"Azure:SignalR:GracefulShutdown:TimeOutInSeconds", "4" },
})
.Build();
var serviceProvider = services.AddSignalR()
.AddAzureSignalR()
.Services
.AddSingleton<IConfiguration>(config)
.AddSingleton(loggerFactory)
.BuildServiceProvider();

var options = serviceProvider.GetRequiredService<IOptions<ServiceOptions>>().Value;

Assert.Equal(DefaultValue, options.ConnectionString);
Assert.Equal(ServerStickyMode.Preferred, options.ServerStickyMode);
Assert.Equal("ABC", options.ApplicationName);
Assert.Equal(1, options.InitialHubServerConnectionCount);
Assert.Equal(2, options.MaxHubServerConnectionCount);
Assert.Equal(1, options.AccessTokenLifetime.Seconds);
Assert.Equal(2, options.ServiceScaleTimeout.Seconds);
Assert.Equal(3, options.MaxPollIntervalInSeconds);
Assert.Equal(GracefulShutdownMode.WaitForClientsClose, options.GracefulShutdown.Mode);
Assert.Equal(4, options.GracefulShutdown.Timeout.Seconds);
}
}

[Fact]
public void AddAzureReadsConnectionStringFirst()
{
Expand All @@ -159,7 +202,7 @@ public void AddAzureReadsConnectionStringFirst()
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
{"Azure:SignalR:ConnectionString", DefaultValue},
{"Azure:SignalR:ConnectionString", DefaultValue},
{"Azure:SignalR:StickyServerMode", "invalid" }
})
.Build();
Expand Down