您可以將 SQL 配接器設定為從 SQL Server 接收強類型的輪詢訊息。 您可以指定配接器執行的輪詢指令,用於輪詢資料庫。 輪詢語句可以是 SELECT 語句或傳回結果集的預存程式。 您必須在想要接收強型別結果的情境中使用強型別輪詢。 如需詳細了解配接器如何支援強型別輪詢,請參閱 使用輪詢支援輸入呼叫。
這很重要
如果您想要在單一應用程式中有多個輪詢作業,您必須將 InboundID 連線屬性指定為連線 URI 的一部分,使其是唯一的。 您指定的輸入識別碼會新增至作業命名空間,使其是唯一的。
本主題如何展示輪詢的運作方式
在本主題中,為了示範 SQL 配接器如何支援接收強型別資料變更訊息,請建立 .NET 應用程式,並產生用於TypedPolling作業的 WCF 服務合約。 請確定您在產生 WCF 服務合約時指定下列項目:
您必須將 InboundID 指定為連線 URI 的一部分。
您必須為 PollingStatement 系結屬性指定一個輪詢語句。
此外,如果您想要在產生 Proxy 類別時指定其他輪詢相關係結屬性,請將 PolledDataAvailableStatement 指定為:
SELECT COUNT(*) FROM Employee
PolledDataAvailableStatement 必須傳回含有正值的第一個單元格的結果集。 如果第一個單元格不包含正值,配接器就不會執行輪詢語句。
在輪詢陳述中,執行下列作業:
從 Employee 資料表中選取所有數據列。
執行預存程式 (MOVE_EMP_DATA),將所有記錄從 Employee 數據表移至 EmployeeHistory 資料表。
執行預存程式 (ADD_EMP_DETAILS) 將新記錄新增至 Employee 資料表。 此程式會採用員工名稱、指定和薪資作為參數。
若要執行這些作業,您必須為 PollingStatement 系結屬性指定下列專案,同時產生WCF服務合約和助手類別:
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 配接器系結屬性。 除了 PollingStatement 系結 屬性之外,執行 .NET 應用程式時,本節中所列的所有其他系結屬性都是必要的。 您必須先指定 PollingStatement 系結 屬性,才能產生 WCF 服務合約 TypedPolling 作業。
綁定屬性 | 說明 |
---|---|
InboundOperationType | 指定您要執行 輪詢、類型化輪詢 或 通知 輸入作業。 預設為 輪詢。 若要接收強型別輪詢訊息,請將此設定為 TypedPolling。 |
PolledDataAvailableStatement | 指定配接器執行的 SQL 語句,以判斷是否有任何數據可供輪詢。 SQL 語句必須傳回包含數據列和數據行的結果集。 只有當數據列可用時,才會執行針對 PollingStatement系結 屬性指定的SQL語句。 |
PollingIntervalInSeconds | 指定 SQL 配接器執行 PolledDataAvailableStatement 系結屬性 指定語句的間隔時間,以秒為單位。 預設值為30秒。 輪詢間隔會決定連續輪詢之間的時間間隔。 如果語句是在指定的間隔內執行,配接器會等候間隔中的剩餘時間。 |
PollingStatement | 指定要查詢 SQL Server 資料庫資料表的 SQL 語句。 您可以為輪詢語句指定簡單的 SELECT 語句或預存程式。 預設值為 null。 您必須指定 PollingStatement 的值,才能啟用輪詢。 只有在有數據可供輪詢時,才會執行輪詢語句,這是 由 PolledDataAvailableStatement 系結 屬性所決定。 您可以指定以分號分隔的任意數目 SQL 語句。 重要: 針對 TypedPolling,您必須先指定這個系結屬性,才能產生元數據。 |
PollWhileDataFound | 指定如果正在輪詢的數據表中有數據可用,SQL 配接器是否忽略輪詢間隔,並持續執行針對 PolledDataAvailableStatement 系結 屬性指定的 SQL 語句。 如果數據表中沒有可用的數據,配接器會還原為在指定的輪詢間隔執行 SQL 語句。 預設值為 false。 |
如需這些屬性的更完整描述,請參閱 閱讀 BizTalk Adapter for SQL Server 配接器系結屬性。 為了完整了解如何使用 SQL 配接器來輪詢 SQL Server,請閱讀下文。
在 WCF 服務模型中設定強類型輪詢
若要在使用 WCF 服務模型時接收 輪詢 作業,您必須:
從配接器所公開的元數據產生 TypedPolling 作業的 WCF 服務合約(介面)。 若要這樣做,您可以使用新增配接器服務參考 Visual Studio 外掛程式。 產生此範例的 WCF 服務合約時,請確定:
您會將 InboundID 指定為 Employee。
您指定 PollingStatement 繫結屬性的輪詢語句。 在此範例中,將「查詢語句」指定為:
SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000
從這個介面實作 WCF 服務。
使用服務主機裝載此 WCF 服務(System.ServiceModel.ServiceHost)。
關於本主題中使用的範例
本主題中的範例會查詢 Employee 資料表。 此範例也會使用 MOVE_EMP_DATA 和 ADD_EMP_DETAILS 預存程式。 產生這些成品的腳本會隨附範例。 如需範例的詳細資訊,請參閱 SQL 配接器的範例。 隨附 SQL 配接器範例的還有一個根據本主題的範例,名為TypedPolling_ServiceModel。
WCF 服務合約和類別
您可以使用新增配接器服務參考外掛程式來建立 WCF 服務合約(介面)和支援 TypedPolling 作業的類別。 如需產生 WCF 服務合約的詳細資訊,請參閱 產生 SQL Server 項目的 WCF 用戶端或 WCF 服務合約。
WCF 服務合約 (介面)
下列程式代碼顯示針對 TypedPolling 作業產生的 WCF 服務合約(介面)。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/", ConfigurationName="TypedPolling_Employee")]
public interface TypedPolling_Employee {
// CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/Sql/2008/05/TypedPolling/Employee) of message TypedPolling
// does not match the default value (https://schemas.microsoft.com/Sql/2008/05/)
[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="TypedPolling")]
void TypedPolling(TypedPolling request);
}
訊息合約
如果指定,訊息合約命名空間會由連線 URI 中的 InboundID 參數修改。 在此範例中,您已將輸入標識元指定為 Employee。 要求訊息會傳回強型別的結果集。
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="TypedPolling", WrapperNamespace="http://schemas.microsoft.com/Sql/2008/05/TypedPolling/Employee", IsWrapped=true)]
public partial class TypedPolling {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/TypedPolling/Employee", Order=0)]
public schemas.microsoft.com.Sql._2008._05.TypedPolling.Employee.TypedPollingResultSet0[] TypedPollingResultSet0;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/TypedPolling/Employee", Order=1)]
public schemas.microsoft.com.Sql._2008._05.TypedPolling.Employee.TypedPollingResultSet1[] TypedPollingResultSet1;
public TypedPolling() {
}
public TypedPolling(schemas.microsoft.com.Sql._2008._05.TypedPolling.Employee.TypedPollingResultSet0[] TypedPollingResultSet0, schemas.microsoft.com.Sql._2008._05.TypedPolling.Employee.TypedPollingResultSet1[] TypedPollingResultSet1) {
this.TypedPollingResultSet0 = TypedPollingResultSet0;
this.TypedPollingResultSet1 = TypedPollingResultSet1;
}
}
WCF 服務類別
[新增配接器服務參考外掛程式] 也會產生一個檔案,其中包含根據服務合約 (介面) 所建立的 WCF 服務類別的存根。 檔名是SqlAdapterBindingService.cs。 您可以將邏輯直接插入這個類別中,以處理TypedPolling作業。 下列程式代碼顯示新增配接器服務參考外掛程式所產生的 WCF 服務類別。
namespace SqlAdapterBindingNamespace {
public class SqlAdapterBindingService : TypedPolling_Employee {
// CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/Sql/2008/05/TypedPolling/Employee) of message TypedPolling
// does not match the default value (https://schemas.microsoft.com/Sql/2008/05/)
public virtual void TypedPolling(TypedPolling request) {
throw new System.NotImplementedException("The method or operation is not implemented.");
}
}
}
接收輪詢作業的強型別輸入訊息
本節說明如何撰寫 .NET 應用程式,以便使用 SQL 介面卡接收強類型的傳入輪詢訊息。
使用 [新增配接器服務參考外掛程式] 來產生 TypedPolling 作業的 WCF 服務合約(介面)和協助程序類別。 請確保您在產生此範例的 WCF 服務合約時指定以下內容:
您必須將 InboundID 指定為 Employee。
您必須為 PollingStatement 系結屬性指定輪詢語句。 在此範例中,將輪詢語句設定為:
SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000
如需詳細資訊,請參閱 為 SQL Server 工件產生 WCF 用戶端或 WCF 服務合約。 您可以選擇性地指定繫結屬性,在產生服務合約和輔助類別時。 這可確保它們已正確設定在產生的組態檔中。
從步驟 1 所產生的介面和協助程式類別實作 WCF 服務。 如果在處理從 TypedPolling 作業接收到的資料時遇到錯誤,這個類別的 TypedPolling 方法可能會擲回例外狀況以中止輪詢程序。否則,該方法不會傳回任何內容。 請按照以下方式設定 WCF 服務類別的屬性:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
在 TypedPolling 方法內,您可以直接實作應用程式邏輯。 您可以在 SqlAdapterBindingService.cs中找到這個類別。 此範例中的這個程式代碼子類別是 SqlAdapterBindingService 類別。 在此程式代碼中,接收為強型別結果集的輪詢訊息會寫入主控台。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class PollingService : SqlAdapterBindingNamespace.SqlAdapterBindingService { public override void TypedPolling(TypedPolling request) { Console.WriteLine("\nNew Polling Records Received"); Console.WriteLine("*************************************************"); Console.WriteLine("Employee ID\tName\tDesignation\tSalary"); for (int i = 0; i < request.TypedPollingResultSet0.Length; i++) { Console.WriteLine("{0}\t{1}\t{2}\t{3}", request.TypedPollingResultSet0[i].Employee_ID, request.TypedPollingResultSet0[i].Name, request.TypedPollingResultSet0[i].Designation, request.TypedPollingResultSet0[i].Salary); } Console.WriteLine("*************************************************"); Console.WriteLine("\nHit <RETURN> to stop polling"); } }
因為 SQL 配接器不接受認證作為連線 URI 的一部分,因此您必須實作下列類別來傳遞 SQL Server 資料庫的認證。 在應用程式的後半部分中,您將具現化此類別,以傳遞 SQL Server 認證。
class PollingCredentials : ClientCredentials, IServiceBehavior { public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { bindingParameters.Add(this); } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } protected override ClientCredentials CloneCore() { ClientCredentials clone = new PollingCredentials(); clone.UserName.UserName = this.UserName.UserName; clone.UserName.Password = this.UserName.Password; return clone; } }
藉由指定系結屬性,建立 SqlAdapterBinding 並設定輪詢作業。 您可以在程式代碼中明確執行此動作,或在組態中以宣告方式執行此動作。 您至少必須指定 InboundOperationType、 PolledDataAvailableStatement 和 PollingStatement。
SqlAdapterBinding binding = new SqlAdapterBinding(); binding.InboundOperationType = InboundOperation.TypedPolling; binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE"; binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";
藉由具現化您在步驟 3 中建立的 PollingCredentials 類別,指定 SQL Server 資料庫認證。
PollingCredentials credentials = new PollingCredentials(); credentials.UserName.UserName = "<Enter user name here>"; credentials.UserName.Password = "<Enter password here>";
建立在步驟 2 中建立之 WCF 服務的實例。
// create service instance PollingService service = new PollingService();
使用 WCF 服務和基底連線 URI 建立 System.ServiceModel.ServiceHost 的實例。 基底連線 URI 不能包含輸入標識碼。 您也必須在這裡指定認證。
// Enable service host Uri[] baseUri = new Uri[] { new Uri("mssql://mysqlserver//mydatabase") }; ServiceHost serviceHost = new ServiceHost(service, baseUri); serviceHost.Description.Behaviors.Add(credentials);
將服務端點新增至服務主機。 要達成此目的:
使用在步驟 4 中建立的系結。
指定包含認證的連線 URI,並視需要指定輸入識別碼。
將合約指定為 「TypedPolling_Employee」。
// Add service endpoint: be sure to specify TypedPolling_Employee as the contract Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?InboundID=Employee"); serviceHost.AddServiceEndpoint("TypedPolling_Employee", binding, ConnectionUri);
若要接收輪詢數據,請開啟服務主機。 每當查詢傳回結果集時,配接器就會傳回數據。
// Open the service host to begin polling serviceHost.Open();
若要終止輪詢,請關閉服務主機。
這很重要
轉接器會繼續輪詢,直到服務主機關閉為止。
serviceHost.Close();
範例
下列範例顯示執行 Employee 數據表的輪詢查詢。 輪詢語句會執行下列工作:
從 [員工] 數據表中選取所有記錄。
執行MOVE_EMP_DATA預存程式,將所有記錄從 Employee 資料表移至 EmployeeHistory 數據表。
執行ADD_EMP_DETAILS預存程式,將單一記錄新增至 Employee 數據表。
第一筆輪詢訊息將包含所有來自員工資料表的記錄。 後續輪詢訊息只會包含ADD_EMP_DETAILS預存程式所插入的最後一筆記錄。 配接器會繼續輪詢,直到您按下
<RETURN>
關閉服務主機為止。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Adapters.Sql;
using Microsoft.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Collections.ObjectModel;
namespace TypedPolling_ServiceModel
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PollingService : SqlAdapterBindingNamespace.SqlAdapterBindingService
{
public override void TypedPolling(TypedPolling request)
{
Console.WriteLine("\nNew Polling Records Received");
Console.WriteLine("*************************************************");
Console.WriteLine("Employee ID\tName\tDesignation\tSalary");
for (int i = 0; i < request.TypedPollingResultSet0.Length; i++)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}",
request.TypedPollingResultSet0[i].Employee_ID,
request.TypedPollingResultSet0[i].Name,
request.TypedPollingResultSet0[i].Designation,
request.TypedPollingResultSet0[i].Salary);
}
Console.WriteLine("*************************************************");
Console.WriteLine("\nHit <RETURN> to stop polling");
}
}
class PollingCredentials : ClientCredentials, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
bindingParameters.Add(this);
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{ }
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{ }
protected override ClientCredentials CloneCore()
{
ClientCredentials clone = new PollingCredentials();
clone.UserName.UserName = this.UserName.UserName;
clone.UserName.Password = this.UserName.Password;
return clone;
}
}
class Program
{
static void Main(string[] args)
{
ServiceHost serviceHost = null;
try
{
Console.WriteLine("Sample started...");
Console.WriteLine("Press any key to start polling...");
Console.ReadLine();
SqlAdapterBinding binding = new SqlAdapterBinding();
binding.InboundOperationType = InboundOperation.TypedPolling;
binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";
binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";
Console.WriteLine("Binding properties assigned...");
// This URI is used to specify the address for the ServiceEndpoint
// It must contain the InboundId that was used to generate
// the WCF service callback interface
Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?InboundId=Employee");
// This URI is used to initialize the ServiceHost. It cannot contain
// the InboundID; otherwise,an exception is thrown when
// the ServiceHost is initialized.
Uri[] baseUri = new Uri[] { new Uri("mssql://mysqlserver//mydatabase") };
PollingCredentials credentials = new PollingCredentials();
credentials.UserName.UserName = "<Enter user name here>";
credentials.UserName.Password = "<Enter password here>";
Console.WriteLine("Opening service host...");
PollingService service = new PollingService();
serviceHost = new ServiceHost(service, baseUri);
serviceHost.Description.Behaviors.Add(credentials);
serviceHost.AddServiceEndpoint("TypedPolling_Employee", binding, ConnectionUri);
serviceHost.Open();
Console.WriteLine("Service host opened...");
Console.WriteLine("Polling started...");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Exception :" + e.Message);
Console.ReadLine();
/* If there is an error it will be specified in the inner exception */
if (e.InnerException != null)
{
Console.WriteLine("InnerException: " + e.InnerException.Message);
Console.ReadLine();
}
}
finally
{
// IMPORTANT: you must close the ServiceHost to stop polling
if (serviceHost.State == CommunicationState.Opened)
serviceHost.Close();
else
serviceHost.Abort();
}
}
}
}