WCF サービス モデルを使用して Oracle データベース変更通知を受信する1
このトピックでは、Oracle データベース からクエリ通知メッセージを受信するように Oracle Database アダプターを構成する方法について説明します。 通知を示すために、"処理済み" 列を含むテーブル ACCOUNTACTIVITY を検討してください。 このテーブルに新しいレコードが挿入されると、Status 列の値は 'n' に設定されます。 "Processed" 列を持つすべてのレコードを 'n' として取得する SQL ステートメントを使用して通知を登録することで、通知を受信するようにアダプターを構成できます。 これを行うには、 NotificationStatement バインド プロパティに SQL ステートメントを指定します。 アダプター クライアントは、通知を受信すると、Oracle データベースで後続のタスクを実行するロジックを含めることができます。 この例では、わかりやすくするために、アダプター クライアントは、"Processed" 列が "n" であるテーブル内のすべてのレコードを一覧表示します。
Oracle データベース アダプターのバインド プロパティを使用した通知の構成
次の表は、Oracle データベースからの通知の受信を構成するために使用する Oracle Database アダプター のバインド プロパティをまとめたものです。 通知を受信するには、.NET アプリケーションの実行中にこれらのバインド プロパティを指定する必要があります。
Binding プロパティ | 説明 |
---|---|
InboundOperationType | 実行する受信操作を指定します。 通知メッセージを受信するには、これを [通知] に設定します。 |
NotificationPort | Oracle データベースからのデータベース変更通知をリッスンするために ODP.NET 開く必要があるポート番号を指定します。 |
NotificationStatement | クエリ通知の登録に使用する SELECT ステートメントを指定します。 アダプターは、指定された SELECT ステートメントの結果セットが変更された場合にのみ通知メッセージを取得します。 |
NotifyOnListenerStart | リスナーの起動時にアダプターがアダプター クライアントに通知を送信するかどうかを指定します。 |
これらのプロパティの詳細については、「 Oracle Database のバインド プロパティを構成する」を参照してください。 Oracle データベース アダプターを使用して Oracle データベースから通知を受信する方法の詳細については、詳細を参照してください。
WCF サービス モデルを使用した通知の構成
WCF サービス モデルを使用して通知を受信するには、次の手順を実行する必要があります。
アダプターによって公開されるメタデータから 、通知 操作の WCF サービス コントラクト (インターフェイス) を生成します。 これを行うには、アダプター サービス参照の追加プラグインを使用できます。
ACCOUNTACTIVITY テーブルの Select 操作用の WCF クライアントを生成します。 これを行うには、アダプター サービス参照の追加プラグインを使用できます。
このインターフェイスから WCF サービスを実装します。
サービス ホスト (System.ServiceModel.ServiceHost) を使用して、この WCF サービスをホストします。
WCF サービス コントラクトとクラス
アダプター サービス参照の追加プラグインを使用して、WCF サービス コントラクト (インターフェイス) と 通知 操作のサポート クラスを作成できます。 WCF サービス コントラクトの生成の詳細については、「 Oracle Database ソリューション成果物の WCF クライアントまたは WCF サービス コントラクトを生成する」を参照してください。
WCF サービス コントラクト (インターフェイス)
次のコードは、 Notification 操作用に生成された 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 Database アダプターを使用してクエリ通知を受信する .NET アプリケーションを作成する方法について説明します。
クエリ通知を受信するには
アダプター サービス参照の追加プラグインを使用して、ACCOUNTACTIVITY テーブルに対する選択操作用の 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 Database ソリューション成果物の WCF クライアントまたは WCF サービス コントラクトを生成する」を参照してください。 必要に応じて、サービス コントラクトとヘルパー クラスの生成中にバインド プロパティを指定できます。 これにより、生成された構成ファイルに正しく設定されます。
手順 2 で生成されたインターフェイス クラスとヘルパー クラスから WCF サービスを実装します。 このクラスの Notification メソッドは、 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 で作成したバインディングを使用します。
資格情報と必要に応じて受信 ID を含む接続 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();
例
次の例は、ACCOUNTACTIVITY テーブルの通知メッセージを受信する .NET アプリケーションを示しています。
Note
次のコード スニペットは 、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();
}
}
}
}