应用程序状态允许保存被所有客户访问的全局对象。应用程序状态基于 System.Web.HttpApplicationState 类,该类在 Web 页面中通过内建的 Application 对象提供。
例如,可以创建一个 global.asax 事件处理程序来跟踪有多少会话被创建了,也可以使用相同的逻辑追踪某一页面的访问次数:
protected void Page_Load(object sender, EventArgs e)
{
int count = 0;
if (Application["HitCounterForOrderPage"] != null)
{
count = (int)Application["HitCounterForOrderPage"];
count++;
Application["HitCounterForOrderPage"] = count;
}
}
应用程序状态用对象类型保存状态项,所有集合中取值需要转换类型。应用程序状态中项目从不过期,一直被保存到应用程序或服务器重启。
应用程序状态不太经常使用,因为效率不高。在上一个例子中,计数器的数字不精确,大量用户同时访问时,会丢失计数。为了避免这个情况的出现,可以使用 Lock()和 UnLock()方法,它们禁止用户同时访问 Application 集合:
protected void Page_Load(object sender, EventArgs e)
{
Application.Lock();
int count = 0;
if (Application["HitCounterForOrderPage"] != null)
{
count = (int)Application["HitCounterForOrderPage"];
count++;
Application["HitCounterForOrderPage"] = count;
}
Application.UnLock();
}
遗憾的是,所有请求该页面的用户都将被暂停直到 Application 集合被释放。这会大大的降低性能。一般而言,经常改变的值不适合放到应用程序状态中。
事实上,ASP.NET 中极少使用应用程序状态,因为它的两个最常用的功能已经被更简单,更有效的方法替代了:
- 以前,人们使用应用程序状态来保存应用程序级别的常量,如数据库连接字符串。现在这类常量可以保存在web.config中,它通常更为灵活,因为它易于修改而不需要更改代码或重新编译应用程序。
- 应用程序状态还可以用来保存常用但创建较费时的信息,比如进行数据库查询全部产品目录。但现在更相似,明智的做法是在 ASP.NET 的缓存中保存常用的信息。应用程序状态的很多应用可以使用缓存有效替换。
静态应用程序变量
还可以在 global.asax 文件中添加静态成员变量:
public static string[] FileList;
这能够起作用的关键在于变量时静态的。因为 ASP.NET 创建 HttpApplication 类的连接池来服务多个请求。这样,每次请求都可能由不同的 HttpApplication 对象来服务,每个 HttpApplication 对象都有自己的实例数据,然而,静态数据的副本只有一份。
仍然存在多个页面会调用这个静态变量的可能性,但是由于不是 Application 对象因此没有了自动锁,所以应该使用 C# 的锁语句来临时将变量限定于某个单独的线程里。
private static Dictionary<string, string> metadata = new Dictionary<string, string>();
public void AddMetadata(string key, string value)
{
lock (metadata)
{
metadata[key] = value;
}
}
public string GetMetadata(string key)
{
lock (metadata)
{
return metadata[key];
}
}
使用静态成员变量而不使用 Application 集合有两大优势。
- 首先,在值被访问或修改时(通过在属性过程或者方法中绑定数据),它允许你编写可自动运行的编码。可以使用这段代码记录某个值被访问了多少次,可以检查数据是否依然有效,或者是否需要重新创建。这个示例使用延迟初始化模式,且仅在第一次请求时创建全局对象:
private static string[] fileList;
public static string[] FileList
{
get
{
if (fileList == null)
{
fileList = Directory.GetFiles(HttpContext.Current.Request.PhysicalApplicationPath);
}
return fileList;
}
}
// 这个示例使用文件访问类来读取 Web 应用程序的文件列表
// 这个功能不可能通过 Application 集合实现
- 使用静态成员变量的另一个好处是类型安全,从 Global 类中取得的变量类型不需要转换。