demoshop

demo, trying to be the best_

客戶經常性的會說我想知道線上使用人數有多人,製作方式大家都知道(不知道的Google一下一堆寫法...)但是 demo 今天遇到一個很有趣的事情,一個剛做好的專案一天上線人數也才4 ~ 5百人線上人數卻可以飆到1600多人...雖然我們都知道線上人數不會準,但這也太唬爛了...勢必需要修一下。

通用型的「線上人數」寫法都會利用 Application 來玩,所以很自然的在 Global.asax 中的 Session_Start() 撰寫 Code

protected void Session_Start()
{
    Application.Lock();
    if (Application["OnlineUserCount"] == null)
        Application["OnlineUserCount"] = 0;
 
    Application["OnlineUserCount"] = (int)Application["OnlineUserCount"] + 1;
    Application.UnLock();
} 

 

protected void Session_End()
{
    Application.Lock();
    if (Application["OnlineUserCount"] == null)
        Application["OnlineUserCount"] = 0;
 
    Application["OnlineUserCount"] = (int)Application["OnlineUserCount"] - 1;
    if ((int)Application["OnlineUserCount"] < 0)
        Application["OnlineUserCount"] = 0;
 
    Application.UnLock();
} 

這樣寫是很自然的,但是 demo 這次遇到這問題的原因是,客戶的網站來源訪客會大量的使用Proxy 造成瀏覽器不吃 Cookie 所以每次瀏覽一頁就會觸發三次 Session_Start() 然後就會很帥的發生按一頁線上人數+3的有趣事件,過程中嘗試不少寫法還是無法過濾,請了保哥幫我看看以後,保哥就想到了一個有趣的解法。

首先我們把 Session_Start() 的 Code 改成這樣

HttpContext.Current.Items["Session_Start"] = "";
Session["A"] = ""; 

然後再寫一個 ActionFilter

public override void OnActionExecuting(ActionExecutedContext filterContext)
{
    if (filterContext.HttpContext.Items["Session_Start"] == null && filterContext.HttpContext.Session["A"] != null && filterContext.HttpContext.Session["B"] == null)
    {
        filterContext.HttpContext.Application.Lock();
 
        if (filterContext.HttpContext.Application["OnlineUserCount"] == null)
            filterContext.HttpContext.Application["OnlineUserCount"] = 0;
 
        filterContext.HttpContext.Application["OnlineUserCount"] = (int)filterContext.HttpContext.Application["OnlineUserCount"] + 1;
        filterContext.HttpContext.Application.UnLock();
 
        filterContext.HttpContext.Session["B"] = "";
    }
} 

因為 demo 有習慣使用 BaseController 所以只需要將此 ActionFilter  附加到 BaseController 就可以讓使用者不管從哪個頁面進來都可以吃到了

[CookieCheck]
public class BaseController : Controller 


上面的 ActionFilter 中判斷了HttpContext.Items有沒有,以及Session["A"]、 Session["B"]是否有值,HttpContext.Items是一個很有趣的玩意,生命週期相當的短,想要詳細了解可以看看文章底部的參考的文章,這整段的邏輯就是,如果使用者有開啟 Cookie 那在「Session_Start()」就會同時賦予HttpContext.Current.Items["Session_Start"]和Session["A"]值,程式執行到 ActionFilter 時第一次就會順利的進入到 if 內部,而 if 的內部最後有賦予 Session["B"] 值,所以下次就不會進入此段 if 了,可以避免了那種線上人數瘋狂衝的詭異事情。


以上方法或許不是很優,如果各位有覺得恨好的作法歡迎提供。

 

回應討論