Winform 模擬Session


背景

  在Web中Session的功能很好用,於是想Winform中實現該功能,典型應用場景則是登陸成功后,當一段時間不操作,則該會話過期,提示重新登陸。

資源下載

  測試代碼

  示例說明:登陸進去10s不操作或者訪問Cache后10秒不操作,則會提示登陸超時

實現

  1. 設計CacheContainer類,使用Dictionary存放變量,並添加互斥鎖SyncRoot,避免多線程操作帶來異常。

  2. CacheContainer內部的變量,如果持續10秒(測試使用的默認值)沒有訪問或操作,則自動移除該變量,並觸發回調。

  3. 當程序訪問CacheContainer內部的變量,過期時間從當前時間開始計時。

  4. 變量第一次計時在加入CacheContainer時。

  具體代碼如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace WindowsFormsApplication1
{
    public sealed class CacheContainer
    {
        //互斥鎖
        private object SyncRoot = new object();
        //對象字典
        private Dictionary<string, CacheObj> dic = new Dictionary<string, CacheObj>();

        internal class CacheObj : IDisposable
        {
            //公有變量
            public object Value { get; set; }
            public int Expired { get; set; }
            public WaitCallback callback { get; set; }
            public AutoResetEvent ar = new AutoResetEvent(false);
            public TimeSpan Timeout
            {
                get
                {
                    return TimeSpan.FromSeconds(Expired);
                }
            }
            public CacheObj(object value, int expired = 10)
            {
                Value = value;
                Expired = expired;
                callback = new WaitCallback((obj) =>
                {
                    Console.WriteLine("{0}:已過期,過期時間:{1}", obj, DateTime.Now);
                });
            }

            public void Dispose()
            {
                GC.SuppressFinalize(this);
            }

            ~CacheObj()
            {
                Dispose();
            }
        }

        private static CacheContainer container = new CacheContainer();
        private CacheContainer() { }
        public static CacheContainer GetInstance() { return container; }

        public object this[string key]
        {
            get
            {
                //訪問變量成功,則時間重新計時
                CacheObj cache;
                lock (SyncRoot)
                {
                    if (dic.TryGetValue(key, out cache))
                    {
                        cache.ar.Set();
                        return cache.Value;
                    }
                }
                return null;
            }
            set
            {
                //通過屬性添加參數,有則覆蓋,無則添加,操作完畢重新計時
                CacheObj cache;
                lock (SyncRoot)
                {
                    if (dic.TryGetValue(key, out cache))
                    {
                        cache.Value = value;
                        cache.ar.Set();
                    }
                    else
                        Add(key, value);
                }
            }
        }

        public void Add(string key, object value)
        {
            lock (SyncRoot)
                dic.Add(key, new CacheObj(value));
            AutoCheck(key);
        }

        public void Add(string key, object value, int expired)
        {
            lock (SyncRoot)
                dic.Add(key, new CacheObj(value, expired));
            AutoCheck(key);
        }

        public void Add(string key, object value, int expired, WaitCallback callback)
        {
            lock (SyncRoot)
                dic.Add(key, new CacheObj(value, expired) { callback = callback });
            AutoCheck(key);
        }

        private void AutoCheck(string key)
        {
            //開啟一個子線程去控制變量的過期
            ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
            {
                CacheObj tmpCache;
                while (true)
                {
                    //從字典中取出對象
                    lock (SyncRoot)
                        tmpCache = dic[key];
                    //打印變量過期時間
                    Console.WriteLine("{0} 等待銷毀變量 時間為:{1}秒", DateTime.Now, tmpCache.Expired);
                    //記錄開始時間
                    var timeStart = DateTime.Now;
                    //中斷,超時時間一到,自動向下執行
                    tmpCache.ar.WaitOne(TimeSpan.FromSeconds(tmpCache.Expired));
                    //檢查時間是否已經達到超時時間,超時則移除該信息,並觸發回調
                    if ((DateTime.Now - timeStart) >= tmpCache.Timeout)
                    {
                        lock (SyncRoot)
                            dic.Remove(key);
                        if (tmpCache.callback != null) tmpCache.callback(tmpCache.Value);
                        break;
                    }
                }
            }));
        }

        public void Remove(string key)
        {
            lock (SyncRoot)
            {
                CacheObj cache;
                if (dic.TryGetValue(key, out cache))
                {
                    cache.Expired = 0;
                    cache.ar.Set();
                }
            }
        }
    }
}

 問題  

  CacheContainer中的變量,均是在線程池里有個線程去檢測它,也就是說有10個變量,線程池里就會多10個子線程,這樣會不會不太好。

  該方法僅是拋磚引玉,不知道在Winform中實現緩存變量xx分鍾這樣的功能有沒有更好的方法,歡迎賜教,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM