Compartir vía


Recibir notificaciones de consulta de SQL mediante el modelo de servicio WCF

En este tema se muestra cómo configurar el adaptador de SQL para recibir mensajes de notificación de consulta de una base de datos de SQL Server. Para mostrar las notificaciones, considere una tabla, Employee, con una columna "Status". Cuando se inserta un nuevo registro en esta tabla, el valor de la columna Estado se establece en 0. Puede configurar el adaptador para recibir notificaciones registrando notificaciones mediante una instrucción SQL que recupera todos los registros que tienen la columna Estado como "0". 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 SQL Server. En este ejemplo, por motivos de simplicidad, el cliente del adaptador muestra todos los registros de la tabla que tienen la columna Estado como "0".

Nota:

Si está realizando operaciones en tablas que tienen columnas de tipos definidos por el usuario, asegúrese de hacer referencia a Operaciones en tablas y vistas con tipos definidos por el usuario mediante el tema adaptador de SQL antes de empezar a desarrollar la aplicación.

Configuración de notificaciones con las propiedades de enlace del adaptador de SQL

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

Propiedad de enlace Descripción
InboundOperationType Especifica la operación de entrada que desea realizar. Para recibir mensajes de notificación, establézcalo en Notificación.
NotificationStatement Especifica la instrucción SQL (SELECT o EXEC <procedimiento almacenado>) que se utiliza para registrarse en las notificaciones de consulta. El adaptador obtiene un mensaje de notificación de SQL Server solo cuando cambia el conjunto de resultados de la instrucción SQL 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, vea Leer acerca del adaptador de BizTalk para las propiedades de enlace del adaptador de SQL Server. Para obtener una descripción completa de cómo usar el adaptador de SQL para recibir notificaciones de SQL Server, lea más adelante.

Configuración de notificaciones mediante el modelo de servicio WCF

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

  1. 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.

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

  3. Implemente un servicio WCF desde esta interfaz.

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

Acerca de los ejemplos usados en este tema

Los ejemplos de este tema reciben notificaciones para la tabla de empleados. Se proporciona un script para generar la tabla con los ejemplos. Para obtener más información sobre los ejemplos, vea Ejemplos para el adaptador de SQL. También se proporciona un ejemplo, Notification_ServiceModel, que se basa en este tema, con los ejemplos del adaptador de SQL.

El contrato de servicio WCF y la clase

Puede usar el complemento "Add Adapter Service Reference" para crear un contrato de servicio WCF (interfaz) y clases auxiliares para la operación 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 SQL Server.

El 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://schemas.microsoft.com/Sql/2008/05/", ConfigurationName="NotificationOperation")]
public interface NotificationOperation {

    // CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/Sql/2008/05/Notification/) of message
    // Notification does not match the default value (https://schemas.microsoft.com/Sql/2008/05/)
    [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="Notification")]
    void Notification(Notification request);
}

Contratos de mensajes

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://schemas.microsoft.com/Sql/2008/05/Notification/", IsWrapped=true)]
public partial class Notification {

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/Notification/", Order=0)]
    public string Info;

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/Notification/", Order=1)]
    public string Source;

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/Notification/", Order=2)]
    public string Type;

    public Notification() {
    }

    public Notification(string Info, string Source, string Type) {
        this.Info = Info;
        this.Source = Source;
        this.Type = Type;
    }
}

Clase de servicio WCF

El complemento Add Adapter Service Reference también genera un archivo que contiene un stub para la clase de servicio WCF implementada desde el contrato de servicio (interfaz). El nombre del archivo es SqlAdapterBindingService.cs. Puede insertar la lógica para procesar la operación de notificación directamente en esta clase. El código siguiente muestra la clase de servicio WCF generada por el complemento Agregar referencia de servicio de adaptador.

namespace SqlAdapterBindingNamespace {

    public class SqlAdapterBindingService : NotificationOperation {

        // CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/Sql/2008/05/Notification/)
        // of message Notification does not match the default value (https://schemas.microsoft.com/Sql/2008/05/)
        public virtual void Notification(Notification request) {
            throw new System.NotImplementedException("The method or operation is not implemented.");
        }
    }
}

Recepción de notificaciones de consulta 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 SQL.

Para recibir notificaciones de consulta

  1. Utilice el complemento Agregar Referencia de Servicio de Adaptador para generar un cliente WCF para la operación Select en la tabla Employee. 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
    {
        public class TableOperation
        {
            public void TableOp()
            {
                ///////////////////////////////////////////////////////////////////////
                // CREATING THE CLIENT
                ///////////////////////////////////////////////////////////////////////
    
                TableOp_dbo_EmployeeClient client = new TableOp_dbo_EmployeeClient("SqlAdapterBinding_TableOp_dbo_Employee");
    
                client.ClientCredentials.UserName.UserName = "<Enter user name here>";
                client.ClientCredentials.UserName.Password = "<Enter password here>";
    
                ///////////////////////////////////////////////////////////////////////
                // OPENING THE CLIENT
                ///////////////////////////////////////////////////////////////////////
    
                try
                {
                    Console.WriteLine("Opening Client...");
                    client.Open();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                    throw;
                }
    
                ///////////////////////////////////////////////////////////////////////
                // SELECTING THE LAST INSERTED RECORD FROM THE TABLE
                ///////////////////////////////////////////////////////////////////////
                schemas.microsoft.com.Sql._2008._05.Types.Tables.dbo.Employee[] selectRecords;
    
                try
                {
                    selectRecords = client.Select("*", "where Status=0");
                }
    
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                    throw;
                }
    
                Console.WriteLine("The details of the newly added employee are:");
                Console.WriteLine("********************************************");
                for (int i = 0; i < selectRecords.Length; i++)
                {
                    Console.WriteLine("Employee Name      : " + selectRecords[i].Name);
                    Console.WriteLine("Employee Designation: " + selectRecords[i].Designation);
                    Console.WriteLine("Employee Status    : " + selectRecords[i].Status);
                    Console.WriteLine();
                }
                Console.WriteLine("********************************************");
    
    

    Importante

    Dado que este fragmento de código realiza operaciones en la tabla Employee que contiene una columna UDT point, asegúrese de colocar el archivo DLL de UDT en la carpeta \bin\Debug del proyecto mientras ejecuta la aplicación.

  2. Utilice el complemento Add Adapter Service Reference (Agregar referencia de servicio de adaptador) para generar un contrato de servicio WCF (interfaz) y clases auxiliares para la operación Notification.

    Para obtener más información, vea Generar un cliente WCF o un contrato de servicio WCF para artefactos de SQL Server. De manera opcional, 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 produce 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 SqlAdapterBindingService.cs. Este código de este ejemplo subclase la clase SqlAdapterBindingService . 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 : SqlAdapterBindingNamespace.SqlAdapterBindingService
    {
        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("*************************************************");
    
            // Invoke th TableOp method in the TableOperation class
            TableOperation Ops = new TableOperation();
            Ops.TableOp();
        }
    }
    
  4. Dado que el adaptador de SQL no acepta credenciales como parte del URI de conexión, debe implementar la siguiente clase para pasar las credenciales de la base de datos de SQL Server. En la última parte de la aplicación, creará una instancia de esta clase para pasar las credenciales de SQL Server.

    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 sqlAdapterBinding 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 .

    SqlAdapterBinding binding = new SqlAdapterBinding();
    binding.InboundOperationType = InboundOperation.Notification;
    binding.NotificationStatement = "SELECT Employee_ID, Name FROM dbo.Employee WHERE Status=0";
    binding.NotifyOnListenerStart = true;
    
  6. Especifique las credenciales de base de datos de SQL Server mediante la creación de instancias de la clase NotificationCredentials que creó en el paso 4.

    NotificationCredentials credentials = new NotificationCredentials();
    credentials.UserName.UserName = "<Enter user name here>";
    credentials.UserName.Password = "<Enter password here>";
    
  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("mssql://mysqlserver//mydatabase") };
    ServiceHost serviceHost = new ServiceHost(service, baseUri);
    serviceHost.Description.Behaviors.Add(credentials);
    
    
  9. Agregue un punto de conexión al host del servicio. Para ello, siga estos pasos:

    • Usa la vinculación creada 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 "NotificationOperation".

      // Add service endpoint: be sure to specify NotificationOperation as the contract
      Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");
      serviceHost.AddServiceEndpoint("NotificationOperation", binding, ConnectionUri);
      
  10. Para recibir el mensaje de notificación, abra el host del 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 Employee.

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.Sql;
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 : SqlAdapterBindingNamespace.SqlAdapterBindingService
    {
        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
            {
                SqlAdapterBinding binding = new SqlAdapterBinding();
                binding.InboundOperationType = InboundOperation.Notification;
                binding.NotificationStatement = "SELECT Employee_ID, Name FROM dbo.Employee WHERE Status=0";
                binding.NotifyOnListenerStart = true;

                // This URI is used to specify the address for the ServiceEndpoint
                // It must contain the InboundId (if any) that was used to generate
                // the WCF service callback interface
                Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");

                // This URI is used to initialize the ServiceHost. It cannot contain
                // a query_string (InboundID); otherwise,an exception is thrown when
                // the ServiceHost is initialized.
                Uri[] baseUri = new Uri[] { new Uri("mssql://mysqlserver//mydatabase") };

                NotificationCredentials credentials = new NotificationCredentials();
                credentials.UserName.UserName = "<Enter user name here>";
                credentials.UserName.Password = "<Enter password here>";

                Console.WriteLine("Opening service host...");
                NotificationService service = new NotificationService();
                serviceHost = new ServiceHost(service, baseUri);
                serviceHost.Description.Behaviors.Add(credentials);
                serviceHost.AddServiceEndpoint("NotificationOperation", 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 receiving notifications
                if (serviceHost.State == CommunicationState.Opened)
                    serviceHost.Close();
                else
                    serviceHost.Abort();
            }
        }
    }
}

Véase también

Desarrollo de aplicaciones SQL mediante el modelo de servicio WCF