One my friends wanted to call a WCF Service from a Stored Procedure in Microsoft SQL Server 2012. So this is how you can do it.
Before starting off with coding, there are some things that we all need to know and understand well.
When wring functionalities such as Stored Procedures, Triggers etc. for a database which sits inside Microsoft SQL Server, there are two things we can use.
- T-SQL
- SQL CLR (SQL Common Language Runtime)
You can either write your operation using T-SQL or you can use SQL CLR. Since you all are familiar with T-SQL, let’s see what SQL CLR is.
SQL CLR is use of the Microsoft .NET Common Language Runtime within SQL Server. SQL CLR is very useful when you want to accomplish a task which is not possible with T-SQL. The best example for such task would be the task that I am going to do right now.
You can’t use only T-SQL to consume a WCF Service. But SQL CLR gives the ability to call and consume a WCF Service. So what we can do is write a Stored Procedure with the use of SQL CLR which will call and consume from the WCF Service. Then we can write a T-SQL Stored Procedure to call the SQL CLR Stored Procedure.
Different SQL Server versions uses different CLR versions. SQL Server 2012 uses version 4.0 of the CLR although previous versions of SQL Server (from SQL Server 2005) uses version 2.0 of the CLR.
Keeping that in mind let’s jump into the action.
In my development environment, I have Microsoft Visual Studio 2013 and Microsoft SQL Server 2012 installed.
First let me start off with with creating a WCF Service which will be consumed by the Stored Procedure. I am creating a WCF Service application, targeting .NET Framework 4.5.1. If you are thinking since my SQL Server version is 2012 and the CLR version for SQL Server 2012 is 4.0, I should be using .NET framework 4.0 instead of 4.5.1. Don’t worry, the .NET Framework 4.0, 4.5, and 4.5.1 include CLR 4.0, the .NET Framework 2.0, 3.0, and 3.5 include CLR 2.0 as there was no version 3 of the CLR.
Create WCF Service Application |
Here I have the following WCF Service with a method “SayHello” which accepts a string. So I will be calling this method from my Stored Procedure.
[ServiceContract]
public interface IService1
{
[OperationContract]
string SayHello(string name);
}
public class Service1 : IService1
{
public string SayHello(string name)
{
return string.Format("Hello {0}!", name);
}
}
WCF Service Up and Running |
Now I am done with creating the WCF Service Application. Now before moving into next steps let me briefly explain the approach I am going to follow.
I will need to have a SQL CLR project created using Visual Studio 2013. There I will have a Stored Procedure created. But when you are creating SQL project using Visual Studio 2013 and if you think about calling WCF Service directly from SQL project by adding a web reference, you can’t do that. From SQL Projects you can’t add web references.
Because of that I should have an intermediate WCF client. So I will be creating a DLL which will acts as the WCF Client here. There I will be exposing a public static method which in turn call the WCF Service. Then in my SQL CLR project, I will be adding a reference to that particular DLL, and then I can call it’s public static method which will in turn call the WCF Service. Hope you all got a clear idea on my approach here.
Now coming back in to the action, I will now create a Class Library Project.
Create Class Library |
Add Service Reference |
From the next window, click on Advance (That’s because we should add the reference as a Web Reference, and not as a WCF Service Reference. The WCF Client is not supported in SQL CLR, and in SQL 2012 it doesn't work).
Advanced |
Add Web Reference |
Add Reference |
using MyClassLibrary.svcService;
namespace MyClassLibrary
{
public class MyClass
{
public static string CallWcfService(string name)
{
string result = string.Empty;
using (Service1 client = new Service1())
{
result = client.SayHello(name);
}
return result;
}
}
}
Now I am done with creating the DLL, Next part is creating the SQL Project using CLR. In Visual Studio 2013, under installed templates go to Other Languages section. There inside SQL Server category, I can find the SQL Server Database Project.
Create SQL Server Database Project |
Add New Item |
Create SQL CLR C# Stored Procedure |
Now I am adding a reference to my above created DLL by right clicking on Reference, clicking on Add Reference and browsing for the DLL.
Reference Added |
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void spCallWcfService(string name)
{
try
{
SqlPipe sqlPipe = SqlContext.Pipe;
string result = MyClassLibrary.MyClass.CallWcfService(name);
SqlContext.Pipe.Send(result);
}
catch (Exception ex)
{
SqlContext.Pipe.Send(ex.Message);
}
}
}
Now the modified Stored Procedure will accepts a string. Then I am calling the static method inside my DLL and will send the result directly to the client or current output consumer.
Now I am all done with Visual Studio. Let’s move into the SQL Server Management Studio. I have an empty database created there named “MyDemoDB”.
For that I am running the following query.
IF EXISTS (
SELECT [name]
FROM sys.assemblies
WHERE [name] = N'MySQLCLRProject')
BEGIN
DROP ASSEMBLY MySQLCLRProject
ALTER ASSEMBLY MySQLCLRProject
FROM 'D:\...\MySQLCLRProject.dll'
WITH PERMISSION_SET = UNSAFE ;
END
ELSE
BEGIN
CREATE ASSEMBLY MySQLCLRProject
FROM 'D:\...\MySQLCLRProject.dll'
WITH PERMISSION_SET = UNSAFE;
END
CREATE ASSEMBLY for assembly 'MySQLCLRProject' failed because assembly 'MySQLCLRProject' is not authorized for PERMISSION_SET = UNSAFE. The assembly is authorized when either of the following is true: the database owner (DBO) has UNSAFE ASSEMBLY permission and the database has the TRUSTWORTHY database property on; or the assembly is signed with a certificate or an asymmetric key that has a corresponding login with UNSAFE ASSEMBLY permission.
For that I am running the following query.
alter database [MyDemoDB]
set trustworthy on;
go
Now I am creating a T-SQL Stored Procedure inside “MyDemoDB” which calls the CLR Stored Procedure.
CREATE PROCEDURE [dbo].[spWcfCall]
@parameter1 NVARCHAR(MAX)
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME MySQLCLRProject.StoredProcedures.spCallWcfService
“spWcfCall” will be accepting a string. It will be then passed to to the CLR Stored Procedure. It will be again get passed to public static method in my DLL which in turn call the WCF Service.
After executing the query I can see my T-SQL Procedure inside Stored Procedures in “MyDemoDB”
Stored Procedure Created |
EXEC spWcfCall "Jaliya"
Execution of user code in the .NET Framework is disabled. Enable "clr enabled" configuration option.
For that I am running the following query.
USE [MyDemoDB]
EXEC sp_configure 'clr enabled', '1';
RECONFIGURE;
It got completed and again I am executing the “spWcfCall” stored procedure. And this time no errors. My Stored Procedure has successfully called the WCF Service and resulted string is as follows.
Result |
Happy Coding.
Regards,
Jaliya
Cannot load dynamically generated serialization assembly. In some hosting environments assembly load functionality is restricted, consider using pre-generated serializer. Please see inner exception for more information.
ReplyDeleteAny Clue why this is happening???
The same issue here ! did you find a solution ?
DeleteTwo questions. 1) The resulting string "Hello Jaliya!"(or any other name) where is returned?All your routines are return string.(result)
ReplyDelete2)When i execute the sp query executes successfully although SqlServer says: "Unable to connect to the remote server".Any ideas?