Android Addicted Apps Creator

October 15, 2009

Using a web service straight from SQL Server 2005

Filed under: Uncategorized — alinberce @ 17:33
Tags: , , ,

Interesting idea with lots of potential. I managed to consume web services from Window Forms application,from ASP.Net web pages but never directly from a SQL Server Database. I’ve researched a little and I know that it can be done and how it can be done. So let us proceed then.

To be able to use the web service from SQL Server we will use a component called CLR (Common Language Runtime) which has been included since the 2005 version. Using this component, we will create a UDF (User Defined Function) within Visual Studio which will consume the web service and which will be used in a SQL Server Table Valued Function to get the results as a SQL table. It does sound kind of tricky but I’ll try to explain it step by step.

I will make this into 2 parts, one that will take place in Visual Studio 2005 and one that will take place in SQL Server Management Studio.

Part I – The Visual Studio side of the story

Everything starts with creating a new project in Visual Studio pf SQL Server Project type. Its name will be CLRWebService

image

Before creating the UDF object we need to get a reference to the web service. The web service I will use for exemplification is offered free by www.infovalutar.ro , a website owned by a friend of mine.

To add a reference right click on the name of the solution and choose from the menu the option Add web reference. In the window that appears, it he URL field write the web service’s address

http://www.infovalutar.ro/curs.asmx?wsdl

image

In the right site of the window you can observe all the methods offered by the service and the parameters required. In The Web reference name filed will rename it to infovalutar and will press the button Add Reference

After the window closes you can see in Solution explorer that the reference has been added.

image

Now we can create the UDF object. Add a new item to the solution:

image

As I said before, the template used will be User-Defined Function and it will have the name GetCursuriValutare. The main scope of this function will be to access the getall(Date) method of the web service and get the exchange rate for the date sent as parameter.

Before writing any code we must analyze and see what exactly this function must achieve:

  • it must be read only, since it only shows data
  • it will have a method to populate the data (GetCursuriValutare_FillRow)
  • will return a table that will contain the fields returned by web service’s method

Let’ start by defining the functions attributes using SQLFunction command

[SqlFunction(
       DataAccess = DataAccessKind.Read,
       FillRowMethodName = "GetCursuriValutare_FillRow",
       TableDefinition =   "IDCurrency NVARCHAR(10), " +
                           "Value float  "
       )
   ]

We have a method that returns the final result

public static IEnumerable GetCursuriValutare()
    {
        DateTime dt = DateTime.Now.AddDays(-1);
        return new Curs().getall(dt).Rows;
    }

Here we take care of the DateTime parameter requested. This method returns an object Of type IEnumerable for the web service Curs() contained in the namespace infovalutar.

The GetCursuriValutare_FillRow methods populates UDF the record set from the object Curs returned as IEnumerable

public static void GetCursuriValutare_FillRow(
        object CursObj,
        out SqlString IDCurrency,
        out SqlDouble Value
        )
    {
        DataRow r = (DataRow)CursObj;
        IDCurrency = new SqlString(r[0].ToString());
        Value = new SqlDouble(Convert.ToDouble(r[1]));
    }

The final piece of code should look like this:

using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Xml;
using CLRWebService.infovalutar;

public partial class UserDefinedFunctions
{
    [SqlFunction(
       DataAccess = DataAccessKind.Read,
       FillRowMethodName = "GetCursuriValutare_FillRow",
       TableDefinition =
      "IDCurrency NVARCHAR(10), " +
       "Value float  "
       )
   ]

    public static IEnumerable GetCursuriValutare()
    {
        DateTime dt = DateTime.Now.AddDays(-1);
        return new Curs().getall(dt).Rows;
    }

    public static void GetCursuriValutare_FillRow(
        object CursObj,
        out SqlString IDCurrency,
        out SqlDouble Value
        )
    {
        DataRow r = (DataRow)CursObj;
        IDCurrency = new SqlString(r[0].ToString());
        Value = new SqlDouble(Convert.ToDouble(r[1]));
    }

};

Because we managed to finalize the function we must now obtain the required dll files to be able to use it in SQL Server. A very important thing to mention here, the XML object aren’t automatically serialized so we need to do this our self. This is being done using a tool included in Visual Studio: sgen.

To automate things a little bit will use Solution’s Build events to tale care of serialization. Right click on Solution name -> Properties ->Build Events and in the Command line for the Post-build event add the following

“C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\sgen.exe” /force “$(TargetPath)”

image

From the Build menu choose Build CLRWebService and pray that there will be no errors.

If everything went well, in the project folder should be 3 generated files:

image

If you have those files it means that the UDF creation is done. Go grab a snack and come back for the second step of this tutorial.

Step II – What does SQL Server has to say

To make things easyier will make a new folder on C:\ named CLRGetCurs in which we will copy 2 of the 3 generated files: CLRWebService.dll and CLRWebService.XmlSerializers.dll

Open SQL Server Management Studio, connect to the desired SQL Server instance and open a new Query. For exemplification we will use the AdventureWorks database.

use AdventureWorks
go
-- allows access from exterior
ALTER DATABASE AdventureWorks SET TRUSTWORTHY ON;
GO

--checking that the objects exists before creation
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'GetCursuriValutareWS')
   DROP FUNCTION GetProductWS
go
IF EXISTS (SELECT [name] FROM sys.assemblies WHERE [name] = N'XmlSerializers')
    DROP ASSEMBLY [XmlSerializers]
IF EXISTS (SELECT name FROM sys.assemblies WHERE name = 'GetCusturiValutareCLR')
   DROP ASSEMBLY GetProductCLR
GO

-- create assemblys for the  2 dll files from folder CLRGetCurs
Create ASSEMBLY GetCusturiValutareCLR FROM 'C:\CLRGetCurs\CLRWebService.dll'
WITH PERMISSION_SET = External_Access

CREATE ASSEMBLY [XmlSerializers] from
'C:\CLRGetCurs\CLRWebService.XmlSerializers.dll'
WITH permission_set = SAFE
GO

We are one step closer to the finish line. We only need to create a Table Valued Function that makes use of the external UDF function:

CREATE FUNCTION GetCursuriValutareWS() 

RETURNS TABLE (
IDCurrency NVARCHAR(10),
Value FLOAT
   )
AS EXTERNAL NAME GetCusturiValutareCLR.UserDefinedFunctions.[GetCursuriValutare]
GO

And now, let us enjoy the results of our work:

image

Impressive, I was really amassed to see the web service result in the SQL Server Management Studio. It makes you feel you can do anything you want. I wonder if these UDF functions can be used to alter the content of the database ? Hmm… I’ll check and see.

A good source of information for this article I’ve found on www.databasejournal.com.

I hope you enjoyed this short tutorial. Until next time, Happy coding.

P.S. I know I’ve started a series of tutorials regarding n-tier concepts. Now I left this aside and I started learning about DDD (Domain Driven Design) and how these concepts can be implemented using C# techniques. Still layers but in a more effective “proven” way and a more documented concept.  I would like to THANK Emanuel for guidance and for pointing me into the right direction. There will be some interesting tutorials so stay put.

For the romanian version of the tutorial check this address http://www.infovalutar.ro/howto/sqlserver.aspx

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: