下載本文代碼 下載本期雜誌代碼 見資源 |
By Alan Gordon
使用VS.NET引進的技術,你能夠比以前更容易地建立一個電子商務網站。使用VS.NET和.NET Framework SDK你可以用很少的代碼去建立一個完善的Web應用程序,這些代碼比起大多數ASP應用程序中使用的一大堆混亂的腳本和HTML代碼,它更靈活,更易維護。
|
書店展示了現有的一些圖書和不久將出版的一些圖書,這些圖書是關於.NET或者與.NET相關的,比如XML、COM+、SQL Server和BizTalk Server。事實上,我發現在“今日專刊”上擺放的圖書對開發這個程序也是很有用的(見圖2)。.NET Books應用程序也可以在SQL7.0上運行。它沒有使用任何SQL Server 2000的特性。
|
BizTalk Orchestration是微軟BizTalk Server 2000產品的子集。它是一套用來建模、實施和完成複雜的商業過程的工具。BizTalk Orchestration是由 基於Visio 2000的設計工具,基於XML描述商業過程的被稱之爲XLANG的語言和執行XLANG商業過程的引擎組成。
|
當用戶訪問.NET Books時,他或她可以根據一些識別信息比如標題或者作者去搜索一本書(見圖3)。搜索結果返回符合條件圖書的目錄,當用戶點擊到標題上時,我們將連到關於這本書的更詳細資料的頁面上去。如果用戶決定購買這本書,點擊“加入購物車”把這本書加入到購物車,然後我們就到了購物車頁面(見圖4)。在這兒,用戶可以看到當前所選的圖書,可以編輯圖書的數量,可以把數量設置爲0以刪除圖書。當用戶已經做出決定,他或她選擇提交連接,當用戶還沒有登陸時,這個連接提示用戶登陸。當用戶已經登陸進去,他或她會被帶到一個三步定購嚮導,在這裏輸入郵購地址和信用卡信息。第三步說明用戶已經完成了訂單,當用戶點擊這個頁面上的確認按鈕,訂單被提交併開始處理。
當顧客提交了訂單開始處理時,應用程序更新了這個訂單的數據庫信息,同時,向消息列表發送一個描述此訂單的的XML文檔。在分佈式處理的過程中,這兩個動作都被執行。如果任何一項操作失敗,處理將會被退回,換句話說,如果XML文檔沒有被送到信息隊列中去的話,數據庫將不會更新,反之亦然。
建立搜索
|
http://localhost/DotNetBooks/Default.aspx?SearchType=Title&SearchData;=C# |
搜索控件會出現在網站的大多數頁面上,它被當作一個Web user controls來使用。Web user control是ASP.NET Web From代碼的小片段。它被包裝起來可以很容易的被其他頁面重新使用。在項目菜單中選擇增加Web User Control可以在項目中增加Web User Control。這樣在VS.NET中將有一個表單,你可以象編輯其它Web Form一樣來編輯這個表單。然後,VS.NET把這個表單存成擴展名爲ASCX的文件。把Web User Control拖放到客戶端的Web Form中使用它,這樣,VS.NET就會加代碼到客戶端Web Form的頂部,並在客戶端Web Form中註冊Web User Control。
<%@ Register TagPrefix="DotNetBooks" TagName="Search" Src="SearchControl.ascx" %> |
VS.NET也在客戶端Web Form中下面的地方增加標識Web user control的標籤如下:<?XML:NAMESPACE PREFIX = DotNetBooks />
DataList、DataGrid和Reapeater控件是Web Forms工具庫中功能最強大的控件。在你列出內容的每個地方都可以用DataList來顯示,包括在搜索控件中的目錄列表,和執行搜索後得到的圖書列表。購物車頁面使用DataGrid控件。你可以在各種不同的地方使用DataList控件,但是能夠最強有力地和靈活地使用它的地方還是數據綁定。使用數據綁定最強有力的和靈活的地方是在項目模板中。
項目模板允許你定義一小段HTML代碼來顯示數據源中的每行數據(見列表2)。比如,列表2中的代碼表示了用來展示執行搜索得到圖書列表的項目模板。這個模板定義了HTML表。表中包含一個圖象和兩行超鏈接文字。DataBinder.Eval方法用來把數據源得到的數據顯示在模板上。例如,下面的代碼(從列表2中摘錄)展示瞭如何把每本書的圖片綁定到項目模板的圖片控件上。
<?xml:namespace prefix = asp /> |
《ASP+預覽》的第三章有關於DataList, DataGrid, 和 Repeater控件的詳細討論。
設計購物車
幾乎所有的電子商務網站都有一個購物車,當客戶在網站上瀏覽時,這就說明如果想購買的話他們可以把商品加入到購物車中。顧客也可以修改購物車中商品的數量或者刪除他們。如果你用ASP建立應用程序,有兩種方法可以實現購物車功能:一是把商品信息存儲到Session對象中,二是把商品信息存儲到數據庫中去,僅在Session對象中有一個索引。把購物車存儲在Session中很容易也會很快,當然我們假設你的代碼沒有問題。不幸的是,在ASP中Session對象被當作儲存的數據結構執行,這些結構放在IIS的進程中。這就會引起兩個主要問題:首先當IIS進程失敗或者關閉時,所有的Session對象就會丟失;再者,在服務器上運行網站會變得更復雜,這是因爲Session被綁定在產生Session的機器的IIS進程中。爲了在網頁中使用Session,你必須能夠保證客戶端總是返回到同一個服務器,否則客戶端的Session就會丟失。
ASP.NET解決了這些問題。現在,你有三個選擇來存儲Session.首先,在默認情況下你可以放在當前主機上的網絡服務的進程中,這點和ASP一樣。第二,Session可以存儲在網絡服務的一個獨立的進程中,這個網絡服務是在你的服務器羣的機器上。你的服務器羣的其他機器也可以訪問這個進程。最後,你可以存儲在SQL Server中。你可以使用你的網絡程序中的配置文件(Config.web)來選擇你的Session信息存儲在什麼地方。你向Session中寫信息或者從Session中讀信息,將不會根據你選擇哪兒存儲Session對象而改變。下面的代碼展示了.NET Books中的網頁如何去Session對象中取回購物車。
public Cart GetShoppingCart() { // Try to get the cart from Session Cart shoppingCart =(Cart)(Session["ShoppingCart"]); if (null == shoppingCart) { // If there is no cart, create it now shoppingCart = new Cart(); // Save the cart for later use Session.Add("ShoppingCart",shoppingCart); } return shoppingCart; } |
這個邏輯對於使用ASP的人是非常熟悉的。Rob Howard寫了一篇關於ASP.NET session state的精彩的文章(見資源)。同樣,你也可以看.NET Framework開發者嚮導中被稱爲“Session State”的文章。
對於這個應用程序,我建立了一個類叫Cart,它提供很方便的方法來更改購物車中商品的數量、把購物車發送到服務器(申請訂單)、和在訂單發送後清空購物車(見表1)。購物車的數據是按照嚴格的數據類型來儲存的,這個類型是從我所建立的一個XML Schema (XSD)文件中得來的。
爲了從XSD schema文件中生成一個嚴格的數據類型,首先,你必須把XSD文件增加到VS.NET項目中。當你雙擊這個文件,VS.NET在一個可視化的編輯器中顯示這個XML schema文件(見圖5)。右擊XML schema編輯器選擇Generate DataSet來建立一個嚴格的數據類型來匹配schema。你可以用處理從數據庫的來的數據的方法來處理這個數據。當你的數據集中使用Xml或者XmlData屬性時,它建立一個XML 文檔,這個XML文檔使用數據集產生的那個XML schema。
這個功能包含了另外一點,即和BizTalk 2000的整合性。你可以選擇一個BizTalk schema或者在BizTalk編輯器中建立一個XML schema,在VS.NET中來讀,然後根據這個schema建立一個嚴格的數據類型的數據集。我打算使用這個方法,但是因爲BizTalk 2000 beta生成XDR schema, 所以沒有辦法實現。在.NET Framework中包含能夠把XDR schema轉化爲XSD schema的XML schema定義工具(見.NET Framework SDK中更多的關於xsd.exe的信息)。
我試圖使用這個方法,但卻不斷的陷入這個beta版的bugs中。最後,我放棄了這個想法,直接用VS.NET編輯器建立了一個簡單的XML schema。當用戶下了一個訂單後,應用程序把數據集送到Web Service,Web Service從數據集提取出定單信息,然後調用存儲過程向數據庫中插入數據。Web Service使用數據集中的XML屬性返回一個XML文檔,並把這個文檔送到微軟信息列表中去。
安全機制
商業應用 .NET降低了開發成本 通過使用VS.NET和.NET Framework提供的工具你可以靈活且高效的開發B2B或B2C應用程序。 你所要知道的是哪些工具可用,他們能做什麼,如何把他們結合起來使用來簡化從概念到開發的過程。 理解.NET不同功能之間的關係可以加強你項目管理的能力。 |
ASP.NET提供了所有的這些鑑定功能。你必須首先選擇一個可獲得的鑑定方法。你可以選擇:Windows, Passport, Forms(在beta 1中叫Cookie)和none。(關於選擇的更多信息見資源中“ASP.NET鑑定”)。在.NET Books程序中使用Forms。在你的應用程序的config.web文件中選擇ASP.NET鑑定方法。下面代碼展示如何選擇一個Forms鑑定。
在這個例子中,你確認了系統將會使用的cookie名(DOTNETBOOKSCOOKIE)和當用戶需要授權時被重新指向的地址(login.aspx)。一旦你選擇了鑑定方法,你可以在Config.web文件中用下面的方法限制訪問到特定頁面的用戶:
這兒你拒絕匿名訪問CheckOut1.aspx(訂單向導的第一頁)。因此,沒有登陸的用戶將會被自動指到login.aspx。在login.aspx裏,用戶可以輸入用戶名和密碼。然後login.aspx將會調用.NET Books Web Service中的登陸方法。如果用戶名和密碼在數據庫中存在,登陸方法返回一個成功代碼並連到CheckOut1.aspx,否則,將返回一個錯誤信息。
分離商業邏輯
.NET Books網站的商業邏輯作爲一個Web Service來實現。你能夠在DotNetBooksWebService (見表2,從.NET 雜誌網站下載代碼)C#網絡服務項目發現這個Web Service所有的代碼。把這個網站的商業邏輯分成網絡服務,這就使得在你的網站的其他部分重新使用這些商業邏輯變得更容易了。例如,建立一個圖書俱樂部的網站,其中使用我們的網絡服務來搜索和定購圖書。現在已經有好多文章介紹如何用.NET建立網絡服務(見資源中我的Visual C++開發期刊),所以我就不再介紹如何建立網絡服務的基本知識了了。然而,有關如何使用COM+服務的文章很少,比如分佈式處理和對象池(object pooling)(和.NET中的消息隊列),所以我將展示在你的網絡服務中如何用這些技術。
下面的代碼展示瞭如何把.NET類轉化成一個服務組件,黑體表示重要的部分。
using System.EnterpriseServices;;[Transaction(TransactionOption.Required)] public class Books :ServicedComponent { [WebMethod] [AutoComplete] public DataSet GetBooksByTitle(string title) { //… } } |
爲了建立一個服務組件,你首先要參考System.EnterpriseServices集合,使用“using”聲明來增加參考。接着,你要給服務組件增加一個特性來說明你想用哪個COM+服務。在System.EnterpriseServices名字空間的文檔中,你能發現現有的COM+相關特性的完全列表。在這個例子中,我使用事務處理特性,註明這個類要求事務處理。服務組件也必須繼承於一個稱爲ServicedComponent的類,這個類你也可以從System.EnterpriseServices名字空間中找到。Books類使用叫AutoComplete的COM+特性。這個特性當方法成功返回時調用SetComplete()自動完成商品交易,當方法拋出異常時調用SetAbort()。
當客戶端實例化了一個服務組件類,如果COM+應用程序不存在的話,Common Language Runtime(CLR)建立了一個COM+應用程序來運行這個類,然後增加服務組件和它的特性一起到COM+應用程序。你把下面代碼加入到你的集合文件(在VS.NET 項目的assemblyInfo.cs)中,這些代碼就可以控制COM+應用程序如何被建立,也可以影響在COM+應用程序中使用的應用層COM+特性:
[assembly: ApplicationName("DotNetBooksApp")] [assembly: ApplicationActivation(ActivationOption.Library)] [assembly: Description("A COM+ Application to test .NET Serviced Components")] |
這兒你詳細瞭解了DotNetBooksApp COM+應用程序,並且使用了類庫(過程中)激活。
如果你建立一個服務組件類同時它也是一個網絡服務的話,你需要注意下面三點:首先,這個類不能象大多數網絡服務那樣從WebService中繼承。你不能從WebService繼承是因爲C#只能從一個單獨的類繼承,而服務組件類必須從ServicedComponent基類繼承。如果你沒有從一個WebService基類繼承,你就不能訪問Session、Application、和Context對象,但是其它的網絡服務功能和期待的一樣都可以使用。第二點:如果你想使用服務組件來實現網絡服務,你必須在使用服務組件之前,把包含服務組件的集合代碼增加到公共集合緩衝Global Assembly Cache (GAC)中去。這個代碼可以使IIS能夠發現服務組件類。服務組件必須有一個引人注目的名字。你可以使用共享的命名工具(sn.exe)來起一個引人注目的名字,然後通過把下面代碼加到你的集合信息文件中來把這個名字加到集合中去。
[assembly: AssemblyKeyFile("filenameforkey")] |
第三點是VS.NET將不會在其設計器中顯示從服務組件繼承來的網絡服務。你將會看到一個錯誤提示:“基類System.EnterpriseServices.ServicedComponent不能被設計”。這個錯誤並不能阻止你看到網絡服務的代碼。如果你必須使用設計器的話,那你就把它存爲服務組件,直到你不再使用設計器爲止。
如果你想使用分佈處理,但卻不想建立一個服務組件的話,你也可以象概括表單所顯示的那樣設置在WebMethod特性中的TransactionOption屬性。
public class Books : WebService { [WebMethod(TransactionOption=TransactionOption.Required)] [AutoComplete] public DataSet GetBooksByTitle (string title) { //… } } |
使用這個方法,你可以使用能夠訪問Session、Application和Context對象的網絡服務基類。
記住,不管你通過服務組件還是通過網絡服務特性的TransactionOption屬性來做分佈處理,你都要協調涉及多個資源管理器的處理,這些資源管理器包括SQL Server 和 MSMQ,在我們例子中是一個單一的網絡服務。目前沒有機構可以協調包括多個網絡服務的處理。這個功能要求擴展到簡單對象訪問協議Simple Object Access Protocol (SOAP)上去。
你的網絡服務使用ADO.NET去從數據庫中讀數據和向數據庫中寫數據。網絡服務中大多數的方法是發送0個或者多個參數然後向客戶端返回一個數據集的搜索。爲了最大化的代碼再利用,我建立了一個叫做GetDataSetFromStoredProc的方法。這個方法中包括了調用儲存過程返回數據集(見列表3)的大多數ADO.NET邏輯。GetBooksByISBN方法建立了一個參數,給這個參數正確的類型和值,然後把這個參數和存儲過程的名稱一起傳遞到GetDataSetFromStoredProc方法中(見列表4)。
網絡服務中最複雜的方法是InsertOrder()方法,如果你從.NET 雜誌網站下載代碼的話你可以看到這個方法。當用戶確認下定單時,客戶端調用這個方法。這個方法執行了兩個主要功能:把訂單加入到數據庫,把XML文檔送到信息隊列。
爲了最大可能的實現和可擴展性,我建立了一個存儲過程,也叫InsertOrder,這個存儲過程使得我們一次調用就可以向數據庫中增加用戶和詳細信息。InsertOrder存儲過程接受顧客ID、通訊地址、信用卡信息,和訂單總數及包含訂單信息的限定的字段:
Item[1].ID,Item[1].Quantity, Item[1].UnitPrice/ Item[2].ID,Item[2].Quantity, Item[2].UnitPrice |
InsertOrder存儲過程解析字符串,並把訂單細節增加到數據庫的OrderItems表中。InsertOrder()方法把購物車信息當作輸入信息。這個方法從數據集中提取出顧客ID、通訊地址,和信用卡信息。然後把訂單細節信息轉化成顯示格式的字符串。然後把字符串和訂單參數傳給InsertOrder存儲過程。
當InsertOrder()方法把定單信息增加到數據庫之後,它把包含定單信息的XML文檔寫入消息隊列中去。網絡服務在發送消息之前檢查私有消息隊列“DevDotNet”是否存在。你必須在運行網絡服務的主機上建立這個隊列。
.NET框架包括許多消息轉換器,你可以用它們把.NET對象寫到消息隊列中去。在這個應用程序中,我們使用ActiveXMessageFormatter,這是因爲我們用這個轉換器發送到隊列中的消息是很容易在BizTalk Orchestration商業過程中使用的VB6 COM對象訪問的。
使用BizTalk Orchestration
我決定使用BizTalk Orchestration來執行支付授權商業過程。這個商業過程使用一個隨機數生成器來批准一些訂單和拒絕其它訂單。它然後更新訂單的狀況以顯示其是否成功交易。你必須擁有BizTalk 2000 Server的最終版本來使用支付授權商業過程,但是如果你沒有,.NET Books應用程序的其它部分將仍然繼續工作。
|
爲了運行商業過程,確信你建立了DevDotNet消息隊列,然後在網站上建立一對訂單。.NET Books網絡服務中的InsertOrder方法向消息隊列發送訂單。從Start/Programs/Administrative Tools/打開計算機管理瀏覽器,驗證訂單存在在DevDotNet消息隊列中。記下隊列中的訂單編號。
現在我們進入這篇文章代碼中BizTalk子目錄下面的RunSchedule目錄。運行ExecuteOrderProcess.exe文件。下載訂購過程XLANG文件(orderprocess.skx),點擊運行XLANG進程按鈕。你就會看到一條消息顯示商業過程運行成功。當你在回到DevDotNet消息隊列中,第一條信息已經從隊列中移走了。再看數據庫中的定單表,你將會 看到從消息隊列中移去的訂單號的狀態已經發生了改變,如果是1,則表明信用卡得到授權劃款,如果是-1,則表明信用卡被拒絕了。這篇文章的代碼中包括一篇Word文檔,文中一步步描述瞭如何在BizTalk Orchestration中構建商業過程。
項目中還有許多工作要做。網頁可以變得更漂亮些。如果網站能夠被一個有經驗的網站設計師重新設計界面的話,我將會更感興趣。我也沒有時間實現帳戶管理能力。換句話說,用戶應該能夠看到沒有提交的訂單,能夠改變地址和交易信息。數據庫設計也可以支持顧客填寫多個地址。你可以根據這些擴充來改變界面。你也可以試着在網絡服務中不通過服務組件來執行分佈式處理,取而代之,使用WebMethod屬性的TransactionOption特性。
關於作者:
Alan Gordon是FieldCentrix的項目管理者。FieldCentrix主要開發應用在服務行業的基於Internet的軟件。他在UCLA Extension教過有關COM的課程,也是“The COM and COM+ Programming Primer (Prentice Hall, 2000)“的作者。目前他正在爲COM+的程序員寫.NET的書籍,這本書將於2001年由Apress出版。你可以通過[email protected]與他聯繫。