ASP/JScript将字典对象(Scripting.Dictionary)存储到Application

!本文可能 超过1年没有更新,今后内容也许不会被维护或者支持,部分内容可能具有时效性,涉及技术细节或者软件使用方面,本人不保证相应的兼容和可操作性。

最近要改进一个旧项目,项目采用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也不知道这个是什么类型。

最后我放出在这次项目中用到的部分封装代码供大家参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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做项目了,哎,廉颇老矣尚能饭否啊。

参考文档

若无特别说明,本网站文章均为原创,原则上这些文章不允许转载,但是如果阁下是出于研究学习目的可以转载到阁下的个人博客或者主页,转载遵循创作共同性“署名-非商业性使用-相同方式共享”原则,请转载时注明作者出处谢绝商业性、非署名、采集站、垃圾站或者纯粹为了流量的转载。谢谢合作!
请稍后...

发表评论

电子邮件地址不会被公开。 必填项已用*标注