Lock on ASP.NET Session

Ok some background. I have something similar to this:

class ConnectionFactory { public IConnection Connect() { if (User.IsAuthenticated) { return InternalConnect(User.Username, null); } return null; } public IConnection Connect(string username, string password) { return InternalConnect(username, password); } private IConnection InternalConnect(string username, string password) { IConnection connection; var cacheKey = Session[CacheKeySessionKey] as string; if (!string.IsNullOrEmpty(cacheKey)) { connection = HttpCache[cacheKey] as IConnection; } if (!IsGoodConnection(connection) { connection = MakeConnection(username, password); // very costly cacheKey = Session[CacheKeySessionKey] = // some key HttpCache[cacheKey] = connection; } return connection; } private bool IsGoodConnection(IConnection conn) { return conn != null && conn.IsConnected; } } 

I am currently running a concurrency task when this Connect() is called several times and creates several IConnection for each request. I only need one. It is injected using the IoC container into various instances. MakeConnnection is very expensive as it spins the WCF channel.

My question is: how to block InternalConnect calls per session? I don’t think that blocking a request is the right way, as several requests may appear for each user. Of course, I do not want to block every call, as this will give poor performance.

I think this is a bad idea:

 lock(Session.SessionID) { // Implementation of InternalConnect } 

Note. Overloading the username and password is what I only call when I log in.

+7
source share
4 answers

This is just unverified code from the start, but can it work?

 // globally declare a map of session id to mutexes static ConcurrentDictionary<string, object> mutexMap = new ConcurrentDictionary(); // now you can aquire a lock per session as follows object mutex = mutexMap.GetOrAdd(session.SessionId, key => new object()); lock(mutex) { // Do stuff with the connection } 

You will need to find a way to clear old sessions from mutexMap , but this should not be too complicated.

+10
source

I would have ninject create the class as singleton, and then save the connection in the factory class itself.

When you make an InternalConnect call, check if _connection null or not. If so, new new IConnect and assign it _connection

0
source

Here's the suggestion: Create a connection creator object that has MakeConnection logic in it, and it blocks the whole process in the usual way. When the session begins to store the connection creator in it and calls this method in the internal connection method.

here is what i mean:

 public class ConnectionMaker { private object _lock=new object(); public IConnection MakeConnection() { lock(_lock) { // } } } 

and then in your Session_Start you can:

 Session["ConnectionMaker"]=new ConnectionMaker(); 

and then in your inner join:

 if(! IsGoodConnection(connection)) { var connectionMaker=Session["ConnectionMaker"] as ConnectionMaker; connection=connectionMaker.MakeConnection(); .... } 
0
source

Another option is to save the object in each user session directly.

The lock will look like this:

 lock (Session["SessionLock"]) { // DoStuff } 

and you can create an object in global.asax every time you start a session

 protected void Session_Start(object sender, EventArgs e) { Session["SessionLock"] = new object(); } 

Thus, the lock object is automatically deleted after the session.

0
source

All Articles