Condividi tramite


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

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

Configurazione delle notifiche con le proprietà di associazione dell'adapter di 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.

Binding, proprietà 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 essere aperto per ascoltare la notifica di modifica del database dal database Oracle.
NotificaStatement Specifica l'istruzione SELECT usata per registrare le notifiche di query. L'adapter ottiene un messaggio di notifica solo quando il set di risultati per l'istruzione SELECT specificato cambia.
NotifyOnListenerStart Specifica se l'adapter invia una notifica ai client dell'adapter quando viene avviato il 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 ulteriormente.

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 dalla scheda. A tale scopo, è possibile usare il plug-in Aggiungi plug-in del servizio adapter.

  • Generare un client WCF per l'operazione Select nella tabella ACCOUNTACTIVITY. A tale scopo, è possibile usare il plug-in Aggiungi plug-in del servizio adapter.

  • Implementare un servizio WCF da questa interfaccia.

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

Contratto e classe del servizio WCF

È possibile usare il plug-in Add Adapter Service Reference per creare un contratto di servizio WCF (interfaccia) e le 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 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 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 mostra la classe di 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 fornisce istruzioni su come scrivere un'applicazione .NET per ricevere notifiche di query usando l'adapter Oracle Database.

Per ricevere notifiche di query

  1. Usare il plug-in Add Adapter Service Reference per generare un client WCF per Selezionare l'operazione nella tabella ACCOUNTACTIVITY . Questo client verrà usato per eseguire operazioni Select dopo aver ricevuto 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 le 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 di classi del contratto di servizio e helper. Ciò garantisce che siano impostate 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 viene rilevato un errore durante l'elaborazione dei dati ricevuti dall'operazione di notifica ; in caso contrario, il metodo non restituisce nulla. È necessario specificare la classe di servizio WCF come indicato di seguito:

    [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. È necessario implementare la classe seguente per passare le credenziali per il database Oracle. Nella seconda parte dell'applicazione verrà creata 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. Almeno, è necessario specificare 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 eccezioni di Windows Firewall. Per istruzioni su come aggiungere porte all'elenco eccezioni di Windows Firewall, vedere https://go.microsoft.com/fwlink/?LinkId=196959.

    Importante

    Se non si imposta la proprietà di associazione NotificationPort , l'adapter presuppone il valore predefinito di -1 per questa proprietà di associazione. In tal caso, sarà necessario 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 creata 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 eseguire questa operazione:

    • 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 il messaggio di notifica, aprire l'host del servizio.

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

    serviceHost.Close();
    

Esempio

Nell'esempio seguente viene illustrata un'applicazione .NET per ricevere messaggi di notifica per la tabella ACCOUNTACTIVITY.

Nota

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 di database Oracle usando il modello di servizio WCF