您可以設定 Microsoft BizTalk Adapter for Oracle Database,以接收針對 Oracle 資料表或檢視的輪詢型資料變更訊息。 若要接收數據變更的訊息,配接器會定期針對 Oracle 數據表或檢視執行 SQL 查詢,後面接著選擇性 PL/SQL 程式代碼區塊。 Oracle 資料庫配接器會將 SQL 查詢的結果作為強型別結果集返回到您的應用程式,這發生在 POLLINGSTMT 作業的輸入階段。 如需使用 Oracle 資料庫配接器設定和執行 Oracle 資料庫輪詢之機制的詳細資訊,請參閱 在 Oracle 資料庫配接器中接收輪詢型數據變更訊息。 強烈建議您在繼續之前先閱讀本主題。
若要在使用 WCF 服務模型時接收 POLLINGSTMT 操作,您必須:
從配接器所公開的元數據產生POLLINGSTMT作業的WCF服務合約(介面)。 若要這樣做,您可以使用新增配接器服務參考 Visual Studio 外掛程式或 ServiceModel 元數據公用程式工具 (svcutil.exe)。
從這個介面實作 WCF 服務。
使用服務主機裝載此 WCF 服務(System.ServiceModel.ServiceHost)。
本節中的主題提供資訊和程序,協助您在 WCF 服務模型中對 Oracle 資料庫資料表和視圖執行輪詢。
關於本主題中使用的範例
本主題中的範例會使用 /SCOTT/ACCOUNTACTIVITY 數據表和 /SCOTT/Package/ACCOUNT_PKG/PROCESS_ACTIVITY 函式。 產生這些成品的腳本會隨附 BizTalk 配接器套件範例。 如需範例的詳細資訊,請參閱 配接器範例。
在 WCF 服務模型中設定輪詢
您可以藉由設定系結屬性和選擇性連接屬性 (parameter) 來設定 Oracle 資料庫配接器,以對 Oracle 資料庫數據表和檢視表執行輪詢。 其中有些屬性是必要屬性,有些屬性必須同時在設計時間和運行時間設定。
在設計時間,當您連接到 Oracle Database 以產生 WCF 服務合約時,您會設定連線參數和系結屬性。
在運行時間,您會在用來建立服務主機的 OracleDBBinding 對象上設定系結屬性。 當您將服務接聽程式新增至服務主機時,您會設定連接參數。
下列清單提供用來設定輪詢之系結屬性和連接參數的簡短概觀:
PollingStatement 繫結屬性。 您必須在設計時間與運行時間設定這個系結屬性。
選擇性系結屬性。 只需要在執行期間設定。
AcceptCredentialsInUri 系結屬性。 如果您想要在連線 URI 中啟用認證,則必須在運行時間期間將此系結屬性設定為 true 。 當您將服務端點新增至服務主機時,使用者名稱和密碼必須存在於連線 URI 中。
謹慎
此範例或指引會參考敏感性資訊,例如連接字串或使用者名稱和密碼。 請勿在程式代碼中硬式編碼這些值,並確定您使用最安全的驗證來保護機密數據。 如需詳細資訊,請參閱下列文件:
線上 URI 中的 PollingId 查詢字串參數。 如果您要變更 POLLINGSTMT 作業的命名空間,您必須在設計時間和運行時間設定此連接屬性。
如需用來設定輪詢之系結屬性和聯機參數的完整描述,請參閱 在 Oracle Database 配接器中接收輪詢型數據變更訊息。
WCF 服務合約和類別
您可以使用「新增配接器服務參考」Visual Studio 插件或「ServiceModel 元數據實用工具(svcutil.exe)」來建立用於 POLLINGSTMT 操作的 WCF 服務合約(介面)和支援類別。
當您使用下列其中一個工具來連線到 Oracle 資料庫時,為 POLLINGSTMT 作業產生服務合約:
您必須指定 PollingStatement 系結 屬性。 配接器會使用此系結屬性中的 SELECT 語句,為 POLLINGSTMT 作業所傳回的強型別結果集產生正確的元數據。
您可以選擇性地在連線 URI 中指定 PollingId 參數。 配接器會使用此參數來產生POLLINGSTMT作業的命名空間。
在下列範例中:
PollingStatement 設定為 “SELECT * FROM ACCOUNTACTIVITY FOR UPDATE”。
PollingId 設定為 「AcctActivity」。。
WCF 服務合約 (介面)
下列程式代碼顯示針對 POLLINGSTMT 作業產生的 WCF 服務合約(介面)。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03", ConfigurationName="POLLINGSTMT_OperationGroup")]
public interface POLLINGSTMT_OperationGroup {
// CODEGEN: Generating message contract since the wrapper namespace (http://Microsoft.LobServices.OracleDB/2007/03/POLLINGSTMTAcctActivity)
// of message POLLINGSTMT does not match the default value (http://Microsoft.LobServices.OracleDB/2007/03)
[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://Microsoft.LobServices.OracleDB/2007/03/POLLINGSTMT")]
void POLLINGSTMT(POLLINGSTMT request);
}
訊息合約
訊息合約命名空間是由連線 URI 中的 PollingId 參數所修改。 要求訊息會傳回一組具嚴格類型定義的記錄。
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="POLLINGSTMT", WrapperNamespace="http://Microsoft.LobServices.OracleDB/2007/03/POLLINGSTMTAcctActivity", IsWrapped=true)]
public partial class POLLINGSTMT {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03/POLLINGSTMTAcctActivity", Order=0)]
public microsoft.lobservices.oracledb._2007._03.POLLINGSTMTAcctActivity.POLLINGSTMTRECORD[] POLLINGSTMTRECORD;
public POLLINGSTMT() {
}
public POLLINGSTMT(microsoft.lobservices.oracledb._2007._03.POLLINGSTMTAcctActivity.POLLINGSTMTRECORD[] POLLINGSTMTRECORD) {
this.POLLINGSTMTRECORD = POLLINGSTMTRECORD;
}
}
數據合約命名空間
「 資料合約 」(Data Contract) 是服務與用戶端之間的正式合約,其中會抽象地描述要交換的資料。 也就是說,為了進行通訊,客戶端和服務不需要共用相同的類型,只有相同的數據合約。
如果是資料變更訊息,資料契約命名空間也會由連線 URI 中指定的 PollingId 參數修改。 數據合約是由一個類別組成,用於表示查詢結果集中的強類型記錄。 在此範例中會省略類別定義的詳細數據。 類別包含表示結果集中欄位的屬性。
在下列範例中,會使用PollingId“AcctActivity”。
namespace microsoft.lobservices.oracledb._2007._03.POLLINGSTMTAcctActivity {
using System.Runtime.Serialization;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="POLLINGSTMTRECORD", Namespace="http://Microsoft.LobServices.OracleDB/2007/03/POLLINGSTMTAcctActivity")]
public partial class POLLINGSTMTRECORD : object, System.Runtime.Serialization.IExtensibleDataObject {…}
}
}
WCF 服務類別
[新增配接器服務參考外掛程式] 也會產生一個檔案,其中包含根據服務合約 (介面) 所建立的 WCF 服務類別的存根。 檔案的名稱是OracleDBBindingService.cs。 您可以將邏輯直接插入此類別,以處理 POLLINGSTMT 作業。 如果您使用 svcutil.exe 來產生服務合約介面,您必須自行實作此類別。 下列程式代碼顯示新增配接器服務參考外掛程式所產生的 WCF 服務類別。
namespace OracleDBBindingNamespace {
public class OracleDBBindingService : POLLINGSTMT_OperationGroup {
// CODEGEN: Generating message contract since the wrapper namespace (http://Microsoft.LobServices.OracleDB/2007/03/POLLINGSTMTAcctActivity)
// of message POLLINGSTMT does not match the default value (http://Microsoft.LobServices.OracleDB/2007/03)
public virtual void POLLINGSTMT(POLLINGSTMT request) {
throw new System.NotImplementedException("The method or operation is not implemented.");
}
}
}
接收 POLLINGSTMT 作業
從 Oracle 資料庫配接器接收輪詢數據
使用「新增配接器服務參考」外掛程式或 svcutil.exe 來為 POLLINGSTMT 作業產生 WCF 服務合約(介面)和協助類別。 如需詳細資訊,請參閱 產生 ORACLE 資料庫解決方案成品的 WCF 用戶端或 WCF 服務合約。 連線到配接器時,您至少必須設定 PollingStatement 繫結屬性。 您可以選擇性地在連線 URI 中指定 PollingId 參數。 如果您使用 [新增配接器服務參考外掛程式],您應該設定組態所需的所有係結參數。 這可確保它們已正確設定在產生的組態檔中。
從步驟 1 所產生的介面和協助程式類別實作 WCF 服務。 如果在處理從 POLLINGSTMT 作業接收到的數據時遇到錯誤,這個類別的 POLLINGSTMT 方法可能會拋出例外狀況來終止輪詢交易;否則,該方法不會返回任何值。 請按照以下方式設定 WCF 服務類別的屬性:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]如果您使用新增配接器服務參考外掛程式來產生介面,則可以直接在產生的 OracleDBBindingService 類別的 POLLINGSTMT 方法中實作邏輯。 您可以在 OracleDBBindingService.cs 中找到這個類別。 此範例程式碼會將 OracleDBBindingService 類別進行子類化。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class PollingStmtService : OracleDBBindingService { public override void POLLINGSTMT(POLLINGSTMT request) { Console.WriteLine("\nNew Polling Records Received"); Console.WriteLine("Tx Id\tAccount\tAmount\tDate\t\t\tDescription"); for (int i = 0; i < request.POLLINGSTMTRECORD.Length; i++) { Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", request.POLLINGSTMTRECORD[i].TID, request.POLLINGSTMTRECORD[i].ACCOUNT, request.POLLINGSTMTRECORD[i].AMOUNT, request.POLLINGSTMTRECORD[i].TRANSDATE, request.POLLINGSTMTRECORD[i].DESCRIPTION); } } }如果您使用 svcutil.exe 產生介面,您必須建立 WCF 服務來實作 介面,並在這個類別的 POLLINGSTMT 方法中實作邏輯。
建立在步驟 2 中建立之 WCF 服務的實例。
// create service instance PollingStmtService pollingInstance = new PollingStmtService();使用 WCF 服務和基底連線 URI 建立 System.ServiceModel.ServiceHost 的實例。 基底連線 URI 不能包含 userinfoparams 或 query_string。
// Enable service host Uri[] baseUri = new Uri[] { new Uri("oracledb://Adapter") }; ServiceHost srvHost = new ServiceHost(pollingInstance, baseUri);建立 OracleDBBinding ,並藉由設定其系結屬性來設定輪詢作業。 您可以在程式代碼中明確執行此動作,或在組態中以宣告方式執行此動作。 您至少必須指定輪詢語句和輪詢間隔。 在此範例中,您會將認證指定為 URI 的一部分,因此您也必須將 AcceptCredentialsInUri 設定為 true。
// Create and configure a binding for the service endpoint. NOTE: binding // parameters are set here for clarity, but these are already set in the // the generated configuration file OracleDBBinding binding = new OracleDBBinding(); // The credentials are included in the connection URI, so set this property to true binding.AcceptCredentialsInUri = true; // Same as statement specified in Configure Adapter dialog box binding.PollingStatement = "SELECT * FROM ACCOUNTACTIVITY FOR UPDATE"; binding.PostPollStatement = "BEGIN ACCOUNT_PKG.PROCESS_ACTIVITY(); END;"; // Be sure to set the interval long enough to complete processing before // the next poll binding.PollingInterval = 15; // Polling is transactional; be sure to set an adequate isolation level // for your environment binding.TransactionIsolationLevel = TransactionIsolationLevel.ReadCommitted;將服務端點新增至服務主機。 要達成此目的:
使用在步驟 5 中建立的系結。
指定包含認證的連接 URI,並視需要指定 PollingId。
將合約指定為 「POLLINGSTMT_OperationGroup」。
// Add service endpoint: be sure to specify POLLINGSTMT_OperationGroup as the contract Uri serviceUri = new Uri("oracledb://User=SCOTT;Password=TIGER@Adapter?PollingId=AcctActivity"); srvHost.AddServiceEndpoint("POLLINGSTMT_OperationGroup", binding, serviceUri);若要接收輪詢數據,請開啟服務主機。 每當查詢傳回結果集時,配接器就會傳回數據。
// Open the service host to begin polling srvHost.Open();若要終止輪詢,請關閉服務主機。
這很重要
轉接器會繼續輪詢,直到服務主機關閉為止。
srvHost.Close();
範例
下列範例顯示針對 /SCOTT/ACCOUNTACTIVITY 數據表執行的輪詢查詢。 輪詢後語句會叫用 Oracle 函式,將已處理的記錄移至另一個數據表 /SCOTT/ACCOUNTHISTORY。 POLLINGSTMT 作業的命名空間會藉由將 Connection URI 中的 PollingId 參數設定為 “AccountActivity” 來修改。 在此範例中,POLLINGSTMT 作業的 WCF 服務是由產生的 OracleDBBindingService 類別子類別所建立;不過,您可以直接在產生的類別中實作邏輯。
using System;
using System.Collections.Generic;
using System.Text;
// Add these three references to use the Oracle adapter
using System.ServiceModel;
using Microsoft.ServiceModel.Channels;
using Microsoft.Adapters.OracleDB;
using microsoft.lobservices.oracledb._2007._03.POLLINGSTMTAcctActivity;
using OracleDBBindingNamespace;
namespace OraclePollingSM
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PollingStmtService : OracleDBBindingService
{
public override void POLLINGSTMT(POLLINGSTMT request)
{
Console.WriteLine("\nNew Polling Records Received");
Console.WriteLine("Tx Id\tAccount\tAmount\tDate\t\t\tDescription");
for (int i = 0; i < request.POLLINGSTMTRECORD.Length; i++)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", request.POLLINGSTMTRECORD[i].TID,
request.POLLINGSTMTRECORD[i].ACCOUNT,
request.POLLINGSTMTRECORD[i].AMOUNT,
request.POLLINGSTMTRECORD[i].TRANSDATE,
request.POLLINGSTMTRECORD[i].DESCRIPTION);
}
Console.WriteLine("\nHit <RETURN> to stop polling");
}
}
class Program
{
static void Main(string[] args)
{
ServiceHost srvHost = null;
// This URI is used to specify the address for the ServiceEndpoint
// It must contain credentials and the PollingId (if any) that was used to generate
// the WCF service callback interface
Uri serviceUri = new Uri("OracleDb://User=SCOTT;Password=TIGER@Adapter?PollingId=AcctActivity");
// This URI is used to initialize the ServiceHost. It cannot contain
// userinfoparms (credentials) or a query_string (PollingId); otherwise,
// an exception is thrown when the ServiceHost is initialized.
Uri[] baseUri = new Uri[] { new Uri("OracleDb://Adapter") };
Console.WriteLine("Sample started, initializing service host -- please wait");
// create an instanc of the WCF service callback class
PollingStmtService pollingInstance = new PollingStmtService();
try
{
// Create a ServiceHost with the service callback instance and a base URI (address)
srvHost = new ServiceHost(pollingInstance, baseUri);
// Create and configure a binding for the service endpoint. Note: binding
// parameters are set here for clarity but these are already set in the
// generated configuration file
//
// The following properties are set
// AcceptCredentialsInUri (true) to enable credentials in the connection URI for AddServiceEndpoint
// PollingStatement
// PostPollStatement calls PROCESS_ACTIVITY on Oracle. This procedure moves the queried records to
// the ACCOUNTHISTORY table
// PollingInterval (15 seconds)
// TransactionIsolationLevel
OracleDBBinding binding = new OracleDBBinding();
// The Credentials are included in the Connection Uri so set this property true
binding.AcceptCredentialsInUri = true;
// Same as statement specified in Configure Adapter dialog box
binding.InboundOperationType = InboundOperation.Polling;
binding.PollingStatement = "SELECT * FROM ACCOUNTACTIVITY FOR UPDATE";
binding.PostPollStatement = "BEGIN ACCOUNT_PKG.PROCESS_ACTIVITY(); END;";
// Be sure to set the interval long enough to complete processing before
// the next poll
binding.PollingInterval = 15;
// Polling is transactional, be sure to set an adequate isolation level
// for your environment
binding.TransactionIsolationLevel = TransactionIsolationLevel.ReadCommitted;
// Add service endpoint: be sure to specify POLLINGSTMT_OperationGroup as the contract
srvHost.AddServiceEndpoint("POLLINGSTMT_OperationGroup", binding, serviceUri);
Console.WriteLine("Opening the service host");
// Open the service host to begin polling
srvHost.Open();
// Wait to receive request
Console.WriteLine("\nPolling started. Returned records will be written to the console.");
Console.WriteLine("Hit <RETURN> to stop polling");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Exception :" + e.Message);
Console.ReadLine();
/* If there is an Oracle 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 (srvHost.State == CommunicationState.Opened)
srvHost.Close();
else
srvHost.Abort();
}
}
}
}