ASP/JScript将字典对象(Scripting.Dictionary)存储到Application
提醒:本页面将不再更新、维护或者支持,文章、评论所叙述内容存在时效性,涉及技术细节或者软件使用方面不保证能够完全有效可操作,请谨慎参考!
最近要改进一个旧项目,项目采用ASP(JScript)编写,由于时间问题一直没有重构,所以还是ASP将就着,考虑到效率问题,准备把部分内容缓存起来,当然直接读写Application缓存不是很妥当的,遂采取缓存字典对象( Scripting.Dictionary )来实现。好了,一般会认为代码如下所示:
var key = "dict_cache"
var obj = Server.CreateObject("Scripting.Dictionary");
Application.Lock();
Application.Contents(key) = obj;
Application.Unlock();
偏偏事与愿违,如果你这样做的话,IIS会报“ 不允许的对象使用方式 ”错误,具体内容如下:
Application 对象 错误 'ASP 0197 : 80004005' 不允许的对象使用方式 /index.asp,行 12 不能将具有单元模型行为的对象添加到应用程序的内部对象中。
同样的让我们回到VBScript,编写ASP/VBScript脚本代码如下:
Dim key
key = "dict_cache"
Application.Lock
Set Application(key) = _
Server.CreateObject("Scripting.Dictionary")
Application.Unlock
错误依旧,也就是说我们不能将形如Scripting.Dictionary的对象存储到Application中,这是多么沮丧啊,真的没有办法吗?
下面我给出两个解决办法供大家参考。
1. 使用Application.StaticObjects
其实我们可以变通一下,我们可以将字典对象存储到Application.StaticObjects中,当然这个有点小麻烦,我们需要创建Global.asa文件,内容如下:
<object runat="server" scope="application" id="dict_cache"
progid="Scripting.Dictionary"></object>
注意这里的id所指示的值
dict_cache
,然后我们就可以这样操作了:
Dim key
key = "dict_cache"
Application.Lock
Set Application.StaticObjects(key) = _
Server.CreateObject("Scripting.Dictionary")
Application.Unlock
我在 《ASP/WScript/VBScript实现ActiveX COM对象管理器(2)》 的实现中也简单介绍过这个办法。
2. 使用VBScript数组
肯定有同学不希望使用 Global.asa 文件,那这里还有个办法可以变通一下,那就是VBScript数组,等等,我为什么强调VBScript数组,难道JScript数组不可以吗?别急,答案即将揭晓。
在ASP/VBScript使用数组解决问题的实现代码如下,简单的说就是将对象用Array包装一下:
Dim key
key = "dict_cache"
Application.Lock
Application(key) = _
Array(Server.CreateObject("Scripting.Dictionary"))
Application.Unlock
看样子我们已经成功将字典对象存入Application缓存中了,不过大家在读取时要注意一点,那就是读取要取数组内容,加个下标0,VBScript代码如下:
Application("dict_cache")(0).Add "test", "Hello World!"
Response.Write Application("dict_cache")(0).Item("test")
接下来我来说明为什么JScript数组不可以,因为Application不可以存储对象,而JScript与VBScript不同的是:JScript中一切皆为对象,包括其数组Array,VBScript的数组不是对象(至少没有对象应该有的方法)。所以对于JScript我们不能采用这个技巧。
深入了解过JScript的同学一定知道有个VBArray(),呵呵,这个只是微软为了兼容VBScript而提供的一个访问VB数组的方法,说白了这玩意儿只能读取创建好的VB数组,而不能自己创建一个VB数组。
解决的办法到这儿变得清晰起来,也就是说我们要想方设法的建立一个VB数组,当然这事儿还得VB/VBScript来做,我们可以使用
MSScriptControl.ScriptControl
组件在JScript调用VBScript创建这个特殊的数组:
var dict = Server.CreateObject("Scripting.Dictionary");
var msscript = Server.CreateObject("MSScriptControl.ScriptControl");
msscript.Language = "VBScript";
msscript.AllowUI = false;
msscript.AddObject("SafeVBArrayValue", dict);
var key = "dict_cache"
var obj = Server.CreateObject("Scripting.Dictionary");
Application.Lock();
Application.Contents(key) = msscript.Eval("Array(SafeVBArrayValue)");
Application.Unlock();
测试无误,说明这个方法是可行的,typeof这个VB数组,显示类型为
Unknown
,看来JScript也不知道这个是什么类型。
最后我放出在这次项目中用到的部分封装代码供大家参考:
var RawCache = function() {
this.setItem = function(key, value) {
Application.Lock();
Application.Contents(key) = value;
Application.Unlock();
}
this.getItem = function(key, defvalue) {
value = Application.Contents(key);
return typeof(value) != 'undefined' ? value : defvalue;
}
this.remove = function(key) {
Application.Lock();
Application.Contents.Remove(key);
Application.Unlock();
}
this.isAvailable = function() {
return true;
}
}
var TinyCache = function(name, useStaticObjects) {
if (useStaticObjects) {
this.cache = Application.StaticObjects(name);
}
if (!this.cache) {
this.raw_cache = new RawCache();
this.cache = this.raw_cache.getItem(name, null);
if (this.cache != null) {
this.cache = this.cache.getItem(0);
}
if (!this.cache || typeof this.cache != "object") {
this.mem = Server.CreateObject("Scripting.Dictionary");
var msscript = Server.CreateObject("MSScriptControl.ScriptControl");
msscript.Language = "VBScript";
msscript.AllowUI = false;
msscript.AddObject("SafeVBArrayValue", this.mem);
this.raw_cache.setItem(name, msscript.Eval("Array(SafeVBArrayValue)"));
this.cache = this.raw_cache.getItem(name, null).getItem(0);
}
}
this.setItem = function(key, value) {
if (this.cache.Exists(key)) {
var prevalue = this.cache.Item(key);
this.cache.Item(key) = value;
return prevalue;
} else {
this.cache.Add(key, value);
return null;
}
}
this.getItem = function(key, defvalue) {
if (this.cache.Exists(key)) {
return this.cache.Item(key);
} else {
return defvalue;
}
}
this.remove = function(key) {
if (this.cache.Exists(key)) {
this.cache.Remove(key);
}
}
this.contains = function(key) {
return this.cache.Exists(key);
}
this.isAvailable = function() {
return true;
}
}
使用的方法很简单,比如这样:
var cache = new TinyCache('dict_cache');
Response.Write(cache.setItem("Key1", "Value1"));
Response.Write(cache.getItem("Key1", "N/A"));
cache.remove("Key1");
Response.Write(cache.getItem("Key1", "N/A"));
好了,到这里就介绍结束了,当然ASP确实有些老旧了,如果不是这次项目修改,我也很长时间没有用ASP做项目了,哎,廉颇老矣尚能饭否啊。
参考文档