Freigeben über


Empfangen von datenändernden Nachrichten auf Abrufbasis vom SQL Server mithilfe des WCF-Dienstmodells

Sie können den SQL-Adapter so konfigurieren, dass regelmäßige Datenänderungsmeldungen für SQL Server-Tabellen oder -Ansichten empfangen werden. Sie können eine Abfrage-Anweisung angeben, die der Adapter ausführt, um die Datenbank abzufragen. Die Abfrage-Anweisung kann eine SELECT-Anweisung oder eine gespeicherte Prozedur sein, die eine Ergebnismenge zurückgibt.

Weitere Informationen dazu, wie der Adapter Abruf unterstützt, finden Sie unter Abrufen in SQL Server mithilfe des SQL-Adapters.

Hinweis

In diesem Thema wird gezeigt, wie der Polling-Vorgang genutzt wird, um Polling-Nachrichten zu verwenden. Die Nachricht für die Abfrageoperation ist nicht stark typisiert. Wenn Sie eine stark typisierte Abfrage-Nachricht erhalten möchten, müssen Sie den TypedPolling-Vorgang verwenden. Sie müssen außerdem den TypedPolling-Vorgang verwenden, um in einer einzigen Anwendung mehrere Abrufvorgänge durchzuführen. Anweisungen zum Ausführen des TypedPolling-Vorgangs finden Sie unter Empfangen von Nachrichten mit geänderten Daten, die stark typisiert und Polling-basiert von SQL Server mithilfe des WCF-Dienstmodells empfangen werden.

Von Bedeutung

Wenn Sie mehr als einen Abrufvorgang in einer einzelnen Anwendung ausführen möchten, müssen Sie eine InboundID-Verbindungseigenschaft als Teil des Verbindungs-URI angeben, um ihn eindeutig zu machen. Die von Ihnen angegebene eingehende ID wird dem Vorgangsnamespace hinzugefügt, um sie eindeutig zu machen.

Wie in diesem Thema die Abfrage veranschaulicht wird

In diesem Thema erfahren Sie, wie der SQL-Adapter den Empfang von Datenänderungsmeldungen unterstützt, indem Sie eine .NET-Anwendung erstellen und den WCF-Dienstvertrag für den Abrufvorgang generieren. Wenn Sie beim Generieren des WCF-Dienstvertrags die abfragebezogenen Bindungseigenschaften festlegen möchten, geben Sie die PolledDataAvailableStatement wie folgt an:

SELECT COUNT(*) FROM Employee

Der PolledDataAvailableStatement muss ein Resultset mit der ersten Zelle zurückgeben, die einen positiven Wert enthält. Wenn die erste Zelle keinen positiven Wert enthält, führt der Adapter die Abfrageanweisung nicht aus.

Führen Sie im Rahmen der Abfrageanweisung die folgenden Operationen aus:

  1. Wählen Sie alle Zeilen aus der Tabelle "Mitarbeiter" aus.

  2. Führen Sie eine gespeicherte Prozedur (MOVE_EMP_DATA) aus, um alle Datensätze aus der Tabelle "Mitarbeiter" in eine EmployeeHistory-Tabelle zu verschieben.

  3. Führen Sie eine gespeicherte Prozedur (ADD_EMP_DETAILS) aus, um der Tabelle "Mitarbeiter" einen neuen Datensatz hinzuzufügen. Bei diesem Verfahren werden der Mitarbeitername, die Bezeichnung und das Gehalt als Parameter verwendet.

    Zum Ausführen dieser Vorgänge müssen Sie Folgendes für die PollingStatement-Bindungseigenschaft angeben:

SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000

Nachdem die Abfrage-Anweisung ausgeführt wurde, werden alle Datensätze aus der Tabelle "Mitarbeiter" ausgewählt, und die Nachricht von SQL Server wird empfangen. Nachdem die gespeicherte MOVE_EMP_DATA Prozedur vom Adapter ausgeführt wurde, werden alle Datensätze in die EmployeeHistory-Tabelle verschoben. Anschließend wird die gespeicherte Prozedur ADD_EMP_DETAILS ausgeführt, um der Tabelle "Mitarbeiter" einen neuen Datensatz hinzuzufügen. Die nächste Abfrageausführung gibt nur einen einzelnen Datensatz zurück. Dieser Zyklus wird fortgesetzt, bis Sie den Diensthost schließen.

Konfigurieren einer Polling-Abfrage mit den SQL-Adapterbindungseigenschaften

In der folgenden Tabelle sind die SQL-Adapterbindungseigenschaften zusammengefasst, die Sie zum Konfigurieren des Adapters zum Empfangen von Datenänderungsmeldungen verwenden. Sie müssen diese Bindungseigenschaften als Teil der .NET-Anwendung für die Abfrage angeben.

Binding-Eigenschaft BESCHREIBUNG
InboundOperationType Gibt an, ob Sie Abfragen, TypedPolling oder Benachrichtigungsvorgänge ausführen möchten. Der Standardwert ist Polling.
Abfrage-Datenverfügbarkeitserklärung Gibt die SQL-Anweisung an, die der Adapter ausführt, um zu bestimmen, ob Daten für die Abfrage verfügbar sind. Die SQL-Anweisung muss ein Resultset zurückgeben, das aus Zeilen und Spalten besteht. Nur wenn eine Zeile verfügbar ist, wird die für die PollingStatement-Bindungseigenschaft angegebene SQL-Anweisung ausgeführt.
PollingIntervalInSeconds Gibt das Intervall in Sekunden an, in dem der SQL-Adapter die für die Bindungseigenschaft PolledDataAvailableStatement angegebene Anweisung ausführt. Der Standardwert ist 30 Sekunden. Das Abrufintervall bestimmt das Zeitintervall zwischen aufeinander folgenden Abfragen. Wenn die Anweisung innerhalb des angegebenen Intervalls ausgeführt wird, wartet der Adapter auf die verbleibende Zeit im Intervall.
PollingStatement Gibt die SQL-Anweisung an, um die SQL Server-Datenbanktabelle abzufragen. Sie können eine einfache SELECT-Anweisung oder eine gespeicherte Prozedur für die Abfrage-Anweisung angeben. Der Standardwert ist NULL. Sie müssen einen Wert für PollingStatement angeben, um die Abfrage zu aktivieren. Die Abfrageanweisung wird nur ausgeführt, wenn Daten für die Abfrage verfügbar sind, die von der Bindungseigenschaft PolledDataAvailableStatement bestimmt wird. Sie können eine beliebige Anzahl von SQL-Anweisungen angeben, die durch ein Semikolon getrennt sind.
PollWhileDataFound Gibt an, ob der SQL-Adapter das Abrufintervall ignoriert und kontinuierlich die FÜR die Bindungseigenschaft PolledDataAvailableStatement angegebene SQL-Anweisung ausführt, wenn Daten in der abgerufenen Tabelle verfügbar sind. Wenn in der Tabelle keine Daten verfügbar sind, kehrt der Adapter darauf zurück, die SQL-Anweisung zum angegebenen Abfrageintervall auszuführen. Die Standardeinstellung lautet false.

Eine ausführlichere Beschreibung dieser Eigenschaften finden Sie unter BizTalk Adapter für SQL Server-Adapterbindungseigenschaften. Eine vollständige Beschreibung der Verwendung des SQL-Adapters zum Abrufen von SQL Server finden Sie weiter.

Konfigurieren der Abstimmung im WCF-Dienstmodell

Um den Abrufvorgang zu erhalten, wenn Sie das WCF-Dienstmodell verwenden, müssen Sie:

  1. Generieren Sie einen WCF-Dienstvertrag (Schnittstelle) für den Abrufvorgang aus den Metadaten, die vom Adapter verfügbar gemacht werden. Dazu können Sie das Visual Studio-Plug-In "Adapterdienstreferenz hinzufügen" verwenden.

  2. Implementieren Sie einen WCF-Dienst über diese Schnittstelle.

  3. Hosten Sie diesen WCF-Dienst mithilfe eines Diensthosts (System.ServiceModel.ServiceHost).

Informationen zu den in diesem Thema verwendeten Beispielen

In den Beispielen in diesem Thema wird die Tabelle "Mitarbeiter" abgefragt. Im Beispiel werden auch die gespeicherte Prozedur MOVE_EMP_DATA und ADD_EMP_DETAILS verwendet. Ein Skript zum Generieren dieser Artefakte wird mit den Beispielen bereitgestellt. Weitere Informationen zu den Beispielen finden Sie unter Beispiele für den SQL-Adapter. Ein Beispiel, Polling_ServiceModel, das auf diesem Thema basiert, wird auch mit den SQL-Adapterbeispielen bereitgestellt.

WCF-Dienstvertrag und -Klasse

Sie können das Add Adapter Service Reference Plug-In verwenden, um einen WCF-Dienstvertrag (Schnittstelle) und unterstützende Klassen für den Abrufvorgang zu erstellen. Weitere Informationen zum Generieren eines WCF-Dienstvertrags finden Sie unter Generieren eines WCF-Clients oder WCF-Dienstvertrags für SQL Server Artifacts.

Der WCF-Servicekontrakt (Schnittstelle)

Der folgende Code zeigt den WCF-Dienstvertrag (Schnittstelle), der für den Abrufvorgang generiert wurde.

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/", ConfigurationName="PollingOperation")]
public interface PollingOperation {

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

Die Nachrichtenverträge

Der Nachrichtenvertragsnamespace wird durch den Parameter "InboundID " im Verbindungs-URI geändert, sofern angegeben. In diesem Beispiel haben Sie keine eingehende ID im Verbindungs-URI angegeben. Die Anforderungsnachricht gibt ein DataSet zurück.

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Polling", WrapperNamespace="http://schemas.microsoft.com/Sql/2008/05/Polling/", IsWrapped=true)]
public partial class Polling {

[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/Polling/", Order=0)]
    [System.Xml.Serialization.XmlArrayAttribute(IsNullable=true)]
    [System.Xml.Serialization.XmlArrayItemAttribute("DataSet", Namespace="http://schemas.datacontract.org/2004/07/System.Data", IsNullable=false)]
    public System.Data.DataSet[] PolledData;

    public Polling() {
    }

    public Polling(System.Data.DataSet[] PolledData) {
        this.PolledData = PolledData;
    }
}

WCF-Dienstklasse

Das Add-Adapter Service Reference Plug-In generiert auch eine Datei, die über einen Stub für die WCF-Dienstklasse verfügt, die aus dem Dienstvertrag (Schnittstelle) implementiert wurde. Der Name der Datei ist SqlAdapterBindingService.cs. Sie können die Logik einfügen, um den Abrufvorgang direkt in dieser Klasse zu verarbeiten. Der folgende Code zeigt die WCF-Dienstklasse, die vom Add Adapter Service Reference Plug-In generiert wird.

namespace SqlAdapterBindingNamespace {

    public class SqlAdapterBindingService : PollingOperation {

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

Empfangen eingehender Nachrichten für den Abfragevorgang

Dieser Abschnitt enthält Anweisungen zum Schreiben einer .NET-Anwendung zum Empfangen eingehender Abrufnachrichten mithilfe des SQL-Adapters.

So empfangen Sie Abrufnachrichten vom SQL-Adapter

  1. Verwenden Sie das Plugin "Add Adapter Service Reference", um einen WCF-Dienstvertrag (Schnittstelle) und Hilfsklassen für die Polling-Operation zu generieren. Weitere Informationen finden Sie unter Generieren eines WCF-Client- oder WCF-Dienstvertrags für SQL Server-Artefakte. Optional können Sie die Bindungseigenschaften beim Generieren des Dienstvertrags und der Hilfsklassen angeben. Dadurch wird sichergestellt, dass sie in der generierten Konfigurationsdatei ordnungsgemäß festgelegt sind.

  2. Implementieren Sie einen WCF-Dienst über die Schnittstelle und Hilfsklassen, die in Schritt 1 generiert wurden. Die Polling-Methode dieser Klasse kann eine Ausnahme auslösen, um die Abruftransaktion abzubrechen, wenn beim Verarbeiten der vom Abrufvorgang empfangenen Daten ein Fehler aufgetreten ist; andernfalls gibt die Methode nichts zurück. Sie müssen die WCF-Dienstklasse wie folgt attributen:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    

    Innerhalb der Polling-Methode können Sie Ihre Anwendungslogik direkt implementieren. Diese Klasse finden Sie in SqlAdapterBindingService.cs. In diesem Beispiel erweitert der Code die SqlAdapterBindingService-Klasse. In diesem Code wird die abgefragte Nachricht, die als DataSet empfangen wurde, auf der Konsole ausgegeben.

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    
    public class PollingService : SqlAdapterBindingNamespace.SqlAdapterBindingService
    {
    
    public override void Polling(Polling request)
    {
        Console.WriteLine("\nNew Polling Records Received");
        Console.WriteLine("*************************************************");
        DataSet[] dataArray = request.PolledData;
        foreach (DataTable tab in dataArray[0].Tables)
        {
            foreach (DataRow row in tab.Rows)
            {
                for (int i = 0; i < tab.Columns.Count; i++)
                {
                    Console.WriteLine(row[i]);
                }
            }
        }
        Console.WriteLine("*************************************************");
        Console.WriteLine("\nHit <RETURN> to stop polling");
        }
    }
    
  3. Da der SQL-Adapter Anmeldeinformationen nicht als Teil des Verbindungs-URI akzeptiert, müssen Sie die folgende Klasse implementieren, um Anmeldeinformationen für die SQL Server-Datenbank zu übergeben. Im letzten Teil der Anwendung instanziieren Sie diese Klasse, um die SQL Server-Anmeldeinformationen zu übergeben.

    class PollingCredentials : 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 PollingCredentials();
            clone.UserName.UserName = this.UserName.UserName;
            clone.UserName.Password = this.UserName.Password;
            return clone;
        }
    }
    
  4. Erstellen Sie eine SqlAdapterBinding und konfigurieren Sie den Abrufvorgang, indem Sie die Bindungseigenschaften angeben. Sie können dies entweder explizit im Code oder deklarativ in der Konfiguration tun. Sie müssen mindestens den "InboundOperationType", " PolledDataAvailableStatement" und "PollingStatement" angeben.

    SqlAdapterBinding binding = new SqlAdapterBinding();
    binding.InboundOperationType = InboundOperation.Polling;
    binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";
    binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";
    
  5. Geben Sie SQL Server-Datenbankanmeldeinformationen an, indem Sie die PollingCredentials-Klasse instanziieren, die Sie in Schritt 3 erstellt haben.

    PollingCredentials credentials = new PollingCredentials();
    credentials.UserName.UserName = "<Enter user name here>";
    credentials.UserName.Password = "<Enter password here>";
    
  6. Erstellen Sie eine Instanz des WCF-Diensts, der in Schritt 2 erstellt wurde.

    // create service instance
    PollingService service = new PollingService();
    
  7. Erstellen Sie eine Instanz von System.ServiceModel.ServiceHost mithilfe des WCF-Diensts und eines Basisverbindungs-URI. Der Basisverbindungs-URI darf die eingehende ID nicht enthalten, sofern angegeben. Sie sollten hier auch die Anmeldeinformationen angeben.

    // Enable service host
    Uri[] baseUri = new Uri[] { new Uri("mssql://mysqlserver//mydatabase") };
    ServiceHost serviceHost = new ServiceHost(service, baseUri);
    serviceHost.Description.Behaviors.Add(credentials);
    
    
  8. Fügen Sie dem Diensthost einen Dienstendpunkt hinzu. Um dies zu tun:

    • Verwenden Sie die in Schritt 4 erstellte Bindung.

    • Geben Sie einen Verbindungs-URI an, der Anmeldeinformationen und ggf. eine Eingangs-ID enthält.

    • Geben Sie den Vertrag als "PollingOperation" an.

    // Add service endpoint: be sure to specify PollingOperation as the contract
    Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");
    serviceHost.AddServiceEndpoint("PollingOperation", binding, ConnectionUri);
    
  9. Um Umfragedaten zu empfangen, öffnen Sie den Service-Host. Der Adapter gibt Daten zurück, wenn die Abfrage ein Resultset zurückgibt.

    // Open the service host to begin polling
    serviceHost.Open();
    
  10. Schließen Sie den Diensthost, um die Abfrage zu beenden.

    Von Bedeutung

    Der Adapter fragt weiterhin ab, bis der Diensthost geschlossen ist.

    serviceHost.Close();
    

Beispiel

Das folgende Beispiel zeigt eine Abfrage, die auf die Tabelle "Mitarbeiter" zugreift. Die Abfrageanweisung führt die folgenden Aufgaben aus:

  1. Wählt alle Datensätze aus der Tabelle "Mitarbeiter" aus.

  2. Führt die MOVE_EMP_DATA gespeicherten Prozedur aus, um alle Datensätze aus der Tabelle "Mitarbeiter" in die Tabelle "EmployeeHistory" zu verschieben.

  3. Führt die gespeicherte Prozedur ADD_EMP_DETAILS aus, um der Tabelle "Mitarbeiter" einen Datensatz hinzuzufügen.

    Die erste Abrufnachricht enthält alle Datensätze aus der Tabelle "Mitarbeiter". Die nachfolgenden Abrufnachrichten enthalten nur den letzten Datensatz, der von der gespeicherten Prozedur ADD_EMP_DETAILS eingefügt wurde. Der Adapter wird weiterhin abfragen, bis Sie den Diensthost durch Drücken von <RETURN> schließen.

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;
using System.Data;

namespace Polling_ServiceModel
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

    public class PollingService : SqlAdapterBindingNamespace.SqlAdapterBindingService
    {

        public override void Polling(Polling request)
        {
            Console.WriteLine("\nNew Polling Records Received");
            Console.WriteLine("*************************************************");
            DataSet[] dataArray = request.PolledData;
            foreach (DataTable tab in dataArray[0].Tables)
            {
                foreach (DataRow row in tab.Rows)
                {
                    for (int i = 0; i < tab.Columns.Count; i++)
                    {
                        Console.WriteLine(row[i]);
                    }
                }
            }
            Console.WriteLine("*************************************************");
            Console.WriteLine("\nHit <RETURN> to stop polling");
        }
    }

    class PollingCredentials : 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 PollingCredentials();
            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 polling...");
                Console.ReadLine();

                SqlAdapterBinding binding = new SqlAdapterBinding();
                binding.InboundOperationType = InboundOperation.Polling;
                binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";
                binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";
                Console.WriteLine("Binding properties assigned...");

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

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

                Console.WriteLine("Opening service host...");
                PollingService service = new PollingService();
                serviceHost = new ServiceHost(service, baseUri);
                serviceHost.Description.Behaviors.Add(credentials);
                serviceHost.AddServiceEndpoint("PollingOperation", binding, ConnectionUri);
                serviceHost.Open();
                Console.WriteLine("Service host opened...");
                Console.WriteLine("Polling started...");
                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();
            }
        }
    }
}

Siehe auch

Abrufen von SQL Server mithilfe des SQL-Adapters mit WCF-Dienstmodell