2

在我的 ASP.NET MVC3 Web 应用程序中,我想添加一条小消息,显示当前浏览该站点的用户数量。

我目前正在使用应用程序事件Session_StartSession_End增加或减少 Global.asax 中的静态属性。

这有效,但它根本不精确。由于我的会话超时配置为 2000 万,因此更新之间存在巨大延迟。

有没有更优雅、更精确的方法来做到这一点?

我曾想过通过 AJAX 调用一个动作,这只是Session.Abandon()window.onbeforeunloadjavascript 事件上执行,但是每次用户更改页面时都会调用它。有没有办法确定用户何时关闭浏览器或离开域?

欢迎任何提示、评论或代码示例!

这是当前代码的相关部分:

public class MvcApplication : System.Web.HttpApplication
{
    public static int UsersConnected { get; set; }

    protected void Session_Start(object sender, EventArgs e)
    {
        Application.Lock();
        UsersConnected++;
        Application.UnLock();
    }

    protected void Session_End(object sender, EventArgs e)
    {
        Application.Lock();
        UsersConnected--;
        Application.UnLock();
    }

    ...
}
4

2 回答 2

2

好的,这有点棘手,但我提供了一个“好的”解决方案。

首先,我在 Global.asax中创建了一个静态字典,它将存储客户端的 IP 地址及其最后轮询日期。

public class MvcApplication : System.Web.HttpApplication
{
   public static Dictionary<string, DateTime> ConnectedtUsers { get; set; }

   protected void Application_Start()
   {
        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
        ConnectedtUsers = new Dictionary<string, DateTime>();
   }

   ...
}

然后,在我的CommonsController中,我创建了这个动作,它将添加新客户端,删除过去 30 秒内未轮询的客户端并更新已注册客户端的轮询日期:

public class CommonsController : Controller
{
    ...

    public JsonResult UserConnected()
    {
        string ip = Request.UserHostAddress;

        if (MvcApplication.ConnectedtUsers.ContainsKey(ip))
        {
            MvcApplication.ConnectedtUsers[ip] = DateTime.Now;
        }
        else
        {
            MvcApplication.ConnectedtUsers.Add(ip, DateTime.Now);
        }

        int connected = MvcApplication.ConnectedtUsers.Where(c => c.Value.AddSeconds(30d) > DateTime.Now).Count();

        foreach (string key in MvcApplication.ConnectedtUsers.Where(c => c.Value.AddSeconds(30d) < DateTime.Now).Select(c => c.Key))
        {
            MvcApplication.ConnectedtUsers.Remove(key);
        }

        return Json(new { count = connected }, JsonRequestBehavior.AllowGet);
    }
}

最后,在我的布局页面上,添加了这段代码,它将每 30 秒调用一次我的操作并在 span 中输出结果:

<span id="connectedUsers"></span>

<script type="text/javascript">
    function PollUsers()
    {
        $(function() {
            $.getJSON("/Commons/UserConnected", function(json){ $('#connectedUsers').text(json.count + " user(s) connected")}); 
        });
    }

    setInterval(PollUsers, 30000);
</script>

可能不是那么精确,也可能不是那么优雅,但它确实有效。当然,来自同一 IP 的多个用户将计为一个用户。但这是迄今为止我尝试过的最好的解决方案。

于 2012-07-21T14:48:45.387 回答
0

您可以在卸载正文事件中从 javascript 调用 webmethod。 http://www.codeproject.com/Tips/89661/Execute-server-side-code-on-close-of-a-browser 最好的问候

于 2012-07-21T14:27:17.840 回答