Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Server Side Dynamic Includes on ASP pages

0.00/5 (No votes)
27 Oct 2003 1  
COM Object for Server Side Dynamic Includes on ASP pages

Introduction

This component is trying to solve a problem I faced while I was building a web site. At some stage of the web site building I realized I had many pages (continually growing) with the same format and almost same content except some parts that differed mainly in html code. The web site size was getting bigger and bigger while only few parts of the pages where different. So I looked for a way to keep the web site size as small as possible, while not making it hard to manage.

The solution

The basic concept was creating an asp page that would hold the common parts of the pages and dynamically include some other sub-page I would provide.

I did some search on MSDN and I came to the magic server side #include statement that allows to include another sub-page in a web page. On a first attempt I hardcoded the filename and was happy to see it working. But when I tried to use a variable or a parameter instead of hardcoding the filename I only received an "HTTP 500 - Internal server error".

After many failed attempts on this technique another thought was to take the reverse path and change all the sub-pages to asp pages and use again the server side includes to add all the other common content. I knew this would work, and would also decrease the web site size a lot but would create another big problem to me. First would be too much work to be done, and second would keep the complexity of the site increasing as the pages number increased, making it harder to manage. If I wanted later to move the sub-pages to different subdirectories one level down categorizing them based on some keywords, I would have to edit links to many files. The user wouldn't notice changes but the hard part would be on me.

Another thought was to create a database, store the sub-page contents in it, and then use a recordset to include the record text I wanted. It was easy to create the database, add some sample pages, and test it. Althought it was successfull, updating the page contents was hard and maintaining the site to changes was inefficient. I had to take the record data, store it in a file, make any changes, and store the content back to the table. It could be good it the sub-pages where not not changing but I wanted something more flexible, quicker and easy.

So I decided to implement something similar to server side includes on my own and be able to:

  1. Have dynamic includes to keep the web site size small.
  2. Avoid copying of the common parts in the sub pages.
  3. Keep the sub pages in text/html files to benefit of the existing web authoring tools.
  4. Keep all the links to only as few places as needed.
  5. Not require database and/or database tools to view/edit the page contents.
  6. Keep the maintaining process as fast and simple as possible.
  7. Not require learning anything new but just add a few lines to existing asp pages.

Using the COM objects

To use this COM object you have to copy somewhere in the web server the dll (e.g. C:\Inetpub) and register it using regsvr32 (e.g. regsvr32 C:\Inetpub\SSDI.dll).

Then copy the files of the directory IIS Files under your web site root on your web server. Now you are ready to test by typing http://localhost/master.asp?file=subPageFilename on internet explorer address bar. (subPageFilename can be test1.html or test2.html. If no parameter provided it will default to test1.html).

Code Explanation

The asp page creates an instance of SSDI.Util

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

and calls the Include member function.

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

full asp page code:

<%@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>

The COM object it self is a simple COM object exporting one simple interface IUtil with one property Include. The code for this property will opens the file, reads it into an allocated buffer, convert the buffer contents to BSTR and return it for use from scripting languages freeing the file.

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;
}

Rebuilding the demo

This demo uses (WTL 7.0) CString to handle strings. WTL 7.0 is available to download from microsoft web site.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here