DBA.NET 3.0Visual Studio 2005SQL Server 2005C# 3.0IntermediateDevVisual StudioSQL ServerSQLWindows.NETC#
从 CLR 触发器调用 WCF 服务






4.90/5 (19投票s)
从 SQL Server 2005 中的 CLR 触发器通信 WCF 的分步指南
引言
本文将引导您完成设置示例项目的全部步骤,该项目演示了如何在 SQL Server 2005 中创建 CLR 触发器,该触发器可以与您设计的 WCF 服务进行通信。这并不是 WCF 的入门教程,而是关于如何从 SQL Server 2005 CLR 触发器使用 WCF 的入门教程。
背景
在学习了 WCF 的相关知识后,我迫不及待地想在一些现有的数据库项目中利用它。我的目标之一是让 CLR 触发器与 WCF 服务进行通信。我认为这应该是一个相当简单的过程,但其中涉及许多棘手的问题,因此我认为分享其中一些问题并提供一个实现此目标的演示方法会很有用。
Using the Code
必备组件
- 开发机:VS2005,VS2005 的 WCF 扩展,.NET 3.0 运行时
- 数据库机:SQL Server 2005 或 SQL Server 2005 Express,.NET 3.0 运行时
创建 WCF 服务
- 打开 Visual Studio。
- 创建一个新的 C# 控制台应用程序,并将其命名为 'Service'。
- 添加对:
System.ServiceModel
的引用。 - 创建服务契约
using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; namespace SampleService { [ServiceContract] interface IServiceContract { [OperationContract] void UpdateOccured(); [OperationContract] void InsertOccured(); }
- 向项目中添加一个名为 '
IServiceContract
' 的interface
。 - 将接口中的代码替换为
- 向项目中添加一个名为 '
- 实现服务契约。
using System; using System.Collections.Generic; using System.Text; namespace SampleService { class MyService : IServiceContract { public void UpdateOccured() { Console.WriteLine("Update Occured"); } public void InsertOccured(int RecordID) { Console.WriteLine("Insert Occured"); } } }
- 添加一个新类,并将其命名为 '
ServiceContract
'。 - 将类中的代码替换为
- 添加一个新类,并将其命名为 '
- 托管服务
using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; namespace SampleService { class Program { static void Main(string[] args) { //Create Uri that acts as the service Base Address Uri baseAddress = new Uri("https://:8000/services"); //Create a service host ServiceHost MyHost = new ServiceHost(typeof(MyService), baseAddress); //Create a binding context for the service WSHttpBinding MyBinding = new WSHttpBinding(); //Declare and configure Metadata behavoir //that we will later add to the serivce ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; /*Add endpoint to the service. After adding this endpoint, the full address of the service will comprise base address (https://:8000/services) and endpoint address ("MyService") Full Service Address == https://:8000/services/MyService*/ MyHost.AddServiceEndpoint(typeof(IServiceContract), MyBinding, "MyService"); //add behaviour to host MyHost.Description.Behaviors.Add(smb); //Run the host MyHost.Open(); Console.WriteLine("Your service has been started"); Console.WriteLine("Press <enter /> to terminate service."); Console.WriteLine(); Console.ReadLine(); } } }
- 将 Program.cs 中的代码替换为
准备数据库
这个过程花费的时间最长,也遇到了最大的问题。如果您按照此处概述的步骤进行操作,它将允许您准备任何数据库以允许与 WCF 服务进行通信。
-- Turn advanced options on
EXEC sp_configure 'show advanced options' , '1';
go
reconfigure;
go
EXEC sp_configure 'clr enabled' , '1'
go
reconfigure;
-- Turn advanced options back off
EXEC sp_configure 'show advanced options' , '0';
go
use custdb
ALTER DATABASE custdb SET TRUSTWORTHY ON
reconfigure
CREATE ASSEMBLY
SMDiagnostics from
'C:\Windows\Microsoft.NET\Framework\v3.0\Windows
Communication Foundation\SMDiagnostics.dll'
with permission_set = UNSAFE
GO
CREATE ASSEMBLY
[System.Web] from
'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Web.dll'
with permission_set = UNSAFE
GO
CREATE ASSEMBLY
[System.Messaging] from
'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Messaging.dll'
with permission_set = UNSAFE
GO
CREATE ASSEMBLY
[System.IdentityModel] from
'C:\Program Files\Reference Assemblies\Microsoft\
Framework\v3.0\System.IdentityModel.dll'
with permission_set = UNSAFE
GO
CREATE ASSEMBLY
[System.IdentityModel.Selectors] from
'C:\Program Files\Reference Assemblies\Microsoft\
Framework\v3.0\System.IdentityModel.Selectors.dll'
with permission_set = UNSAFE
GO
CREATE ASSEMBLY -- this will add service modal
[Microsoft.Transactions.Bridge] from
'C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication
Foundation\Microsoft.Transactions.Bridge.dll'
with permission_set = UNSAFE
GO
- 创建一个名为 '
custDB
' 的基本数据库,并在其中添加一个名为 'tbCR
' 的表,包含以下列[CustomerName] [varchar](50)
[CustomerTel] [varchar](50)
[CustomerEmail] [varchar](50)
- 默认情况下,SQL Server 2005 中的 CLR 是禁用的。通过执行以下查询启用 CLR 执行
- 您的数据库将访问“不安全”的程序集。为了防止安全异常,您必须通过执行以下查询将您的数据库标记为“受信任”状态。(有关此选项的更多信息,请参阅:TRUSTWORTHY 数据库属性)
- 默认情况下,您可以从 SQL Server CLR 对象引用的程序集是有限的。为了访问我们与 WCF 通信所需的一些程序集,我们需要将它们加载到我们的数据库中。要做到这一点,请执行以下查询
准备数据库 - 注意事项
创建程序集时,您可能会收到以下警告。此警告可以忽略。
Warning: The Microsoft .Net frameworks assembly 'system.servicemodel, version=3.0.0.0,
culture=neutral, publickeytoken=b77a5c561934e089, processorarchitecture=msil.'
you are registering is not fully tested in SQL Server hosted environment.
在我的一台测试系统(SQL Server 2005 - 未打补丁)上,我在创建程序集时遇到了各种“内存不足
”错误。似乎没有任何好的理由,并且在我的其他系统上并未出现相同的问题。问题的解决方案?安装 SQL Server 2005 SP2。
创建 CLR 对象
现在您应该看到已将服务引用添加到我们的客户端项目中,并且已创建名为 localhost.map 的文件。
- 向解决方案添加一个名为 "
ServiceClient
" 的新 C# SQL Database Project。 - 选择或添加对目标数据库的引用(如果未提示:右键单击您的 "
ServiceClient
" 项目,选择属性,数据库,浏览,然后选择您的连接)。 - 添加对我们创建的服务进行引用
- 在解决方案资源管理器中右键单击 '
Service
' 项目,然后选择 'Debug' > 'Start New Instance'。 - 服务运行时:右键单击 '
ServiceClient
' 项目,然后选择 'Add Service Reference'。 - 在 'Service URI' 中,键入:https://:8000/services。
- 点击“确定”。
- 在解决方案资源管理器中右键单击 '
- 向项目添加一个名为 '
WCFTrigger
' 的触发器。using System; using System.Data; using System.Data.SqlClient; using Microsoft.SqlServer.Server; using System.ServiceModel.Description; using System.ServiceModel; using System.Collections; using System.Diagnostics; using System.Threading; public partial class Triggers { //Create an endpoint address for our serivce public static EndpointAddress endpoint = new EndpointAddress(new Uri("https://:8000/services/myservice")); //Create a binding method for our service public static WSHttpBinding httpBinding = new WSHttpBinding(); //Create an instance of the service proxy public static ServiceClient.localhost.ServiceContractClient myClient = new ServiceClient.localhost.ServiceContractClient(httpBinding, endpoint); //A delegate that is used to asynchronously talk //to the service when using the FAST METHOD public delegate void MyDelagate(String crudType); [SqlProcedure()] public static void SendData(String crudType) { /*A very simple procedure that accepts a string parameter based on the CRUD action performed by the trigger. It switches based on this parameter and calls the appropriate method on the service proxy*/ switch (crudType) { case "Update": myClient.UpdateOccured(); break; case "Insert": myClient.InsertOccured(); break; } } [Microsoft.SqlServer.Server.SqlTrigger(Name = "WCFTrigger", Target = "tbCR", Event = "FOR UPDATE, INSERT")] public static void Trigger1() { /*This is a very basic trigger that performs two very simple actions: * 1) Gets the current trigger Context * and then switches based on the triggeraction * 2) Makes a call to a stored procedure * Two methods of calling the stored procedure are presented here. * View the article on Code Project for a discussion on these methods */ SqlTriggerContext myContext = SqlContext.TriggerContext; //Used for the FAST METHOD MyDelagate d; switch (myContext.TriggerAction) { case TriggerAction.Update: //Slow method - NOT RECOMMENDED IN PRODUCTION! SendData("Update"); //Fast method - STRONGLY RECOMMENDED FOR PRODUCTION! //d = new MyDelagate(SendData); //d.BeginInvoke("Update",null,null); break; case TriggerAction.Insert: //Slow method - NOT RECOMMENDED IN PRODUCTION! SendData("Insert"); //Fast method - STRONGLY RECOMMENDED FOR PRODUCTION! //d = new MyDelagate(SendData); //d.BeginInvoke("Insert", null, null); break; } } }
- 将触发器代码替换为以下内容
创建 CLR 对象 - 注意事项
上面的代码在数据库中创建了两个对象
- 存储过程
SendData
是使用服务代理所必需的。您不能从触发器内部引用服务代理。老实说,我不太确定具体原因,但如果有人能对此有所启发,那就太好了!SendData
实际上并没有做什么花哨的事情,它只是根据输入参数调用代理上的正确方法。 - 触发器
WCFTrigger
设置为在我们的表中发生更新或插入时触发。同样,这并不复杂,触发器用于调用具有正确参数的SendData
存储过程。上面代码中显示了两种调用存储过程的方法:简单方法(注释为慢速方法)只是直接调用存储过程。第二个选项(注释为快速方法)使用委托异步调用存储过程。这有助于提高触发器的性能。
以下是注意事项
- 在我的测试中,使用 SQL Profiler,基于委托的方法将查询完成时间从 100 毫秒减少到 8 毫秒!
- 免责声明:为简化起见,我在项目中的默认解决方案中包含了慢速(同步)方法。强烈建议在任何生产实现中使用快速(异步)方法。
整合
我们现在已经创建了演示从 SQL Server 2005 CLR 触发器与 WCF 服务通信所需的所有元素;现在只需要将它们整合在一起!
- 将服务发布到您的数据库服务器:在 VS2005 中右键单击您的 '
Service
' 项目,然后选择 'Publish
'。选择运行数据库的计算机上的一个位置(例如,\\YourDBServer\Samples),然后单击 'Finish
'。 - 在数据库服务器上启动服务:连接到您的数据库服务器。找到您刚刚发布的服务的服务位置。双击 "Setup.exe"。您的服务应该会启动。
- 回到开发机:部署您的触发器和存储过程:在 VS2005 中右键单击您的 '
ServiceClient
' 项目,然后选择 'Deploy
'。 - 使用 SQL Server Management Studio 验证触发器和存储过程的部署(确保您可以看到它们!)。
准备就绪!
现在一切都应该准备就绪。对您的测试表运行一些 INSERT
和 UPDATE
查询,您应该会在服务控制台中看到一些输出。