Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use AppId from config and use GetDeterministicHashCode #97

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<Compile Include="SqlFxCompatSessionStateRepository.cs" />
<Compile Include="SqlSessionStateRepository.cs" />
<Compile Include="SqlSessionStateRepositoryUtil.cs" />
<Compile Include="StringExtensions.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\SR.resx">
Expand Down
114 changes: 71 additions & 43 deletions src/SqlSessionStateProviderAsync/SqlSessionStateProviderAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class SqlSessionStateProviderAsync : SessionStateStoreProviderAsyncBase
private const string RETRY_INTERVAL_CONFIGURATION_NAME = "retryInterval";
private const string CONNECTIONSTRING_NAME_CONFIGURATION_NAME = "connectionStringName";
private const string SESSION_TABLE_CONFIGURATION_NAME = "sessionTableName";
private const string APP_ID_CONFIGURATION_NAME = "appId";
private const string SESSIONSTATE_SECTION_PATH = "system.web/sessionState";
private const double SessionExpiresFrequencyCheckIntervalTicks = 30 * TimeSpan.TicksPerSecond;
private static long s_lastSessionPurgeTicks;
Expand All @@ -41,7 +42,7 @@ public class SqlSessionStateProviderAsync : SessionStateStoreProviderAsyncBase
private static RepositoryType s_repositoryType;

private int _rqOrigStreamLen;

/// <summary>
/// Initialize the provider through the configuration
/// </summary>
Expand All @@ -65,7 +66,7 @@ public override void Initialize(string name, NameValueCollection config)
}

// for unit tests
internal void Initialize(string name, NameValueCollection config, SessionStateSection ssc, ConnectionStringSettings connectionString,
internal void Initialize(string name, NameValueCollection config, SessionStateSection ssc, ConnectionStringSettings connectionString,
bool shouldCreateTable = false)
{
base.Initialize(name, config);
Expand Down Expand Up @@ -105,27 +106,52 @@ internal void Initialize(string name, NameValueCollection config, SessionStateSe
// Initialize the repository
if (s_repositoryType == RepositoryType.InMemory || s_repositoryType == RepositoryType.InMemoryDurable)
{
s_sqlSessionStateRepository = new SqlInMemoryTableSessionStateRepository(connectionString.ConnectionString, tableName,
(int)ssc.SqlCommandTimeout.TotalSeconds, GetRetryInterval(config), GetMaxRetryNum(config), (s_repositoryType == RepositoryType.InMemoryDurable));
s_sqlSessionStateRepository = new SqlInMemoryTableSessionStateRepository(
connectionString.ConnectionString,
tableName,
(int)ssc.SqlCommandTimeout.TotalSeconds,
GetRetryInterval(config),
GetMaxRetryNum(config),
(s_repositoryType == RepositoryType.InMemoryDurable)
);
}
else if (s_repositoryType == RepositoryType.FrameworkCompat)
{
s_sqlSessionStateRepository = new SqlFxCompatSessionStateRepository(connectionString.ConnectionString, tableName,
(int)ssc.SqlCommandTimeout.TotalSeconds, GetRetryInterval(config), GetMaxRetryNum(config));
s_sqlSessionStateRepository = new SqlFxCompatSessionStateRepository(
connectionString.ConnectionString,
tableName,
(int)ssc.SqlCommandTimeout.TotalSeconds,
GetRetryInterval(config),
GetMaxRetryNum(config)
);
}
else
{
s_sqlSessionStateRepository = new SqlSessionStateRepository(connectionString.ConnectionString, tableName,
(int)ssc.SqlCommandTimeout.TotalSeconds, GetRetryInterval(config), GetMaxRetryNum(config));
s_sqlSessionStateRepository = new SqlSessionStateRepository(
connectionString.ConnectionString,
tableName,
(int)ssc.SqlCommandTimeout.TotalSeconds,
GetRetryInterval(config),
GetMaxRetryNum(config)
);
}
if (shouldCreateTable)
{
s_sqlSessionStateRepository.CreateSessionStateTable();
}

var appId = AppId ?? HttpRuntime.AppDomainAppId;
//============================================================================ robs ==
// Use AppId from config if specified, otherwise use AppDomainAppId
//====================================================================== 2023-07-21 ==
string configAppId = config[APP_ID_CONFIGURATION_NAME];
if (string.IsNullOrEmpty(configAppId))
{
configAppId = HttpRuntime.AppDomainAppId;
}

string appId = AppId ?? configAppId;
Debug.Assert(appId != null);
s_appSuffix = appId.GetHashCode().ToString("X8", CultureInfo.InvariantCulture);
s_appSuffix = appId.GetDeterministicHashCode().ToString("X8", CultureInfo.InvariantCulture);

s_oneTimeInited = true;
}
Expand Down Expand Up @@ -188,7 +214,7 @@ internal static Func<HttpContext, HttpStaticObjectsCollection> GetSessionStaticO
{
int retryInterval;
var val = config[RETRY_INTERVAL_CONFIGURATION_NAME];
if(val != null && int.TryParse(val, out retryInterval))
if (val != null && int.TryParse(val, out retryInterval))
{
return retryInterval;
}
Expand All @@ -214,9 +240,9 @@ public override SessionStateStoreData CreateNewStoreData(HttpContextBase context

/// <inheritdoc />
public override async Task CreateUninitializedItemAsync(
HttpContextBase context,
string id,
int timeout,
HttpContextBase context,
string id,
int timeout,
CancellationToken cancellationToken)
{
if (id == null)
Expand Down Expand Up @@ -259,8 +285,8 @@ public override Task<GetItemResult> GetItemAsync(HttpContextBase context, string

/// <inheritdoc />
public override Task<GetItemResult> GetItemExclusiveAsync(
HttpContextBase context,
string id,
HttpContextBase context,
string id,
CancellationToken cancellationToken)
{
return DoGet(context, id, true, cancellationToken);
Expand All @@ -274,9 +300,9 @@ public override void InitializeRequest(HttpContextBase context)

/// <inheritdoc />
public override async Task ReleaseItemExclusiveAsync(
HttpContextBase context,
string id,
object lockId,
HttpContextBase context,
string id,
object lockId,
CancellationToken cancellationToken)
{
if (id == null)
Expand All @@ -295,10 +321,10 @@ public override async Task ReleaseItemExclusiveAsync(

/// <inheritdoc />
public override async Task RemoveItemAsync(
HttpContextBase context,
string id,
object lockId,
SessionStateStoreData item,
HttpContextBase context,
string id,
object lockId,
SessionStateStoreData item,
CancellationToken cancellationToken)
{
if (id == null)
Expand All @@ -317,8 +343,8 @@ public override async Task RemoveItemAsync(

/// <inheritdoc />
public override async Task ResetItemTimeoutAsync(
HttpContextBase context,
string id,
HttpContextBase context,
string id,
CancellationToken cancellationToken)
{
if (id == null)
Expand All @@ -337,11 +363,11 @@ public override async Task ResetItemTimeoutAsync(

/// <inheritdoc />
public override async Task SetAndReleaseItemExclusiveAsync(
HttpContextBase context,
string id,
SessionStateStoreData item,
object lockId,
bool newItem,
HttpContextBase context,
string id,
SessionStateStoreData item,
object lockId,
bool newItem,
CancellationToken cancellationToken)
{
byte[] buf;
Expand All @@ -368,7 +394,7 @@ public override async Task SetAndReleaseItemExclusiveAsync(
}
catch
{
if(!newItem)
if (!newItem)
{
await ReleaseItemExclusiveAsync(context, id, lockId, cancellationToken);
}
Expand All @@ -393,15 +419,15 @@ private async Task<GetItemResult> DoGet(HttpContextBase context, string id, bool
throw new ArgumentException(SR.Session_id_too_long);
}
id = AppendAppIdHash(id);

SessionStateStoreData data = null;
var sessionItem = await s_sqlSessionStateRepository.GetSessionStateItemAsync(id, exclusive);

if(sessionItem == null)
if (sessionItem == null)
{
return null;
}
if(sessionItem.Item == null)
if (sessionItem.Item == null)
{
return new GetItemResult(null, sessionItem.Locked, sessionItem.LockAge, sessionItem.LockId, sessionItem.Actions);
}
Expand All @@ -423,14 +449,14 @@ internal static string AppendAppIdHash(string id)
return id + s_appSuffix;
}
return id;
}
}

// Internal code copied from SessionStateUtility
internal static void SerializeStoreData(
SessionStateStoreData item,
int initialStreamSize,
out byte[] buf,
out int length,
SessionStateStoreData item,
int initialStreamSize,
out byte[] buf,
out int length,
bool compressionEnabled)
{
using (MemoryStream s = new MemoryStream(initialStreamSize))
Expand Down Expand Up @@ -518,7 +544,7 @@ private static SessionStateStoreData Deserialize(HttpContextBase context, Stream
try
{
BinaryReader reader = new BinaryReader(stream);

timeout = reader.ReadInt32();
hasItems = reader.ReadBoolean();
hasStaticObjects = reader.ReadBoolean();
Expand All @@ -527,15 +553,17 @@ private static SessionStateStoreData Deserialize(HttpContextBase context, Stream
{
sessionItems = SessionStateItemCollection.Deserialize(reader);
}
else {
else
{
sessionItems = new SessionStateItemCollection();
}

if (hasStaticObjects)
{
staticObjects = HttpStaticObjectsCollection.Deserialize(reader);
}
else {
else
{
staticObjects = GetSessionStaticObjects(context.ApplicationInstance.Context);
}

Expand Down Expand Up @@ -600,6 +628,6 @@ private static ConnectionStringSettings GetConnectionString(string connectionstr
String.Format(CultureInfo.CurrentCulture, SR.Connection_string_not_found, connectionstringName));
}
return conn;
}
}
}
}
29 changes: 29 additions & 0 deletions src/SqlSessionStateProviderAsync/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Microsoft.AspNet.SessionState
{
internal static class StringExtensions
{
//============================================================================ robs ==
// This is to replace the call to GetHashCode() when appending AppId to the session id.
// Using GetHashCode() is not deterministic and can cause problems when used externally (e.g in SQL)
// Credit: https://andrewlock.net/why-is-string-gethashcode-different-each-time-i-run-my-program-in-net-core/
//====================================================================== 2023-07-21 ==
internal static int GetDeterministicHashCode(this string str)
{
unchecked
{
int hash1 = (5381 << 16) + 5381;
int hash2 = hash1;

for (int i = 0; i < str.Length; i += 2)
{
hash1 = ((hash1 << 5) + hash1) ^ str[i];
if (i == str.Length - 1)
break;
hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
}

return hash1 + (hash2 * 1566083941);
}
}
}
}