Winform 模拟Session_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > Winform 模拟Session

Winform 模拟Session

 2013/8/1 10:08:47  冲动  博客园  我要评论(0)
  • 摘要:背景在Web中Session的功能很好用,于是想Winform中实现该功能,典型应用场景则是登陆成功后,当一段时间不操作,则该会话过期,提示重新登陆。资源下载测试代码示例说明:登陆进去10s不操作或者访问Cache后10秒不操作,则会提示登陆超时实现1.设计CacheContainer类,使用Dictionary存放变量,并添加互斥锁SyncRoot,避免多线程操作带来异常。2.CacheContainer内部的变量,如果持续10秒(测试使用的默认值)没有访问或操作,则自动移除该变量
  • 标签:for winform

背景

  在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分钟这样的功能有没有更好的方法,欢迎赐教,谢谢!

发表评论
用户名: 匿名