LoveCherry

技术无极限

博客园 首页 新随笔 联系 订阅 管理
  192 Posts :: 0 Stories :: 3240 Comments :: 656 Trackbacks

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

不知大家还有没有更好的方法?
posted on 2008-05-09 14:36 lovecherry 阅读(3633) 评论(10) 编辑 收藏

Feedback

#1楼 2008-05-09 14:40 笑清风      
ding
 回复 引用 查看   

#2楼 2008-05-09 16:09 怪怪      
挺有启发性 :)
 回复 引用 查看   

#3楼 2008-05-09 16:35 alisx      
学习
 回复 引用 查看   

#4楼 2008-05-09 21:25 代码乱了      
很不错的,值得研究啊
 回复 引用 查看   

#5楼 2008-05-12 00:39 镜涛      
学习
 回复 引用 查看   

#6楼 2008-05-14 09:48 张子阳.      
给你留了言,可能你没有注意到,就再这里在说一遍了。不知道有没有兴趣加入我新建的小组?可以短消息回复我,谢谢 ^O^


 回复 引用 查看   

#7楼 2008-05-31 10:28 yyliuliang      
大对象保存在Session中。。 高并发应用还不敢这么用。。
 回复 引用 查看   

学到了!谢谢!
 回复 引用   

很是认同!
 回复 引用   

#10楼 2009-12-09 16:38 httt[未注册用户]
freshwater pearl
akoya pearl
cultured pearl
cultured freshwater pearl
cultured akoya pearl
freshwater pearl jewelry
akoya pearl jewelry
cultured pearl jewelry
pearl necklace
pearl earrings
pearl bracelet
pearl pendant
freshwater pearl necklace
freshwater pearl earrings
akoya pearl necklace
pearl strand
pearl beads

 回复 引用