65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP 页面上的服务器端动态包含

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.67/5 (5投票s)

2003年10月28日

4分钟阅读

viewsIcon

92991

downloadIcon

690

用于 ASP 页面上服务器端动态包含的 COM 对象

引言

此组件旨在解决我在构建网站时遇到的一个问题。在构建网站的某个阶段,我意识到我有很多页面(不断增长),它们具有相同的格式,并且内容几乎相同,除了某些主要在 HTML 代码方面有所不同的部分。网站的规模越来越大,而只有少数页面部分不同。因此,我一直在寻找一种方法来尽可能减小网站的规模,同时又不会使其难以管理。

解决方案

基本概念是创建一个 asp 页面,该页面将包含页面的公共部分,并动态地包含我将提供的其他子页面。

我在 MSDN 上进行了一些搜索,并找到了神奇的服务器端 #include 语句,该语句允许在一个网页中包含另一个子页面。在第一次尝试中,我硬编码了文件名,并很高兴看到它工作了。但是,当我尝试使用变量或参数而不是硬编码文件名时,我只收到“HTTP 500 - 内部服务器错误”。

在多次尝试此技术失败后,另一种想法是采取相反的路径,并将所有子页面更改为 asp 页面,并再次使用服务器端包含来添加所有其他公共内容。我知道这会起作用,并且也会大大减小网站的规模,但会给我带来另一个大问题。首先是需要完成的工作太多,其次是会随着页面数量的增加而使网站的复杂性增加,从而使其更难以管理。如果我稍后想将子页面移动到不同的子目录中,并根据某些关键字对它们进行分类,则我将不得不编辑许多文件的链接。用户不会注意到更改,但困难的部分将在于我。

另一种想法是创建一个数据库,将子页面内容存储在其中,然后使用记录集来包含我想要的记录文本。创建数据库、添加一些示例页面并进行测试很容易。尽管这很成功,但更新页面内容很困难,并且维护网站以进行更改的效率很低。我必须获取记录数据,将其存储在文件中,进行任何更改,然后将内容存储回表中。如果子页面没有更改,那可能很好,但我想获得更灵活、更快、更轻松的东西。

因此,我决定实现类似于我自己的服务器端包含内容,并能够

  1. 拥有动态包含以保持网站的规模较小。
  2. 避免在子页面中复制公共部分。
  3. 将子页面保留在文本/html 文件中,以受益于现有的 Web 创作工具。
  4. 将所有链接仅保留在所需位置。
  5. 不需要数据库和/或数据库工具来查看/编辑页面内容。
  6. 使维护过程尽可能快且简单。
  7. 不需要学习任何新东西,只需在现有的 asp 页面中添加几行代码即可。

使用 COM 对象

要使用此 COM 对象,您必须将 dll 复制到 Web 服务器的某个位置(例如 C:\Inetpub),并使用 regsvr32 注册它(例如 regsvr32 C:\Inetpub\SSDI.dll)。

然后将目录 IIS Files 的文件复制到 Web 服务器上 Web 站点根目录下的目录中。现在,您可以通过在 Internet Explorer 地址栏中键入 https:///master.asp?file=subPageFilename 来进行测试。(subPageFilename 可以是 test1.htmltest2.html。如果未提供参数,它将默认为 test1.html)。

代码解释

asp 页面创建一个 SSDI.Util 的实例

<%
...
var x=Server.CreateObject("SSDI.Util");
%>

并调用 Include 成员函数。

<%=x.Include(Server.MapPath(szFile))%>

完整的 asp 页面代码

<%@language="javascript"%>
<HTML>
<%
var szFile = String(Request.QueryString("file"));
if ((szFile == "undefined") || (szFile == ""))
    szFile = "test1.html";
var x = Server.CreateObject("SSDI.Util");
%>
<BODY>
<P>We are about to include file: <%=szFile%></P>
<%=x.Include(Server.MapPath(szFile))%>
</BODY>
</HTML>

COM 对象本身是一个简单的 COM 对象,它导出一个简单的接口 IUtil,其中包含一个属性 Include。此属性的代码将打开文件,将其读入已分配的缓冲区,将缓冲区内容转换为 BSTR ,并将其返回以供脚本语言使用,从而释放该文件。

STDMETHODIMP CUtil::get_Include(BSTR filename, BSTR *pVal)
{
    CString szFilename = filename;
    DWORD cbRead = 0;

    //Open the file

    HANDLE hFile = ::CreateFile( szFilename, GENERIC_READ, 
        FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        pVal = NULL;
        return S_FALSE;
    }

    //Get file size and allocate enough buffer to read it.

    DWORD cbFile = ::GetFileSize( hFile, NULL );
    if ( cbFile == (DWORD) -1 )
    {
        CloseHandle( hFile );
        return S_FALSE;
    }

    char *pszFileContent = (char *)LocalAlloc( LPTR, cbFile + 1 );
    if ( !pszFileContent )
    {
        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
        CloseHandle( hFile );
        return S_FALSE;
    }

    if ( !::ReadFile( hFile, pszFileContent, cbFile, &cbRead, NULL ))
    {
        CloseHandle( hFile );
        LocalFree( pszFileContent );
        return S_FALSE;
    }

    pszFileContent[cbRead] = '\0';

    //Convert buffer data to BSTR and return it for script use

    CString szFileContents = pszFileContent;
    *pVal = szFileContents.AllocSysString();

    CloseHandle( hFile );
    LocalFree( pszFileContent );

    return S_OK;
}

重新构建演示

此演示使用 (WTL 7.0) CString 来处理字符串。可以从 Microsoft 网站 下载 WTL 7.0。

© . All rights reserved.