Recibir notificaciones de cambio de base de datos de Oracle mediante el modelo de servicio WCF1

En este tema se muestra cómo configurar el adaptador de Oracle Database para recibir mensajes de notificación de consulta de una base de datos de Oracle. Para demostrar las notificaciones, considere una tabla, ACCOUNTACTIVITY, con una columna "Procesada". Cuando se inserta un nuevo registro en esta tabla, el valor de la columna Estado se establece en "n". Puede configurar el adaptador para recibir notificaciones registrando notificaciones mediante una instrucción SQL que recupera todos los registros que tienen la columna "Procesado" como "n". Para ello, especifique la instrucción SQL para la propiedad de enlace NotificationStatement . Una vez que el cliente del adaptador recibe la notificación, puede contener la lógica para realizar cualquier tarea posterior en la base de datos de Oracle. En este ejemplo, por motivos de simplicidad, el cliente del adaptador muestra todos los registros de la tabla que tienen la columna "Procesado" como "n".

Configuración de notificaciones con las propiedades de enlace del adaptador de base de datos de Oracle

En la tabla siguiente se resumen las propiedades de enlace del adaptador de Oracle Database que se usan para configurar la recepción de notificaciones de la base de datos de Oracle. Debe especificar estas propiedades de enlace mientras ejecuta la aplicación .NET para recibir notificaciones.

Binding (propiedad) Descripción
InboundOperationType Especifica la operación de entrada que desea realizar. Para recibir mensajes de notificación, establezca esta opción en Notificación.
NotificationPort Especifica el número de puerto que ODP.NET debe abrir para escuchar la notificación de cambio de base de datos de Oracle.
NotificationStatement Especifica la instrucción SELECT usada para registrarse para las notificaciones de consulta. El adaptador obtiene un mensaje de notificación solo cuando cambia el conjunto de resultados de la instrucción SELECT especificada.
NotifyOnListenerStart Especifica si el adaptador envía una notificación a los clientes del adaptador cuando se inicia el agente de escucha.

Para obtener una descripción más completa de estas propiedades, consulte Configuración de las propiedades de enlace para Oracle Database. Para obtener una descripción completa de cómo usar el adaptador de Oracle Database para recibir notificaciones de la base de datos de Oracle, lea más.

Configuración de notificaciones mediante el modelo de servicio WCF

Para recibir las notificaciones mediante el modelo de servicio WCF, debe hacer lo siguiente:

  • Genere un contrato de servicio WCF (interfaz) para la operación de notificación a partir de los metadatos expuestos por el adaptador. Para ello, puede usar el complemento Agregar referencia de servicio de adaptador.

  • Genere un cliente WCF para la operación Select en la tabla ACCOUNTACTIVITY. Para ello, puede usar el complemento Agregar referencia de servicio de adaptador.

  • Implemente un servicio WCF desde esta interfaz.

  • Hospede este servicio WCF mediante un host de servicio (System.ServiceModel.ServiceHost).

El contrato de servicio y la clase WCF

Puede usar el complemento Agregar referencia de servicio de adaptador para crear un contrato de servicio WCF (interfaz) y clases auxiliares para la operación de notificación . Para obtener más información sobre cómo generar un contrato de servicio WCF, vea Generar un cliente WCF o un contrato de servicio WCF para artefactos de la solución oracle Database.

Contrato de servicio WCF (interfaz)

El código siguiente muestra el contrato de servicio WCF (interfaz) generado para la operación de notificación .

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

Contratos de mensaje

A continuación se muestra el contrato de mensaje para la operación de notificación.

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

Clase de servicio WCF

El complemento Add Adapter Service Reference también genera un archivo que tiene un código auxiliar para la clase de servicio WCF implementada desde el contrato de servicio (interfaz). El nombre del archivo es OracleDBBindingService.cs. Puede insertar la lógica para procesar la operación de notificación directamente en esta clase. En el código siguiente se muestra la clase de servicio WCF generada por el complemento 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.");
        }
    }
}

Recepción de notificaciones de cambio de base de datos mediante el modelo de servicio WCF

En esta sección se proporcionan instrucciones sobre cómo escribir una aplicación .NET para recibir notificaciones de consulta mediante el adaptador de Oracle Database.

Para recibir notificaciones de consulta

  1. Use el complemento Agregar referencia de servicio de adaptador para generar un cliente WCF para la operación Select en la tabla ACCOUNTACTIVITY . Usará este cliente para realizar operaciones Select después de recibir un mensaje de notificación. Agregue una nueva clase, TableOperation.cs al proyecto y agregue el siguiente fragmento de código para realizar una operación 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. Use el complemento Agregar referencia de servicio de adaptador para generar un contrato de servicio WCF (interfaz) y clases auxiliares para la operación de notificación .

    Para obtener más información, vea Generar un cliente WCF o un contrato de servicio WCF para artefactos de la solución oracle Database. Opcionalmente, puede especificar las propiedades de enlace al generar el contrato de servicio y las clases auxiliares. Esto garantiza que se establecen correctamente en el archivo de configuración generado.

  3. Implemente un servicio WCF desde la interfaz y las clases auxiliares generadas en el paso 2. El método Notification de esta clase puede producir una excepción para anular la operación, si se encuentra un error al procesar los datos recibidos de la operación notificación ; de lo contrario, el método no devuelve nada. Debe atribuir la clase de servicio WCF de la siguiente manera:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    

    Dentro del método Notification , puede implementar la lógica de la aplicación directamente. Esta clase se puede encontrar en OracleDBBindingService.cs. Este código de este ejemplo subclase la clase OracleDBBindingService . En este código, el mensaje de notificación recibido se escribe en la consola. Además, se invoca el método TableOp dentro de la clase TableOperation para realizar la operación 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. Debe implementar la siguiente clase para pasar las credenciales de la base de datos de Oracle. En la última parte de la aplicación, creará una instancia de esta clase para pasar las credenciales.

    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. Cree un OracleDBBinding y configure el adaptador para recibir notificaciones de consulta especificando las propiedades de enlace. Puede hacerlo explícitamente en el código o mediante declaración en la configuración. Como mínimo, debe especificar las propiedades de enlace InboundOperationType y 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

    El valor de la propiedad de enlace NotificationPort debe establecerse en el mismo número de puerto que debe haber agregado a la lista de excepciones del Firewall de Windows. Para obtener instrucciones sobre cómo agregar puertos a la lista de excepciones del Firewall de Windows, consulte https://go.microsoft.com/fwlink/?LinkId=196959.

    Importante

    Si no establece la propiedad de enlace NotificationPort , el adaptador asume el valor predeterminado de -1 para esta propiedad de enlace. En tal caso, tendrás que deshabilitar completamente firewall de Windows para recibir mensajes de notificación.

  6. Especifique las credenciales de base de datos de Oracle mediante la creación de instancias de la clase NotificationCredentials que creó en el paso 4.

    NotificationCredentials credentials = new NotificationCredentials();
    credentials.UserName.UserName = "SCOTT";
    credentials.UserName.Password = "TIGER";
    
  7. Cree una instancia del servicio WCF creado en el paso 3.

    // create service instance
    NotificationService service = new NotificationService();
    
  8. Cree una instancia de System.ServiceModel.ServiceHost mediante el servicio WCF y un URI de conexión base. También debe especificar las credenciales aquí.

    // Enable service host
    Uri[] baseUri = new Uri[] { new Uri("oracledb://adapter") };
    ServiceHost serviceHost = new ServiceHost(service, baseUri);
    serviceHost.Description.Behaviors.Add(credentials);
    
    
  9. Agregue un punto de conexión de servicio al host de servicio. Para ello, siga estos pasos:

    • Use el enlace creado en el paso 5.

    • Especifique un URI de conexión que contenga credenciales y, si es necesario, un identificador de entrada.

    • Especifique el contrato como "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. Para recibir el mensaje de notificación, abra el host de servicio.

    // Open the service host to begin receiving notifications
    serviceHost.Open();
    
  11. Para dejar de recibir notificaciones, cierre el host del servicio.

    serviceHost.Close();
    

Ejemplo

En el ejemplo siguiente se muestra una aplicación .NET para recibir mensajes de notificación para la tabla ACCOUNTACTIVITY.

Nota

El siguiente fragmento de código crea una instancia de una clase TableOperation.cs e invoca el método TableOp . La clase y el método se describen en el paso 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();
            }

        }
    }
}

Consulte también

Desarrollo de aplicaciones de Oracle Database mediante el modelo de servicio WCF