Skip to content

Commit 8620efb

Browse files
Thread-safe Item Collections for Concurrent mode (#112)
* New thread-safe Item Collection Fixes #95 Added new ThreadSafeSessionStateItemCollection to replace built-in Microsoft one. This fixes the race condition in the indexers. Also commented out all serialization since this is intended to only be used with the in-memory session, so serialization is not necessary. * Rename to ConcurrentSessionStateItemCollection; Add to project * Bring Concurrent collection up to par with in-box implementation so it can be used by serializing providers. * Use concurrent collection in all providers - only when using AllowConcurrentRequestsPerSession. * Update tests for storeData serialization to cover concurrent collection. * Bring back simple non-serializing collection for in-proc provider. --------- Co-authored-by: mellamokb <[email protected]>
1 parent bda2db4 commit 8620efb

10 files changed

Lines changed: 1196 additions & 18 deletions

File tree

src/CosmosDBSessionStateProviderAsync/CosmosDBSessionStateProviderAsync.cs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ public override SessionStateStoreData CreateNewStoreData(HttpContextBase context
611611
staticObjects = GetSessionStaticObjects(context.ApplicationInstance.Context);
612612
}
613613

614-
return new SessionStateStoreData(new SessionStateItemCollection(), staticObjects, timeout);
614+
return new SessionStateStoreData(CreateItemCollection(), staticObjects, timeout);
615615
}
616616

617617
/// <inheritdoc />
@@ -628,7 +628,7 @@ public override async Task CreateUninitializedItemAsync(
628628

629629
string encodedBuf;
630630

631-
var item = new SessionStateStoreData(new SessionStateItemCollection(),
631+
var item = new SessionStateStoreData(CreateItemCollection(),
632632
GetSessionStaticObjects(context.ApplicationInstance.Context),
633633
timeout);
634634

@@ -1038,6 +1038,28 @@ private static string GetEncodedStringFromMemoryStream(MemoryStream s)
10381038
return Convert.ToBase64String(bytes.Array, bytes.Offset, bytes.Count);
10391039
}
10401040

1041+
private static ISessionStateItemCollection CreateItemCollection()
1042+
{
1043+
return SessionStateModuleAsync.AllowConcurrentRequestsPerSession ?
1044+
new ConcurrentSessionStateItemCollection() as ISessionStateItemCollection :
1045+
new SessionStateItemCollection() as ISessionStateItemCollection;
1046+
}
1047+
1048+
private static void SerializeItemCollection(ISessionStateItemCollection items, BinaryWriter writer)
1049+
{
1050+
if (items is ConcurrentSessionStateItemCollection concurrentItems)
1051+
concurrentItems.Serialize(writer);
1052+
else if (items is SessionStateItemCollection defaultItems)
1053+
defaultItems.Serialize(writer);
1054+
}
1055+
1056+
private static ISessionStateItemCollection DeserializeItemCollection(BinaryReader reader)
1057+
{
1058+
return SessionStateModuleAsync.AllowConcurrentRequestsPerSession ?
1059+
ConcurrentSessionStateItemCollection.Deserialize(reader) as ISessionStateItemCollection :
1060+
SessionStateItemCollection.Deserialize(reader) as ISessionStateItemCollection;
1061+
}
1062+
10411063
private static void Serialize(SessionStateStoreData item, Stream stream)
10421064
{
10431065
bool hasItems = true;
@@ -1060,7 +1082,7 @@ private static void Serialize(SessionStateStoreData item, Stream stream)
10601082

10611083
if (hasItems)
10621084
{
1063-
((SessionStateItemCollection)item.Items).Serialize(writer);
1085+
SerializeItemCollection(item.Items, writer);
10641086
}
10651087

10661088
if (hasStaticObjects)
@@ -1089,7 +1111,7 @@ internal static SessionStateStoreData DeserializeStoreData(HttpContextBase conte
10891111
private static SessionStateStoreData Deserialize(HttpContextBase context, Stream stream)
10901112
{
10911113
int timeout;
1092-
SessionStateItemCollection sessionItems;
1114+
ISessionStateItemCollection sessionItems;
10931115
bool hasItems;
10941116
bool hasStaticObjects;
10951117
HttpStaticObjectsCollection staticObjects;
@@ -1106,11 +1128,11 @@ private static SessionStateStoreData Deserialize(HttpContextBase context, Stream
11061128

11071129
if (hasItems)
11081130
{
1109-
sessionItems = SessionStateItemCollection.Deserialize(reader);
1131+
sessionItems = DeserializeItemCollection(reader);
11101132
}
11111133
else
11121134
{
1113-
sessionItems = new SessionStateItemCollection();
1135+
sessionItems = CreateItemCollection();
11141136
}
11151137

11161138
if (hasStaticObjects)

src/SessionStateModule/InProcSessionStateStoreAsync.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,14 @@ private SessionStateStoreData CreateLegitStoreData(
437437
{
438438
if (sessionItems == null)
439439
{
440-
sessionItems = new SessionStateItemCollection();
440+
if (SessionStateModuleAsync.AllowConcurrentRequestsPerSession)
441+
{
442+
sessionItems = new ConcurrentNonSerializingSessionStateItemCollection();
443+
}
444+
else
445+
{
446+
sessionItems = new SessionStateItemCollection();
447+
}
441448
}
442449

443450
if (staticObjects == null && context != null)

src/SessionStateModule/Microsoft.AspNet.SessionState.SessionStateModule.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@
6666
</Compile>
6767
<Compile Include="SessionEventSource.cs" />
6868
<Compile Include="SessionOnEndTarget.cs" />
69+
<Compile Include="SessionStateItemCollections.cs" />
6970
<Compile Include="SessionStateModuleAsync.cs" />
7071
<Compile Include="SessionStateStoreProviderAsyncBase.cs" />
72+
<Compile Include="StateSerializationUtil.cs" />
7173
<Compile Include="TaskAsyncHelper.cs" />
7274
</ItemGroup>
7375
<ItemGroup>

src/SessionStateModule/Resources/SR.Designer.cs

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/SessionStateModule/Resources/SR.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="Cant_serialize_session_state" xml:space="preserve">
121+
<value>Unable to serialize the session state. For out-of-proc session stores, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted.</value>
122+
</data>
120123
<data name="Error_Occured_Reading_Config_Secion" xml:space="preserve">
121124
<value>Error occured when reading config secion '{0}'.</value>
122125
</data>
@@ -126,6 +129,9 @@
126129
<data name="Invalid_session_custom_provider" xml:space="preserve">
127130
<value>The custom session state store provider name '{0}' is invalid.</value>
128131
</data>
132+
<data name="Invalid_session_state" xml:space="preserve">
133+
<value>The session state information is invalid and might be corrupted.</value>
134+
</data>
129135
<data name="Missing_session_custom_provider" xml:space="preserve">
130136
<value>The custom session state store provider '{0}' is not found.</value>
131137
</data>

0 commit comments

Comments
 (0)