在一些項目中,通常需要采用C/S&B/S的混合架構來實現,這樣就涉及到了Web開發,在MS的.Net沒有出現之前,因為是運行於windows環境之上,理所當然的首選ASP來實現了,直到有一天,蓋茨扛出了.Net大旗,振臂高呼:用灑家的.Net吧,安全快捷無副作用,一個字"牛B"!
ASP經過這麼多年的敲敲打打,一些自身難以克服的缺陷也漸漸浮出水面,此時聽了他的話,興奮地一陣小跑馬上就.Net了,但幾個閃著.Net金色光環的項目出手以後,結果並不盡如人意,於是暫時性的倒退回ASP了,呵呵,可能是境界不夠高的緣故吧,sigh……
因為腳本屬於基於對象的解釋型語言,它的執行依賴於宿主,這就不可避免的存在一些固有的不足,如執行效率偏低,模塊組織起來也沒有C++項目來得得心應手,特別是腳本和HTML混雜的時候,很難有勇氣再回頭看第二遍。在這樣的情況下,把服務端代碼部分組件化倒是可以解決部分問題,這樣WEB頁面的代碼除了幾句機械的組件調用,剩下的全是DW生成的HTML了,頁面編碼部分我們的美工師都能輕松搞定。
另外不得不承認VB在實現ASP組件方面具有某些優勢,現在網絡上流行的一些Web組件很多就是用VB來實現的。因為它實現起來簡單,跟VBScript又有一些形式上的相通之處。在對腳本代碼組件化時可以很容易的引用ASP的內置對象。那麼用VC呢?其實只要你對COM不算陌生,用起來也一樣簡單,而且你看了下面的實現後,也許會覺得不是一般的簡單,因為它本身就是一個COM組件,跟我們使用其它組件沒有什麼不同,呵呵,來試試看。
1、新建一個名稱為ASPCOM的"ATL項目"。
2、設置項目選項。
服務器類型:我們要在ASP中調用,選擇DLL類型;
屬性化:為了更清楚地看到實現代碼,我們在這裡暫時謝絕MS的好意,謝謝啦,不過這是一個賊有前途的東東,當然,只是對於構建MS的COM來說;
合並Stub:我們這裡可以把客戶端的代理/存根實現合並到服務端;
支持MFC:這個,這個 …… 免了吧,呵呵;
支持COM+:我們這裡用不到啦;
3、添加支持ASP內建對象的組件接口類。
i、選擇"ATL Active Server Page 組件",添加一個名為MyTest的接口,同樣,我們這裡不使用"屬性化";
ii、"選項"選項卡內的各個選項采用默認值即可,因為我們剛才選擇的是"ASP組件",所以這裡沒有列出雙重接口或自動化的選項。封裝的腳本組件,你不在腳本裡用還會在哪裡用呢?呵呵;
iii、轉到"ASP"選項卡,在這裡我們可以看到ASP的五大內置對象(也可以說是六個,有時會把ObjectContext也算上,當然這些說法都不嚴格),不必客氣啦,統統選上,即使我們這個DEMO中沒有全部用到,嘿嘿。另外OnStartPage和OnEndPage分別在腳本開始使用和結束使用本對象時調用,這給了我們獲取ASP對象接口和釋放的機會,這個跟VB組件的實現是完全一致的;
4、好了,現在我們在類視圖和實現文件裡可以看到WIZARD兄已經幫我們搞定了所有的接口獲取和釋放工作,我們直接使用就可以了,真是一位好同志呀;
5、現在我們在MyTest接口裡分別用Request和Response對象實現一個巨簡單的方法,實際上現在ASP的五大法寶都交給你了,你要怎麼用就看你自己的啦。
TestASPComp方法用來從一個Post到服務端的Form裡獲取元素的值,隨後把剛才獲取的值顯示出來。具體實現如下:
STDMETHODIMP CMyTest::TestASPComp(void)
{
//declare a IRequestDictionary interface pointer
CComPtr<IRequestDictionary> pDict = NULL;
HRESULT hr = S_OK;
_bstr_t str;
try
{
//use the get_Form method of the Reqeust object to access the Form collection
hr = m_piRequest->get_Form(&pDict);
if (FAILED(hr))
return hr;
//get the specified field value
hr = GetDictItemValue(pDict, L"Name", str);
if (FAILED(hr))
_com_issue_errorex(hr, pDict, __uuidof(IRequestDictionary));
//write out the field name and its value
m_piResponse->Write(_variant_t(L"Name="));
m_piResponse->Write(_variant_t(str));
//ditto
hr = GetDictItemValue(pDict, L"Message", str);
if (FAILED(hr))
_com_issue_errorex(hr, pDict, __uuidof(IRequestDictionary));
m_piResponse->Write(_variant_t(L"<br>\nMessage="));
m_piResponse->Write(_variant_t(str));
}
catch (_com_error e)
{
return e.Error();
}
return S_OK;
}
6、簡單測試一下咱們的組件
打開記事本,敲入下面的腳本代碼,分別保存為form.htm和show.asp兩個文件,然後,然後……當然是放到服務器上測試一把了 :-) < form.htm >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>windstep.com</title>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<form name="form" method="post" action="show.asp"><tr>
<td width="100" height="30">Name:</td>
<td width="200">
<input name="Name" type="text" id="Name">
</td>
</tr>
<tr>
<td height="30">Message:</td>
<td><input name="Message" type="text" id="Message"></td>
</tr>
<tr>
<td height="36"> </td>
<td><input type="submit" name="Submit" value="Submit"></td>
</tr></form>
</table>
</body>
</html>
< show.asp >
<%@LANGUAGE="JSCRIPT" CODEPAGE="65001"%>
<%
function TestComponent()
{
try
{
var obj = new ActiveXObject ("ASPCOM.MyTest");
obj.TestASPComp();
delete obj;
}
catch(e)
{
Response.Write("Error " + (e.Number & 0xFFFF));
Response.Write(" - " + e.Description);
}
}
%><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>windstep.com</title>
</head>
<body>
<%
TestComponent();
%>
</body>
</html>
下面分別是兩個頁面的執行結果:
< form.htm >
< show.asp >
OK,就是這個樣子了,其它對象的使用都跟在腳本裡差不多,你可以簡單試一下。本DEMO在Windows 2003 Server(website)+ VC.Net 2003 + IIS 6.0 環境下測試通過。
本文配套源碼