zoukankan      html  css  js  c++  java
  • 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分钟这样的功能有没有更好的方法,欢迎赐教,谢谢!

  • 相关阅读:
    TranslateAnimation 运行动画后实际位置不正确问题
    Linux下如何编译并运行C程序
    row_number() OVER (PARTITION BY COL1 ORDER BY COL2)
    C++软件开发常用辅助软件——gprof
    C++软件开发常用辅助软件——Cppcheck
    C++软件开发常用辅助软件——SCons
    C++软件开发常用辅助软件——Valgrind
    救援linux
    C/C++代码覆盖率生成
    排列的逆
  • 原文地址:https://www.cnblogs.com/codealone/p/3228077.html
Copyright © 2011-2022 走看看