使用 WCF 服務模型在 Oracle 資料庫中接收輪詢型資料變更訊息
您可以設定 Microsoft BizTalk Adapter for Oracle Database,針對 Oracle 資料表或檢視接收輪詢型資料變更訊息。 若要接收資料變更的訊息,配接器會定期針對 Oracle 資料表或檢視執行 SQL 查詢,後面接著選擇性的 PL/SQL 程式碼區塊。 然後,Oracle Database 配接器會將 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 服務模型中設定輪詢
您可以設定 Oracle Database 配接器,以在 Oracle 資料庫資料表和檢視表上執行輪詢,方法是設定系結屬性和選擇性連接屬性 (參數) 。 其中有些屬性是必要屬性,有些屬性必須同時在設計階段和執行時間設定。
在設計階段,當您連線到 Oracle 資料庫以產生 WCF 服務合約時,您可以設定連接參數和系結屬性。
在執行時間,您會在用來建立服務主機的 OracleDBBinding 物件上設定系結屬性。 當您將服務接聽程式新增至服務主機時,您可以設定連接參數。
下列清單提供用來設定輪詢之系結屬性和連接參數的簡短概觀:
PollingStatement系結屬性。 您必須在設計階段和執行時間設定這個系結屬性。
選擇性的系結屬性。 這些只需要在執行時間設定。
AcceptCredentialsInUri系結屬性。 如果您想要在連線 URI 中啟用認證,則必須在執行時間期間將此系結屬性設定為 true 。 當您將服務端點新增至服務主機時,使用者名稱和密碼必須存在於連線 URI 中。
連線 URI 中的 PollingId 查詢字串參數。 如果您想要變更 POLLINGSTMT 作業的命名空間,則必須在設計階段和執行時間設定此連接屬性。
如需用來設定輪詢之系結屬性和連接參數的完整描述,請參閱 在 Oracle 資料庫配接器中接收輪詢型資料變更訊息。
WCF 服務合約和類別
您可以使用新增配接器服務參考 Visual Studio 外掛程式或 ServiceModel 中繼資料公用程式工具 (svcutil.exe) 來建立 WCF 服務合約, (介面) 和支援 POLLINGSTMT 作業的類別。
當您使用下列任一工具來連線到 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 作業的命名空間會藉由將連線 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();
}
}
}
}