1. 程式人生 > 其它 >一個儲存資料的方法(可以切換存放的位置,可以設定金鑰)

一個儲存資料的方法(可以切換存放的位置,可以設定金鑰)

      在asp.net裡面一般的生命週期都比較短,如果想要比較長久的儲存資料的話,一般有選擇幾種方式可供選擇,即cookies、ViewState、Session、Cache、application等。他們各有優缺點,也各有其自己的使用範圍。

      我現在遇到了兩個問題,第一個是如何在這幾種方式裡面快速、方便的切換,第二個是如何實現一個既可以區分使用者,又可以區分頁面,又節省伺服器的資源,又比較安全的儲存資料的方式。

      ViewState比較符合第二個問題的要求,但是他不太安全,表面上看他存放在客戶端的是亂碼,其實是可以解密的,解密之後就是明文了,你存放的是什麼就一目瞭然。如果是使用ViewState儲存一般的資料倒也是沒有什麼問題,但是我想儲存的是表名、欄位名、SQL語句這樣的很敏感的資料,這樣的資料放在ViewState裡面,估計會被人罵死,呵呵。

      以前的QuickPager分頁控制元件確實是這麼處理的,現在越想越不安全,自己用用也就湊合了,如果推廣的話,那就害人了。所以我不得不想辦法來解決這個很嚴重的問題。於是我想寫一個獨立的能夠儲存資料的類。這個類可以使用各種方式來存放資料,如果要加密資料的話,也可以自己設定金鑰,這樣不知道金鑰的話,就不能解密了(除非暴力破解),當然您也可以選擇不加密(儲存在Session、Cache就不用加密了),也可以選擇不儲存。

      這樣這個類就很靈活了,使用範圍也可以廣泛一點。

      在實現這個函式的時候,遇到了兩大難題,一個是如何操作隱藏域,另一個是如何“自動”儲存和“自動”載入。ViewState可是不用單獨呼叫SaveViewState()來儲存資料的。

      在Class裡面操作cookie、Session等還是比較容易的(System.Web.HttpContext.Current.Response.Cookies[ClientID]),可是如何控制隱藏域呢?想了好久也沒有想到好的方法,只好用笨方法了——傳遞一個Page例項(System.Web.UI.Page)進來,然後使用Page.ClientScript.RegisterHiddenField(ClientID, myData) 來搞定。

      至於自動儲存,也是採用了一個笨笨的方法,既然已經把Page傳遞進來了,那麼就給他加一個事件吧,_page.PreRender += new EventHandler(MyPage_PreRender);在執行Render之前儲存資料。我想用類似的思路來搞定自動載入資料的(_page.PreLoad += new EventHandler(MyPage_PreLoad);),但是遇到了一個小問題。我們一般都是習慣在Page_Load函式裡面給屬性賦值,但是我要加的事件卻是在Page_Load之前執行,也就是說如果在Page_Load裡面賦值的話,即使把事件加上了,那麼也早已經失去了執行的機會。當然可以在OnInit裡面給屬性賦值,只是這麼做不太符合習慣。

      我也研究了一下IStateManager 這個介面,也試了一下,可惜沒有成功,也許是我功力不夠的原因吧。

      Ps:這個難題解決之後,QuickPager分頁控制元件就可以一份為二了,變成QuickPager_UI、QuickPager_SQL兩個部分,再加上我的資料訪問函式庫和現實資料的控制元件,就是一套完整的分頁解決方案了。

      QuickPager_SQL就是專門處理分頁演算法(也就是分頁用的SQL語句)的,這些部分都可以獨立使用,也可以替換成其他的控制元件、類庫。

      下面是原始碼,原始檔等整理之後和分頁控制元件一起傳送。

namespace JYK.Common
{
    列舉enum SaveViewStateLocation#region 列舉enum SaveViewStateLocation
    /**//// <summary>
    /// 儲存資料的位置
    /// </summary>
    public enum SaveViewStateLocation
    {
        /**//// <summary>
        /// 不儲存
        /// </summary>
        NoSave = 1,
        /**//// <summary>
        /// 放在Cookie裡面儲存
        /// </summary>
        Cookie = 2,
        /**//// <summary>
        /// 放在隱藏域裡面儲存
        /// </summary>
        Hidden = 3,
        /**//// <summary>
        /// 放在Session裡面儲存
        /// </summary>
        Session = 4,
        /**//// <summary>
        /// 放在Cache裡面儲存
        /// </summary>
        Cache = 5,
        /**//// <summary>
        /// 放在Application裡面儲存
        /// </summary>
        Application = 6
    }
    #endregion
    public class MyViewState        //: IStateManager
    {
        成員#region 成員
        /**//// <summary>
        /// 儲存資料的字典
        /// </summary>
        private Dictionary<string, string> vs = new Dictionary<string, string>();
        /**//// <summary>
        /// 用於給表單裡面新增隱藏域和加事件
        /// </summary>
        private System.Web.UI.Page _page;
        /**//// <summary>
        /// 金鑰
        /// </summary>
        private string _key = "";
        #endregion
        public MyViewState()
        {
            //預設設定為不儲存
            SaveLocation = SaveViewStateLocation.NoSave;
        }
      
        屬性#region 屬性
        /**//// <summary>
        /// 存放資料的位置
        /// </summary>
        public SaveViewStateLocation SaveLocation;
        /**//// <summary>
        /// 金鑰,不同的金鑰會生成不同的密文。空字串表示不需要加密
        /// </summary>
        public string Key
        {
            set
            {
                _key = value;
            }
            get
            {
                return _key;
            }
        }
        /**//// <summary>
        /// 儲存資料的標識
        /// </summary>
        public string ClientID = "myVS";
       
        /**//// <summary>
        /// 傳遞Page例項,以實現自動儲存資料,和新增隱藏域的功能
        /// </summary>
        public Page Page
        {
            set
            {
                _page = value;
                _page.PreLoad += new EventHandler(MyPage_PreLoad);          //本來想在Page_Load之前載入內容,但是出現了一點問題
                _page.PreRender += new EventHandler(MyPage_PreRender);      //自動儲存內容
            }
            get { return _page; }
        }
        索引器,類似於ViewState的使用方式#region 索引器,類似於ViewState的使用方式
        /**//// <summary>
        /// 索引器,類似於ViewState的使用方式
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string this[string key]
        {
            set 
            {
                if (vs.ContainsKey(key))
                {
                    vs[key] = value; 
                }
                else 
                {
                    vs.Add(key, value);
                }
            }
            get 
            {
                if (vs.ContainsKey(key))
                {
                    return vs[key];
                }
                else
                {
                    return null;
                }
            }
        }
        #endregion
        #endregion
        用於自動載入和儲存資料的事件#region 用於自動載入和儲存資料的事件
        void MyPage_PreRender(object sender, EventArgs e)
        {
            SaveViewState();
            //throw new NotImplementedException();
        }
        void MyPage_PreLoad(object sender, EventArgs e)
        {
            LoadViewState();
            //throw new NotImplementedException();
        }
        #endregion

        函式#region 函式
        /**//// <summary>
        /// 把資料儲存到指定的位置裡面
        /// </summary>
        public void SaveViewState()
        {
            //拼接字串
            System.Text.StringBuilder str = new StringBuilder(1000);
            foreach (KeyValuePair<string,string> entry in vs)
            {
                str.Append(entry.Key);
                str.Append("`");
                str.Append(entry.Value);
                str.Append("`");
            }
            if (str.Length == 0)        //沒有賦值
                return ;
            str.Remove(str.Length - 1, 1);
            string myData =  str.ToString();
            if (Key.Length > 0)
            {
                //加密
                myData = Encryptor.Encrypt(myData, Key);
            }
            str.Length = 0;
            儲存#region 儲存
            switch (SaveLocation)
            {
                case SaveViewStateLocation.Cookie :
                    System.Web.HttpContext.Current.Response.Cookies[ClientID].Value = myData;
                    break;
                case SaveViewStateLocation.Hidden:
                    #region
                    if (Page != null)
                    {
                        Page.ClientScript.RegisterHiddenField(ClientID, myData);
                    }
                    #endregion
                    break;
                case SaveViewStateLocation.Session :
                    System.Web.HttpContext.Current.Session[ClientID] = myData;
                    break;
                case SaveViewStateLocation.Cache :
                    System.Web.HttpContext.Current.Cache[ClientID] = myData;
                    break;
                
                case SaveViewStateLocation.Application :
                    System.Web.HttpContext.Current.Application[ClientID] = myData;
                    break;
            }
            #endregion
          
        }
        
        public void LoadViewState()
        {
            //載入
            string str = "";
            string[] arr = null;
            switch (SaveLocation)
            {
                case SaveViewStateLocation.Cookie:
                    if (System.Web.HttpContext.Current.Request.Cookies[ClientID] == null)
                        return;
                    str = System.Web.HttpContext.Current.Request.Cookies[ClientID].Value;
                    break;
                case SaveViewStateLocation.Hidden :
                    if (Page == null) return;
                    if (System.Web.HttpContext.Current.Request[ClientID] == null) return;
                    str = System.Web.HttpContext.Current.Request[ClientID];
                    break;
                case SaveViewStateLocation.Session:
                    str = System.Web.HttpContext.Current.Session[ClientID].ToString();
                    break;
                case SaveViewStateLocation.Cache:
                    str = System.Web.HttpContext.Current.Cache[ClientID].ToString();
                    break;
                case SaveViewStateLocation.Application:
                    str = System.Web.HttpContext.Current.Application[ClientID].ToString();
                    break;
            }
            if (str.Length == 0)        //沒有取到值
                return;
            if (Key.Length > 0)
            {
                //加密
                str = Encryptor.Decrypt(str, Key);
            }
            //拆分
            arr = str.Split('`');
                  
            //賦值
            for (int i = 0; i < arr.Length; i += 2)
            {
                vs.Add(arr[i], arr[i + 1]);
            }
        }
        #endregion
      
    }
}