I got a feature request that I should store something on session start. In the old ASP.NET Framework world it was easy because we had Globbal.asax.cs
and its Session_Start
event. The original answer to this question is here. But, as I prefer overengineering modular architecture and Sitecore Helix principles I wanted to make it extensible without touching this Foundation piece of code. As you probably know we have Startup.cs
instead of Global.asax.cs
and DistributedSessionStore
. To extend the Create method of the DistributedSessionStore
you can just simply inherit from its interface ISessionStore
.
public class DistributedSessionStoreWithStart : DistributedSessionStore, ISessionStore | |
{ | |
readonly IStartSession _startSession; | |
public DistributedSessionStoreWithStart( | |
IDistributedCache cache, | |
ILoggerFactory loggerFactory, | |
IStartSession startSession) | |
: base(cache, loggerFactory) | |
{ | |
_startSession = startSession; | |
} | |
public new ISession Create( | |
string sessionKey, | |
TimeSpan idleTimeout, | |
TimeSpan ioTimeout, | |
Func<bool> tryEstablishSession, | |
bool isNewSessionKey) | |
{ | |
var session = base.Create(sessionKey, idleTimeout, ioTimeout, tryEstablishSession, isNewSessionKey); | |
if (isNewSessionKey) | |
{ | |
_startSession.InvokeStartSesssionActions(session); | |
} | |
return session; | |
} | |
} |
As its seen above I have implemented a custom interface which contains all the actions I want to call on Create
. These 2 classes lays in the Foundation layer if you follow Sitecore Helix principles.
public interface IStartSession | |
{ | |
void InvokeStartSesssionActions(ISession session); | |
void AddToStartSession(Action<ISession> action); | |
} | |
public class StartSession : IStartSession | |
{ | |
private static readonly IList<Action<ISession>> StartSessionActions = new List<Action<ISession>>(); | |
public void InvokeStartSesssionActions(ISession session) | |
{ | |
foreach (var action in StartSessionActions) | |
{ | |
action.Invoke(session); | |
} | |
} | |
public void AddToStartSession(Action<ISession> action) | |
{ | |
StartSessionActions.Add(action); | |
} | |
} |
As a last but one, a SessionExtensions
(lays in the Foundation layer as well) implemented to put together the configuration of the session in one place:
public static class SessionExtensions | |
{ | |
public static void AddSessionWithStartSession(this IServiceCollection services) | |
{ | |
services.AddSingleton<ISessionStore, DistributedSessionStoreWithStart>(); | |
services.AddDistributedMemoryCache(); | |
services.AddSession(options => | |
{ | |
options.Cookie.IsEssential = true; | |
}); | |
services.AddSingleton<IStartSession>(s => | |
{ | |
var startSession = new StartSession(); | |
// Add here other actions if more funcionality is needed for session start | |
startSession.AddToStartSession(s.GetRequiredService<IUrlRefererService>().SetSessionStartRefererUrl); | |
return startSession; | |
}); | |
} | |
} |
As a last step call this method in the ConfigureServices
method and setup the application to use session – this lays in the Project layer.
public class Startup | |
{ | |
... | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
... | |
services.AddSessionWithStartSession(); | |
... | |
} | |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |
{ | |
... | |
app.UseSession(); | |
... | |
} | |
... | |
} |