有關一些狀態機器制的封裝

來源:互聯網
上載者:User

直接使用字串訪問會話字典的方式有幾個缺點:
1、很容易由於字串拼錯產生錯誤;
2、擷取的對象是object類型的,需要轉換到實際類型

好一點的方式是實現編寫一個類,封裝成屬性來使用,比如:
http://www.codeproject.com/KB/aspnet/typedsessionstate.aspx
其實可以使用BuildProvider+CodeDom來自動產生這個封裝代碼(類似Profile的原理)

先來實現BuildProvider:

using System.Linq;
using System.Web.Compilation;
using System.CodeDom;
using System.Xml.Linq;

namespace SessionBuildProvider
{
    public class TestBuildProvider : BuildProvider
    {
        public override void GenerateCode(AssemblyBuilder ab)
        {
            CodeCompileUnit ccu = GenerateClass(@"C:\Users\yzhu.MAGICGRIDS\Documents\Visual Studio 2008\WebSites\SessionTest\App_Code\test.session");
            ab.AddCodeCompileUnit(this, ccu);
        }

        private CodeCompileUnit GenerateClass(string filePath)
        {
            var doc = XDocument.Load(filePath);
            var q = from session in doc.Elements("sessions").Elements("session") select session;
            CodeCompileUnit ccu = new CodeCompileUnit();
            CodeNamespace cn = new CodeNamespace("Util");
            ccu.Namespaces.Add(cn);
            CodeTypeDeclaration entityClass = new CodeTypeDeclaration("MyObj");
            cn.Types.Add(entityClass);
            CodeTypeDeclaration sessionClass = new CodeTypeDeclaration("Sessions");
            CodeTypeConstructor defaultConstructor = new CodeTypeConstructor();
            defaultConstructor.Statements.Add(new CodeSnippetStatement("obj = new MyObj(); System.Web.HttpContext.Current.Session[\"data\"] = obj;"));
            sessionClass.Members.Add(defaultConstructor);
            CodeMemberField objField = new CodeMemberField(new CodeTypeReference("MyObj"), "obj");
            objField.Attributes = MemberAttributes.Static;
            sessionClass.Members.Add(objField);
            cn.Types.Add(sessionClass);
            foreach (var s in q)
            {
                CodeMemberField field = new CodeMemberField(new CodeTypeReference(s.Attribute("Type").Value), s.Attribute("Name").Value.ToLower());
                entityClass.Members.Add(field);
                CodeMemberProperty prop = new CodeMemberProperty();
                prop.Name = s.Attribute("Name").Value;
                prop.Type = new CodeTypeReference(s.Attribute("Type").Value);
                prop.Attributes = MemberAttributes.Public;
                prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), s.Attribute("Name").Value.ToLower())));
                prop.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), s.Attribute("Name").Value.ToLower()), new CodePropertySetValueReferenceExpression()));
                entityClass.Members.Add(prop);
                prop = new CodeMemberProperty();
                prop.Name = s.Attribute("Name").Value;
                prop.Type = new CodeTypeReference(s.Attribute("Type").Value);
                prop.Attributes = MemberAttributes.Public | MemberAttributes.Static;
                prop.GetStatements.Add(new CodeSnippetExpression(string.Format("return ((MyObj)System.Web.HttpContext.Current.Session[\"data\"]).{0};", s.Attribute("Name").Value)));
                prop.SetStatements.Add(new CodeAssignStatement(new CodeSnippetExpression(string.Format("((MyObj)System.Web.HttpContext.Current.Session[\"data\"]).{0}", s.Attribute("Name").Value)), new CodePropertySetValueReferenceExpression()));
                sessionClass.Members.Add(prop);
            }
            return ccu;
        }
    }

}

然後在web.config進行配置,放到compilation節點下:<buildProviders>
<add extension=".session" type="SessionBuildProvider.TestBuildProvider"/>
</buildProviders>

然後在app_code目錄中加一個.session設定檔test.session(由於是demo代碼,上面我直接寫入程式碼了路徑,可以從BuildProvider基類的VirtualPath屬性擷取路徑):<?xml version="1.0" encoding="utf-8"?>
<sessions>
    <session Type="System.Int32" Name="UserID" Key="userid" />
  <session Type="System.String" Name="UserName" Key="username" />
</sessions>

使用一個設定檔來定義會話的索引值等也可以方便團隊協作,避免會話使用上的衝突等。

最後就可以在寫代碼的時候直接這麼使用了:        Sessions.UserID = 1;
        Response.Write(Sessions.UserID);
        Sessions.UserName = "hello";
        Response.Write(Sessions.UserName);

資料並沒有直接儲存在Session中,而是全部儲存在MyObject大對象中,大對象再完整儲存到了Session中。
ViewState、Session、Cache的封裝其實都可以這麼實現,完全可以複雜一點,把值範圍檢測或對象的生命週期管理也自動產生進去。
由於是demo代碼,其中還有很多不完善的地方,大家可以順這個思路自己去實現。

對於QueryString的封裝也可以這樣,當然缺點就是不夠靈活,而且由於從QueryString中擷取的資料也就是簡單實值型別和string,應該可以這樣:    public static Nullable<T> GetQueryString<T>(this Page p, string param)
        where T : struct
    {
        string s = p.Request.QueryString[param];
        Nullable<T> r = null;
        if (s == null)
            return r;
        try
        {
            r = (T)Convert.ChangeType(s, typeof(T));
        }
        catch
        {
        }
        return r;
    }

    public static string GetQueryString(this Page p, string param)
    {
        return p.Request.QueryString[param];
    }

使用的時候:        Debug.Assert(this.GetQueryString<int>("i") == null, "i == null");
        Debug.Assert(this.GetQueryString("s") == null, "s == null");

不知大家還有沒有更好的方法?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.