May 25, 2010 at 11:41 am
So i have a sql sript that i'm converting to a proc. Theres a chunk of sql that runs then the end user is supposed to goto an asp page that when opened has some inline sql that updates the db. Step one for me is to convert this to a proc. Once done i'll swing back and pull the sql out of the asp page and throw it into my proc accordingly.
Long story short is there a way to make an http call in sql stored proc? Was going to use bat file but i have to assume there's a better way.
i just need to embed http://www.helloWorld.asp in my stored proc
Make sence?
May 25, 2010 at 11:58 am
I had to do this very recently (last few days), and I ended up creating the stored procedure as a CLR. I wasn't sure how I felt about it at first, but it ended up working really well. I created the CLR in Visual Studio and was able to go from conception to realization in only a few hours.
Here's the code for the CLR ion C# (I ended up making it as a UDF so I could call it for every line):
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Net;
using System.IO;
using System.Text;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString ufnFunction(string variable)
{
string str = "";
string cn = "http://server/default.aspx?variable=" + variable;
HttpWebRequest http = (HttpWebRequest)
WebRequest.Create(cn);
http.KeepAlive = false;
HttpWebResponse resp = (HttpWebResponse)http.GetResponse();
Stream receiveStream = resp.GetResponseStream();
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
StreamReader readStream = new StreamReader(receiveStream, encode);
while (!readStream.EndOfStream)
{
str = str + readStream.ReadLine();
}
readStream.Close();
resp.Close();
return new SqlString(str);
}
};
May 25, 2010 at 12:19 pm
thanks for the solution. unfortunatly my mngr over heard me discussing your sol w/ a teamate and he hixed it on the spot. I appreciate the solution though.
May 25, 2010 at 12:20 pm
sorry. Nixed it on the spot.
May 25, 2010 at 12:22 pm
He nixed the solution or the entire project? Did he give a reason?
--J
May 25, 2010 at 12:27 pm
Nixed the solution. He's big on keeping things as simple as possable for easy debugging purposes. As i mentioned before we're monitoring serveral different apps accross 50 or so sql instances. So i understand where he's coming from. We switch the pager weekly between 5 of us so any backend dev work needs to be easily supported between all 5 of us. I'll prob end up createing a vbs that makes the http request and call vbs via .bat file in my proc.
I can't complain. We've finally moved all sql 2000 instances to 2005 or 2008. I'm really enjoying being away for 2000 thats for damn sure.
May 25, 2010 at 12:39 pm
I'd argue that calling a VBS from the command line is much less manageable than using CLR. Calling VBS from the command line introduces points of failure that don't exist in CLR, and it also introduces a possible security hole. Unless you already have the operating system extension enabled, I suggest you keep them disabled. CLR is much more secure.
The CLR doesn't have to be in C# either, it can be in VB. And, as you see, it's very short. Personally, I keep my CLRs under source control, and they are very easy to manage. Once deployed, I don't usually have problems with them at all...
It's ultimately up to you and your boss what you do, but personally I'd try to make the case for the CLR. Relying on the operating system seems sloppy, especially when the database provided the mechanism to do what you're doing, within the system, without compromising security.
--J
May 25, 2010 at 12:40 pm
Noted. Thanks J.
May 25, 2010 at 1:16 pm
J i've got a question for you regarding deployment;
i created a new VS project named "MyCLRProjects, and added only your Partial Public class as an example;
it compiled, and i was able to run the command to add the assembly:
CREATE ASSEMBLY MyCLRProjects from 'C:\data\MyCLRProjects.dll' WITH PERMISSION_SET = SAFE
when i try to add the udf with the command below, i get this simple error:
Msg 6505, Level 16, State 2, Procedure fn_ReadHttpPage, Line 1
Could not find Type 'UserDefinedFunctions' in assembly 'MyCLRProjects'.
the code:
CREATE FUNCTION fn_ReadHttpPage(@pageToRead varchar(250))
RETURNS varchar(max)
EXTERNAL NAME MyCLRProjects.UserDefinedFunctions.ufnFunction
can you point out my obvious error? i'm sure my Root namespace is simply "MyCLRProjects"
Lowell
May 25, 2010 at 1:48 pm
That's definitely strange. Personally, I deployed mine from VS, but I've deployed CLRs manually before, and didn't have any such problem.
If I script out my function, it looks mostly identical to your SQL script:
CREATE FUNCTION [dbo].[ufnFunction](@variable [nvarchar](4000))
RETURNS [nvarchar](4000) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [SqlServerCLR].[UserDefinedFunctions].[ufnFunction]
So I'm not sure what's going on. Have you tried deploying from VS? Before this project, I had never tried deploying from VS before, but I tried it and it was pain-free. Might be worth a shot since the manual way is giving you trouble...
I'm not sure if this will make a difference, but the permission level will need to be External. I had to change that in the project properties before deploying.
--J
May 25, 2010 at 1:52 pm
You will also need to:
ALTER DATABASE <dbname>
SET TRUSTWORTHY ON
For the database you are deploying the assembly to.
May 25, 2010 at 3:39 pm
J that got me looking in the right direction;
for whatever reason, my dll's class name is a little weird; i used hte deploy option, and then when i scripted the function it created out, it looks like htis: notice the middle name has a period in it...
CREATE FUNCTION [dbo].[Function1]()
RETURNS [nvarchar](4000) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [MyCLRProject].[MyCLRProject.UserDefinedFunctions].[Function1]
Lowell
May 25, 2010 at 3:46 pm
Oddly enough, I was looking for a similar thing today. I found the following. Not sure it applies here but might be helpful in what to look for...
Declare @Object as Int;
Declare @ResponseText as Varchar(8000);
--Code Snippet
Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT;
Exec sp_OAMethod @Object, 'open', NULL, 'get',
'http://www.lmgtfy.com/?q=Jeff+Moden', --Your Web Service Url (invoked)
'false'
Exec sp_OAMethod @Object, 'send'
Exec sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT
Select @ResponseText
Exec sp_OADestroy @Object
I also have to warn you that the sp_OA* methods reportedly had some memory leaks in the past. They've supposedly been fixed but I've not confirmed that in testing.
I'll probably catch hell from other forum members but tell him I like his line of thought. "KISS".
--Jeff Moden
Change is inevitable... Change for the better is not.
May 25, 2010 at 3:57 pm
J this thread was the most valuable thing of the week for me; i learned a lot. thank you very much.
I had to change your udf very slightly; i converted it to vb syntax, which is minor, but by making it return SQLChars instead of SQLString, it will map to a varchar(max), instead of raising a truncation issue on some pages:
i was testing it to just return the entire http response of a page, so google.com returns more than 800 chars.
<Microsoft.SqlServer.Server.SqlFunction()> _
Public Shared Function ufnFunction(ByVal variable As String) As SqlChars
Dim str As String = ""
Dim cn As String = variable
Dim http As HttpWebRequest = DirectCast(WebRequest.Create(cn), HttpWebRequest)
http.KeepAlive = False
Dim resp As HttpWebResponse = DirectCast(http.GetResponse(), HttpWebResponse)
Dim receiveStream As Stream = resp.GetResponseStream()
Dim encode As Encoding = System.Text.Encoding.GetEncoding("utf-8")
Dim readStream As New StreamReader(receiveStream, encode)
While Not readStream.EndOfStream
str = str + readStream.ReadLine()
End While
readStream.Close()
resp.Close()
Return New SqlChars(str)
End Function
End Class
Lowell
May 26, 2010 at 5:31 am
Great Lowell, I'm glad I could help. For my requirements, 4000 characters was more than enough. I'm glad you were able to manipulate it to meet your needs.
--J
Viewing 15 posts - 1 through 14 (of 14 total)
You must be logged in to reply to this topic. Login to reply