相同代碼也可用 Visual Basic .NET 撰寫,使用熟悉的 WithEvents 關鍵字與 SqlDependency。注意此程式只接收與處理一個 OnChanged 事件,不管底層資料列集發生多少次改變。收到通知時工作就是重新提交附帶新通知請求的命令,並用命令執行結果重新整理快取以反映新資料。若將前例 Main() 代碼移至具名常式,代碼如下:
static void Main(string[] args)
{
GetAndProcessData();
UpdateCache();
Console.WriteLine("Press Enter to continue");
Console.ReadLine();
}
static void MyOnChanged(object caller, SqlNotificationEventArgs e)
{
GetAndProcessData();
UpdateCache();
}
透過幾小段文字可了解在 ASP.NET 2.0 中採用完全相同方式,使用 ASP.NET Cache 類別作為資料快取。
SqlDependency 仰賴內建於 SQL Server 2005 的分派器建立與客戶端連接並發送通知訊息。分派器使用 out-of-band 通訊而非 SqlConnection。意味著您的客戶端必須能「透過網路到達」SQL Server;防火牆或網路位址轉換可能妨礙此通訊。未來 Beta 版將允許對埠設定有更多控制權,以更友善通過防火牆限制。可透過指定 SqlDependency 建構函式參數完整設定伺服器與客戶端通訊工作。範例:
SqlDependency depend = new SqlDependency(cmd,
null,
SqlNotificationAuthType.None,
SqlNotificationEncryptionType.None,
SqlNotificationTransports.Tcp,
10000);
此建構函式允許選擇不同於預設值的行為。所有可改變行為中最有用的是伺服器用於連接客戶端的傳輸協定。範例使用 SqlNotificationTransports.Tcp,伺服器可用 TCP 或 HTTP。參數預設值為 SqlNotificationTransports.Any;讓伺服器「決定」用哪個協定。若指定 Any,當客戶端作業系統包含核心模式 HTTP 支援時,伺服器將用 HTTP,否則用 TCP。Windows Server 2003 與 Windows XP SP2 均包含核心 HTTP 支援。因訊息透過網路發送,可指定身分驗證類型。目前 EncryptionType 為參數,但未來 Beta 版將移除。目前兩值預設皆為 None。
SqlNotificationAuthType 也支援整合驗證。可顯式指定訂閱逾時值與 SQL Server Service Broker 的 SERVICE 名稱。SERVICE 名稱通常設為空,如範例所示,但也可顯式指定內建 SqlQueryNotificationService 為 SERVICE 名稱。最可能被修改參數是 SqlNotificationTransport 與 timeout。注意這些參數只能套用於 SqlDependency,因參數指定伺服器端分派器行為。使用 SqlNotificationRequest 時不會用到分派器。
使用 SqlNotificationRequest 僅在設定方面比 SqlDependency 複雜一點,但主要取決於程式如何處理訊息。用 SqlDependency 時,伺服器通知發送到 MSDB 資料庫的 SqlQueryNotificationService 由它處理通知。用 SqlNotificationRequest 時必須自己處理訊息。這裡有簡單範例,使用 SqlNotificationRequest 與本文前面定義的 SERVICE:
using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
class Class1
{
string connstring = null;
SqlConnection conn = null;
SqlDataReader rdr = null;
static void Main(string[] args)
{
connstring = GetConnectionStringFromConfig();
conn = new SqlConnection(connstring);
Class1 c = new Class1();
c.DoWork();
}
void DoWork()
{
conn.Open();
rdr = GetJobs(2);
if (rdr != null)
{
rdr.Close();
WaitForChanges();
}
conn.Dispose();
}
public SqlDataReader GetJobs(int JobId)
{
using (SqlCommand cmd = new SqlCommand(
"Select job_id, job_desc from dbo.jobs where job_id = @id", conn))
{
try
{
cmd.Parameters.AddWithValue("@id", JobId);
SqlNotificationRequest not = new SqlNotificationRequest();
not.Id = new Guid();
// 這必須是 pubs 資料庫中名為 MyService 的服務
// 關聯佇列 notificationqueue (見下文)
// 服務必須遵循 QueryNotifications 契約
not.Service = "myservice";
not.Timeout = 0;
// 掛載通知請求
cmd.Notification = not;
rdr = cmd.ExecuteReader();
while (rdr.Read())
Console.WriteLine(rdr[0]);
rdr.Close();
}
catch (Exception ex)
{ Console.WriteLine(ex.Message); }
return rdr;
}
}
public void WaitForChanges()
{
// 等待通知出現在佇列,然後自行讀取
using (SqlCommand cmd = new SqlCommand(
"WAITFOR (Receive convert(XML, message_body) from notificationqueue)", conn))
{
object o = cmd.ExecuteScalar();
// 依喜好處理通知訊息
Console.WriteLine(o);
}
}
}