通过global.asax,Web应用程序能够处理某些由ASP.NET运行库或已注册的HTTP模块引发的应用程序级事件。为使该文件中的内容生效,global.asax文件必须置于应用程序的根目录下。

global.asax的编译

  如果定义了global.asax文件,那么在应用程序启动时,该文件会被解析为源类,并会被编译。下面是ASP.NET根据global.asax文件生成的C#代码:

namespace ASP
{
public class global_asax : System.Web.HttpApplication
{
......
}
}

  该类称为ASP.global_asax,派生自HttpApplication类。大多数情况下,我们会以单独的文本文件形式来部署global.asax。我们还可以编写一个类,将其编译在单独的程序集中或编译到项目的程序集中。该类的源代码必须遵循上述代码的总体结构,最重要的是要派生自HttpApplication。带有global.asax编译版本的程序集必须部署在应用程序的Bin目录下。

  应注意,如果将global.asax文件的逻辑集中在预编译的程序集中,我们仍需要一个没有程序代码的global.asax文件来引用该程序集,如下所示:

<%@ Application Inherits="Core35.Global" %>

  有了预编译的全局应用程序文件,我们便可以在某种程度上避免将源代码通过Web暴露给恶意攻击者,从而降低了风险。

  事实上,系统对global.asax文件的默认配置,使得直接通过URL对它的请求,都会自动被IIS拒之门外。下面的代码(摘自machine.config文件)能够启用该行为:

<add verb="*" path="*.asax" type="System.Web.HttpForbiddenHandler" />

  为处理.asax资源,ASP.NET会向IIS注册,但那些直接的请求会通过HTTP处理程序HttpForbiddenHandler来处理。这样,当浏览器请求.asax资源时,返回的页面会显示一条错误消息。

  我们可以在应用程序的web.config文件中添加类似的代码,阻止特定应用程序中其他类型的资源。为使这个行为生效,应确保IIS会将该类型的请求重定向给ASP.NET。换言之,我们应在IIS元库中让aspnet_isapi.dll类处理那些文件,然后使ASP.NET阻隔相应的请求。

  若运行中的应用程序的global.asax文件被更改,ASP.NET会检查到,之后准备关闭并重新启动该应用程序。待所有挂起的请求都处理完毕且引发Application_End事件后再执行。当浏览器的下一个请求到达时,ASP.NET会做某些准备,重新编译globa.asax文件,并引发Application_Start事件。

global.asax的语法

  global.asax文件的语法包括4个元素:应用程序指令、代码声明块、服务器端<object>标签、服务器端包括指令。

应用程序指令

  global.asax文件支持@Application、@Import和@Assembly三个应用程序指令。

  @Application指令支持Description、Language和Inherits几个属性。

代码声明块

  global.asax文件包含的指令由<script>标签包装。与页面一样,<script>标签必须有runat="server"属性,language指定主体部分的语言:

<script language="C#" runat="server">
...
</script>

  如果未指定language属性,ASP.NET默认使用VB语言。源代码也可以从外部文件加载,通过Src属性设置虚拟路径即可。该文件的位置由Server.MapPath方法进行解析。

<script language="C#" runat="server" src="somecode.aspx.cs" />

  这种情况下,<script>块内部声明的任何代码都会被忽略。

服务器端的<object>标签

  服务器端的<object>标签使我们能够通过声明式的语法来创建新的对象。由于引用类型的不同,所有<object>有三种形式:

<object id="..." runat="server" scope="..." class="..." />
<object id="..." runat="server" scope="..." progid="..." />
<object id="..." runat="server" scope="..." classid="..." />

  对于第一行代码,对象由类和包含它的程序集的名称来标识。后两个表明要创建的对象为COM对象,分别由程序标识符和128位的CLSID业标识。scope属性用于指定声明对象的作用范围,下表对该属性的有效值进行了说明:

服务器端的include指令

  #include指令用于将指定的文件内容插入到它的ASP.NET文件中。该指令必须位于HTML注释内,不以纯文本的形式输出:

<!-- #include file="filename" -->
<!-- #include virtual="filename" -->

  如果使用file属性,文件名必须是相对路径,且该文件必须位于当前目录或当前目录的子目录下。如果使用virtual属性,文件名必须为当前Web网站虚拟目录的完整虚拟路径。

静态属性

  在global.asax文件中定义的静态属性可以被应用程序中所有页面读/写:

<script language="C#" runat="server" >
public static int Counter=0;
</script>

  上述代码中的Counter变量在页面和会话中都可见。要想在页面中访问该属性,我们必须使用ASP.global_asax限定符,如下所示:

Response.Write(ASP.global_asax.Counter.ToString());

  我们可以通过global.asax文件来处理HTTP模块暴露的事件。HTTP模块暴露事件的处理程序必须遵循以下命名模式:ModuleName_EventName。要使用的模块名应定义在配置文件的<httpModules>区段中。

错误和异常跟踪

  在global.asax文件中编写Application_Error事件处理程序后,系统会在应用程序中出现未处理异常时调用它。

  示例代码:

<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Text" %>

<script language="C#" runat="server">
void Application_Error(object sender, EventArgs e)
{
//获取请求URL
string url = Request.Path;

Exception error
= Server.GetLastError();
    //生成日志信息
StringBuilder text
= new StringBuilder("Error occurred. ");
text.Append(error.ToString());
text.Append(
" at ");
text.Append(url);
    //写入日志

EventLog log
= new EventLog();
log.Source
= "Core35 Log";
log.WriteEntry(text.ToString(), EventLogEntryType.Error);
}
</script>
posted on 2011-04-23 15:31  辛勤的代码工  阅读(930)  评论(0编辑  收藏  举报