现在的位置: 首页 > 综合 > 正文

理解Session State模式+FAQ [翻译]

2013年08月17日 ⁄ 综合 ⁄ 共 20056字 ⁄ 字号 评论关闭

作者:Patrick Y. Ng
原文地址:http://forums.asp.net/7504/ShowPost.aspx
译者:Tony Qu
译者Blog:tonyqus.cnblogs.com

原文最后一次更新:2004年9月21日

本文被分成两部分:
1.“理解Session State模式”——帮助你理解三种Session State的不同之处
2. FAQ

1.理解Session State模式

存储位置
InProc:session在服务器中以活动对象方式存储(aspnet_wp.exe)

StateServer: session被序列化并保存在单独的aspnet_state.exe的内存中。StateServer能够运行在另一台服务器上

SQLServer: session被序列化并保存在SQL Server中

性能:
InProc:最快,但是session数据越多,web服务器上消耗的内存也越多,它可能影响性能。

StateServer:当存储基本类型(如string,integer等)数据时,在同一个测试环境中它比InProc慢15%。如果你存储大量对象,序列化和反序列化可能影响到性能

SQLServer:当存储基本类型(如string,integer等)数据时,在同一个测试环境中它比InProc慢25%。它也有与StateServer一样的序列化性能问题。

关于Out-of-Proc(OOP,非InProc)模式的性能提示
如果你使用OOP模式(即StateServer或SQLServer),session state中的序列化和反序列化对象将成为你的主要性能消耗之一。对于基本类型,ASP.NET通过一种内部优化方法来完成序列化和反序列化。(基本类型包括所有的数字类型(如Int, Byte, Decimal,String, DateTime, TimeSpan, Guid, IntPtr和UIntPtr等))

如果你有一个session变量(如一个ArrayList对象),且它不是一个基本类型,ASP.NET将使用BinaryFormatter来进行序列化和反序列化,那可能会相对慢一些。

所以出于性能考虑,最好使用上面列出的基本类型来存储所有的session state数据。例如,如果你需要存储两个东西,名字和地址,在session state中你既可以(方法a)使用两个string session变量来存储它们,也可以(方法b)创建一个内含两个string的类来保存它们,然后把这个类对象保存在一个session变量中。出于性能考虑,你应该选择方法a。

为了进一步理解这个主题,请看FAQ中的一个问题:“序列化和反序列化如何在SqlServer和StateServer模式下工作”

健壮性
InProc:如果工作者进程(aspnet_wp.exe)进行资源回收或者应用程序域(appdomain)重启动,session state就会丢失。这是因为session state是保存在一个应用程序域的内存空间中的。对配置文件(如web.config和machine.config)的修改或者/bin目录的任何改变(例如在你使用VS编译应用程序后产生了一个新的dll)都可能引起重启动,详细请见KB324772。在1.0中,也有一个bug可能引起工作者进程重启动,但这个bug在1.1中已经修复,见KB321792。

如果你使用的是IIS6.0,你可以在IIS Manager中找到Application Pools/DefaultAppPool,其中可以看到回收(Recycling)选项卡与性能(Performace)选项卡中是否有引起IIS工作者进程(w3svc.exe)停止工作的参数。

更多有关应用程序资源回收的内容,可以看我的另一篇FAQ:
http://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=232621

StateServer:解决了InProc模式的session state丢失问题。允许一个webfarm在中央服务器中存储session。只能在State Server上出现失败。

SQLServer:与StateServer相似。session state的数据在SQL Server重启后仍然保留着,你也可以按照KB311209的步骤使用SQL server failover cluster

警告
InProc:它不能在web garden模式下工作,因为在这个模式下会有多个aspnet_wp.exe在同一台机器上运行。建议在使用web garden使切换到State Server或SQL Server。仅在InProc模式下支持Session_End事件。

StateServer
- 在web farm中,请确认在所有的web服务器上有相同的<machineKey>。KB313091描述了如何设置它。
- 请确保你的对象是可序列化的。详见KB312112
- 为了在web farm中的不同web服务器上维护session state,IIS Metabase中的网站应用程序路径(如/LM/W3SVC/2)应该在所有的服务器上保持一致(大小写敏感)。详见KB325056

SQLServer
- 在1.0中有一个bug,如果你在连接字符串中指定integrity security(如"trusted_connection=true"或 "integrated security=sspi"),且你打开了asp.net的身份模拟,它将不会工作。这个问题在KB324479中有描述,不幸的是这份文档中的描述和原因部分是错误的。不过已经有一个QFE fix对它作了修复,这个fix将包含在1.0 sp3中。这个问题在1.1中已经修复了。
- 请确认你的对象是可序列化的,否则你的请求可能被挂住,详见KB312112。SQLServer模式的挂起问题已经在1.1中修复,KB324479的QFE fix也修复了这个问题。1.0 sp3也对这个问题作了修复。
- 为了在web farm中的不同web服务器上维护session state,IIS Metabase中的网站应用程序路径(如/LM/W3SVC/2)应该在所有的服务器上保持一致(大小写敏感)。详见KB325056

其他资源
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/aspnetsessionstate.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/CachingArchch2.asp
http://www.411asp.net/home/tutorial/specific/web/sessions

2. FAQ问题列表
Q: session state在部分浏览器上工作,而在其他一些上不工作。为什么呢?
Q: 在InProc模式中,为什么我有时会丢失所有的session?
Q: session state在一些web服务器上工作,但是在其他服务器上不工作。
Q: 为什么session state不可用?
Q: 为什么session_end没有触发?
Q: 使用InProc模式时,为什么我的session变量频繁丢失?
Q: 在session超时或删除之后,为什么SessionID保持不变
Q: 为什么SessionID每一次请求都会改变
Q: Session.Abandon()和Session.Clear()有什么区别
Q: session的Timeout属性是一个滑动超时值吗?
Q: 我可以在ASP.NET和ASP之间共享session吗?
Q: 我可以在web应用程序(例如虚拟目录或者IIS的应用程序)间共享session state吗?
Q: 在session state中可以存储哪些类型的对象?
Q: 为什么我的请求在切换到SQLServer模式之后挂住了?
Q: 为什么Response.Redirect和Server.Transfer在Session_End中不工作?
Q: 在Session_End中,我可以获得一个有效的HttpSessionState对象和HttpContext对象吗?
Q: 在web service中如何使用session?
Q:我正在写一个HttpHandler,为什么session stae不工作?
Q: 我正在使用web farm,并且每当我重定向到其他服务器时,session state就会丢失?
Q: 如果使用cookieless,我该如何从一个HTTP页面重定向到一个HTTPS页面?
Q: session state有没有一个锁机制来安排对session的访问顺序?
Q: 我该如何检测一个session过期,然后重定向到另一个页面
Q: 在Session_End中,我尝试使用SQL做一些清理工作,但是失败了,请问为什么?
Q: 我使用的是SQLServer模式,为什么我的session不会过期
Q: 我有一个以htm为扩展名的frameset页面,并且我发觉其中包含的每个帧在第一次请求时都有一个不同的SessionID,这是为什么?
Q: 我将EnableSessionState设置为ReadOnly,但是在InProc模式下,我仍然可以修改session,为什么?
Q: 我将cookieless设置为true,在Redirect之后session变量丢失了,为什么?
Q: 将cookieless设置为true有哪些缺点
Q: 在InProc模式下,我用编程方式改变了session的超时时间,它触发了Session_End,为什么?
Q: 在SQLServer模式下,我可以把session state保存在除tempdb之外的数据库中吗?
Q: 如何防止将未加密的字符串放在我的连接字符串汇总?
Q: 在使用SQLServer模式时,我需要怎样的SQL权限?
Q: 我可以自己写定制的session state模式吗?
Q: 在SQLServer或StateServer模式下,序列化和反序列化如何工作?
Q: 我该如何让我的state server更安全?
Q: 我能否可以使用非global.asax中的处理程序来订阅SessionStateModule.End事件?
Q: 不同的应用程序可以把他们的session state保存在同一个SQL Server上的不同数据库中吗?

Q: session state在部分浏览器上工作,而在其他一些上不工作。为什么呢?
A: 估计你没有使用cookieless,你必须保证你的浏览器支持cookie。请参考这份KB:http://support.microsoft.com/default.aspx?scid=kb;EN-US;q316112

Q: 在InProc模式中,为什么我有时会丢失所有的session?
A: 请见理解session state模式的健壮性部分

Q: session state在一些web服务器上工作,但是在其他服务器上不工作。
A: 可能是机器名的问题,见http://support.microsoft.com/default.aspx?scid=kb;EN-US;q316112

Q: 为什么session state不可用?
A:
- 首先,检查web.config、machine.config和Page标签来确认你启用了session state
参考资料:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconsessionstate.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconpage.asp
- 请注意session state并非在任何地方、任何时间都可以使用,它仅在HttpApplication.AcquireRequestState事件之后可用。例如,在 global.asax中的Application_OnAuthenticateRequest处理程序中,session state不可用
- 请确认System.Web.SessionState.SessionStateModule已包含在配置文件的< httpModules>节中。一个常见的例子是,出于性能考虑,SharePoint应用程序会把这个模块从web.config文件中移除,因此导致session不可用

Q: 为什么session_end没有触发?
A: 这是最常见的问题之一
1. 请记住session_end仅在InProc模式中可用
2. 关闭浏览器,session_end是不会触发的。HTTP是一种无状态协议,服务器没有办法知道你的浏览器是否已经关闭。
3. 当有n分钟(n=timeout值)的无操作或调用Session.Abandon时,Session_End才会触发
4. 对于情况1而言,Session_End将由一个后台线程触发,这表示:
a. Session_End中的代码使用工作者进程账号运行,如果你访问如数据库这样的资源时,可能会有权限问题。
b. 如果在Session_End中发生错误,程序不会通知发生了什么
5. 对于情况2而言,为了让Session_End触发,session state必须先存在。这意味着你必须在session state中存储一些数据,并且已经完成了至少一个请求
6. 还是对于情况2而言,Session_End仅在被丢弃的session被找到的时候才会触发。这样的话,如果你在同一个请求中创建并丢弃一个 session,由于session没有被保存,因此也不会被找到,Session_End将不会被调用。这是v1.0和v1.1中的bug。

Q: 使用InProc模式时,为什么我的session变量频繁丢失?
A: 有可能是应用程序资源回收引起的,见http://support.microsoft.com/default.aspx?scid=kb;en-us;Q316148
在v1.0中有一个bug可能会导致工作者进程重启动。在v1.1和v 1.0sp2中已经修复。见http://support.microsoft.com/default.aspx?scid=kb;EN-US;321792

关于应用程序资源回收的详细信息,请见我的另一篇:FAQhttp://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=232621

Q: 在session超时或删除之后,为什么SessionID保持不变
A: 尽管在超时周期之后session state过期,sessionID将一直保持到浏览器session过期为止,也就是说,一个相同的sessionID可以有多次session超时,但是始终对应着一个相同的浏览器实例。

Q: 为什么SessionID每一次请求都会改变
A: 如果你的应用程序从未在session state中存储过数据。在这种情况下,那么每次请求都会创建一个新的session state(ID也是新的),但是不会被存储,因为里面什么数据都没有。

尽管如此,有两种例外可能产生相同的Session ID
- 如果用户使用相同的浏览器实例来请求另一个使用session state的页面,那么你每次获得的Session ID是相同的。详见“在session超时或删除之后,为什么SessionID保持不变?”
- 如果使用了Session_OnStart事件,即使session为空,asp.net也会保存session state。

Q: Session.Abandon()和Session.Clear()有什么区别
A: 主要的区别在于,如果你调用Session.Abandon(), Session_End将被触发(仅在InProcxi下适用),在下一个请求中,Session_Start触发。而Session.Clear()仅仅是清除数据,但没有删除session。

Q: session的Timeout属性是一个滑动超时值吗?
A: Session的Timeout是一个滑动过期时间,意思是一旦你的页面访问session state,过期时间就会向挪。注意,只要页面没有被禁用,在请求时页面就会自动访问session

Q: 我可以在ASP.NET和ASP之间共享session吗?
A:不可以。但是有一篇文章讲到了如何来绕过这个问题:http://www.msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/ConvertToASPNET.asp

当然也有一些第三方解决方案。

Q: 我可以在web应用程序(例如虚拟目录或者IIS的应用程序)间共享session state吗?
A:不能。

Q: 在session state中可以存储哪些类型的对象?
A:这是由你使用的模式决定的
- 如果你使用的是InProc模式,存储在session state中的对象是活对象,那么你就可以存储你创建的任何对象
- 如果你使用的是SQLServer或State Server模式,当处理一个请求时,session state中的对象对象将被序列化和反序列化,所以请确认你的对象都是可序列化的,而它们的类都作了可序列化标记。如果没有,session state将不会成功存储。在v1.0中,有一个bug,当这个问题发生时,如果使用SQLServer模式,请求可能在不知情的情况下被挂起。挂起的问题在v1.1和v1.0 sp3中已经修复。KB324479的QFE fix也包含了对这一问题的修复。

更多信息请见:http://support.microsoft.com/directory/article.asp?ID=KB;EN-US;q312112

Q: 为什么我的请求在切换到SQLServer模式之后挂住了?
A:请看问题“在session state中可以存储哪些类型的对象?”的答案

Q: 为什么Response.Redirect和Server.Transfer在Session_End中不工作?
A:Session_End是在服务器内部触发的,它基于一个内部的计时器。因此,在事件触发时,与任何HttpRequest对象无关。这也是为什么Response.Redirect 和Server.Transfer不工作的原因。

Q: 在Session_End中,我可以获得一个有效的HttpSessionState对象和HttpContext对象吗?
A:  你可以获得httpSessionState对象,你可以使用'Session'来访问该对象。但是你无法访问HttpContext,因为这个事件和请求没有任何关系。

Q: 在web service中如何使用session?
A: 需要在调用方使用一些技巧,你必须保存web服务使用的cookie。请见关于HttpWebClientProtocol.CookieContainer的MSDN文档。

尽管如此,如果你是通过代理对象从你的页面调用web服务,由于架构限制,web服务和你的页面无法共享session state。

如果你通过redirect调用web服务,这是可以完成的

Q:我正在写一个HttpHandler,为什么session stae不工作?

A: 你的HttpHandler接口必须实现标记接口IRequiresSessionState或IReadOnlySessionState,方能使用session state。

Q: 我正在使用web farm,并且每当我重定向到其他服务器时,session state就会丢失?
A: 为了在web farm中的不同服务器之间维护session state,IIS Metabase中的网站应用程序路径(例如 /LM/W3SVC/2)应该在所有的web服务器上保持一致(大小写敏感)。详见KB325056

Q: 如果使用cookieless,我该如何从一个HTTP页面重定向到一个HTTPS页面?
A: 尝试使用下面的代码:
String originalUrl = "/fxtest3/sub/foo2.aspx";
String modifiedUrl = "https://localhost" + Response.ApplyAppPathModifier(originalUrl);
Response.Redirect(modifiedUrl);

Q: session state有没有一个锁机制来安排对session的访问顺序?
A:session state实现了读写锁定机制:
- 对session state有写权限(如<%@ Page EnableSessionState="True" %> )的页面或帧将获得这个session的写锁,直到请求结束。
- 对session state有读权限(如<%@ Page EnableSessionState="ReadOnly" %> )的页面或帧将获得这个session的读锁,直到请求结束。
- 读锁会阻塞写锁;读锁不会阻塞读锁;写锁会阻塞所有的读锁和写锁
- 这也是为什么当两个帧同时拥有session的访问权限时,一个帧必须等待另一帧先完成

Q: 我该如何检测一个session过期,然后重定向到另一个页面
A: 这是经常要遇到的问题,但不幸的是没有很简单的方法来完成它。我们将期待在一个主要版本中实现它。同时,如果你使用cookie,你可以在cookie中存储一个标志,这样你就可以区分新浏览器+新session及旧浏览器+过期session,下面的代码在session过期时会重定向到一个过期页面。
void Session_OnStart(Object sender, EventArgs e) {
    HttpContext context = HttpContext.Current;
    HttpCookieCollection cookies = context.Request.Cookies;

    if (cookies["starttime"] == null) {
        HttpCookie cookie = new HttpCookie("starttime", DateTime.Now.ToString());
        cookie.Path = "/";
        context.Response.Cookies.Add(cookie);
    }
    else {
        context.Response.Redirect("expired.aspx");
    }
}

Q: 在Session_End中,我尝试使用SQL做一些清理工作,但是失败了,请问为什么?
A: 首先,session_End仅在InProc模式下支持。
第二,Session_End是用运行工作者进程(aspnet_wp.exe)的帐号运行的,这个账号可以在machine.config中指定。因此,在你的Session_End中,如果使用integrity security连接SQL,它将使用工作者进程账号身份连接,这可能会引起登录失败,这要看你的SQL安全设置了。

Q: 我使用的是SQLServer模式,为什么我的session不会过期
A: 在SQLServer模式下,session过期是由SQL Agent使用一个注册任务完成的,请确认你的SQL Agent是否已经运行。

Q: 我有一个以htm为扩展名的frameset页面,并且我发觉其中包含的每个帧在第一次请求时都有一个不同的SessionID,这是为什么?
A: 原因是你的frameset页面是一个htm文件而不是一个aspx页面

在通常情况下,如果一个frameset页为一个aspx文件,当你请求该页面时,会首先发请求给web服务器,你会收到一个asp.net session cookie(其中保存着session id),然后浏览器会为frame发送一个单独的请求,而每个请求将拥有相同的session id。

然而,因为你的页面是一个htm文件,第一个请求就不会获得任何session cookie,因为页面是由asp处理的而非asp.net,然后浏览器会为每个帧发送单独的请求。但是,这次每个单独的请求将不会持有任何 session id,这样的话每个帧将创建自己的session。这也是为什么你在每个帧中看到的session id都不同。最后一个请求将赢得胜利,因为它将覆盖前两个请求写入的cookie。如果你刷新一次,你将看到它们拥有了相同的session id。

这个行为是设计所决定的,简单的解决方法就是将frameset页面改称aspx
 
Q: 我将EnableSessionState设置为ReadOnly,但是在InProc模式下,我仍然可以修改session,为什么?
A: 尽管那些EnableSessionState被设置为ReadOnly,但是在InProc模式中,用户仍然可以修改session。唯一的区别在于session在请求中不会被锁住,这一限制是设计所决定的。对于这一点没有在msdn中提到我表示抱歉。

Q: 我将cookieless设置为true,在Redirect之后session变量丢失了,为什么?
A: 如果你使用的是cookieless,你必须使用相对路径(如../hello.aspx),而不是绝对路径(如/foo/bar/hello.aspx)。如果你使用的是绝对路径,ASP.NET不会将session id保存在url中。

Q: 将cookieless设置为true有哪些缺点
A: 设置cookieless=true表示一些潜在的规则,主要有:
1. 你不能在你的页面中使用绝对路径
2. 在http和https之间切换的话,你必须做一些额外的动作
3. 如果你的客户发送了一个链接到一个朋友,URL将包含session id,两个用户可以在同一时间使用相同的session id

Q: 在InProc模式下,我用编程方式改变了session的超时时间,它触发了Session_End,为什么?
A: 这是InProc的一个bug。如果你更改session的timeout值为另一个值,Session_End将被调用(但不会调用Session_Start)。我们期待在v2.0中能够修复这个错误。

Q: 在SQLServer模式下,我可以把session state保存在除tempdb之外的数据库中吗?
A: 是的。见KB311209。

Q: 如何防止将未加密的字符串放在我的连接字符串汇总?
A: 见sql trusted connection或者将连接字符串以加密数据形式保存在注册表中。详情请见,KB329250和KB329290。

Q: 在使用SQLServer模式时,我需要怎样的SQL权限?
A: 调用者需要对下面的存储过程拥有EXEC权限,
dbo.TempGetAppID
dbo.TempGetStateItem
dbo.TempGetStateItemExclusive
dbo.TempReleaseStateItemExclusive
dbo.TempInsertStateItemLong
dbo.TempInsertStateItemShort
dbo.TempUpdateStateItemLong
dbo.TempUpdateStateItemShort
dbo.TempUpdateStateItemShortNullLong
dbo.TempUpdateStateItemLongNullShort
dbo.TempRemoveStateItem
dbo.TempResetTimeout
在v1.1中,你也需要对下面的存储过程拥有EXEC权限
dbo.TempGetStateItem2
dbo.TempGetStateItemExclusive2

请注意存储过程的拥有者必须对session state表(dbo.ASPStateTempSessions和 dbo.ASPStateTempApplications)拥有SELECT/INSERT/UPDATE/DELETE 权限。通常,拥有者是执行installsqlstate.sql(或者持久版本,见KB311209)的帐号来安装sql session state需要的表、存储过程、数据库

也请注意,如果你的session state表在tempdb中(默认情况下)如果你对SQL Server进行资源回收,所有在这张表上的权限设置将丢失。

Q: 我可以自己写定制的session state模式吗?
A:(待翻译)

Q: 在SQLServer或StateServer模式下,序列化和反序列化如何工作?
A: (待翻译)

Q: 我该如何让我的state server更安全?
A:如果state server和web server运行在一台机器上,通过设置HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/ aspnet_state/Param ters/AllowRemoteConnection的dword项为0,可以让state server仅在本地运行。这样就可以防止远程客户端连见到state server上。这一特性在v1.1中可用,在v1.0 sp3中也有。

state server必须受防火墙保护,以防止外部连接以保证真正安全。默认的端口是TCP 42424,你可以设置HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/ aspnet_state/Param ters/Port来改变它。如果是本地模式,除了127.0.0.1以外,屏蔽所有外来连接;如果是远程模式,显式的禁用所有的地址,除了对wev服务器的连接。

使用IPSec是另一种保护state server的方式。

Q: 我能否可以使用非global.asax中的处理程序来订阅SessionStateModule.End事件?
A: 答案是否定的。当SessionStateModule触发End事件时,只有定义在global.asax中的方法才会被触发

这是出于安全原因考虑的才对此进行限制。假设asp.net允许用户使用的其他的处理程序来处理End事件。在这种情况下,用户通常使用一个页面方法作为处理程序,当你在事件订阅时传入处理程序,处理程序将与你的程序运行在的HttpApplication实例关联。请注意, HttpApplication实例会被回收来处理其他请求。这样的话,当End事件触发时,asp.net将调用处理程序,而与之关联的 HttpApplication实例已经被另一个请求所使用,这样的情况将引发各种各样的问题。为了避免这种危险,在v1.0中决定进调用 Global.asax中定义的方法。希望你们都可以忍受这一限制。

Q: 不同的应用程序可以把他们的session state保存在同一个SQL Server上的不同数据库中吗?
A: 答案是肯定的。详情请见:http://support.microsoft.com/default.aspx?scid=kb;EN-US;836680

posted @ 2006-10-24 22:10 Tony Qu 阅读(1307) | 评论 (1)编辑 收藏

2006年8月25日

科学计算器 2.3发布
简介
    支持表达式计算的科学计算器。完全可以替代Windows自带的计算器,使用起来更加人性化。支持变量保存、三角函数运算、指幂运算、角度弧度转换,除了Windows计算器的进制计算不支持外,其他的功能都已经实现。

关于我为什么要做这个计算器,请见http://www.cnblogs.com/tonyqus/archive/2005/04/14/137792.html

What's NEW
1. 支持负号(原来使用@代替负号)
2. 在菜单中显示变量值
3. 支持弧度/角度切换
4. 支持两种视图模式:Full和Compact
5. 支持结果显示方式切换:Auto, Fixed, Scientific, Grouped
    以123445.12345为例
    Auto: 123445.12345
    Fixed: 123445.12
    Scientific: 1.234451E+005
    Grouped:  123,445.12
6. 在提示屏幕中显示实际的计算公式(替换所有变量)

Bug修正
1. 禁止用户输入#,否则可能出错
2. 修正ANS无法参与计算的问题

新版本采用Visual Studio 2005开发
不再提供基于Visual Studio.net 2003的更新版本,基于VS2003的最高版本为2.1

源代码下载地址:http://www.cnblogs.com/Files/tonyqus/Calculator.NET.v2.3.zip

如果有任何意见或者bug,请写在回复中,谢谢!

如果想了解该计算器的制作原理,请见 http://www.cnblogs.com/tonyqus/category/23590.html 中的文章
=============================Update on 2006.8.28==============================
请8月28日之前下载的朋友重新下载源代码,修正两个表达式显示的小问题
1. 未替换小写的变量为真实值
2. 未将大小写的ans替换为真实值

posted @ 2006-08-25 17:59 Tony Qu 阅读(392) | 评论 (2)编辑 收藏

2006年8月8日

function getFlashVer() {//获得flashplayer的版本 google
 var f="",n=navigator; 
 
if (n.plugins && n.plugins.length) {
  
for (var ii=0;ii<n.plugins.length;ii++) {
   
if (n.plugins[ii].name.indexOf('Shockwave Flash')!=-1) {
    f
=n.plugins[ii].description.split('Shockwave Flash ')[1];
    
break;
   }
  }
 } 
else if (window.ActiveXObject) {
  
for (var ii=10;ii>=2;ii--) {
   
try {   
    
var fl=eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+ii+"');");
    
if (fl) {f=ii + '.0'; break; }
   }
   
catch(e) {}
  }
 }
 document.write(
"您的FlashPlayer版本为 <b>"+f+"</b>"); 
}

posted @ 2006-08-08 11:47 Tony Qu 阅读(83) | 评论 (0)编辑 收藏

2006年6月29日

Code Snippets Manager是VS2005专门用来管理代码块智能感知的工具。

然而,使用它并没有预想中的那么顺利,特别是在做过多次目录添加和删除之后,可能出现添加在列表中的目录无法在智能感知列表中显示出来的情况;甚至会出现列表当中明明没有这个目录,却也添加不进去的情况,它总是认为这个目录已经在列表中存在。为了解决这个问题,我对它的存储方式作了一些研究,并跟踪了相关的注册表和文件变化,下面是我的研究结果。

Code Snippets Manager主要在三个地方保存信息:

1. HKEY_CURRENT_USER/Software/Microsoft/VisualStudio/8.0/Open Find/Microsoft Visual Studio/Settings/Code Snippets Directory/File Name MRU/Value

这是一个REG_MULTI_SZ 类型的值,可以用来存储多个字符串,可以看作是一个字符串数组,这里用来存储路径,用回车作为分隔符,在我的机器上,它的值是这样的。

C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/filesystem
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/datatypes
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/database
C:/Documents and Settings/tonyqus/My Documents/code1
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/
C:/Program Files/Microsoft Visual Studio 8/VC#/Snippets/1033/Refactoring
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/application

2.  HKEY_CURRENT_USER/Software/Microsoft/VisualStudio/8.0/Languages/CodeExpansions/Visual C#/Path

这是一个REG_SZ 类型的值,可以用来存储字符串,这里用来存储路径,用分号分割,在我的机器上,它的值如下:

%InstallRoot%/VC#/Snippets/%LCID%/Visual C#/;%MyDocs%/Code Snippets/Visual C#/My Code Snippets/;%InstallRoot%/VC#/Snippets/%LCID%/OfficeDevelopment/;%InstallRoot%/VC#/Snippets/%LCID%/Refactoring/;C:/Documents and Settings/tonyqus/My Documents/code1/;C:/Program Files/Microsoft Visual Studio 8/VC#/Snippets/1033/Workflow/;C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/datatypes/

3.  C:/Documents and Settings/<Your Account Name>/Local Settings/Application Data/Microsoft/VisualStudio/8.0/1033/ExpansionsXML.xml

这是一个xml文件,结构比较复杂,我们可以看到在上面的两个设置中,仅存储目录,而在这个文件中既保存目录又保存目录中的.snippet文件的完整路径,这可能是为了提供.snippet文件的import功能而特地设计的。这里就不做展开了,大家有兴趣的话,可以研究一下它的结构。

来说说可能出现的问题:
问题 1

在HKEY_CURRENT_USER/Software/Microsoft/VisualStudio/8.0/Languages/CodeExpansions/Visual C#/Path 中存储着两个完全相同的路径,如
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/database
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/database/
我们可以看到这两个路径唯一的差别就是一个'/',但似乎Code Snippets Manager不会对这样的情况进行处理,它会认为这是两个完全不同的路径,所以如果出现这种情况,建议删掉其中一个。

问题 2
在注册表的两个值中目录明明存在,但却无法在智能感知时列出该目录,这可能是由于ExpansionsXML.xml没有改目录的相关信息所致,建议删除或者重命名ExpansionsXML.xml,然后重新启动VS2005,并打开Code Snippets Manager,你会发现一个Code Snippets Manager会根据注册表中的路径新建一个新的ExpansionsXML.xml文件。

问题 3
智能感知可以列出的目录,在Code Snippets Manager的列表中根本没有,但每次试图添加目录时,会报目录已存在的错误。遇到这种情况,恐怕要对这三个存储位置都要做处理,首先要确保注册表中确实把这个目录删除了,还有就是重建ExpansionXML.xml文件。

posted @ 2006-06-29 18:23 Tony Qu 阅读(1580) | 评论 (4)编辑 收藏

2006年5月19日

表名:aspnet_Applications
说明:保存应用程序信息

字段名  类型  属性 说明
 ApplicationName  nvarchar(256)    应用程序名
 LoweredApplicationName  nvarchar(256)    小写的应用程序名
ApplicationId  uniqueidentifier  PK 应用程序的id, GUID值
 Description  nvarchar(256)  nullable 应用程序的 描述

表名:aspnet_Paths
说明:路径信息

字段名  类型  属性 说明
 ApplicationId  uniqueidentifier  FK: appnet_Applications.ApplciationId  应用程序Id
 PathId  uniqueidentifier  PK  路径Id
 Path  nvarchar(256)    路径信息
 LoweredPath  nvarchar(256)   小写的路径信息

表名:aspnet_Users
说明:用户信息

 字段名  类型  属性  说明
 ApplicationId  uniqueidentifier    应用程序Id
 UserId  uniqueidentifier  PK 用户Id
 UserName  nvarchar(256)    用户名
 LoweredUserName  nvarchar(256)    小写的用户名
 MobileAlias  nvarchar(16)    移动电话的pin码(未使用)
 IsAnonymous  bit    是否为匿名用户
LastActivityDate  datetime    最后活动日期

表名:aspnet_Membership
说明:成员信息

 字段名  类型  属性  说明
 ApplicationId  uniqueidentifier  FK: appnet_Applications.ApplciationId  应用程序Id
 UserId  uniqueidentifier  FK: aspnet_Users.UserID 用户Id
 Password  nvarchar(128)    密码
 PasswordFormat  int   存储密码的格式 
 PasswordSalt  nvarchar(128)   密码的Hash值
 MobilePIN  nvarchar(16)    手机PIN码
 Email  nvarchar(256)    电子邮件地址
 LoweredEmail  nvarchar(256)    小写的电子邮件地址
 PasswordQuestion  nvarchar(256)    遗忘密码问题
 PasswordAnswer  nvarchar(128)    遗忘密码答案
 IsApproved  bit    
 IsLockedOut  bit    是否锁住
 CreateDate  datetime    创建时间
 LastLoginDate  datetime    最后登录时间
 LastPasswordChangedDate  datetime    最后密码更改时间
 LastLockoutDate  datetime    最后一次锁帐号的时间
 FailedPasswordAttemptCount  int    密码失败尝试次数
 FailedPasswordAttemptWindowStart  datetime    密码失败尝试窗口打开时间
 FailedPasswordAnswerAttemptCount  int    遗失密码问题尝试次数
 FailedPasswordAnswerAttemptWindowStart  datetime    遗失密码问题输入窗口打开时间
 Comment  ntext    备注

表名:aspnet_Roles
说明:角色表

 字段名  类型  属性  说明
ApplicationId  uniqueidentifier  FK: appnet_Applications.ApplciationId 应用程序Id
 RoleId  uniqueidentifier  PK  角色Id
 RoleName  nvarchar(256)    角色名称
 LoweredRoleName  nvarchar(256)    小的角色名称
 Description  nvarchar(256)  nullable  描述

表名:aspnet_UsersInRoles
说明:用户角色关系表

 字段名  类型 属性 说明
 UserID  uniqueidentifier  FK: aspnet_Users.UserId 用户ID 
 RoleID  uniqueidentifier  FK: aspnet_Roles.RoleId  角色ID

表名:aspnet_Profile
说明:Profile对象存储表

字段名 类型  属性  说明 
 UserId  uniqueidentifier  FK: aspnet_Users.UserId  用户ID
 PropertyNames  ntext    属性名称
 PropertyValuesString  ntext    字符串值
 PropertyValuesBinary  image    二进制值
LastUpdatedDate  datetime   最后更新日期 

posted @ 2006-05-19 15:28 Tony Qu 阅读(768) | 评论 (2)编辑 收藏

2006年5月9日

原文地址:http://www.flipcode.com/articles/scripting_issue04.shtml
作者:Jan Niestadt
译者:Tony Qu

介绍

既然我们在上两部分中做了一些有益的事,我们就需要把我们从程序的数据结构中收集的数据保存起来,这就是我们接下来要做的事情,其中有两个相当重要的东西:符号表和文法树

符号表,有点像命名建议,它是一张包含了所有我们的程序中需要用到的符号的表,在我们的案例中,也包括所有的字符串变量和常量字符串。如果你有语言包括函数和类,那么它们也将在符号表中出现。

文法树是我们的程序结构的一种树形的表示形式,看看下面的图。在下一部分中,我们将用这个表示形式来生成中间代码,虽然并没有强制规定一定要生成文法树(因为我们已经从解析器那里获得了所有的程序结构信息),我觉得这使得编译器更加透明,这也是我写这篇文章的原因。

这将是第一个拥有“真正”代码的部分,在你看到它之前,我想澄清一点这些代码是为了更好的理解而写的,但可能结构方面不是很好,它将满足我们正在制作的编译器的需要,但真实的编译器远远不止这些。我会在遇到实际问题时,提到一些真实编译器的东西。

在规则间传递信息

很明显,我们不得不向解析器添加功能——当我们找到一个符号时,我们把它添加到符号表中,但是我们也需要“家长”规则来了解符号的描述信息(家长规则是指真正使用唯一标识符的规则)。

当我们构建一棵文法树的时候,一些相似的东西是必须的。我们需要家长规则拥有一个指向孩子规则结点的指针(孩子规则是由家长规则构建而成的)

还记得yylval集吗?Yacc也使用这个集合在规则间传递信息。在yylval集中,每个规则会有一个相关联字段,那是规则的类型。在string.y代码的最上面,你可以看到下面的类型声明

%type <symbol> identifier string
%type <tnode>  statement expression

symbol和tnode是这个集

抱歉!评论已关闭.