zoukankan      html  css  js  c++  java
  • 有关一些状态机制的封装

    直接使用字符串访问会话字典的方式有几个缺点:
    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");

    不知大家还有没有更好的方法?
    欢迎大家阅读我的极客时间专栏《Java业务开发常见错误100例》【全面避坑+最佳实践=健壮代码】
  • 相关阅读:
    Execl(2003)数据 导入 SQL Server(2005)
    访问远程MySQL
    国学堂—梁冬对话林曦
    男人对自己狠一点
    国学堂-梁冬对话王东岳
    国学堂—梁冬对话栗强
    内功
    学说话见识语言的力量
    一语道破中国千年潜规则——每天懂一点人情世故
    禅茶茶艺 (十二道)
  • 原文地址:https://www.cnblogs.com/lovecherry/p/1189990.html
Copyright © 2011-2022 走看看