使用 WCF 服務模型接收 Oracle 資料庫變更通知1
本主題示範如何設定 Oracle Database 配接器,以接收來自 Oracle 資料庫的查詢通知訊息。 若要示範通知,請考慮具有 「已處理」資料行的資料表 ACCOUNTACTIVITY。 當新記錄插入此資料表時,Status 資料行的值會設定為 'n'。 您可以使用 SQL 語句來擷取具有 「Processed」 資料行的所有記錄 'n' 來註冊通知,以設定配接器以接收通知。 您可以藉由指定 NotificationStatement 系結屬性的 SQL 語句來執行此動作。 配接器用戶端收到通知之後,它可以包含邏輯,以在 Oracle 資料庫上執行任何後續工作。 在此範例中,為了簡單起見,配接器用戶端會列出資料表中具有 「Processed」 資料行的所有記錄為 'n'。
使用 Oracle 資料庫配接器系結屬性設定通知
下表摘要說明您用來設定從 Oracle 資料庫接收通知的 Oracle 資料庫配接器系結屬性。 您必須在執行 .NET 應用程式時指定這些系結屬性,才能接收通知。
Binding 屬性 | Description |
---|---|
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 服務模型接收資料庫變更通知
本節提供如何撰寫 .NET 應用程式以使用 Oracle 資料庫配接器接收查詢通知的指示。
接收查詢通知
使用 [新增配接器服務參考外掛程式],在ACCOUNTACTIVITY資料表上產生選取作業的 WCF 用戶端。 您將使用此用戶端在收到通知訊息之後執行 Select 作業。 將新的類別 TableOperation.cs 新增至專案,並新增下列程式碼片段來執行選取作業。
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();
}
}
}
}