从 SQL Server 执行 VB.NET DLL
目标:
我们想要使用 .Net 3.5 使用 VB.NET 2008 编写一个 DLL,执行 HTTP 请求,
然后我们想要从 SQL Server 2005 调用 DLL(在触发器中)并向 DLL 传递一些变量并获取返回值。
我在这个过程中的位置。
我创建了 DLL 'HTTPDLL.dll'
来源:
Imports System
Imports System.Configuration
Imports System.Collections.Generic
Imports System.Text
Imports System.Net
Imports System.Security
Imports System.Security.Permissions
Imports System.IO
Imports Microsoft.SqlServer.Server
Public Class HTTPDLL
Public Function HTTPPost(ByVal URL As String, ByVal Content As String) As Boolean
Dim myURL As String = Trim(URL)
Dim mycontent As String = Trim(Content)
Dim rawOutput As String = ""
'Get Acces Right to web
Dim p As New WebPermission(NetworkAccess.Connect, myURL)
p.Assert()
'Prepare the web Request
Dim req As WebRequest = WebRequest.Create(myURL)
req.Timeout = 60000
req.Method = "POST"
req.ContentLength = mycontent.Length
req.ContentType = "application/x-www-form-urlencoded"
Dim sw As New StreamWriter(req.GetRequestStream())
sw.Write(mycontent)
sw.Close()
Dim resp As WebResponse = req.GetResponse()
Dim sr As New StreamReader(resp.GetResponseStream)
rawOutput = sr.ReadToEnd()
sr.Close()
Return True
End Function
Public Function Test() As Integer
Return 1
End Function
Public Function DllMain(ByVal hInst As Long, ByVal fdwReason As Long, _
ByVal lpvReserved As Long) As Boolean
Dim s As String = "sdfghjkolihdgjkhgiueghkyhekygigdjhgfkhsgdkhfgksjdhgkjshdgfkjhsgdkjfhgkshdgfkjhgskjdhgfkjhsdgkfhgskjdhfgkjsdhgfkshdgfkhgsdkfhgksdhfgkshdgfkshdgfkjhsgdkfhgskdhfgksjdhgfkjshgdfkhsgdkfhgskdhfgkshgdfkjhgskdjg"
s &= "kjhdgjkshkdjfhklsjdhfljhgkhvbfiuvbli klrfgliu ghliebliuhdflivbdkljhgljuhfvliuhdf"
Return True
End Function
End Class
我已将 DLL 放置在 SQL Server c:/Windows/System 文件夹中
我已加载这些程序集
HelloWorld 系统核心 System.XML.Linq
使用这些命令,
EXEC sp_configure 'show advanced options' , '1';
go
reconfigure
go
EXEC sp_configure 'clr enabled' , '1'
go
sp_configure 'Ole Automation Procedures', '1'
GO
RECONFIGURE
-- Turn advanced options back off
EXEC sp_configure 'show advanced options' , '0';
go
reconfigure
GO
-- assembly style
ALTER DATABASE master SET TRUSTWORTHY ON
GO
CREATE ASSEMBLY [System.Core]
AUTHORIZATION [dbo]
FROM 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll'
WITH PERMISSION_SET = UNSAFE
GO
CREATE ASSEMBLY [System.Xml.Linq]
AUTHORIZATION [dbo]
FROM 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll'
WITH PERMISSION_SET = UNSAFE
GO
create assembly HelloWorld from 'C:\WINDOWS\system\HTTPDLL.dll'
with permission_set = safe
GO
然后添加了扩展过程
USE [master]
GO
/****** Object: ExtendedStoredProcedure [dbo].[HTTPDLL] Script Date: 02/03/2010 11:45:28 ******/
EXEC dbo.sp_addextendedproc N'HTTPDLL', 'C:\WINDOWS\system\HTTPDLL.dll'
(此时我不确定为什么或是否需要添加程序集,因为它直接引用 Dll。)
我需要解决什么。 我现在想调用 DLL 的(扩展过程)HTTPPost 函数
我尝试过的 执行HTTPPost “消息 17750,级别 16,状态 0,过程 HTTPPost,第 1 行 无法加载 DLL HelloWorld 或其引用的 DLL 之一。原因: 126(找不到指定的模块。)。"
exec HelloWorld.HTTPPost 'http://www.somewebsite.com',''
"Msg 2812, Level 16, State 62, Line 1 找不到存储过程“HelloWorld.HTTPPost”。”
我需要什么: 如果您可以查看我的实现,看看我是否正确设置了所有内容,并告诉我(请举例)如何正确调用该 DLL、向其发送变量并捕获其返回值。我将非常感激。
我浏览了很多帖子/文章,并得到了一些让我到目前为止的点滴,但没有什么是包罗万象的。
我也尝试过这个
-- Scratch variables used in the script
DECLARE @retVal INT
DECLARE @comHandle INT
DECLARE @errorSource VARCHAR(8000)
DECLARE @errorDescription VARCHAR(8000)
DECLARE @retString VARCHAR(100)
-- Initialize the COM component.
EXEC @retVal = sp_OACreate 'HTTPDLL.HTTPDLL', @comHandle OUTPUT
IF (@retVal <> 0)
BEGIN
-- Trap errors if any
EXEC sp_OAGetErrorInfo @comHandle, @errorSource OUTPUT, @errorDescription OUTPUT
SELECT [Error Source] = @errorSource, [Description] = @errorDescription
RETURN
END
(以及其他此类变体) 的返回中获取此信息
并在 sp_OAGetErrorInfo “错误源描述” ODSOLE 扩展过程无效的类字符串”
也许我错误地调用了它,但我无法让它工作(总是返回“无效的类字符串”)
提前感谢您的帮助!
Objective:
we want to write a DLL using VB.NET 2008 using .Net 3.5 that performs an HTTP request
we then want to call the DLL From SQL Server 2005 (in a trigger) and pass the DLL some variables and get a return value.
Where im at in the process.
I have created the DLL 'HTTPDLL.dll'
Source:
Imports System
Imports System.Configuration
Imports System.Collections.Generic
Imports System.Text
Imports System.Net
Imports System.Security
Imports System.Security.Permissions
Imports System.IO
Imports Microsoft.SqlServer.Server
Public Class HTTPDLL
Public Function HTTPPost(ByVal URL As String, ByVal Content As String) As Boolean
Dim myURL As String = Trim(URL)
Dim mycontent As String = Trim(Content)
Dim rawOutput As String = ""
'Get Acces Right to web
Dim p As New WebPermission(NetworkAccess.Connect, myURL)
p.Assert()
'Prepare the web Request
Dim req As WebRequest = WebRequest.Create(myURL)
req.Timeout = 60000
req.Method = "POST"
req.ContentLength = mycontent.Length
req.ContentType = "application/x-www-form-urlencoded"
Dim sw As New StreamWriter(req.GetRequestStream())
sw.Write(mycontent)
sw.Close()
Dim resp As WebResponse = req.GetResponse()
Dim sr As New StreamReader(resp.GetResponseStream)
rawOutput = sr.ReadToEnd()
sr.Close()
Return True
End Function
Public Function Test() As Integer
Return 1
End Function
Public Function DllMain(ByVal hInst As Long, ByVal fdwReason As Long, _
ByVal lpvReserved As Long) As Boolean
Dim s As String = "sdfghjkolihdgjkhgiueghkyhekygigdjhgfkhsgdkhfgksjdhgkjshdgfkjhsgdkjfhgkshdgfkjhgskjdhgfkjhsdgkfhgskjdhfgkjsdhgfkshdgfkhgsdkfhgksdhfgkshdgfkshdgfkjhsgdkfhgskdhfgksjdhgfkjshgdfkhsgdkfhgskdhfgkshgdfkjhgskdjg"
s &= "kjhdgjkshkdjfhklsjdhfljhgkhvbfiuvbli klrfgliu ghliebliuhdflivbdkljhgljuhfvliuhdf"
Return True
End Function
End Class
I have placed the DLL in the SQL Server c:/Windows/System folder
I have loaded these assemblies
HelloWorld
System.Core
System.XML.Linq
using these commands
EXEC sp_configure 'show advanced options' , '1';
go
reconfigure
go
EXEC sp_configure 'clr enabled' , '1'
go
sp_configure 'Ole Automation Procedures', '1'
GO
RECONFIGURE
-- Turn advanced options back off
EXEC sp_configure 'show advanced options' , '0';
go
reconfigure
GO
-- assembly style
ALTER DATABASE master SET TRUSTWORTHY ON
GO
CREATE ASSEMBLY [System.Core]
AUTHORIZATION [dbo]
FROM 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll'
WITH PERMISSION_SET = UNSAFE
GO
CREATE ASSEMBLY [System.Xml.Linq]
AUTHORIZATION [dbo]
FROM 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll'
WITH PERMISSION_SET = UNSAFE
GO
create assembly HelloWorld from 'C:\WINDOWS\system\HTTPDLL.dll'
with permission_set = safe
GO
I then Added the Extended Procedure
USE [master]
GO
/****** Object: ExtendedStoredProcedure [dbo].[HTTPDLL] Script Date: 02/03/2010 11:45:28 ******/
EXEC dbo.sp_addextendedproc N'HTTPDLL', 'C:\WINDOWS\system\HTTPDLL.dll'
(at this point im not sure why or if i needed to add the assembly, since this references the Dll directly.)
What I need solved.
I now want to call the DLL's (extended procedure) HTTPPost Function
What I have Tried
exec HTTPPost
"Msg 17750, Level 16, State 0, Procedure HTTPPost, Line 1
Could not load the DLL HelloWorld, or one of the DLLs it references. Reason: 126(The specified module could not be found.)."
exec HelloWorld.HTTPPost 'http://www.somewebsite.com',''
"Msg 2812, Level 16, State 62, Line 1
Could not find stored procedure 'HelloWorld.HTTPPost'."
What I need:
If you can look over my implimentation and see if i am setting everything up properly, and also tell me (with examples please) how to call that DLL properly, sending it variables and catching its return value. I will be very gratefull.
I have looked through MANY posts/articles and have got bits and peices that have taken me this far, but nothing has been all inclusive.
I have also tried this
-- Scratch variables used in the script
DECLARE @retVal INT
DECLARE @comHandle INT
DECLARE @errorSource VARCHAR(8000)
DECLARE @errorDescription VARCHAR(8000)
DECLARE @retString VARCHAR(100)
-- Initialize the COM component.
EXEC @retVal = sp_OACreate 'HTTPDLL.HTTPDLL', @comHandle OUTPUT
IF (@retVal <> 0)
BEGIN
-- Trap errors if any
EXEC sp_OAGetErrorInfo @comHandle, @errorSource OUTPUT, @errorDescription OUTPUT
SELECT [Error Source] = @errorSource, [Description] = @errorDescription
RETURN
END
(and other such variants)
and get this in the return of sp_OAGetErrorInfo
"Error Source Description
ODSOLE Extended Procedure Invalid class string"
Perhaps i am calling it incorrectly but i havent been able to get it to work (always return 'invalid class string')
Thank you in advance for your help!.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您创建的 CLR 程序集不同于非托管扩展存储过程或 OLE 自动化 COM 对象。在添加扩展存储过程之前,您已经步入正轨。你在这里不这样做。您需要使用程序集中的 CREATE PROCEDURE DDL 语法创建存储过程。查看我关于 SQL Server Central 的文章的源代码和创建脚本:
http:// www.sqlservercentral.com/articles/SQLCLR/65657/
您将需要程序集的外部访问权限,它无法使用 SAFE 创建并进行类似的 Web 服务调用。除此之外,添加此功能作为触发器是一个坏主意。如果 Web 服务出现问题并且生成未处理的 CLR 异常,则可能会导致触发器中的事务失败和回滚。除此之外,如果 Web 服务调用存在延迟,您将延迟 SQL 中事务的完成,这可能会导致阻塞和响应时间变慢。
对此更好的解决方案是使用 Service Broker 队列和通知服务以及外部激活器来激活外部进程,以便在 SQL Server 外部异步操作队列。触发器所要做的就是向队列发送一条消息,然后就完成了。这样,如果服务调用存在延迟或服务关闭,信息仍会存储,并且如果您正确构建激活应用程序,它将以事务方式处理队列,因此失败会将信息保留在队列中以供稍后重试。
You created a CLR Assembly which is different than a Unmanaged Extended Stored Procedure, or a OLE Automation COM object. You were somewhat on track up to the point of adding the Extended Stored Procedure. You don't do that here. You need to create a Stored Procedure using CREATE PROCEDURE DDL syntax from the Assembly. Take a look at the source and creation scripts for my article on SQL Server Central:
http://www.sqlservercentral.com/articles/SQLCLR/65657/
You will need External Access rights on the Assembly, it can't be created with SAFE and make a web service call like that. In addition to this, adding this functionality as a trigger is a bad idea. If there is a problem with the webservice and you generate an unhandled CLR exception, it can cause transactional failure and rollback in the trigger. In addition to that if there is latency in the webservice call you will delay the completion of your transaction in SQL which can cause blocking and slow response times.
A better solution to this would be to use a Service Broker Queue and Notification Service with the External Activator to activate an external process to work the queue asynchronously and outside of SQL Server. All the trigger has to do is send a message to the queue and it is done. This way if there is latency in the service call or the service is down the information is still stored and if you build your activation app correctly it will transactionally process the queue so a failure would keep the information in queue for retry later.
请看一下这个 http://dbalink.wordpress.com/2008/10/25/cannot-load-the-dll-error-in-sql-server-2005/
这可能就是您所需要的;-)
Please take a look at this http://dbalink.wordpress.com/2008/10/25/cannot-load-the-dll-error-in-sql-server-2005/
That is probably what you need ;-)
ACPerkins @ Experts-exchange 的这篇文章给了我们启发
最差实践 - 触发外部事件
http://www.sqlservercentral.com/articles/Triggers/worstpracticetriggeringexternalevents/1283/< /a>
因此,我们目前正在研究一些其他方法。
感谢您的帮助。
安东尼
ACPerkins @ Experts-exchange has enlightened us with this article
Worst Practice - Triggering External Events
http://www.sqlservercentral.com/articles/Triggers/worstpracticetriggeringexternalevents/1283/
and as such we are currently looking into some other methedologies.
thanks for your help.
Anthony