• 解决 MVC 用户上线下线状态问题


     以前工作项目中就有一个微博类功能,其中也出现了用户在线和离线的问题。 

    但是因为初入程序猿 使用的是 Session _end 上个事件。 Session _end 这个事件不需要怎么解释吧 就是在seesion过期的时候所触发的事件,但有BUG啊! 因为 iis 中由于有进程回收机制,系统繁忙的话Session会丢失。 当然 微软解决又弄了个 进程外seesion 来解决了一下 。额 当时楞是没想起来为啥 ,还是经验少啊。

    今天突然看了些  在线状态的问题  突发奇想   想自己不适用Seesion _end  来做一个 在线状态的实现。  百度了半天 还是没啥收获,最后决定  得  自己写吧!

       首先想到就是 利用静态对象  得特性 (在程序执行前就创建好对象并且知道程序结束之前不会被释放掉。)前几天从新看了一下进程和线程   进程和线程执行是通过操作系统维护的一个进程表维护着的 调度器  调整执行的。 所以就联想到 在管道事件 Application_Start() 中来维护一个 静态集合对象 通过定时器 实现 session_end 这个事件 

       Globel.asax.cs 文件中添加一个事件

     public class MvcApplication : System.Web.HttpApplication
        {
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
              
                WebApiConfig.Register(GlobalConfiguration.Configuration);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
                // 开启一个定时器  并且执行一个方法
                StatusMy.GetStatusMy().TestTimer();
    
            }
        }
     StatusMy 对象类 是关键的问题   代码并不多 应该很好理解  

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace OnlineStatus.Models
    {
        using System.Data.Entity;
        using System.Data.Entity.Infrastructure;
        using System.Data.Entity.Validation;
    
        using OnlineStatus.Models.Model;
    
        public class StatusMy : System.Web.HttpApplication
        {
            #region 单例
            private StatusMy()
            {
            }
    
            private static StatusMy IStatusMy;
    
            public static StatusMy GetStatusMy()
            {
                return IStatusMy ?? (IStatusMy = new StatusMy());
            }
            #endregion
    
            /// <summary>
            /// 定义定时器 如果是public 很有可能被GC掉
            /// </summary>
            private System.Threading.Timer timerClose;
    
            /// <summary>
            /// 定义个静态集合  
            /// </summary>
            private static List<MyUser> listMy;
    
            /// <summary>
            /// 定义一个 Lock 的时候使用的 Object 可以使用this 但是如果当前的这个this 是public 的话会有可能出现异常 保险期间还是使用MSDN 官方
            /// </summary>
            private object thisLock = new object();
    
            /// <summary>
            /// 执行定时器
            /// </summary>
            public void TestTimer()
            {
                timerClose = new System.Threading.Timer(ToMyContent, null, 0, 30000);
            }
    
    
            /// <summary>
            /// 利用Application的特性 维护一个 集合表 表中记录了最后一次网站时间 如果最后一次访问时间 小于服务器时间20分钟者在数据库中设置为 离线状态
            /// </summary>
            /// <param name="o">
            /// The o.
            /// </param>
            private void ToMyContent(object o)
            {
                if (listMy == null || listMy.Count <= 0)
                {
                    return;
                }
    
                DbContext db = MyDbContext.GetCurrentEFContext();//使用的是CallContxt 确保当前进程内唯一
    
                // 定义一个变量用来判断  维护着的List 对象是否有值  方便最后EF统一执行SQL 语句
                int i = 0;
                foreach (MyUser myContent in listMy)
                {
                    TimeSpan s = new TimeSpan(0, 0, 0, 20);// 这是时间差为20分钟
    
                    System.TimeSpan ts = DateTime.Now.Subtract(myContent.UTime); //通过当前服务器时间减去用户最后一次访问服务器的时间的出来的 时间差
    
                    if (ts < s)
                    {
                        continue; // 跳出这次循环 不执行  if 后续代码
                    }
    
                    // 做修改标注
                    User u = new User { ID = myContent.ID, Status = false, UTime = myContent.UTime, Name = myContent.Name };
                    DbEntityEntry<User> entry = db.Entry<User>(u);
                    entry.State = System.Data.EntityState.Modified;
                    entry.Property(a => a.Status).IsModified = true;
    
                    i++;
                }
    
                if (i == 0)
                {
                    return;
                }
    
                try
                {
                    db.SaveChanges();
                }
                catch (DbEntityValidationException dbEx)
                {
    
                }
            }
    
    
            /// <summary>
            ///  用户访问的 将其添加维护到 集合中
            /// </summary>
            /// <param name="u"></param>
            public void AddList(User u)
            {
                if (u == null && u.ID <= 0)
                    return;
    
                MyUser myU = new MyUser { ID = u.ID, Name = u.Name, UTime = DateTime.Now, Status = u.Status };
    
                if (listMy == null)
                {
                    lock (thisLock)
                    {
                        listMy = new List<MyUser> { myU };
                    }
    
                    return;
                }
    
                MyUser m = listMy.FirstOrDefault(c => c.ID == myU.ID);
                if (m != null && m.ID != 0)
                {
                    lock (thisLock)
                    {
                        listMy.Remove(m);
                        listMy.Add(myU);
                    }
                }
                else
                {
                    lock (thisLock)
                    {
                        listMy.Add(myU);
                    }
                }
            }
        }
    }

       MyDbContext类   线程唯一   EF上下文的问题 你懂的

    public  static class MyDbContext
        {
            public static DbContext GetCurrentEFContext()
            {
    
                DbContext dbContext = CallContext.GetData("EFContext") as DbContext;
                if (dbContext==null)
                {
                    dbContext = new Model1Container();
                    dbContext.Configuration.ValidateOnSaveEnabled = true;
                    CallContext.SetData("EFContext", dbContext);
                }
                return dbContext;
               
    
            }
        }

        MVC 的全局过滤器  可以做到  不管用户访问那个服务器页面 都可以进行操作。 额  面向切面编程?  

      在 FilterConfig 类中添加过滤器类

     public class FilterConfig
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
    
                filters.Add(new OnlineStatus.Controllers.LoginValidateAttribute());
            }
        }

      LoginValidateAttribute  自定义过滤器的实现 

     public class LoginValidateAttribute : System.Web.Mvc.AuthorizeAttribute
        {
    
            public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
            {
    
                // 判断 请求的 控制器是不是等于指定的控制器  如果不留下一个不用验证的控制器 那么就会一直在服务器跳转
                if (filterContext.RouteData.Values["controller"].ToString() != "RegisterLogin")
                {
                    #region 1.验证用户是否登陆(Session && Cookie)
                    //1.验证用户是否登陆(Session && Cookie)
                    if (!OnlineStatus.Controllers.Help.ToHelp().IsLogin())
                    {
                        filterContext.Result = filterContext.Result = new RedirectResult("/RegisterLogin/index");
                    }
                    #endregion     
                }
    
            }
        }
    ToHelp 类 的实现 

     public class Help
        {
    
            private Help()
            {
                
            }
    
            private static Help Ihelp;
    
            public static Help ToHelp()
            {
                return Ihelp ?? (Ihelp = new Help());
            }
    
    
            #region 0.1 Http上下文 及 相关属性
            /// <summary>
            /// Http上下文
            /// </summary>
            HttpContext ContextHttp
            {
                get
                {
                    return HttpContext.Current;
                }
            }
    
            HttpResponse Response
            {
                get
                {
                    return ContextHttp.Response;
                }
            }
    
            HttpRequest Request
            {
                get
                {
                    return ContextHttp.Request;
                }
            }
    
            System.Web.SessionState.HttpSessionState Session
            {
                get
                {
                    return ContextHttp.Session;
                }
            }
            #endregion
    
    
            #region 2.1 当前用户对象 +MODEL.Ou_UserInfo Usr
            // <summary>
            /// 当前用户对象
            /// </summary>
            public Models.User Usr
            {
                get
                {
                    return Session["name"] as Models.User;
                }
                set
                {
                    Session["name"] = value;
                }
            }
            #endregion
    
            /// <summary>
            /// 验证用户是否登录
            /// </summary>
            /// <returns></returns>
            public bool IsLogin()
            {
                if (Session["name"] == null)
                {
                    if (Request.Cookies["name"] == null)
                    {
                        return false;
                    }
                    string strUser = Request.Cookies["name"].Value;
    
                    int userid = int.Parse(strUser);
    
                    DbContext db = MyDbContext.GetCurrentEFContext();
                    OnlineStatus.Models.User use = db.Set<OnlineStatus.Models.User>().FirstOrDefault(c => c.ID == userid);
                    if (use == null && use.ID <= 0)
                    {
                        return false;
                    }
                    Usr = use;
    
                    //将其添加到维护的 状态集合中
                    StatusMy.GetStatusMy().AddList(use);
    
    
                }
                return true;
            }
    
    
            /// <summary>
            /// 登录 这里就简单写了 名称密码都对 就true 不对 false  额  以为是想简单写一下 数据库居然没弄密码 额 
            /// </summary>
            /// <param name="name"></param>
            /// <param name="pwd"></param>
            /// <returns></returns>
            public bool Login(string name)
            {
                DbContext db = MyDbContext.GetCurrentEFContext();
                OnlineStatus.Models.User use = db.Set<OnlineStatus.Models.User>().FirstOrDefault(c => c.Name == name);
                if (use == null && use.ID >= 0)
                {
                    return false;
                }
                //将其添加到维护的 状态集合中
                StatusMy.GetStatusMy().AddList(use);
                return true;
            }
    
        }
     
    我试了试 OK

    一直都是自己一个人研究来研究去的 冒泡出来 纯粹是来 希望和大神们交流一下 ,请大神们指点一下。

    不喜勿喷。
    看帖 求评论啊, 真的很希望能有人 指点指点啊






  • 相关阅读:
    codevs1044 拦截导弹(最长不下降子序列dp)
    codevs1014 装箱问题(DP)
    codevs1068 乌龟棋(DP)
    angular.extend vs angular.copy
    angular input框点击别处 变成不可输入状态
    angular select框 option空行
    angular ui 路由传参
    setTimeout 传参
    设置请求头信息的不同方式
    vertical-align
  • 原文地址:https://www.cnblogs.com/atliwen/p/3586680.html
Copyright © 2020-2023  润新知