Condividi tramite


Ricevere notifiche di modifica del database Oracle usando il modello di servizio WCF1

In questo argomento viene illustrato come configurare l'adapter Oracle Database per ricevere messaggi di notifica delle query da un database Oracle. Per illustrare le notifiche, considera una tabella, ACCOUNTACTIVITY, con una colonna "Processato". Quando viene inserito un nuovo record in questa tabella, il valore della colonna Status viene impostato su 'n'. È possibile configurare l'adapter per ricevere notifiche registrando le notifiche usando un'istruzione SQL che recupera tutti i record con la colonna "Processed" come 'n'. A tale scopo, è possibile specificare l'istruzione SQL per la proprietà di associazione NotificationStatement . Dopo che il client dell'adapter riceve la notifica, può contenere la logica per eseguire eventuali attività successive nel database Oracle. In questo esempio, per semplicità, il client dell'adapter elenca tutti i record nella tabella con la colonna "Processed" come 'n'.

Configurazione delle notifiche con le proprietà di associazione dell'adattatore del database Oracle

La tabella seguente riepiloga le proprietà di associazione dell'adapter Oracle Database usate per configurare la ricezione di notifiche dal database Oracle. È necessario specificare queste proprietà di associazione durante l'esecuzione dell'applicazione .NET per ricevere notifiche.

Proprietà di associazione Descrizione
InboundOperationType Specifica l'operazione in ingresso da eseguire. Per ricevere messaggi di notifica, impostare questa opzione su Notifica.
NotificationPort Specifica il numero di porta che ODP.NET deve aprire per ascoltare la notifica di modifica del database dal database Oracle.
NotificationStatement Specifica l'istruzione SELECT utilizzata per registrarsi alle notifiche di query. L'adapter ottiene un messaggio di notifica solo quando cambia il set di risultati per l'istruzione SELECT specificata.
NotifyOnListenerStart Specifica se l'adapter invia una notifica ai client dell'adapter all'avvio del listener.

Per una descrizione più completa di queste proprietà, vedere Configurare le proprietà di associazione per Oracle Database. Per una descrizione completa di come usare l'adapter Oracle Database per ricevere notifiche dal database Oracle, leggere altre informazioni.

Configurazione delle notifiche tramite il modello di servizio WCF

Per ricevere le notifiche usando il modello di servizio WCF, è necessario:

  • Generare un contratto di servizio WCF (interfaccia) per l'operazione di notifica dai metadati esposti dall'adattatore. A tale scopo, è possibile usare il plug-in Aggiungi Riferimento al Servizio Adapter.

  • Generare un client WCF per l'operazione Select nella tabella ACCOUNTACTIVITY. A tale scopo, è possibile usare il plug-in Aggiungi Riferimento al Servizio Adapter.

  • Implementare un servizio WCF da questa interfaccia.

  • Ospitare questo servizio WCF usando un host del servizio (System.ServiceModel.ServiceHost).

Contratto di servizio WCF e classe

È possibile usare il plug-in Add Adapter Service Reference per creare un contratto di servizio WCF (interfaccia) e classi di supporto per l'operazione di notifica . Per altre informazioni sulla generazione di un contratto di servizio WCF, vedere Generare un client WCF o un contratto di servizio WCF per gli artefatti della soluzione Oracle Database.

Contratto di servizio WCF (interfaccia)

Il codice seguente mostra il contratto di servizio WCF (interfaccia) generato per l'operazione di notifica .

[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);
}

Contratti di messaggio

Di seguito è riportato il contratto di messaggio per l'operazione di notifica.

[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;
    }
}

Classe di servizio WCF

Il plug-in Add Adapter Service Reference genera anche un file con uno stub per la classe di servizio WCF implementata dal contratto di servizio (interfaccia). Il nome del file è OracleDBBindingService.cs. È possibile inserire la logica per elaborare l'operazione di notifica direttamente in questa classe. Il codice seguente illustra la classe del servizio WCF generata dal plug-in Add Adapter Service Reference.

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.");
        }
    }
}

Ricezione di notifiche di modifica del database tramite il modello di servizio WCF

Questa sezione contiene istruzioni su come scrivere un'applicazione .NET per ricevere notifiche di query tramite l'adapter Oracle Database.

Per ricevere notifiche di interrogazione

  1. Usare il Plug-in Aggiungi riferimento al servizio adapter al fine di generare un client WCF per operazione Select nella tabella ACCOUNTACTIVITY. Questo client verrà usato per eseguire operazioni Select dopo la ricezione di un messaggio di notifica. Aggiungere una nuova classe, TableOperation.cs al progetto e aggiungere il frammento di codice seguente per eseguire un'operazione 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("********************************************");
            }
        }
    }
    
    
  2. Usare il plug-in Add Adapter Service Reference per generare un contratto di servizio WCF (interfaccia) e classi helper per l'operazione di notifica .

    Per altre informazioni, vedere Generare un client WCF o un contratto di servizio WCF per gli artefatti della soluzione Oracle Database. Facoltativamente, è possibile specificare le proprietà di associazione durante la generazione del contratto di servizio e delle classi di supporto. Ciò garantisce che siano impostati correttamente nel file di configurazione generato.

  3. Implementare un servizio WCF dalle classi di interfaccia e helper generate nel passaggio 2. Il metodo Notification di questa classe può generare un'eccezione per interrompere l'operazione, se si verifica un errore durante l'elaborazione dei dati ricevuti dall'operazione di notifica ; in caso contrario, il metodo non restituisce nulla. È necessario attribuire la classe del servizio WCF come segue:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    

    All'interno del metodo Notification è possibile implementare direttamente la logica dell'applicazione. Questa classe è disponibile in OracleDBBindingService.cs. Questo codice in questa sottoclasse di esempio esegue la classe OracleDBBindingService . In questo codice il messaggio di notifica ricevuto viene scritto nella console. Inoltre, il metodo TableOp all'interno della classe TableOperation viene richiamato per eseguire l'operazione 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();
    
            }
        }
    
  4. Per passare le credenziali per il database Oracle, è necessario implementare la classe seguente. Nella seconda parte dell'applicazione creerai un'istanza di questa classe per passare le credenziali.

    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;
        }
    }
    
  5. Creare un oracleDBBinding e configurare l'adapter per ricevere notifiche di query specificando le proprietà di associazione. È possibile eseguire questa operazione in modo esplicito nel codice o in modo dichiarativo nella configurazione. È necessario specificare almeno le proprietà di associazione InboundOperationType e 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;
    

    Importante

    Il valore della proprietà di associazione NotificationPort deve essere impostato sullo stesso numero di porta che è necessario aggiungere all'elenco delle eccezioni di Windows Firewall. Per istruzioni su come aggiungere porte all'elenco delle eccezioni di Windows Firewall, vedere https://go.microsoft.com/fwlink/?LinkId=196959.

    Importante

    Se non si imposta la proprietà di associazione NotificationPort , l'adapter assumerà il valore predefinito di -1 per questa proprietà di associazione. In questo caso, dovrai disabilitare completamente Windows Firewall per ricevere messaggi di notifica.

  6. Specificare le credenziali del database Oracle creando un'istanza della classe NotificationCredentials creata nel passaggio 4.

    NotificationCredentials credentials = new NotificationCredentials();
    credentials.UserName.UserName = "SCOTT";
    credentials.UserName.Password = "TIGER";
    
  7. Creare un'istanza del servizio WCF creato nel passaggio 3.

    // create service instance
    NotificationService service = new NotificationService();
    
  8. Creare un'istanza di System.ServiceModel.ServiceHost usando il servizio WCF e un URI di connessione di base. È anche necessario specificare le credenziali qui.

    // Enable service host
    Uri[] baseUri = new Uri[] { new Uri("oracledb://adapter") };
    ServiceHost serviceHost = new ServiceHost(service, baseUri);
    serviceHost.Description.Behaviors.Add(credentials);
    
    
  9. Aggiungere un endpoint di servizio all'host del servizio. Per fare questo:

    • Usare l'associazione creata nel passaggio 5.

    • Specificare un URI di connessione contenente le credenziali e, se necessario, un ID in ingresso.

    • Specificare il contratto come "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);
      
  10. Per ricevere un messaggio di notifica, aprire l'host del servizio.

    // Open the service host to begin receiving notifications
    serviceHost.Open();
    
  11. Per interrompere la ricezione delle notifiche, chiudere l'host del servizio.

    serviceHost.Close();
    

Esempio

L'esempio seguente illustra un'applicazione .NET per ricevere messaggi di notifica per la tabella ACCOUNTACTIVITY.

Annotazioni

Il frammento di codice seguente crea un'istanza di una classe TableOperation.cs e richiama il metodo TableOp . La classe e il metodo sono descritti nel passaggio 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();
            }

        }
    }
}

Vedere anche

Sviluppare applicazioni Oracle Database usando il modello di servizio WCF