您的位置:首页 > 其它

有关一些状态机制的封装

2008-05-09 14:36 127 查看
直接使用字符串访问会话字典的方式有几个缺点:

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");

不知大家还有没有更好的方法?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: