Session相关的mock
Session相关的mock主要有以下两个步骤:
1) HttpContext对象的实例化
² session属于HttpContext对象,所以简单来说,就是我们需要构造一个HttpContext,对象然后在给其中的Session附值。然后再把它指定到 System.Web.HttpContext.Current 中
² MSDN里HttpContext构造函数是公开的,
名称 | 说明 | |
HttpContext(HttpWorkerRequest) | 使用指定的辅助请求对象初始化 HttpContext 类的新实例。 |
模拟的代码如下:
但是需要注意的是,如果我们再简单的增加下面一行,虽然编译没有错误,但是执行不通过。
System.Web.HttpContext.Current.Session["Test"] = 8888;
因为SimpleWorkerRequest并没有封装有关Session的功能。
http://msdn.microsoft.com/zh-cn/library/system.web.hosting.simpleworkerrequest
这样我们还需要模拟session。
2) 模拟session的对象
² Session是HttpSessionState 类型,要mock session,必须要自行创建HttpSessionState。那接下来首先想到的是用HttpSessionState的构造函数来创建。
² 在MSDN上查看HttpSessionState类,
http://msdn.microsoft.com/zh-cn/library/system.web.sessionstate.httpsessionstate_members(v=VS.80).aspx
发现公开成员和受保护成员均无构造函数。
² 去代码里看HttpSessionState元数据,也没有找到构造函数。这就很为难了。
² 上网查找得知,可以用“.NET Reflector”这个工具查明。
.NET Reflector 是一个只有 548 KB 的.net 类浏览工具。
它可以读取存储在 .net 应用程序 中的 metadata、IL 指令、资源和XML文档。
并可以把这些信息,以IL、C#、VB.net 、Delphi、MC++、Chrome 这些语言的方式来展示其中的功能.
分析如何用Mock对象,就是借用了这个工具,分析出了HttpSessionState类构造函数的具体接口,进而可以用反射方式构造出HttpSessionState类的实例。
使用方法:这软件以前都是免费的,如今竟然收费了。。。
可耻的是,收费后还通知老版本在2011年5月左右会失效,不自动升级时无法使用的。。。。。
但是办法还是有的,只要把系统时间改为2011年5月之前就可以使用咯~
一般都改为2010年就可以了
² 继续上网搜索,发现有人已经把HttpSessionState类直接Reflector出来了,那就直接看成果吧
.net 2.0 下 HttpSessionState 的构造函数变成了下面方式:
internal HttpSessionState(IHttpSessionState container)
{
this._container = container;
}
这样我们首先要实现一个 IHttpSessionState 接口的对象。
² 查找MSDN可知,
接口 | 说明 |
IHttpSessionState | 定义协定以实现自定义会话状态容器。 |
这个IHttpSessionState接口可以实现自定义session。
创建一个类实现这个接口即可。
IHttpSessionState接口的属性如下
名称 | 说明 |
CodePage | 获取或设置当前会话的代码页标识符。 |
CookieMode | 获取一个值,该值指示是否为无 Cookie 会话配置应用程序。 |
Count | 获取会话状态项集合中的项数。 |
IsCookieless | 获取一个值,该值指示会话 ID 是嵌入在 URL 中还是存储在 HTTP Cookie 中。 |
IsNewSession | 获取一个值,该值指示会话是否是与当前请求一起创建的。 |
IsReadOnly | 获取一个值,该值指示会话是否为只读。 |
IsSynchronized | 获取一个值,该值指示对会话状态值的集合的访问是否是同步(线程安全)的。 |
Item[Int32] | 按数字索引获取或设置会话状态项的值。 |
Item[String] | 按名称获取或设置会话状态项值。 |
Keys | 获取存储在会话状态项集合中的所有值的键的集合。 |
LCID | 获取或设置当前会话的区域设置标识符 (LCID)。 |
Mode | 获取当前会话状态模式。 |
SessionID | 获取会话的唯一会话标识符。 |
StaticObjects | 获取由 ASP.NET 应用程序文件 Global.asax 中的 <object Runat="Server" Scope="Session"/> 标记声明的对象的集合。 |
SyncRoot | 获取一个对象,该对象可用于同步对会话状态值的集合的访问。 |
Timeout | 获取并设置在会话状态提供程序终止会话之前各请求之间所允许的超时期限(以分钟为单位)。 |
IHttpSessionState接口的方法如下
名称 | 说明 |
Abandon | 结束当前会话。 |
Add | 向会话状态集合添加一个新项。 |
Clear | 从会话状态项集合中清除所有值。 |
CopyTo | 将会话状态项值的集合复制到一维数组中(从数组的指定索引处开始)。 |
GetEnumerator | 返回一个枚举数,可用来读取当前会话中所有会话状态项值。 |
Remove | 删除会话状态项集合中的某个项。 |
RemoveAll | 从会话状态项集合中清除所有值。 |
RemoveAt | 删除会话状态项集合中指定索引处的项。 |
可以借用这个接口的范例代码,以下形式来实现这个接口
public sealed class MySessionState : IHttpSessionState
{……}
详细内容请看代码。
http://msdn2.microsoft.com/zh-cn/library/system.web.sessionstate.ihttpsessionstate.aspx
² 由于HttpSessionState的构造函数是internal类型的,要调到它必须通过反射了。
3) HttpContext对象补足
² 结合上述两点,HttpContext对象和session对象都有了。
那如何在HttpContext对象加入session对象呢?
简单的赋值是没用的,因为属性session是只读的。
² 通过.NET Reflector可以得知,HttpContext对象里有如下信息
那么很明显,在HttpContext对象的Item[“AspSession”]里把session对象放入即可。
这是一个很隐蔽的信息。
² 把包含session信息的HttpContext对象赋给HttpContext.Current即可以模拟session成功了
HttpContext.Current = HttpContext对象;