diff --git a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
index 67c74089b..9f106c5c2 100644
--- a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
+++ b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
@@ -228,7 +228,7 @@ protected virtual string GetDefaultClientName() =>
///
/// String version of the StackExchange.Redis library, for use in any options.
///
- protected static string LibraryVersion => Utils.GetLibVersion();
+ public virtual string LibraryVersion => Utils.GetLibVersion();
///
/// Name of the machine we're running on, for use in any options.
diff --git a/src/StackExchange.Redis/ConfigurationOptions.cs b/src/StackExchange.Redis/ConfigurationOptions.cs
index a85232172..3549a8b66 100644
--- a/src/StackExchange.Redis/ConfigurationOptions.cs
+++ b/src/StackExchange.Redis/ConfigurationOptions.cs
@@ -157,7 +157,7 @@ public static string TryNormalize(string value)
private bool? allowAdmin, abortOnConnectFail, resolveDns, ssl, checkCertificateRevocation,
includeDetailInExceptions, includePerformanceCountersInExceptions, setClientLibrary;
- private string? tieBreaker, sslHost, configChannel, user, password;
+ private string? tieBreaker, sslHost, configChannel, user, password, libraryName, libraryVersion;
private TimeSpan? heartbeatInterval;
@@ -249,20 +249,40 @@ public bool UseSsl
///
/// Gets or sets whether the library should identify itself by library-name/version when possible.
///
+ ///
public bool SetClientLibrary
{
get => setClientLibrary ?? Defaults.SetClientLibrary;
set => setClientLibrary = value;
}
-
///
/// Gets or sets the library name to use for CLIENT SETINFO lib-name calls to Redis during handshake.
/// Defaults to "SE.Redis".
///
- /// If the value is null, empty or whitespace, then the value from the options-provideer is used;
- /// to disable the library name feature, use instead.
- public string? LibraryName { get; set; }
+ ///
+ /// To disable the library name feature, set to false.
+ /// For allowed values, see .
+ ///
+ public string? LibraryName
+ {
+ get => libraryName ?? Defaults.LibraryName;
+ set => libraryName = value;
+ }
+
+ ///
+ /// Gets or sets the library version to use for CLIENT SETINFO lib-ver calls to Redis during handshake.
+ /// Defaults to the build version of StackExchange.Redis.
+ ///
+ ///
+ /// To disable the library name feature, set to false.
+ /// For allowed values, see .
+ ///
+ public string? LibraryVersion
+ {
+ get => libraryVersion ?? Defaults.LibraryVersion;
+ set => libraryVersion = value;
+ }
///
/// Automatically encodes and decodes channels.
@@ -709,7 +729,8 @@ public static ConfigurationOptions Parse(string configuration, bool ignoreUnknow
#endif
Tunnel = Tunnel,
setClientLibrary = setClientLibrary,
- LibraryName = LibraryName,
+ libraryName = libraryName,
+ libraryVersion = libraryVersion,
Protocol = Protocol,
};
@@ -834,7 +855,7 @@ private static void Append(StringBuilder sb, string prefix, object? value)
private void Clear()
{
- ClientName = ServiceName = user = password = tieBreaker = sslHost = configChannel = null;
+ ClientName = ServiceName = user = password = tieBreaker = sslHost = configChannel = libraryName = libraryVersion = null;
keepAlive = syncTimeout = asyncTimeout = connectTimeout = connectRetry = configCheckSeconds = DefaultDatabase = null;
allowAdmin = abortOnConnectFail = resolveDns = ssl = setClientLibrary = null;
SslProtocols = null;
diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
index 459f66cf8..f12fa8f4a 100644
--- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
@@ -244,6 +244,8 @@ StackExchange.Redis.ConfigurationOptions.KeepAlive.get -> int
StackExchange.Redis.ConfigurationOptions.KeepAlive.set -> void
StackExchange.Redis.ConfigurationOptions.LibraryName.get -> string?
StackExchange.Redis.ConfigurationOptions.LibraryName.set -> void
+StackExchange.Redis.ConfigurationOptions.LibraryVersion.get -> string?
+StackExchange.Redis.ConfigurationOptions.LibraryVersion.set -> void
StackExchange.Redis.ConfigurationOptions.LoggerFactory.get -> Microsoft.Extensions.Logging.ILoggerFactory?
StackExchange.Redis.ConfigurationOptions.LoggerFactory.set -> void
StackExchange.Redis.ConfigurationOptions.Password.get -> string?
@@ -1611,7 +1613,6 @@ static StackExchange.Redis.Configuration.DefaultOptionsProvider.AddProvider(Stac
static StackExchange.Redis.Configuration.DefaultOptionsProvider.ComputerName.get -> string!
static StackExchange.Redis.Configuration.DefaultOptionsProvider.GetProvider(StackExchange.Redis.EndPointCollection! endpoints) -> StackExchange.Redis.Configuration.DefaultOptionsProvider!
static StackExchange.Redis.Configuration.DefaultOptionsProvider.GetProvider(System.Net.EndPoint! endpoint) -> StackExchange.Redis.Configuration.DefaultOptionsProvider!
-static StackExchange.Redis.Configuration.DefaultOptionsProvider.LibraryVersion.get -> string!
static StackExchange.Redis.ConfigurationOptions.Parse(string! configuration) -> StackExchange.Redis.ConfigurationOptions!
static StackExchange.Redis.ConfigurationOptions.Parse(string! configuration, bool ignoreUnknown) -> StackExchange.Redis.ConfigurationOptions!
static StackExchange.Redis.ConnectionMultiplexer.Connect(StackExchange.Redis.ConfigurationOptions! configuration, System.IO.TextWriter? log = null) -> StackExchange.Redis.ConnectionMultiplexer!
@@ -1803,6 +1804,7 @@ virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.IncludePerforma
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.IsMatch(System.Net.EndPoint! endpoint) -> bool
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.KeepAliveInterval.get -> System.TimeSpan
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.LibraryName.get -> string!
+virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.LibraryVersion.get -> string!
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.LoggerFactory.get -> Microsoft.Extensions.Logging.ILoggerFactory?
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Password.get -> string?
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Proxy.get -> StackExchange.Redis.Proxy
diff --git a/src/StackExchange.Redis/ServerEndPoint.cs b/src/StackExchange.Redis/ServerEndPoint.cs
index ebb66ec2a..56ad81286 100644
--- a/src/StackExchange.Redis/ServerEndPoint.cs
+++ b/src/StackExchange.Redis/ServerEndPoint.cs
@@ -926,7 +926,7 @@ private async Task HandshakeAsync(PhysicalConnection connection, ILogger? log)
var config = Multiplexer.RawConfig;
string? user = config.User;
string password = config.Password ?? "";
-
+
string clientName = Multiplexer.ClientName;
if (!string.IsNullOrWhiteSpace(clientName))
{
@@ -1009,17 +1009,13 @@ private async Task HandshakeAsync(PhysicalConnection connection, ILogger? log)
if (config.SetClientLibrary)
{
+ var libName = config.LibraryName;
+ var libVersion = config.LibraryVersion;
+
// note that this is a relatively new feature, but usually we won't know the
// server version, so we will use this speculatively and hope for the best
- log?.LogInformation($"{Format.ToString(this)}: Setting client lib/ver");
+ log?.LogInformation($"{Format.ToString(this)}: Setting client lib/ver to {libName}/{libVersion}");
- var libName = config.LibraryName;
- if (string.IsNullOrWhiteSpace(libName))
- {
- // defer to provider if missing (note re null vs blank; if caller wants to disable
- // it, they should set SetClientLibrary to false, not set the name to empty string)
- libName = config.Defaults.LibraryName;
- }
if (!string.IsNullOrWhiteSpace(libName))
{
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT,
@@ -1028,11 +1024,10 @@ private async Task HandshakeAsync(PhysicalConnection connection, ILogger? log)
await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait();
}
- var version = Utils.GetLibVersion();
- if (!string.IsNullOrWhiteSpace(version))
+ if (!string.IsNullOrWhiteSpace(libVersion))
{
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT,
- RedisLiterals.SETINFO, RedisLiterals.lib_ver, version);
+ RedisLiterals.SETINFO, RedisLiterals.lib_ver, libVersion);
msg.SetInternalCall();
await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait();
}
diff --git a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs
index e3941f749..70badab25 100644
--- a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs
+++ b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs
@@ -167,11 +167,12 @@ public async Task ClientNameExplicitWins()
public class TestLibraryNameOptionsProvider : DefaultOptionsProvider
{
public string Id { get; } = Guid.NewGuid().ToString();
- public override string LibraryName => Id;
+ public override string LibraryName => Id + "Name";
+ public override string LibraryVersion => Id + "Version";
}
[Fact]
- public async Task LibraryNameOverride()
+ public async Task LibraryNameAndVersionOverride()
{
var options = ConfigurationOptions.Parse(GetConfiguration());
var defaults = new TestLibraryNameOptionsProvider();
@@ -185,10 +186,11 @@ public async Task LibraryNameOverride()
var clients = await GetServer(conn).ClientListAsync();
foreach (var client in clients)
{
- Log("Library name: " + client.LibraryName);
+ Log("Library name: " + client.LibraryName + ", version:" + client.LibraryVersion);
}
Assert.True(conn.IsConnected);
- Assert.True(clients.Any(c => c.LibraryName == defaults.LibraryName), "Did not find client with name: " + defaults.Id);
+ Assert.True(clients.Any(c => c.LibraryName == defaults.LibraryName && c.LibraryVersion == defaults.LibraryVersion),
+ "Did not find client with name: '" + defaults.LibraryName + "' and version: '" + defaults.LibraryVersion + "'");
}
}