有关一些状态机制的封装

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

不知大家还有没有更好的方法?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值