使用 WCF 服務模型從 SQL 接收查詢通知
本主題示範如何設定 SQL 配接器,以接收來自SQL Server資料庫的查詢通知訊息。 若要示範通知,請考慮具有 [狀態] 資料行的資料表 Employee。 當新記錄插入此資料表時,Status 資料行的值會設定為 0。 您可以使用 SQL 語句來擷取 Status 資料行為 「0」 的所有記錄,藉此設定配接器以接收通知。 您可以藉由指定 NotificationStatement 系結屬性的 SQL 語句來執行此動作。 配接器用戶端收到通知之後,它可以包含邏輯,以在SQL Server資料庫上執行任何後續工作。 在此範例中,為了簡單起見,配接器用戶端會將 [狀態] 資料行列為 「0」 資料表中的所有記錄。
注意
如果您要對具有使用者定義型別資料行的資料表執行作業,請務必先使用 SQL 配接器主題來參考 具有使用者定義型別之資料表和檢視的作業 ,然後再開始開發應用程式。
使用 SQL 配接器系結屬性設定通知
下表摘要說明您用來設定從SQL Server接收通知的 SQL 配接器系結屬性。 您必須在執行 .NET 應用程式時指定這些系結屬性,才能從SQL Server資料庫接收通知。
Binding 屬性 | Description |
---|---|
InboundOperationType | 指定您想要執行的輸入作業。 若要接收通知訊息,請將此設定為 [通知]。 |
NotificationStatement | 指定用來註冊查詢通知的 SQL 語句 (SELECT 或 EXEC <預存程式>) 。 只有在指定 SQL 語句的結果集變更時,配接器才會從SQL Server取得通知訊息。 |
NotifyOnListenerStart | 指定當接聽程式啟動時,配接器是否傳送通知給配接器用戶端。 |
如需這些屬性的更完整描述,請參閱閱讀 BizTalk Adapter for SQL Server 配接器系結屬性。 如需如何使用 SQL 配接器接收SQL Server通知的完整描述,請參閱進一步。
使用 WCF 服務模型設定通知
若要使用 WCF 服務模型接收通知,您必須:
從配接器所公開的中繼資料產生 WCF 服務合約 (介面) 。 若要這樣做,您可以使用新增配接器服務參考外掛程式。
為 [員工] 資料表上的 [選取 ] 作業產生 WCF 用戶端。 若要這樣做,您可以使用新增配接器服務參考外掛程式。
從這個介面實作 WCF 服務。
使用服務主機裝載此 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 服務模型接收查詢通知
本節提供如何撰寫 .NET 應用程式以使用 SQL 配接器接收查詢通知的指示。
接收查詢通知
使用 [新增配接器服務參考外掛程式],在Employee資料表上產生選取作業的WCF 用戶端。 您將使用此用戶端在收到通知訊息之後執行 Select 作業。 將新的類別 TableOperation.cs 新增至專案,並新增下列程式碼片段來執行選取作業。
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 資料夾下。
使用 [新增配接器服務參考外掛程式] 來產生 WCF 服務合約, (通知作業的 介面) 和協助程式類別。
如需詳細資訊,請參閱為SQL Server成品產生 WCF 用戶端或 WCF 服務合約。 您可以在產生服務合約和協助程式類別時選擇性地指定系結屬性。 這可確保它們已正確設定在產生的組態檔中。
從步驟 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(); } }
因為 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; } }
建立 SqlAdapterBinding ,並藉由指定系結屬性來設定配接器以接收查詢通知。 您可以在程式碼中明確執行此動作,或在組態中以宣告方式執行此動作。 您至少必須指定 InboundOperationType 和 NotificationStatement 系結屬性。
SqlAdapterBinding binding = new SqlAdapterBinding(); binding.InboundOperationType = InboundOperation.Notification; binding.NotificationStatement = "SELECT Employee_ID, Name FROM dbo.Employee WHERE Status=0"; binding.NotifyOnListenerStart = true;
藉由具現化您在步驟 4 中建立的NotificationCredentials類別,指定SQL Server資料庫認證。
NotificationCredentials credentials = new NotificationCredentials(); credentials.UserName.UserName = "<Enter user name here>"; credentials.UserName.Password = "<Enter password here>";
建立在步驟 3 中建立之 WCF 服務的實例。
// create service instance NotificationService service = new NotificationService();
使用 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);
將服務端點新增至服務主機。 作法如下:
使用步驟 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);
若要接收通知訊息,請開啟服務主機。
// Open the service host to begin receiving notifications serviceHost.Open();
若要停止接收通知,請關閉服務主機。
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();
}
}
}
}