每个ASP.NET会话锁定
确定一些背景。我有一些与此类似:每个ASP.NET会话锁定
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;
}
}
目前,我正在运行到一个并发问题,其中即Connect()
被称为多次,每次请求创建多个IConnection
秒。我只需要一个。它正在使用IoC容器注入各种实例。 MakeConnnection
因为它增加了一个WCF频道而成本很高。
我的问题是:怎样才能锁定每个会话的InternalConnect
电话?我不认为每个请求锁定是正确的方式,因为每个用户可能会发生多个请求。我当然不想锁定每一个电话,因为这会导致糟糕的表现。
我认为这样做是一个坏主意:
lock(Session.SessionID)
{
// Implementation of InternalConnect
}
注:用户名和密码超载就是我所说的只登录。
这只是未经测试的代码,从我的头顶,但它可能工作?
// 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
}
您将需要找到一种方法来清除旧会话出mutexMap
的,但应该不会太困难。
我非常喜欢这种模式。谢谢! – 2012-02-16 16:36:06
你可不只是将锁对象添加到用户会话? – rdans 2015-09-28 10:13:12
@rdans,这将只适用于内存会话存储,因为其他会话提供程序将序列化对象作为保存过程的一部分。 – 2015-09-29 10:57:06
我将ninject创建类作为一个单身人士,然后将连接存储在工厂类本身。
当您拨打到InternalConnect的电话时,请检查_connection
是否为空。如果是的话,新的一个新的IConnect并将其分配给_connection
这就是我基本上在做什么。 'ConnectionFactory'是唯一一个如何知道连接是否为空的连接。 – 2012-02-16 13:31:51
这里有一个建议: 有连接制造商对象,它具有MakeConnection的逻辑,并且它以通常的方式锁定整个过程。当会话开始时,它将一个连接制造商存储在其中并在内部连接方法中调用此方法。
这里就是我的意思:
public class ConnectionMaker
{
private object _lock=new object();
public IConnection MakeConnection()
{
lock(_lock)
{
//
}
}
}
,然后在在session_start你可以有:
Session["ConnectionMaker"]=new ConnectionMaker();
,然后在内部连接:
if(! IsGoodConnection(connection))
{
var connectionMaker=Session["ConnectionMaker"] as ConnectionMaker;
connection=connectionMaker.MakeConnection();
....
}
我试图保持这global.asax,因为这全是在图书馆。所以'Session_Start'不适用。 – 2012-02-16 13:37:02
好吧,您可以在第一次将图书馆添加到会话中,例如在您的登录过程中 – Beatles1692 2012-02-16 13:41:43
另一种选择是直接在每个用户会话中存储一个对象。
锁应该是这样的:
lock (Session["SessionLock"]) {
// DoStuff
}
,你可以创建当每个会话启动
protected void Session_Start(object sender, EventArgs e)
{
Session["SessionLock"] = new object();
}
做这种方式在Global.asax对象是指锁定对象会话结束后自动删除。
isgoodconnection是什么意思? – Beatles1692 2012-02-16 13:17:10
@ Beatles1692 - 它只是一个方法来检查它不是null或者它是否被断开。 – 2012-02-16 13:18:40
您使用的是什么IoC容器?你可以展示你的IoC配置吗? – 2012-02-16 13:23:02