闲云博客

关注互联网科技,记录编程点滴

Page Level Session (logic),类似ViewState的作用

| 0 comments

在ASP.NET开发中,虽然ViewState使用起来很简单方便,但是ViewState也有一些限制和缺点,比如安全性和性能。

ViewState中的数据默认是使用base64进行编码从而保存到页面里,因此,虽然用户不能直接看到里面的数据,但是base64不是加密算法,只是一种编码算法,任何人都能对base64进行反编码,从而看到我们往ViewState里保存的数据。所以敏感机密数据不适合保存在ViewState中。

另一方面,由于ViewState保存在页面里,如果保存了较大数据量的话,比如含100条数据的dataset,你的页面打开就会很慢。不仅每次页面postback,ViewState都会在客户端和服务器端往返,造成网络传输数据量大,服务器端序列化和反序列化加重服务器负担。所以不推荐往ViewState中保存较大数据。

那么在ViewState不适合的地方用Session吧。

但是Session在作为pagelevel用的时候,由于其全局共享的特性,如果key重复的话,容易造成Session数据覆盖的问题。

可能的情况就是在浏览器的两个标签(Tab)中打开同一个页面,如果我们按照Session的正常的用法用的时候(Session[“Key”] = value;),Tab1 中往Session存一个值,然后Tab2中往Session中存值的时候,由于key相同,会覆盖前一个值。如果你的用户不能接受这种情况的话,这就是一个很麻烦的问题,因为从IE7开始包括一些其他主流浏览器,Tab之间都是共享session的。

下面,我实现一个Page Level的Session来解决Key相同的问题。

public static class SessionManager
    {
        private static PageLevelSession _pageLevel;
        public static PageLevelSession PageLevel
        {
            get
            {
                if (_pageLevel == null)
                {
                    _pageLevel = new PageLevelSession();
                }
                return _pageLevel;
            }
        }
    }

public class PageLevelSession
    {
        private const String PAGE_lEVEL_KEY_FORMAT = "{0}_{1}_{2}_{3}";
        private const string PageLevelSessionKeyPrefix = "PAGE_LEVEL_SESSION_KEY";
        private const string PAGE_LEVEL_KEY_GUID_KEY = "PAGE_LEVEL_SESSION_KEY_STORE_VIEW_STATE";

        public void SetSession(string key, object value)
        {
            HttpContext.Current.Session[GetSessionKey(key)] = value;
        }

        public object GetSession(string key)
        {
            return HttpContext.Current.Session[GetSessionKey(key)];
        }

        public void Remove(string key)
        {
            HttpContext.Current.Session.Remove(GetSessionKey(key));
        }

        public void ClearSessionsForPage()
        {
            List keyList = new List();

            foreach (string key in HttpContext.Current.Session.Keys)
            {
                if (key.StartsWith(GetSessionKey(string.Empty)))
                {
                    keyList.Add(key);
                }
            }

            foreach (string key in keyList)
            {
                HttpContext.Current.Session.Remove(key);
            }
        }

        private string GetPageLevelGUID()
        {
            Page page = (Page)HttpContext.Current.CurrentHandler;
            Type type = typeof(Page);
            BindingFlags flags = BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic;
            StateBag viewState = type.InvokeMember("ViewState", flags, null, page, null) as StateBag;
            if (viewState == null)
                throw new Exception("can not access ViewState in SessionManager.");

            object guidKey = viewState[PAGE_LEVEL_KEY_GUID_KEY];
            if (guidKey == null)
            {
                guidKey = Guid.NewGuid().ToString();
                viewState[PAGE_LEVEL_KEY_GUID_KEY] = guidKey;
            }

            return guidKey.ToString();
        }

        private string GetSessionKey(string key)
        {
            return string.Format(PAGE_lEVEL_KEY_FORMAT, PageLevelSessionKeyPrefix, PageID, GetPageLevelGUID(), key);
        }

        private string PageID
        {
            get
            {
                return HttpContext.Current.Request.CurrentExecutionFilePath;
            }
        }
    }

调用的时候:

SessionManager.PageLevel.SetSession("SessionA", DateTime.Now.ToShortTimeString());

Label1.Text += SessionManager.PageLevel.GetSession("SessionA").ToString();

通过给每个页面赋一个GUID来作为Session Key的一部分从而保证Key的唯一性。

需要注意的地方,就是上面的方法并没有对Session的生命周期做自动管理,所以需要使用者自己注意Session的销毁等,否则这些Page Level的Session在你并不需要的时候还会存在,加重服务器的负担。

 

原创文章,转载请注明: 转载自闲云博客

本文链接地址: Page Level Session (logic),类似ViewState的作用

Author: Jian Yun

Hi,我是闲云,感谢您阅读我的博客。我是一个微软ASP.NET方面的开发者,写写博客分享下互联网科技方面感兴趣的事和记录自己程序开发中的点点滴滴。 ------“立志难也,不在胜人,在自胜”

发表评论

Required fields are marked *.