共用方式為


使用 WCF 通道模型從 SQL Server 接收輪詢型數據變更訊息

您可以設定 SQL 配接器來接收 SQL Server 數據表或檢視的定期資料變更訊息。 您可以指定配接器執行的輪詢指令,用於輪詢資料庫。 輪詢語句可以是 SELECT 語句或傳回結果集的預存程式。

如需了解配接器如何支援輪詢的更多資訊,請參閱 輪詢使用的輸入呼叫支援

這很重要

如果您想要在單一應用程式中有多個輪詢作業,您必須將 InboundID 連線屬性指定為連線 URI 的一部分,使其是唯一的。 您指定的輸入識別碼會新增至作業命名空間,使其是唯一的。

本主題如何展示輪詢的運作方式

在本主題中,若要示範 SQL 配接器如何支援接收數據變更訊息,請建立 輪詢 作業的 .NET 應用程式。 針對本主題,將 PolledDataAvailableStatement 指定為:

SELECT COUNT(*) FROM Employee  

PolledDataAvailableStatement 必須傳回含有正值的第一個單元格的結果集。 如果第一個單元格不包含正值,配接器就不會執行輪詢語句。

在輪詢陳述中,執行下列作業:

  1. 從 Employee 資料表中選取所有數據列。

  2. 執行預存程式 (MOVE_EMP_DATA),將所有記錄從 Employee 數據表移至 EmployeeHistory 資料表。

  3. 執行預存程式 (ADD_EMP_DETAILS) 將新記錄新增至 Employee 資料表。 此程式會採用員工名稱、指定和薪資作為參數。

    若要執行這些作業,您必須為 PollingStatement 綁定屬性指定下列項目:

SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000   

執行輪詢語句之後,會選取 Employee 數據表中的所有記錄,並接收來自 SQL Server 的訊息。 MOVE_EMP_DATA預存程式由配接器執行之後,所有記錄都會移至 EmployeeHistory 數據表。 然後,會執行ADD_EMP_DETAILS預存程式,將新記錄新增至 Employee 數據表。 下一個輪詢操作只會傳回單一記錄。 此循環會繼續進行,直到您關閉通道接聽程序為止。

使用 SQL 配接器系結屬性設定輪詢查詢

下表摘要說明您用來設定配接器以接收數據變更訊息的SQL 配接器系結屬性。 您必須將這些系結屬性指定為 .NET 應用程式的一部分以進行輪詢。

綁定屬性 說明
InboundOperationType 指定您要執行 輪詢類型化輪詢通知 輸入作業。 預設為 輪詢
PolledDataAvailableStatement 指定配接器執行的 SQL 語句,以判斷是否有任何數據可供輪詢。 SQL 語句必須傳回包含數據列和數據行的結果集。 只有當數據列可用時,才會執行針對 PollingStatement系結 屬性指定的SQL語句。
PollingIntervalInSeconds 指定 SQL 配接器執行 PolledDataAvailableStatement 系結屬性 指定語句的間隔時間,以秒為單位。 預設值為30秒。 輪詢間隔會決定連續輪詢之間的時間間隔。 如果語句是在指定的間隔內執行,配接器會等候間隔中的剩餘時間。
PollingStatement 指定要查詢 SQL Server 資料庫資料表的 SQL 語句。 您可以為輪詢語句指定簡單的 SELECT 語句或預存程式。 預設值為 null。 您必須指定 PollingStatement 的值,才能啟用輪詢。 只有在有數據可供輪詢時,才會執行輪詢語句,這是 由 PolledDataAvailableStatement 系結 屬性所決定。 您可以指定以分號分隔的任意數目 SQL 語句。
PollWhileDataFound 指定如果正在輪詢的數據表中有數據可用,SQL 配接器是否忽略輪詢間隔,並持續執行針對 PolledDataAvailableStatement 系結 屬性指定的 SQL 語句。 如果數據表中沒有可用的數據,配接器會還原為在指定的輪詢間隔執行 SQL 語句。 預設值為 false

如需這些屬性的更完整描述,請參閱 閱讀 BizTalk Adapter for SQL Server 配接器系結屬性。 如需完整描述如何使用 SQL 配接器輪詢 SQL Server,請閱讀本主題的其餘部分。

處理輪詢請求訊息

配接器會在程式代碼上叫用 輪詢 作業,以輪詢 SQL Server 資料庫。 也就是說,配接器會透過IInputChannel通道圖形傳送您收到的輪詢要求訊息。 輪詢要求訊息包含PollingStatement系結屬性所指定的查詢結果集。 您可以使用下列兩種方式之一來取用輪詢訊息:

  • 若要使用節點值串流來取用訊息,您必須在回應訊息上呼叫 WriteBodyContents 方法,並將實作節點值串流的 XmlDictionaryWriter 傳遞給它。

  • 若要使用節點串流來取用訊息,您可以在回應訊息上呼叫 GetReaderAtBodyContents 來取得 XmlReader

關於本主題中使用的範例

本主題中的範例會查詢 Employee 資料表。 此範例也會使用 MOVE_EMP_DATA 和 ADD_EMP_DETAILS 預存程式。 產生這些成品的腳本會隨附範例。 如需範例的詳細資訊,請參閱 SQL 配接器的範例。 依據此主題的範例Polling_ChannelModel,也包含在 SQL 配接器範例中。

使用 WCF 通道模型接收輪詢操作的傳入訊息

本節提供如何撰寫 .NET 應用程式(通道模型)以使用 SQL 配接器接收輸入輪詢訊息的指示。

從 SQL 配接器接收輪詢訊息

  1. 在 Visual Studio 中建立Microsoft Visual C# 專案。 針對本主題,建立主控台應用程式。

  2. 在 [方案總管] 中,新增 Microsoft.Adapters.SqlMicrosoft.ServiceModel.ChannelsSystem.ServiceModelSystem.Runtime.Serialization 的參考。

  3. 開啟Program.cs檔案,並新增下列命名空間:

    • Microsoft.Adapters.Sql

    • System.ServiceModel

    • System.ServiceModel.Description

    • System.ServiceModel.Channels

    • System.Xml

  4. 指定連線 URI。 如需配接器連線 URI 的詳細資訊,請參閱 建立 SQL Server 連線 URI

    Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");  
    
  5. 建立 SqlAdapterBinding 的實例,並設定設定輪詢所需的系結屬性。 您至少必須設定 InboundOperationTypePolledDataAvailableStatementPollingStatement 系結 屬性。 如需用來設定輪詢之繫結屬性的詳細資訊,請參閱 使用輪詢支持輸入呼叫

    SqlAdapterBinding binding = new SqlAdapterBinding();  
    binding.InboundOperationType = InboundOperation.Polling;  
    binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";  
    binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";  
    
  6. 建立係結參數集合並設定認證。

    ClientCredentials credentials = new ClientCredentials();  
    credentials.UserName.UserName = "<Enter user name here>";  
    credentials.UserName.Password = "<Enter password here>";  
    
    BindingParameterCollection bindingParams = new BindingParameterCollection();  
    bindingParams.Add(credentials);  
    
  7. 建立通道接聽程式並加以開啟。 您可以在 SqlAdapterBinding 上叫用 BuildChannelListener<IInputChannel> 方法來建立接聽程式。

    IChannelListener<IInputChannel> listener = binding.BuildChannelListener<IInputChannel>(connectionUri, bindingParams);  
    listener.Open();  
    
  8. 藉由在接聽程式上叫用 AcceptChannel 方法並開啟它,以取得 IInputChannel 通道。

    IInputChannel channel = listener.AcceptChannel();  
    channel.Open();  
    
  9. 在通道上叫用 Receive ,以從配接器取得下一個 POLLINGSTMT 訊息。

    Message message = channel.Receive();  
    
  10. 取用 POLLINGSTMT 作業所傳回的結果集。 您可以使用 XmlReaderXmlDictionaryWriter 來取用訊息。

    XmlReader reader = message.GetReaderAtBodyContents();  
    
  11. 當您完成處理要求時,請關閉通道。

    channel.Close()  
    

    這很重要

    完成 POLLINGSTMT 作業之後,您應該關閉該通道。 無法關閉通道可能會影響程式代碼的行為。

  12. 當您完成接收資料變更的訊息時,請關閉接聽程式。

    listener.Close()  
    

    這很重要

    關閉接聽程式不會關閉使用接聽程式建立的通道。 您必須明確地關閉使用接聽程式建立的每個通道。

範例

下列範例顯示執行 Employee 數據表的輪詢查詢。 輪詢語句會執行下列工作:

  • 從 [員工] 數據表中選取所有記錄。

  • 執行MOVE_EMP_DATA預存程式,將所有記錄從 Employee 資料表移至 EmployeeHistory 數據表。

  • 執行ADD_EMP_DETAILS預存程式,將單一記錄新增至 Employee 數據表。

    輪詢訊息會儲存在 C:\PollingOutput.xml

using System;  
using Microsoft.Adapters.Sql;  
using System.ServiceModel;  
using System.ServiceModel.Description;  
using System.ServiceModel.Channels;  

using System.Xml;  

namespace ConsoleApplication1  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Console.WriteLine("Sample started. This sample will poll 5 times and will perform the following tasks:");  
            Console.WriteLine("Press any key to start polling...");  
            Console.ReadLine();  
            IChannelListener<IInputChannel> listener = null;  

            IInputChannel channel = null;  

            try  
            {  
                TimeSpan messageTimeout = new TimeSpan(0, 0, 30);  

                SqlAdapterBinding binding = new SqlAdapterBinding();  
                binding.InboundOperationType = InboundOperation.Polling;  
                binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";  
                binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";  

                Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");  

                ClientCredentials credentials = new ClientCredentials();  
                credentials.UserName.UserName = "<Enter user name here>";  
                credentials.UserName.Password = "<Enter password here>";  

                BindingParameterCollection bindingParams = new BindingParameterCollection();  
                bindingParams.Add(credentials);  

                listener = binding.BuildChannelListener<IInputChannel>(ConnectionUri, bindingParams);  
                listener.Open();  

                channel = listener.AcceptChannel();  
                channel.Open();  

                Console.WriteLine("Channel and Listener opened...");  
                Console.WriteLine("\nWaiting for polled data...");  
                Console.WriteLine("Receive request timeout is {0}", messageTimeout);  

                // Poll five times with the specified message timeout   
                // If a timeout occurs polling will be aborted  
                for (int i = 0; i < 5; i++)  
                {  
                    Console.WriteLine("Polling: " + i);  
                    Message message = null;  
                    XmlReader reader = null;  
                    try  
                    {  
                        //Message is received so process the results  
                        message = channel.Receive(messageTimeout);  
                    }  
                    catch (System.TimeoutException toEx)  
                    {  
                        Console.WriteLine("\nNo data for request number {0}: {1}", i + 1, toEx.Message);  
                        continue;  
                    }  

                    // Get the query results using an XML reader  
                    try  
                    {  
                        reader = message.GetReaderAtBodyContents();  
                    }  
                    catch (Exception ex)  
                    {  
                        Console.WriteLine("Exception :" + ex);  
                        throw;  
                    }  

                    XmlDocument doc = new XmlDocument();  
                    doc.Load(reader);  
                    using (XmlWriter writer = XmlWriter.Create("C:\\PollingOutput.xml"))  
                    {  
                        doc.WriteTo(writer);  
                        Console.WriteLine("The polling response is saved at 'C:\\PollingOutput.xml'");  
                    }  

                    // return the cursor  
                    Console.WriteLine();  

                    // close the reader  
                    reader.Close();  

                    message.Close();  
                }  
                Console.WriteLine("\nPolling done -- hit <RETURN> to finish");  
                Console.ReadLine();  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("Exception is: " + ex.Message);  
                if (ex.InnerException != null)  
                {  
                    Console.WriteLine("Inner Exception is: " + ex.InnerException.Message);  
                }  
            }  
            finally  
            {  
                // IMPORTANT: close the channel and listener to stop polling  
                if (channel != null)  
                {  
                    if (channel.State == CommunicationState.Opened)  
                        channel.Close();  
                    else  
                        channel.Abort();  
                }  

                if (listener != null)  
                {  
                    if (listener.State == CommunicationState.Opened)  
                        listener.Close();  
                    else  
                        listener.Abort();  
                }  
            }  
        }  
    }  
}  

另請參閱

使用 WCF 通道模型開發 SQL 應用程式