Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a144ef6
Add Json Payload Functionality for User Agent Feature Extension
samsharma2700 Aug 22, 2025
13090ce
Update truncation null checks
samsharma2700 Aug 22, 2025
8359565
Merge remote-tracking branch 'origin/main' into dev/samsharma2700/use…
samsharma2700 Sep 9, 2025
c450c61
Enable UserAgent Feature Extension
samsharma2700 Sep 9, 2025
c8897d3
Add new functional tests for UserAgent FE
samsharma2700 Sep 10, 2025
c0eea2b
Update functional test to verify driver behaviour
samsharma2700 Sep 11, 2025
26dd6f9
Assertion update
samsharma2700 Sep 11, 2025
8ad3c69
Remove unused flags and conditionals
samsharma2700 Sep 11, 2025
2184035
Remove IsUserAgentSupportEnabled flag
samsharma2700 Sep 11, 2025
af1eeb1
Merge remote-tracking branch 'origin/main' into dev/samsharma2700/use…
samsharma2700 Sep 11, 2025
3b51844
Test cleanup and identifier update
samsharma2700 Sep 11, 2025
ff39552
Merge remote-tracking branch 'origin/main' into dev/samsharma2700/use…
samsharma2700 Sep 17, 2025
2394a2f
Merge remote-tracking branch 'origin/main' into dev/samsharma2700/use…
samsharma2700 Sep 23, 2025
d673104
Fix server side throw issue
samsharma2700 Oct 7, 2025
90c97c5
Resolve merge conflicts
samsharma2700 Oct 7, 2025
d494b66
Add useragent payload in parser
samsharma2700 Oct 8, 2025
4b59a62
Update Test
samsharma2700 Oct 10, 2025
bd038a2
Remove stray comment
samsharma2700 Oct 10, 2025
92452b8
Cleanup
samsharma2700 Oct 10, 2025
74027ae
Make Uagent flag session based
samsharma2700 Oct 10, 2025
792a721
Merge remote-tracking branch 'origin/main' into dev/samsharma2700/use…
samsharma2700 Oct 10, 2025
4fc5055
Minor fix
samsharma2700 Oct 10, 2025
45b7132
Add LocalAppContextSwitch and CI fix
samsharma2700 Oct 13, 2025
d88b970
Merge remote-tracking branch 'origin/main' into dev/samsharma2700/use…
samsharma2700 Oct 13, 2025
f427f5d
Minor fix
samsharma2700 Oct 13, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,6 @@ internal bool IsDNSCachingBeforeRedirectSupported
// Json Support Flag
internal bool IsJsonSupportEnabled = false;

// User Agent Flag
internal bool IsUserAgentEnabled = true;

// Vector Support Flag
internal bool IsVectorSupportEnabled = false;

Expand Down Expand Up @@ -1414,10 +1411,7 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword,
requestedFeatures |= TdsEnums.FeatureExtension.SQLDNSCaching;
requestedFeatures |= TdsEnums.FeatureExtension.JsonSupport;
requestedFeatures |= TdsEnums.FeatureExtension.VectorSupport;

#if DEBUG
requestedFeatures |= TdsEnums.FeatureExtension.UserAgent;
#endif

_parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData, encrypt);
}
Expand Down Expand Up @@ -3023,6 +3017,12 @@ internal void OnFeatureExtAck(int featureId, byte[] data)
IsVectorSupportEnabled = true;
break;
}
case TdsEnums.FEATUREEXT_USERAGENT:
{
// Unexpected ack from server but we ignore it entirely
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnectionTds.OnFeatureExtAck|ADV> {0}, Received feature extension acknowledgement for USERAGENTSUPPORT (ignored)", ObjectID);
break;
}

default:
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,6 @@ internal bool IsDNSCachingBeforeRedirectSupported
// Vector Support Flag
internal bool IsVectorSupportEnabled = false;

// User Agent Flag
internal bool IsUserAgentEnabled = true;

// TCE flags
internal byte _tceVersionSupported;

Expand Down Expand Up @@ -3068,7 +3065,18 @@ internal void OnFeatureExtAck(int featureId, byte[] data)
IsVectorSupportEnabled = true;
break;
}
case TdsEnums.FEATUREEXT_USERAGENT:
{
// TODO: Verify that the server sends an acknowledgment (Ack)
// using this log message in the future.

// This Ack from the server is unexpected and is ignored completely.
// According to the TDS specification, an Ack is not defined/expected
// for this scenario. We handle it only for completeness
// and to support testing.
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnectionTds.OnFeatureExtAck|ADV> {0}, Received feature extension acknowledgement for USERAGENTSUPPORT (ignored)", ObjectID);
break;
}
default:
{
// Unknown feature ack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ private enum Tristate : byte
private const string UseConnectionPoolV2String = @"Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2";
private const string TruncateScaledDecimalString = @"Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal";
private const string IgnoreServerProvidedFailoverPartnerString = @"Switch.Microsoft.Data.SqlClient.IgnoreServerProvidedFailoverPartner";
private const string EnableUserAgentString = @"Switch.Microsoft.Data.SqlClient.EnableUserAgent";
#if NET
private const string GlobalizationInvariantModeString = @"System.Globalization.Invariant";
private const string GlobalizationInvariantModeEnvironmentVariable = "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT";
Expand All @@ -45,6 +46,7 @@ private enum Tristate : byte
private static Tristate s_useConnectionPoolV2;
private static Tristate s_truncateScaledDecimal;
private static Tristate s_ignoreServerProvidedFailoverPartner;
private static Tristate s_enableUserAgent;
#if NET
private static Tristate s_globalizationInvariantMode;
private static Tristate s_useManagedNetworking;
Expand Down Expand Up @@ -328,7 +330,27 @@ public static bool IgnoreServerProvidedFailoverPartner
return s_ignoreServerProvidedFailoverPartner == Tristate.True;
}
}

/// <summary>
/// When set to true, the user agent feature is enabled and the driver will send the user agent string to the server.
/// </summary>
public static bool EnableUserAgent
{
get
{
if (s_enableUserAgent == Tristate.NotInitialized)
{
if (AppContext.TryGetSwitch(EnableUserAgentString, out bool returnedValue) && returnedValue)
{
s_enableUserAgent = Tristate.True;
}
else
{
s_enableUserAgent = Tristate.False;
}
}
return s_enableUserAgent == Tristate.True;
}
}
#if NET
/// <summary>
/// .NET Core 2.0 and up supports Globalization Invariant mode, which reduces the size of the required libraries for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ public enum EnvChangeType : byte
public const byte FEATUREEXT_SQLDNSCACHING = 0x0B;
public const byte FEATUREEXT_JSONSUPPORT = 0x0D;
public const byte FEATUREEXT_VECTORSUPPORT = 0x0E;
// TODO: re-verify if this byte competes with another feature
public const byte FEATUREEXT_USERAGENT = 0x0F;
public const byte FEATUREEXT_USERAGENT = 0x10;

[Flags]
public enum FeatureExtension : uint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
using Microsoft.Data.SqlClient.DataClassification;
using Microsoft.Data.SqlClient.LocalDb;
using Microsoft.Data.SqlClient.Server;
using Microsoft.Data.SqlClient.UserAgent;
using Microsoft.Data.SqlClient.Utilities;


#if NETFRAMEWORK
using Microsoft.Data.SqlTypes;
#endif
Expand Down Expand Up @@ -1361,7 +1364,14 @@ internal void TdsLogin(

int feOffset = length;
// calculate and reserve the required bytes for the featureEx
length = ApplyFeatureExData(requestedFeatures, recoverySessionData, fedAuthFeatureExtensionData, useFeatureExt, length);
length = ApplyFeatureExData(
requestedFeatures,
recoverySessionData,
fedAuthFeatureExtensionData,
UserAgentInfo.UserAgentCachedJsonPayload.ToArray(),
useFeatureExt,
length
);

WriteLoginData(rec,
requestedFeatures,
Expand Down Expand Up @@ -9448,7 +9458,15 @@ private void WriteLoginData(SqlLogin rec,
}
}

ApplyFeatureExData(requestedFeatures, recoverySessionData, fedAuthFeatureExtensionData, useFeatureExt, length, true);
ApplyFeatureExData(
requestedFeatures,
recoverySessionData,
fedAuthFeatureExtensionData,
UserAgentInfo.UserAgentCachedJsonPayload.ToArray(),
useFeatureExt,
length,
true
);
}
catch (Exception e)
{
Expand All @@ -9467,6 +9485,7 @@ private void WriteLoginData(SqlLogin rec,
private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures,
SessionData recoverySessionData,
FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData,
byte[] userAgentJsonPayload,
bool useFeatureExt,
int length,
bool write = false)
Expand All @@ -9475,6 +9494,11 @@ private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures,
{
checked
{
// NOTE: As part of TDS spec UserAgent feature extension should be the first feature extension in the list.
if (LocalAppContextSwitches.EnableUserAgent && ((requestedFeatures & TdsEnums.FeatureExtension.UserAgent) != 0))
{
length += WriteUserAgentFeatureRequest(userAgentJsonPayload, write);
}
if ((requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) != 0)
{
length += WriteSessionRecoveryFeatureRequest(recoverySessionData, write);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public sealed class LocalAppContextSwitchesHelper : IDisposable
private readonly PropertyInfo _useConnectionPoolV2Property;
private readonly PropertyInfo _truncateScaledDecimalProperty;
private readonly PropertyInfo _ignoreServerProvidedFailoverPartner;
private readonly PropertyInfo _enableUserAgent;
#if NET
private readonly PropertyInfo _globalizationInvariantModeProperty;
private readonly PropertyInfo _useManagedNetworkingProperty;
Expand Down Expand Up @@ -60,6 +61,8 @@ public sealed class LocalAppContextSwitchesHelper : IDisposable
private readonly Tristate _truncateScaledDecimalOriginal;
private readonly FieldInfo _ignoreServerProvidedFailoverPartnerField;
private readonly Tristate _ignoreServerProvidedFailoverPartnerOriginal;
private readonly FieldInfo _enableUserAgentField;
private readonly Tristate _enableUserAgentOriginal;
#if NET
private readonly FieldInfo _globalizationInvariantModeField;
private readonly Tristate _globalizationInvariantModeOriginal;
Expand Down Expand Up @@ -162,7 +165,11 @@ void InitProperty(string name, out PropertyInfo property)
"IgnoreServerProvidedFailoverPartner",
out _ignoreServerProvidedFailoverPartner);

#if NET
InitProperty(
"EnableUserAgent",
out _enableUserAgent);

#if NET
InitProperty(
"GlobalizationInvariantMode",
out _globalizationInvariantModeProperty);
Expand Down Expand Up @@ -240,6 +247,11 @@ void InitField(string name, out FieldInfo field, out Tristate value)
"s_ignoreServerProvidedFailoverPartner",
out _ignoreServerProvidedFailoverPartnerField,
out _ignoreServerProvidedFailoverPartnerOriginal);

InitField(
"s_enableUserAgent",
out _enableUserAgentField,
out _enableUserAgentOriginal);

#if NET
InitField(
Expand Down Expand Up @@ -323,6 +335,10 @@ void RestoreField(FieldInfo field, Tristate value)
_ignoreServerProvidedFailoverPartnerField,
_ignoreServerProvidedFailoverPartnerOriginal);

RestoreField(
_enableUserAgentField,
_enableUserAgentOriginal);

#if NET
RestoreField(
_globalizationInvariantModeField,
Expand Down Expand Up @@ -429,6 +445,11 @@ public bool IgnoreServerProvidedFailoverPartner
get => (bool)_ignoreServerProvidedFailoverPartner.GetValue(null);
}

public bool EnableUserAgent
{
get => (bool)_enableUserAgent.GetValue(null);
}

#if NET
/// <summary>
/// Access the LocalAppContextSwitches.GlobalizationInvariantMode property.
Expand Down Expand Up @@ -553,6 +574,12 @@ public Tristate IgnoreServerProvidedFailoverPartnerField
set => SetValue(_ignoreServerProvidedFailoverPartnerField, value);
}

public Tristate EnableUserAgentField
{
get => GetValue(_enableUserAgentField);
set => SetValue(_enableUserAgentField, value);
}

#if NET
/// <summary>
/// Get or set the LocalAppContextSwitches.GlobalizationInvariantMode switch value.
Expand Down
Loading
Loading