本主题演示如何将 SQL 适配器配置为从 SQL Server 数据库接收查询通知消息。 若要演示通知,请考虑包含“状态”列的表“Employee”。 将新记录插入此表时,状态列的值设置为 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 | 指定适配器在启动侦听器时是否向适配器客户端发送通知。 |
有关这些属性的更完整说明,请参阅 有关适用于 SQL Server 适配器绑定属性的 BizTalk 适配器的信息。 有关如何使用 SQL 适配器从 SQL Server 接收通知的完整说明,请阅读详细信息。
使用 WCF 服务模型配置通知
若要使用 WCF 服务模型接收通知,必须:
为通知操作生成从适配器公开的元数据的WCF服务合约(接口)。 为此,可以使用“添加适配器服务引用插件”。
为 Employee 表上的 选择 操作生成 WCF 客户端。 为此,可以使用“添加适配器服务引用插件”。
从此接口实现 WCF 服务。
使用服务主机(System.ServiceModel.ServiceHost)托管此 WCF 服务。
关于本主题中使用的示例
本主题中的示例将接收到有关 Employee 表的通知。 生成表的脚本随示例一起提供。 有关示例的详细信息,请参阅 SQL 适配器的示例。 提供了一个基于本主题的示例 Notification_ServiceModel,此示例也包括在 SQL 适配器示例中。
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 表执行 Select 操作的 WCF 客户端。 在收到通知消息后,你将使用此客户端执行选择操作。 将新类 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 文件夹下。
使用“Add Adapter Service Reference Plug-in”生成 通知作业的 WCF 服务协定(接口)和帮助类。
有关详细信息,请参阅 为 SQL Server 项目生成 WCF 客户端或 WCF 服务协定。 可以选择在生成服务协定和帮助程序类时指定绑定属性。 这可以保证在生成的配置文件中正确设置它们。
从步骤 2 中生成的接口和帮助程序类实现 WCF 服务。 如果在处理从Notification操作接收的数据时遇到错误,此类的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,并根据需要指定入站 ID。
将合同指定为“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 中介绍了类 (class) 和方法 (method)。"
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();
}
}
}
}