本主題示範如何設定 Oracle 資料庫配接器,以接收來自 Oracle 資料庫的查詢通知訊息。 若要示範通知,請考慮一個名為 ACCOUNTACTIVITY 的資料表,其中有一個「已處理」欄。 將新記錄插入此數據表時,Status 資料行的值會設定為 『n』。 您可以使用 SQL 語句來註冊通知,以設定配接器接收通知,這樣可以擷取所有「Processed」欄位為『n』的記錄。 您可以指定 NotificationStatement 系結 屬性的 SQL 語句來執行此動作。 配接器用戶端收到通知后,它可以包含邏輯,以在 Oracle 資料庫上執行任何後續工作。 在此範例中,為了簡單起見,配接器用戶端會列出數據表中具有 「Processed」 資料行的所有記錄為 『n』。
使用 Oracle 資料庫配接器綁定屬性設定通知
下表摘要說明您用來設定從 Oracle 資料庫接收通知的 Oracle Database 配接器系結屬性。 您必須在執行 .NET 應用程式時指定這些系結屬性,才能接收通知。
| 綁定屬性 | 說明 |
|---|---|
| InboundOperationType | 指定您要執行的輸入作業。 若要接收通知訊息,請將此設定為 [通知]。 |
| NotificationPort | 指定 ODP.NET 必須開啟的埠號碼,以接聽 Oracle 資料庫中的資料庫變更通知。 |
| NotificationStatement | 指定用來註冊查詢通知的SELECT語句。 只有在指定 SELECT 語句的結果集變更時,配接器才會取得通知訊息。 |
| NotifyOnListenerStart | 指定當接聽程序啟動時,配接器是否傳送通知給配接器用戶端。 |
如需這些屬性的更完整描述,請參閱 設定 Oracle 資料庫的系結屬性。 如需如何使用 Oracle 資料庫配接器從 Oracle 資料庫接收通知的完整描述,請閱讀進一步。
使用 WCF 服務模型設定通知
若要使用 WCF 服務模型接收通知,您必須:
從配接器所公開的元數據產生 通知 作業的 WCF 服務合約(介面)。 若要這樣做,您可以使用 [新增配接器服務參考外掛程式]。
在 ACCOUNTACTIVITY 數據表上產生 Select 作業的 WCF 用戶端。 若要這樣做,您可以使用 [新增配接器服務參考外掛程式]。
從這個介面實作 WCF 服務。
使用服務主機裝載此 WCF 服務(System.ServiceModel.ServiceHost)。
WCF 服務合約和類別
您可以使用新增配接器服務參考外掛程式來建立 WCF 服務合約(介面)和支援 通知 作業的類別。 如需產生 WCF 服務合約的詳細資訊,請參閱 產生 WCF 用戶端或 Oracle 資料庫解決方案成品的 WCF 服務合約。
WCF 服務合約 (介面)
下列程式代碼顯示針對 通知 作業產生的 WCF 服務合約(介面)。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03", ConfigurationName="Notification_OperationGroup")]
public interface Notification_OperationGroup {
// CODEGEN: Generating message contract since the wrapper namespace (http://Microsoft.LobServices.OracleDB/2007/03/Notification/) of message Notification
// does not match the default value (http://Microsoft.LobServices.OracleDB/2007/03)
[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://Microsoft.LobServices.OracleDB/2007/03/Notification")]
void Notification(Notification request);
}
訊息合約
以下是通知作業的訊息合約。
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Notification", WrapperNamespace="http://Microsoft.LobServices.OracleDB/2007/03/Notification/", IsWrapped=true)]
public partial class Notification {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03/Notification/", Order=0)]
public microsoft.lobservices.oracledb._2007._03.Notification.NotificationDetails[] Details;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03/Notification/", Order=1)]
public string Info;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03/Notification/", Order=2)]
public string[] ResourceNames;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03/Notification/", Order=3)]
public string Source;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.OracleDB/2007/03/Notification/", Order=4)]
public string Type;
public Notification() {
}
public Notification(microsoft.lobservices.oracledb._2007._03.Notification.NotificationDetails[] Details, string Info, string[] ResourceNames, string Source, string Type) {
this.Details = Details;
this.Info = Info;
this.ResourceNames = ResourceNames;
this.Source = Source;
this.Type = Type;
}
}
WCF 服務類別
[新增配接器服務參考外掛程式] 也會產生一個檔案,其中包含根據服務合約 (介面) 所建立的 WCF 服務類別的存根。 檔案的名稱是OracleDBBindingService.cs。 您可以將處理 通知 作業的邏輯直接插入到此類別中。 下列程式代碼顯示新增配接器服務參考外掛程式所產生的 WCF 服務類別。
namespace OracleDBBindingNamespace {
public class OracleDBBindingService : Notification_OperationGroup {
// CODEGEN: Generating message contract since the wrapper namespace (http://Microsoft.LobServices.OracleDB/2007/03/Notification/) of message Notification
// does not match the default value (http://Microsoft.LobServices.OracleDB/2007/03)
public virtual void Notification(Notification request) {
throw new System.NotImplementedException("The method or operation is not implemented.");
}
}
}
使用 WCF 服務模型接收資料庫變更通知
本節提供如何使用 Oracle 資料庫配接器撰寫 .NET 應用程式以接收查詢通知的指示。
接收查詢通知
使用 [新增配接器服務參考外掛程式],在 ACCOUNTACTIVITY 數據表上產生 SELECT 作業的 WCF 用戶端。 您將使用此用戶端在收到通知訊息之後執行 Select 作業。 將新的類別TableOperation.cs新增至您的專案,並新增下列代碼段來執行 Select 作業。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Notification_ServiceModel { class TableOperation { public void TableOp() { ////////////////////////////////////////////////////////////////////// // CREATING THE CLIENT AND SETTING CLIENT CREDENTIALS ////////////////////////////////////////////////////////////////////// SCOTT_Table_ACCOUNTACTIVITYClient client = new SCOTT_Table_ACCOUNTACTIVITYClient("OracleDBBinding_SCOTT_Table_ACCOUNTACTIVITY"); client.ClientCredentials.UserName.UserName = "SCOTT"; client.ClientCredentials.UserName.Password = "TIGER"; //////////////////////////////////////////////////////////////////// // OPENING THE CLIENT ////////////////////////////////////////////////////////////////////// try { Console.WriteLine("Opening the client ..."); client.Open(); } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); throw; } //////////////////////////////////////////////////////////////////////////////////////// // SELECTING THE LAST INSERTED VALUE //////////////////////////////////////////////////////////////////////////////////////// Console.WriteLine("The application will now select the last inserted record"); microsoft.lobservices.oracledb._2007._03.SCOTT.Table.ACCOUNTACTIVITY.ACCOUNTACTIVITYRECORDSELECT[] selectRecords; try { selectRecords = client.Select("*", "WHERE PROCESSED = 'n'"); } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); throw; } Console.WriteLine("The details of the newly added records are:"); Console.WriteLine("********************************************"); for (int i = 0; i < selectRecords.Length; i++) { Console.WriteLine("Transaction ID : " + selectRecords[i].TID); Console.WriteLine("Account ID : " + selectRecords[i].ACCOUNT); Console.WriteLine("Processed Status : " + selectRecords[i].PROCESSED); Console.WriteLine(); } Console.WriteLine("********************************************"); } } }使用 [新增配接器服務參考外掛程式] 來產生 通知 作業的 WCF 服務合約(介面)和協助程序類別。
如需詳細資訊,請參閱 產生 ORACLE 資料庫解決方案成品的 WCF 用戶端或 WCF 服務合約。 您可以選擇性地指定繫結屬性,在產生服務合約和輔助類別時。 這可確保它們已正確設定在產生的組態檔中。
從步驟 2 中產生的介面和協助程式類別實作 WCF 服務。 如果發生錯誤處理從通知作業收到的數據,這個類別的 Notification 方法可能會擲回例外狀況來中止作業;否則方法不會傳回任何專案。 請按照以下方式設定 WCF 服務類別的屬性:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]在 Notification 方法內,您可以直接實作應用程式邏輯。 您可以在 OracleDBBindingService.cs 中找到這個類別。 此範例程式碼會將 OracleDBBindingService 類別進行子類化。 在此程式代碼中,收到的通知訊息會寫入主控台。 此外,會叫用 TableOperation 類別內的 TableOp 方法來執行 Select 作業。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class NotificationService : OracleDBBindingNamespace.OracleDBBindingService { public override void Notification(Notification request) { Console.WriteLine("\nNew Notification Received"); Console.WriteLine("*************************************************"); Console.WriteLine(request.Info); Console.WriteLine(request.Source); Console.WriteLine(request.Type); Console.WriteLine("*************************************************"); TableOperation Ops = new TableOperation(); Ops.TableOp(); } }您必須實作下列類別,才能傳遞 Oracle 資料庫的認證。 在應用程式的後一個部分中,您將具現化此類別以傳遞認證。
class NotificationCredentials : 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 NotificationCredentials(); clone.UserName.UserName = this.UserName.UserName; clone.UserName.Password = this.UserName.Password; return clone; } }建立 OracleDBBinding ,並藉由指定系結屬性來設定配接器以接收查詢通知。 您可以在程式代碼中明確執行此動作,或在組態中以宣告方式執行此動作。 您至少必須指定 InboundOperationType 和 NotificationStatement 系結 屬性。
OracleDBBinding binding = new OracleDBBinding(); binding.InboundOperationType = InboundOperation.Notification; binding.NotificationStatement = "SELECT TID,ACCOUNT,PROCESSED FROM APPS.ACCOUNTACTIVITY WHERE PROCESSED = 'n'"; binding.NotifyOnListenerStart = true; binding.NotificationPort = 10;這很重要
NotificationPort 系結屬性的值必須設定為與您已經新增至 Windows 防火牆例外清單的相同埠號碼。 如需如何將埠新增至 Windows 防火牆例外狀況清單的指示,請參閱 https://go.microsoft.com/fwlink/?LinkId=196959。
這很重要
如果您未設定 NotificationPort 系結屬性,配接器會假設此系結屬性的預設值為 -1。 在這種情況下,您必須完全停用 Windows 防火牆以接收通知訊息。
藉由具現化您在步驟 4 中建立的 NotificationCredentials 類別,指定 Oracle 資料庫認證。
NotificationCredentials credentials = new NotificationCredentials(); credentials.UserName.UserName = "SCOTT"; credentials.UserName.Password = "TIGER";建立在步驟 3 中建立之 WCF 服務的實例。
// create service instance NotificationService service = new NotificationService();使用 WCF 服務和基底連線 URI 建立 System.ServiceModel.ServiceHost 的實例。 您也必須在這裡指定認證。
// Enable service host Uri[] baseUri = new Uri[] { new Uri("oracledb://adapter") }; ServiceHost serviceHost = new ServiceHost(service, baseUri); serviceHost.Description.Behaviors.Add(credentials);將服務端點新增至服務主機。 要達成此目的:
使用在步驟 5 中建立的系結。
指定包含認證的連線 URI,並視需要指定輸入識別碼。
將合約指定為 「Notification_OperationGroup」。
// Add service endpoint: be sure to specify Notification_OperationGroup as the contract Uri ConnectionUri = new Uri("oracledb://adapter"); serviceHost.AddServiceEndpoint("Notification_OperationGroup", binding, ConnectionUri);
若要接收通知訊息,請開啟服務主機。
// Open the service host to begin receiving notifications serviceHost.Open();若要停止接收通知,請關閉服務主機。
serviceHost.Close();
範例
下列範例示範 .NET 應用程式,以接收 ACCOUNTACTIVITY 數據表的通知訊息。
備註
下列代碼段會具現化 TableOperation.cs 類別,並叫用 TableOp 方法。 類別和 方法會在步驟 1 中說明。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Adapters.OracleDB;
using Microsoft.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Collections.ObjectModel;
namespace Notification_ServiceModel
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class NotificationService : OracleDBBindingNamespace.OracleDBBindingService
{
public override void Notification(Notification request)
{
Console.WriteLine("\nNew Notification Received");
Console.WriteLine("*************************************************");
Console.WriteLine(request.Info);
Console.WriteLine(request.Source);
Console.WriteLine(request.Type);
Console.WriteLine("*************************************************");
TableOperation Ops = new TableOperation();
Ops.TableOp();
}
}
class NotificationCredentials : 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 NotificationCredentials();
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 receiving notifications...");
Console.ReadLine();
OracleDBBinding binding = new OracleDBBinding();
binding.InboundOperationType = InboundOperation.Notification;
binding.NotificationStatement = "SELECT TID,ACCOUNT,PROCESSED FROM APPS.ACCOUNTACTIVITY WHERE PROCESSED = 'n'";
binding.NotifyOnListenerStart = true;
binding.NotificationPort = 10;
// 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("oracledb://adapter");
// This URI is used to initialize the ServiceHost. It cannot contain
// an InboundID; otherwise,an exception is thrown when
// the ServiceHost is initialized.
Uri[] baseUri = new Uri[] { new Uri("oracledb://adapter") };
NotificationCredentials credentials = new NotificationCredentials();
credentials.UserName.UserName = "SCOTT";
credentials.UserName.Password = "TIGER";
Console.WriteLine("Opening service host...");
NotificationService service = new NotificationService();
serviceHost = new ServiceHost(service, baseUri);
serviceHost.Description.Behaviors.Add(credentials);
serviceHost.AddServiceEndpoint("Notification_OperationGroup", binding, ConnectionUri);
serviceHost.Open();
Console.WriteLine("Service host opened...");
Console.WriteLine("Waiting for notification...");
Console.WriteLine("\nHit <RETURN> to stop receiving notification");
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();
}
}
}
}