說明
如果你已經閱讀了我之前的一篇文章《Asp.net建構可擴充的的Comet Web
應用》。你應該能夠了解我将要寫的内容。我解釋了Comet技術并且解釋了怎樣用asp.net建構具有可擴充性的應用。然而,我認為之前的的一篇文章寫得有點像主線。它展示了足夠的技術,但是沒有足夠包含任何有用的代碼。是以,我想我需要寫一個API來将之前一篇文章中的功能封裝起來。封裝為一系列整齊的類,讓它們可以被包含到一個通常的web項目中,給你機會去擴充和測試它。
我将不涉及太多關于線程模型的具體細節。因為在之前的一篇文章中涉及了太多關于它的内容。我僅僅講解涉及到API并且怎樣在你的web應用程式中使用它。
我決定寫一個輕量級的發送消息的API,它類似于Bayeuxprotocol【Bayeux是在和web伺服器間提供低延遲時間、傳輸異步消息的協定(主要基于HTTP)】交換資訊的方式。但是,它沒有它沒有一個基于改協定的實作當我相信它能夠矯枉過正,為了那些被用來需要用這些API工作的需求。并且它也僅僅隻是一個草案。
我的原文将我會給出一個小遊戲。不巧的是,我覺得用一個簡單的聊天程式來說明它可能更加容易。這個程式使用一個Comet通道來接受資訊,用一個WCF服務來發送資訊。
基本的聊天程式:

術語表
下面是我這篇文章中使用的清單,以及他們的描述。
通道:這是一個Comet用戶端能夠連接配接到的結束點。任何發送到用戶端的資訊必須被轉交給通道傳輸。
逾時:當一個用戶端已經連接配接到一個通道,并且過了預定義的一段時間内,還沒有收到任何的消息。當逾時的時候用戶端可以重建立立連接配接。
閑置用戶端:這是一個用戶端沒有連接配接到伺服器的時限。一個閑置的用戶端在一個預設的時間後将被斷開。
消息:通過一個通道發送給一個用戶端的JSON格式的消息。
訂閱:一個用戶端被訂閱到一個通道。他們被連接配接并且準備接受消息。
項目的代碼
項目的代碼包含所有的能夠在你的asp.net項目中使用Comet類。代碼和原文中設計的代碼非常接近。但我擴充了功能,使得能夠在用戶端和服務端傳輸通常的消息。
控制Comet主要的類是CometStateManager。這個類管理單個的通道。這個類使用ICometStateProvider接口的一個執行個體以一種特别的方式來為你的應用程式管理狀态。在API中,有一個内建InProcCometStateProvider的實作,用來在伺服器的記憶體中存儲狀态。很顯然,這不是實作負載均衡環境的一個好做法。但你可以實作一個自定義的提供程式(provider),使用資料庫或者一個自定義的狀态伺服器。
為了向外部暴露你的通道,需要用一個IHttpAsyncHandler的實作來包裝它。我最終試圖使用一個WCF的異步模型。但發現它不會釋放asp.net工作線程,如同使用異步handler一樣。這有點可惜,這并不是期望的。
下面的代碼展示了你應該怎樣去建立一個IHttpAsyncHandler來為你的Comet通道提供一個結束點。
上面的代碼足夠簡單。我們有一個CometStateManager類的靜态執行個體。它被用來建構ICometStateProvider的執行個體。在這個例子中,我們使用一個内置的InProcCometStateProvider的實作。
這個類其餘的實作是簡單得将BeginProcessRequest和EndProcessRequest方法映射到CometStateManager
類執行個體的BeginSubscribe和EndSubscribe方法。我們也需要在web.config中配置handler才能使用它。
這個通道現在已經可以被用戶端訂閱了
CometClient類
通道需要與用戶端保持連接配接。每一個用戶端都代表一些被CometClient的執行個體排序的緩存。我們不希望任何舊的用戶端連接配接着伺服器或者任何沒有被認證的用戶端注冊通道。是以我們希望實作一種授權和認證機制。也許是asp.net标準的
Form認證,或者也許是一個WCF調用一個服務來驗證憑據,并且在我們的通道中執行個體化一個用戶端。
下面的代碼展示了default.aspx頁面的登入操作:
我們沒有驗證密碼或任何其他的東西,我們隻是在頁面上直接輸入使用者名,并且用它來區分不同的用戶端。一個Comet用戶端有兩個token供API使用:
PrivateToken這個token是用戶端私有的,被用來注冊消息到用戶端。
PublicToken這個token被用來區分是哪一個用戶端。它通常在發送消息到一個特殊的用戶端時被使用。
我們使用一個公共令牌和一個私有令牌的原因是,私有令牌能夠被用來注冊一個通道以及從别的使用者那裡接受消息。我們不想任何其他的用戶端能夠隔離原本的用戶端(例如我們不希望消息欺騙)。出于這個原因,如果我們想在兩個用戶端之間發送消息我們使用公共令牌。
為了簡單起見,我已經在用戶端包含了一個DisplayName的屬性來存儲使用者名。
為了在用戶端建立一個通道,你需要調用InitializeClient。在上面有顯示。這個方法攜帶了下面的一些參數:
publicToken – 用戶端公共令牌
privateToken – 用戶端私有令牌
displayName – 用戶端顯示名稱
connectionTimeoutSeconds – 連接配接逾時時間
connectionIdleSeconds-
在伺服器殺掉一些閑置用戶端進而等待一個用戶端重新連接配接的秒數。
上面的例子中,<code>InitializeClient</code><code>會調用。從表單中指定使用者名作為公共令牌,私有令牌以及顯示名稱。這不是非常的安全,但對于一個Demo來說已經足夠了。為了使它更加安全,我本可以産生一個GUID來作為私有令牌。并且使用公共令牌作為使用者名。</code>
<code>InitializeClient</code><code>将通過ICometStateProvider被調用。一個新的InitializeClient執行個體化了CometClient類。并且期望它被存儲在緩存中。</code>
随着<code>CometClient</code><code>的可通路,用戶端可以使用它們自己的私有令牌來訂閱通道。</code>
<code>用戶端 JavaScript</code>
為了實作用戶端的功能,有一個檔案在項目中,Scripts/AspNetComet.js包含了所有的需要訂閱通道的js(以及公有的JSON轉換器)。為了使一切變得簡單一點,我在CometStateManager中包含了一個靜态方法來調用<code>RegisterAspNetCometScripts</code><code>。它接受一個帶有參數的頁面并且在頁面上注冊了腳本。</code>
<code>随着它被調用,我們就能夠很自由得使用我們能夠使用的用戶端API。下面的例子摘自項目中的chat.aspx。并且展示了一旦一個用戶端被執行個體化,你應該怎樣訂閱一個通常的通道。</code>
<code>用戶端API所有的功能都被包裹到一個被叫做AspNetComet的JavaScript類中。這個類的一個執行個體被用來跟蹤一個已連接配接的用戶端的狀态。被要求訂閱的是Comet結束端的handler的URL。CometClient的私有令牌,以及一個别名被用來差別用戶端通道。一旦我們建構一個AspNetComet的執行個體,我們可以在Comet的生命周期内定義一系列的handler以供在特殊時刻調用。</code>
<code>addTimeoutHandler–</code><code>當一個用戶端等待過了一個預定的事件并且沒有接收到消息調用該handler。</code>
<code>addFailureHandler–</code><code>當一個Comet調用失敗,其中一個失敗的例子就是Comet用戶端沒有被連接配接,調用該handler。</code>
<code>addSuccessHandler–</code><code>每一個消息被發送到用戶端的時候handler被調用。</code>
<code>接下來的代碼展示了每一個handler方法的簽名:</code>
<code>SuccessHandler</code><code>的參數是CometMessage類的一個執行個體。下面的代碼顯示了類和它的JSON格式:</code>
<code></code>
<code>發送一條消息</code>
在這個聊天的應用程式中,我已經包含了一個能使用AJAX的WCF web
服務來扮演發送消息功能的結束點。下面的代碼顯示了點選發送消息按鈕的用戶端事件的處理器:
這段代碼建構了一個由asp.net Web Service framework建立的
<code>ChatService</code><code>用戶端對象的執行個體。然後僅僅調用了SendMessage方法,通過傳遞用戶端的私有令牌和消息。</code>
<code>SendMessage</code><code>代碼攜帶參數以及寫了一條消息給所有的用戶端。下面的代碼展示了功能:</code>
<code>這個方法從私有令牌中查找CometClient,并且建立了一個被用來作為消息内容的ChatMessage的對象。這裡的消息内容通過CometStateMessager的執行個體的SendMessage方法被發送到每一個連接配接着的用戶端。它将處罰任何連接配接着的用戶端來回調包含在chat.aspx頁面裡的SuccessHandler方法。它将資訊寫到頁面的聊天區域。</code>
<code>使用這段代碼</code>
解決方案中的網站執行的時候不需要改變任何的配置,僅僅連接配接一些用戶端到應用程式中。并且聊天資訊應該被實時發送。
使用這個API将使你能在你的AJAX程式中使用一個Comet風格的方案。使用WCF能使你發送消息到伺服器,這些都已經為你自動包裝了。然後僅僅隻是在一個Comet通道中回調來連接配接到用戶端。
原文釋出時間為:2011-09-02