在SQL SERVER 2005中調用Web Service

SQL SERVER 2005中調用Web Service

原文:Nico Jacobs

出處:U2U nv/sa http://www.u2u.net/Article.aspx?ART=WebServicesinSQL05

改編,翻譯:劉凡 [email protected]

(譯者注:本人根據VS2005 RTM版和SQL SERVER 2005對涉及到Beta環境的步驟說明進行了調整。根據http://blogs.msdn.com/sqlclr/archive/2005/07/25/Vineet.aspx和實際測試,在VS 2005 RTM版中不需要採用手工的方式生成WebService代理類。)

 

介紹

SQL SERVER2005提供了在.NET中自定義函數、存儲過程、聚合、觸發器以及類型的功能。於是,我們可以在數據庫的函數、存儲過程或類型整合.NET對象方法等。在之前的一篇文章,我們演示瞭如何將正則表達式功能整合到SQL CLR中。在本文中,還是演示這種整合,但是這次是從SQL CLR中調用一個Web Service。我們將使用AdventureWorks這個樣例數據庫,定義一個函數,根據http://www.webservicex.net/CurrencyConvertor.asmx這個Web Service提供的匯率,進行從歐元到美元的外匯轉換。(這個WebService提供的匯率,只用於演示,不能作爲真實金融交易的數據。)

本文沒有詳細的描述所有的細節,讀者應該具有一定的在SQL SERVER2005下開發CLR的基礎。

 

定義轉換函數

      首先,在Visual Studio 2005中,根據開發模板,選擇新建一個C#或者VB.NETSQL SERVER項目。(注意:在Beta版中,必須在安裝VS2005之前安裝SQL SERVER 2005

      *在一些非正式的VS2005的版本中,直接使用工具引用WebService生成的代理類不能在SQL SERVER CLR中使用。原因是這種代理類生成了不能使用在CLR中的同步方法。具體可參考Vineet Rao blogs.msdn.com中的文章。解決的方法是利用C:/Program Files/Microsoft Visual Studio 8/SDK/v2.0/Bin目錄下的WSDL.exe工具生成老式異步方法的代理類,只用這種類才能在CLR中以External ACCESS的權限加載。如果我們使用“新”的代理類,必須使用Unsafe的安全級別,這種方式應儘量避免。我們可以使用一個XML配置文件來生成需要規範的代理類。創建一個以下內容的XML文件:

<wsdlParameters xmlns='http://microsoft.com/webReference/'>

  <language>c#</language>

  <protocol>Soap</protocol>

  <nologo>true</nologo>

  <sharetypes>false</sharetypes>

  <webReferenceOptions>

    <codeGenerationOptions>properties oldAsync</codeGenerationOptions>

  </webReferenceOptions>

</wsdlParameters>

假設保存路徑爲c:/oldwsdlconfig.xml如果使用VB.net項目則替換使用<language>vb</language>元素)。然後,使用以下命令行生成代理類:

C:/Program Files/Microsoft Visual Studio 8/SDK/v2.0/Bin/wsdl.exe /par:c:/ oldwsdlconfig.xml http://www.webservicex.net/CurrencyConvertor.asmx

 

運行結束後將生成CurrencyConvertor.cs(或者.vb)文件。在VS中使用添加現有項”定位到文件的位置後,將CurrencyConvertor.cs(或者.vb)文件增加到現有項目中。同時在項目中增加對System.Web.Services的引用:

下面,我們防止代碼在使用WebService通信中使用序列化和反序列化的過程(創建專門進行序列化的程序集)。在VS中選擇解決方案資源管理器,右鍵選擇屬性。C#VB.NET的設置方法稍有不同:

C#

選擇“生成”標籤,在底部選擇“生成序列化程序集”爲“開”。

VB.NET

選擇“編譯”標籤,點擊“高級”選項,在窗口底部選擇“生成序列化程序集”爲“開”。

同時,在項目屬性窗口中,我們設置權限等級:在數據庫標籤中,設置“權限級別”爲“外部”。這樣,我們聲明這個程序集是“Safe”的,不會作出危害性的過程,外部調用等。但是,它仍然不如聲明爲“Safe”的程序集安全,因爲它進行了網絡通信,訪問硬盤設備等行爲。

 

最後,可以進行主程序開發工作了:編寫貨幣轉化函數。這個函數輸入sql money類型的參數,乘上歐元對美元的匯率,返回一個sql money類型的數據。編寫的方法:在解決方案資源管理器中的項目上,右鍵選擇新增用戶自定義函數。並編寫如下代碼:

C#

public partial class UserDefinedFunctions

{

  [Microsoft.SqlServer.Server.SqlFunction]

  public static SqlMoney EUR2USD(SqlMoney amount)

  {

    CurrencyConvertor cc = new CurrencyConvertor();

    return new SqlMoney(cc.ConversionRate(Currency.EUR,Currency.USD)

      * amount.ToDouble());

  }

};

VB.NET

Partial Public Class UserDefinedFunctions

  <Microsoft.SqlServer.Server.SqlFunction()> _

  Public Shared Function EUR2USD(ByVal amount As SqlMoney) As SqlMoney

    Dim cc As New CurrencyConvertor()

    Return New SqlMoney(amount.ToDouble() * _

    cc.ConversionRate(Currency.EUR, Currency.USD))

  End Function

End Class

接下來,便可以生成並部署項目了。

 

SQL Management Studio調整

現在可以SQL Server 2005 Management Studio嘗試運行代碼。在SQL Server 2005 Management Studio中導航到我們部署代碼的數據庫(比如Adventureworks),可以看到在“可編程行”文件夾下,“程序集”選項中有一個已加載的程序級,並且創建了一個標量函數:

如果這時我們運行函數,會得到一個錯誤。在對象資源管理器中選擇數據庫右鍵打開,新建查詢。在查詢窗口執行以下T-SQL語句:

SELECT dbo.EUR2USD(1)

當我們執行語句的時候,不但不能獲得希望的結果,反而會得到以下錯誤:

Msg 6522, Level 16, State 2, Line 2

A .NET Framework error occurred during execution of user defined routine or aggregate 'EUR2USD':

System.InvalidOperationException: 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. ---> System.IO.FileLoadException: LoadFrom(), LoadFile(), Load(byte[]) and LoadModule() have been disabled by the host.

原因是少部署了一個DLL。當我們查看VS項目的BIN目錄,會發現生成了兩個DLL文件:WebServiceConsume.dll WebServiceConsume.XmlSerializers.dll.後面一個DLL用來在WEB SERVICE調用時候進行序列化和反序列化,它沒有被自動部署到SQL SERVER數據庫中。我們需要進行手工部署:右鍵點擊SQL management studio中對象資源管理器中“程序集”文件夾,選擇“新建程序集”

在顯示的窗口中瀏覽選擇指定WebServiceConsume.XmlSerializers.dll的位置。你可以不改變權限級別的“Safe”,這個程序集不進行外部通信。選擇確定後,刷新“程序集”文件夾,可以看到剛纔新建的程序集。

再次運行剛纔的TSQL語句:它已經能夠成功運行了,提供匯率的Web Service能夠被整合到CLR的函數直接調用了。

 

Web Services和效率

最後叮囑:慎重使用類似的WebService調用。依賴網絡通信的調用,速度較慢。所以如果你要將這些功能處理大數據量的表時,要非常慎重。測試一下,使用下面的查詢,獲取所有的歐元和美元數據(504 rows, AdventureWorks database):

select StandardCost, dbo.EUR2USD(StandardCost) from Production.Product

大概需要444秒才能完成查詢因爲需要調用WebService 504次。然而我們可以重寫成以下的方式:

declare @rate float

select @rate = dbo.EUR2USD(1)

select StandardCost, StandardCost * @rate from AdventureWorks.Production.Product

這樣,我們只需要調用WebService一次,將匯率存儲到本地變量。除非WebService的結果在執行期間改變了,後一種方法比前者快300多倍。

慎重的使用WebService:如果WebService的調用結果被重複的使用,儘量將結果緩存到本地SQL變量或者臨時表,避免不必要的重複調用。但同時注意,不能使用CLR來緩存數據。因爲程序集被加載到SQL SERVER後,時不允許儲存靜態或者共享狀態對象的,除非你聲明程序集爲“Unsafe”。

 

Dr. Nico Jacobs

U2U (www.u2u.net)組織的培訓師和顧問. 關注Microsoft SQL Server ADO.NET領域. 可以通過[email protected]reach Nico聯繫。

 



 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章