解决 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

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

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






 

 

 

 

 

 

 

 

你可能感兴趣的:(mvc)