共用方式為


使用 WCF 服務模型從 SQL 接收查詢通知

本主題示範如何設定 SQL 配接器,以從 SQL Server 資料庫接收查詢通知訊息。 若要示範通知,請假設有一個名為 Employee 的資料表,其中有一個「狀態」欄。 將新記錄插入此數據表時,Status 資料行的值會設定為 0。 您可以使用 SQL 語句註冊通知,設定配接器以接收所有「狀態」欄位為「0」的記錄。 您可以指定 NotificationStatement 系結 屬性的 SQL 語句來執行此動作。 配接器用戶端收到通知之後,它可以包含邏輯,以在 SQL Server 資料庫上執行任何後續工作。 在這個範例中,為了簡化,在配接器用戶端中,會列出表格中所有 Status 欄位為「0」的記錄。

備註

如果您要在具有使用者定義型別數據行的數據表上執行作業,請務必先使用SQL 配接器主題來參考 具有使用者定義型別的數據表和檢視上的作業 ,再開始開發應用程式。

使用 SQL 配接器系結屬性設定通知

下表摘要說明您用來設定從 SQL Server 接收通知的 SQL 配接器系結屬性。 您必須在執行 .NET 應用程式時指定這些系結屬性,才能從 SQL Server 資料庫接收通知。

綁定屬性 說明
InboundOperationType 指定您要執行的輸入作業。 若要接收通知訊息,請將此設定為 [通知]。
NotificationStatement 指定用來註冊查詢通知的 SQL 語句(SELECT 或 EXEC <預存程式>)。 只有在指定 SQL 語句的結果集變更時,配接器才會從 SQL Server 取得通知訊息。
NotifyOnListenerStart 指定當接聽程序啟動時,配接器是否傳送通知給配接器用戶端。

如需這些屬性的更完整描述,請參閱 閱讀 BizTalk Adapter for SQL Server 配接器系結屬性。 如需如何使用 SQL 配接器接收來自 SQL Server 通知的完整描述,請閱讀進一步。

使用 WCF 服務模型設定通知

若要使用 WCF 服務模型接收通知,您必須:

  1. 從配接器所公開的元數據產生 通知 作業的 WCF 服務合約(介面)。 若要這樣做,您可以使用 [新增配接器服務參考外掛程式]。

  2. 針對 Employee 資料表上的 Select 作業產生 WCF 用戶端。 若要這樣做,您可以使用 [新增配接器服務參考外掛程式]。

  3. 從這個介面實作 WCF 服務。

  4. 使用服務主機裝載此 WCF 服務(System.ServiceModel.ServiceHost)。

關於本主題中使用的範例

本主題中的範例會收到 Employee 數據表的通知。 產生數據表的腳本會隨附範例。 如需範例的詳細資訊,請參閱 SQL 配接器的範例。 隨 SQL 配接器範例一起提供的還有一個基於本主題的範例 Notification_ServiceModel

WCF 服務合約和類別

您可以使用新增配接器服務參考外掛程式來建立 WCF 服務合約(介面)和支援 通知 作業的類別。 如需產生 WCF 服務合約的詳細資訊,請參閱 產生 SQL Server 項目的 WCF 用戶端或 WCF 服務合約

WCF 服務合約 (介面)

下列程式代碼顯示針對 通知 作業產生的 WCF 服務合約(介面)。

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

訊息合約

以下是通知作業的訊息合約。

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

WCF 服務類別

[新增配接器服務參考外掛程式] 也會產生一個檔案,其中包含根據服務合約 (介面) 所建立的 WCF 服務類別的存根。 檔名是SqlAdapterBindingService.cs。 您可以將處理 通知 作業的邏輯直接插入到此類別中。 下列程式代碼顯示新增配接器服務參考外掛程式所產生的 WCF 服務類別。

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

使用 WCF 服務模型接收查詢通知

本節提供如何使用 SQL 配接器撰寫 .NET 應用程式以接收查詢通知的指示。

接收查詢通知

  1. 使用 [新增配接器服務參考外掛程式] 來產生 [員工] 數據表上 Select 作業的 WCF 用戶端。 您將使用此用戶端在收到通知訊息之後執行 Select 作業。 將新的類別TableOperation.cs新增至您的專案,並新增下列代碼段來執行 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("********************************************");
    
    

    這很重要

    由於此代碼段會在包含 Point UDT 資料行的 Employee 資料表上執行作業,因此在執行應用程式時,請務必將 UDT DLL 放在專案的 \bin\Debug 資料夾下。

  2. 使用 [新增配接器服務參考外掛程式] 來產生 通知 作業的 WCF 服務合約(介面)和協助程序類別。

    如需詳細資訊,請參閱 為 SQL Server 工件產生 WCF 用戶端或 WCF 服務合約。 您可以選擇性地指定繫結屬性,在產生服務合約和輔助類別時。 這可確保它們已正確設定在產生的組態檔中。

  3. 從步驟 2 中產生的介面和協助程式類別實作 WCF 服務。 如果發生錯誤處理從通知作業收到的數據,這個類別的 Notification 方法可能會擲回例外狀況來中止作業;否則方法不會傳回任何專案。 請按照以下方式設定 WCF 服務類別的屬性:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    

    Notification 方法內,您可以直接實作應用程式邏輯。 您可以在 SqlAdapterBindingService.cs中找到這個類別。 此範例中的這個程式代碼子類別是 SqlAdapterBindingService 類別。 在此程式代碼中,收到的通知訊息會寫入主控台。 此外,會叫用 TableOperation 類別內的 TableOp 方法來執行 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. 因為 SQL 配接器不接受認證作為連線 URI 的一部分,因此您必須實作下列類別來傳遞 SQL Server 資料庫的認證。 在應用程式的後半部分中,您將具現化此類別,以傳遞 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. 建立 SqlAdapterBinding ,並藉由指定系結屬性來設定配接器以接收查詢通知。 您可以在程式代碼中明確執行此動作,或在組態中以宣告方式執行此動作。 您至少必須指定 InboundOperationTypeNotificationStatement 系結 屬性。

    SqlAdapterBinding binding = new SqlAdapterBinding();
    binding.InboundOperationType = InboundOperation.Notification;
    binding.NotificationStatement = "SELECT Employee_ID, Name FROM dbo.Employee WHERE Status=0";
    binding.NotifyOnListenerStart = true;
    
  6. 藉由具現化您在步驟 4 中建立的 NotificationCredentials 類別來指定 SQL Server 資料庫認證。

    NotificationCredentials credentials = new NotificationCredentials();
    credentials.UserName.UserName = "<Enter user name here>";
    credentials.UserName.Password = "<Enter password here>";
    
  7. 建立在步驟 3 中建立之 WCF 服務的實例。

    // create service instance
    NotificationService service = new NotificationService();
    
  8. 使用 WCF 服務和基底連線 URI 建立 System.ServiceModel.ServiceHost 的實例。 您也必須在這裡指定認證。

    // Enable service host
    Uri[] baseUri = new Uri[] { new Uri("mssql://mysqlserver//mydatabase") };
    ServiceHost serviceHost = new ServiceHost(service, baseUri);
    serviceHost.Description.Behaviors.Add(credentials);
    
    
  9. 將服務端點新增至服務主機。 要達成此目的:

    • 使用在步驟 5 中建立的系結。

    • 指定包含認證的連線 URI,並視需要指定輸入識別碼。

    • 將合約指定為 「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. 若要接收通知訊息,請開啟服務主機。

    // Open the service host to begin receiving notifications
    serviceHost.Open();
    
  11. 若要停止接收通知,請關閉服務主機。

    serviceHost.Close();
    

範例

下列範例顯示 .NET 應用程式,以接收 Employee 數據表的通知訊息。

備註

下列代碼段會具現化 TableOperation.cs 類別,並叫用 TableOp 方法。 類別和 方法會在步驟 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();
            }
        }
    }
}

另請參閱

使用 WCF 服務模型開發 SQL 應用程式