Skip to content

Commit dc28598

Browse files
authored
Ensure HttpApplicaiton raises SessionStart (#551)
This fixes two issues that combined to not raise this event: - A typo sent the event SessionEnd instead of SessionStart - Wrapped ASP.NET Core session didn't implement the IsNewSession - it was always false. Now we check if there are any keys to determine if it is a new session
1 parent 9e50058 commit dc28598

File tree

4 files changed

+119
-11
lines changed

4 files changed

+119
-11
lines changed

src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/SessionEventsMiddleware.cs

+38-6
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,51 @@ public SessionEventsMiddleware(RequestDelegate next)
1919

2020
public async Task InvokeAsync(HttpContextCore context)
2121
{
22-
var app = context.Features.GetRequiredFeature<IHttpApplicationFeature>();
23-
var session = context.AsSystemWeb().Session;
22+
if (await RunEventAsync(context, ApplicationEvent.AcquireRequestState))
23+
{
24+
return;
25+
}
26+
27+
if (context.AsSystemWeb().Session is { IsNewSession: true })
28+
{
29+
if (await RunEventAsync(context, ApplicationEvent.SessionStart))
30+
{
31+
return;
32+
}
33+
}
2434

25-
if (session is { IsNewSession: true })
35+
if (await RunEventAsync(context, ApplicationEvent.PostAcquireRequestState))
2636
{
27-
await app.RaiseEventAsync(ApplicationEvent.SessionEnd);
37+
return;
2838
}
2939

3040
await _next(context);
3141

32-
if (session is { State.IsAbandoned: true })
42+
if (context.Features.GetRequiredFeature<IHttpResponseEndFeature>().IsEnded)
43+
{
44+
return;
45+
}
46+
47+
if (await RunEventAsync(context, ApplicationEvent.ReleaseRequestState))
3348
{
34-
await app.RaiseEventAsync(ApplicationEvent.SessionEnd);
49+
return;
3550
}
51+
52+
if (context.AsSystemWeb().Session is { State.IsAbandoned: true })
53+
{
54+
if (await RunEventAsync(context, ApplicationEvent.SessionEnd))
55+
{
56+
return;
57+
}
58+
}
59+
60+
await context.Features.GetRequiredFeature<IHttpApplicationFeature>().RaiseEventAsync(ApplicationEvent.PostReleaseRequestState);
61+
}
62+
63+
private static async ValueTask<bool> RunEventAsync(HttpContextCore context, ApplicationEvent @event)
64+
{
65+
await context.Features.GetRequiredFeature<IHttpApplicationFeature>().RaiseEventAsync(@event);
66+
67+
return context.Features.GetRequiredFeature<IHttpResponseEndFeature>().IsEnded;
3668
}
3769
}

src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/SessionState/Wrapped/AspNetCoreSessionState.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public AspNetCoreSessionState(ISession session, ISessionKeySerializer serializer
2626
_throwOnUnknown = throwOnUnknown;
2727
_logger = factory.CreateLogger<AspNetCoreSessionState>();
2828

29+
IsNewSession = !session.Keys.Any();
2930
IsReadOnly = isReadOnly;
3031
}
3132

@@ -99,7 +100,7 @@ public object? this[string key]
99100

100101
public int Timeout { get; set; } = 20;
101102

102-
public bool IsNewSession => false;
103+
public bool IsNewSession { get; }
103104

104105
public int Count => _session.Keys.Count();
105106

src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/SystemWebAdaptersExtensions.cs

-4
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,9 @@ public static void UseSystemWebAdapters(this IApplicationBuilder app)
9696
ApplicationEvent.PostResolveRequestCache,
9797
ApplicationEvent.MapRequestHandler,
9898
ApplicationEvent.PostMapRequestHandler,
99-
ApplicationEvent.AcquireRequestState,
100-
ApplicationEvent.PostAcquireRequestState,
10199
},
102100
postEvents: new[]
103101
{
104-
ApplicationEvent.ReleaseRequestState,
105-
ApplicationEvent.PostReleaseRequestState,
106102
ApplicationEvent.UpdateRequestCache,
107103
ApplicationEvent.PostUpdateRequestCache,
108104
});

test/Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests/SessionState/SessionIntegrationTests.cs

+79
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Net.Http;
77
using System.Threading.Tasks;
8+
using System.Web;
89
using System.Web.SessionState;
910
using Microsoft.AspNetCore.Builder;
1011
using Microsoft.AspNetCore.Hosting;
@@ -52,6 +53,84 @@ public async Task TestOverrideSessionStateBehavior(string endpoint, string expec
5253
Assert.Equal(expected, actual);
5354
}
5455

56+
[InlineData(true)]
57+
[InlineData(false)]
58+
[Theory]
59+
public async Task SessionStartEvent(bool abandon)
60+
{
61+
// Arrange
62+
using var host = await new HostBuilder()
63+
.ConfigureWebHost(webBuilder =>
64+
{
65+
webBuilder
66+
.UseTestServer(options =>
67+
{
68+
options.AllowSynchronousIO = true;
69+
})
70+
.ConfigureServices(services =>
71+
{
72+
services.AddRouting();
73+
services.AddControllers();
74+
services.AddSystemWebAdapters()
75+
.AddHttpApplication<SessionApplication>()
76+
.AddWrappedAspNetCoreSession();
77+
78+
services.AddDistributedMemoryCache();
79+
})
80+
.Configure(app =>
81+
{
82+
app.UseRouting();
83+
app.UseSession();
84+
app.UseSystemWebAdapters();
85+
86+
if (abandon)
87+
{
88+
app.Use((ctx, next) =>
89+
{
90+
ctx.AsSystemWeb().Session!.Abandon();
91+
return next(ctx);
92+
});
93+
}
94+
95+
app.UseEndpoints(endpoints =>
96+
{
97+
endpoints.MapGet("/", ctx => Task.CompletedTask)
98+
.RequireSystemWebAdapterSession();
99+
});
100+
});
101+
})
102+
.StartAsync();
103+
104+
// Act
105+
var result = await host.GetTestClient().GetStringAsync(new Uri("/", UriKind.Relative));
106+
107+
// Assert
108+
if (abandon)
109+
{
110+
Assert.Equal("SessionStart::SessionEnd", result);
111+
}
112+
else
113+
{
114+
115+
Assert.Equal("SessionStart::", result);
116+
}
117+
118+
await host.StopAsync();
119+
}
120+
121+
private sealed class SessionApplication : HttpApplication
122+
{
123+
private void Session_Start(Object sender, EventArgs e)
124+
{
125+
HttpContext.Current?.Response.Write("SessionStart::");
126+
}
127+
128+
private void Session_End(Object sender, EventArgs e)
129+
{
130+
HttpContext.Current?.Response.Write("SessionEnd");
131+
}
132+
}
133+
55134
private static async Task<string> GetAsync(string endpoint)
56135
{
57136
using var host = await new HostBuilder()

0 commit comments

Comments
 (0)