思路:
1、在服务端定义一个单实例用户列表类,用于维护在线用户;
2、用户登录时添加到用户列表,正常注销,退出系统时从用户列表中删除;
3、如何处理直接关闭浏览器的情景?客户端定时向服务端发送心跳,服务端定时检测未保持心跳的用户。
实现代码:
用户列表:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
namespace MyProject
{
public class UserList
{
private readonly object lockObject;
//心跳线程
private System.Timers.Timer liveTimer;
/// <summary>
/// 用户列表 用户名,客户端未进行心跳的次数
/// </summary>
private Dictionary<string, int> users;
/// <summary>
///只支持单线程因此,使用单例模式,只生成一个对象
/// </summary>
private static readonly UserList instance = new UserList();
/// <summary>
/// 私有构造函数
/// </summary>
private UserList()
{
lockObject = new object();
users = new Dictionary<string, int>();
liveTimer = new System.Timers.Timer();
liveTimer.Elapsed += new System.Timers.ElapsedEventHandler(liveTimer_Elapsed);
liveTimer.Interval = 2000;
liveTimer.Start();
}
/// <summary>
/// 检测用户状态定时器
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void liveTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (liveTimer != null)
{
liveTimer.Enabled = false;
KeyValuePair<string, int>[] tempUsers = users.ToArray();
foreach (KeyValuePair<string, int> keyValue in tempUsers)
{
lock (lockObject)
{
if (keyValue.Value > 5)//删除用户
{
users.Remove(keyValue.Key);
}
if (users.ContainsKey(keyValue.Key))
{
if (users[keyValue.Key] != -1)
{
users[keyValue.Key] = users[keyValue.Key] + 1;
}
}
}
}
liveTimer.Enabled = true;
}
}
/// <summary>
/// 用户列表实例
/// </summary>
/// <returns></returns>
public static UserList Instance
{
get
{
return instance;
}
}
/// <summary>
/// 保持会话
/// </summary>
/// <param name="strUserName">用户</param>
public void KeepLive(string strUserName)
{
lock (lockObject)
{
if (users.ContainsKey(strUserName))//删除用户
{
users[strUserName] =0;
}
else
{
users.Add(strUserName,-1);
}
}
}
/// <summary>
/// 判断用户是否已经登录
/// </summary>
/// <param name="strUserName">用户</param>
/// <param name="strErrMsg">错误信息</param>
/// <returns>成功返回true,失败返回false</returns>
public bool UserIsLogin(string strUserName, out string strErrMsg)
{
strErrMsg = string.Empty;
try
{
if (users.ContainsKey(strUserName))
{
strErrMsg = "该用户已登录,不能重复登录!";
return true;
}
}
catch (Exception ex)
{
strErrMsg = ex.Message;
}
return false;
}
/// <summary>
/// 添加用户
/// </summary>
/// <param name="strUserName">用户</param>
/// <param name="strErrMsg">错误信息</param>
/// <returns>成功返回true,失败返回false</returns>
public bool AddUser(string strUserName, out string strErrMsg)
{
strErrMsg = string.Empty;
if (!string.IsNullOrEmpty(strUserName))
{
try
{
if (!users.ContainsKey(strUserName))
{
lock (lockObject)
{
users.Add(strUserName,-1);
}
}
return true;
}
catch (Exception ex)
{
strErrMsg = ex.Message;
}
}
else
{
strErrMsg = "用户名为空!";
}
return false;
}
/// <summary>
/// 删除用户
/// </summary>
/// <param name="strUserName">用户</param>
/// <param name="strErrMsg">错误信息</param>
/// <returns>成功返回true,失败返回false</returns>
public bool ReMoveUser(string strUserName, out string strErrMsg)
{
strErrMsg = string.Empty;
if (!string.IsNullOrEmpty(strUserName))
{
try
{
if (users.ContainsKey(strUserName))
{
lock (lockObject)
{
users.Remove(strUserName);
}
}
return true;
}
catch (Exception ex)
{
strErrMsg = ex.Message;
}
}
else
{
strErrMsg = "用户名为空!";
}
return false;
}
}
}
主框架aspx代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MyProject.Index" %>
<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
function onKeepLive() {
var btnKeepLive = document.getElementById("btnKeepLive");
btnKeepLive.click();
}
setInterval("onKeepLive()", 3000);//3秒执行一次
</script>
</head>
<body class="topbody">
<form id="form1" runat="server">
<div style="display:none">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnKeepLive" />
</Triggers>
<ContentTemplate>
<asp:Button ID="btnKeepLive" runat="server" OnClick="btnKeepLive_Click" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
主框架后台代码:
using System;
using System.Data;
using System.Text;
namespace MyProject
{
public partial class Index:System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnKeepLive_Click(object sender, EventArgs e)
{
UserList.Instance.KeepLive(UserInfo.UserName);
}
}
}