【问题标题】:How to handle Session timeout if same asp.net sessionId is shared across multiple asp.net web application如果在多个 asp.net Web 应用程序之间共享相同的 asp.net sessionId,如何处理会话超时
【发布时间】:2015-01-07 23:45:06
【问题描述】:

如果在多个 asp.net Web 应用程序之间共享相同的 asp.net 会话 ID,如何处理会话超时。

我们有多个网络应用程序。这些 Web 应用程序在 DNN 上运行并共享会话 ID。但是每个应用程序的会话是在访问应用程序时创建的。 现在我想找到一种方法来处理会话超时,因为传统方法(在 globle.aspx 上使用 Session_Start 检查现有会话 ID 和是否是新会话)不起作用。

请帮助我了解如何处理会话超时,我不会在页面级别实现它。

【问题讨论】:

标签: asp.net asp.net-mvc asp.net-mvc-4 session


【解决方案1】:

除了使用 ASP.NET 会话状态,您还可以使用缓存来实现类似的结果。如果您愿意,您甚至可以将它与多租户应用程序一起使用,这样每个租户都有自己的会话。您可以使用回调方法响应缓存超时,这比使用会话状态事件更可靠。

缺点是它无法扩展到多台服务器,除非您提出分布式缓存解决方案。你可以使用azure distributed caching来解决这个问题,或者有other options

以下是会话缓存解决方案的典型外观:

public class ThreadSafeCache
{   
    public shared ThreadSafeCache()
    {
        if (cache == null)
        {
            cache = System.Runtime.Caching.MemoryCache.Default;
        }
        if (syncLock == null)
        {
            syncLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
        }
    }

    private shared System.Runtime.Caching.ObjectCache cache;
    private shared ReaderWriterLockSlim syncLock;

    public shared bool Contains(string key)
    {
        syncLock.EnterReadLock();
        try
        {
            return this.cache.Contains(key);
        }
        finally
        {
            syncLock.ExitReadLock();
        }
    }

    public shared object GetOrAdd(string key, Func<object> loadFunction, Action<CacheEntryRemovedArguments> callbackFunction)
    {
        // Get or add an item to the cache
        object item = null;

        syncLock.EnterReadLock();
        try
        {
            item = cache.Get(key);
        }
        finally
        {
            syncLock.ExitReadLock();
        }

        if (item == null)
        {
            syncLock.EnterWriteLock();
            try
            {
                // Lazy lock pattern - need to check again after
                // the lock to ensure only 1 thread makes it through
                if (item == null)
                {
                    // Get the item
                    item = loadFunction();

                    var policy = new CacheItemPolicy();

                    // Set the cache expiration (from the last access).
                    policy.SlidingExpiration = TimeSpan.FromMinutes(30);

                    // Setting priority to not removable ensures an 
                    // app pool recycle doesn't unload the item, but a timeout will.
                    policy.Priority = CacheItemPriority.NotRemovable;

                    // Setup expiration callback.
                    policy.RemovedCallback = callbackFunction;

                    cache.Add(key, item, policy);
                }
            }
            finally
            {
                synclock.ExitWriteLock();
            }
        }

        return item;
    }

    public shared void Remove(string key)
    {
        syncLock.EnterWriteLock();
        try
        {
            this.cache.Remove(key);
        }
        finally
        {
            syncLock.ExitWriteLock();
        }
    }
}

然后你会像这样使用它:

var sessionID = "1234"; // string from cookie or string that is stored in ASP.NET session state
var tenantID = "2"; // identifier for the specific tenant within the application
var key = tenantID + "_" + sessionID;

ThreadSafeCache.GetOrAdd(key, LoadItem, CacheItemRemoved);

private object LoadItem()
{
     // TODO: Load the item (from wherever you need to load it from)
     return item;
}

private void CacheItemRemoved(CacheEntryRemovedArguments arguments)
{
    // Respond here when the cache expires
}

诀窍是确保您的缓存密钥由用户的会话 ID(来自 cookie)和应用程序的 ID 组成。

请注意,我尚未对此进行测试,因此可能需要进行一些调整才能使其正常工作。

【讨论】:

  • 感谢@Night,由于我们正在运行系统,因此我们无法对其进行太多更改。我正在寻找一个通用的解决方案,只需放置新页面或进行细微更改即可在应用程序级别处理它。
  • 可以这样做,但前提是您为两个站点使用相同的域名(子域可以不同),因为 cookie 不能在不同域之间传递。见this answer
  • 另外,请查看thisthis
猜你喜欢
  • 1970-01-01
  • 2011-03-07
  • 2011-02-02
  • 2018-12-24
  • 2021-08-19
  • 2023-03-27
  • 2010-09-23
  • 2012-05-04
  • 1970-01-01
相关资源
最近更新 更多