利用 Web Service存取 SQL Server資料庫

by adonis 15. 七月 2013 15:56

作    者:楊先民
審    稿:張智凱

前言
我們都知道,如果你寫應用程式需要連接到 SQL Server,你必需準備 SQL Native Client或是 OLE DB For SQL Server,而且大多數都會希望你的前端應用程式是使用 .NET 開發,然而本文的主題是「如果你的前端並非 .NET的程式」,那你應該如何連接到 SQL Server處理資料呢?
本文的解法將使用 web service來完成。   

Web Service當成資料處理的中繼層

本文的情境前端是使用 iphone的程式開發Objective-C,並且使用原生的方式來呼叫已經寫好的 web service程式,也就是我並不打算使用 Jason的方式來存取 web service,自己控制比較有實作的感覺啊,而且也順便記錄一下這種複雜的存取控制方式,頓時之間你會發現使用 .NET來呼叫 web service是多麼的簡單(只需設定一個 proxy物件就好,但 iphone開發沒那麼容易)!

情境是這樣的,我在 iphone上撰寫了一支車輛油耗管理的程式,詳細請參考下列網站:
https://itunes.apple.com/tw/app/you-hao-wei-xiupro/id491654074?mt=8

這支程式不但管理使用者的車輛油耗以及保養維修記錄,還可以上傳使用者的油耗資訊和其他同車廠同型號的使用者比較,所以我設計了一個如下的界面:

image

當使用者先登錄車籍資料,並且按下「上傳油耗資訊」,使用者就可以將自身的油耗資訊上傳,並且在統計頁面上可以知道自己的油耗,以及全部車種的油耗排名,如下圖:

image

其實,單純就以資料庫的角度來看油耗資訊上傳非常容易,只不過就是寫個 update指令,將油耗資訊寫入資料庫罷了,不過別忘記我們用的是 iphone的程式,並不是 .NET的程式,也許有 3-party的廠商提供函式庫給 iphone呼叫 SQL Server,但最通用的方式還是自己透過 web service最實在了,主因是 web service是一個跨平台的程式,透過 tcp/ip與 xml做為媒界,任何前端(並非只有 Windows前端)可以呼叫 web service,而你只需處理回傳回來的 xml資料即可(xml現今用來廣泛的做為資料交換之用)。

所以我們必需做幾件事情:

1.    在 SQL Server中撰寫更新油耗的 stored procedure,用來做資料處理。
2.    利用 asp .net web service,呼叫1所撰寫的 stored procedure。
3.    在 iphone中利用程式呼叫 web service,更新油耗資訊。

我們就一步步來:
首先,1的部分就是寫一個更新油耗資訊的 stored procedure,如下:

Create proc [dbo].[COil_UpdateOil]
@deviceid int,@totalwalkkm decimal(10,2),@totallitre decimal(10,2)
as
IF @totallitre=0
set @totallitre=1
update Oil set walkkm = @totalwalkkm , Litre = @totallitre where DeviceID = @deviceid
select @@ROWCOUNT

其中就是輸入三個參數,一個是裝置id,一個是總行駛公里,一個是總加油公升,如此而以。

再來,利用 asp .net 的 web service,呼叫寫好的 stored procedure,程式如下:

    <WebMethod()> _
Public Function updateOil(ByVal deviceid As String, ByVal totalwork As String, ByVal totallitre As String) As Integer
        '
Dim returnValue As Integer
returnValue = 0

Dim myConnection As SqlConnection = New SqlConnection(System.Configuration.ConfigurationManager.AppSettings("uploadoil"))
Dim myCommand As SqlCommand
myCommand = New SqlCommand("COil_UpdateOil", myConnection)

myCommand.CommandType = CommandType.StoredProcedure

Dim parameterCustomerid As SqlParameter = New SqlParameter("@deviceid", SqlDbType.Int, 4)
parameterCustomerid.Value = deviceid
Dim parameterdefaultcar As SqlParameter = New SqlParameter("@totalwalkkm", SqlDbType.Decimal, 9)
parameterdefaultcar.Value = Convert.ToDecimal(totalwork)

Dim parameterTotallitre As SqlParameter = New SqlParameter("@totallitre", SqlDbType.Decimal, 9)
parameterTotallitre.Value = Convert.ToDecimal(totallitre)
myCommand.Parameters.Add(parameterCustomerid)
myCommand.Parameters.Add(parameterdefaultcar)
myCommand.Parameters.Add(parameterTotallitre)
' Execute the command
Try
           myConnection.Open()
            returnValue = myCommand.ExecuteScalar
            myConnection.Close()
            Catch ex As Exception
           myConnection.Close()
            returnValue = 0
End Try
        Return returnValue
End Function

寫好的 web service,可以在網站測試一下,初始畫面應該是如下:

image

而我們還要注意下方的 SOAP的呼叫方式,這個將是等會我們要用 iphone 呼叫的程式:

image

目前我依然使用 SOAP 1.1的呼叫方式,你有興趣可以使用再更下方的 SOAP 1.2。
如果你原先寫的是 .NET程式,你可能根本不會想看這張圖,因為 .NET只要把 web service的網址參考進來並且指定一個 proxy物件就可以直接呼叫了,換言之這部分的動作被 .NET給包起來了,如果你在 iphone中是使用 Jason的話,也大概是這麼包(不過絕對沒有 .NET這麼容易就是了)。

不過在 iphone中你要是撰寫的是原生的 web service,就要把上圖的那個呼叫與回傳好好研究一下,因為我們必需自己呼叫 SOAP Action。

我們對照瀏灠器上的 SOAP,將我們自已的 SOAP Action組裝起來,下方的第一張圖是瀏灠器上的Envelope(信封,將 SOAP Action用信封包起來丟出去的意思),第二張則是用 objective-c的 stringformat將 SOAP action組合成訊息字串 soapMessage。

image

image

是的,在 iphone中,你就是要利用 objective-c將這段 SOAP Action傳送到 web service端,然後輸入所需要的參數(以本例而言,是 deviceid、totalwork以及 totallitre這三個參數)。

接下來,設定NSMutableURLRequest,將我們的 web service位址,也就是 http://xxx.xxx.xxx.xxx/upload.asmx 指定,並且包上 HeaderField傳送出去,也就是在瀏灠器中,原本 SOAP Action的上面,還有一段資訊,如下:

image

是的,就是這段資訊,要一併隨著我們的 SOAP Action的信封傳送到 web service中。所以尚需要加上這一段程式碼:

image

其中有一行程式是 msgLength這個變數,主要是 HeaderField中需要 SOAP Action的 Content-Length,所以必需把剛才前面所定義的 soapMessage的長度輸入進來,然後就可以開始處理 web service 所回傳的資訊了。

(當然,這裡不要忘記,由於我們設定 connection 的 delegate屬性為 self,表示 xml web service這段部分的處理是由我們自行來完成,故不要忘記在h檔定義的地方加上NSXMLParserDelegate,如下圖:

image

由於要自己處理 web service的回傳(如果此 web service沒有回傳的話,只需注意網路有沒有連線成功即可,後續不用處理,但由於本例有回傳結果,所以我們必需知道回傳的格式),所以我們必需知道 web service會回傳什麼資訊回來,因此我們先在 web service上測試我們的值以及取得回傳結果的 xml資料,如下兩張圖:

image

回傳結果如下:

image

還記得我們的 stored procedure嗎?當資料修改完,回傳修改數量,以上圖為例,回傳值為1表示有資料被修改,那麼就代表成功了。我們在 iphone中要寫的程式主要是取回1這個數值,只要它是大於零,表示資料有成功修改到,本上傳油耗的程式即大功告成!

至此,我們需要設定剛才的 theConnection,要在它接收到資料時,將回傳的結果存入事先定義好的陣列中,所以我們必需在didReceiveResponse中清空陣列以及在didReceiveData中將取出的值填入陣列中,程式碼如下:

image

在連線結束載入時,利用 NSXMLParser開始剖析回傳回來的 XML資料,如下圖:

image

而可以注意到程式中的 xmlParser的 setDelegate設定為 self,所以代表你要自行撰寫取出 XML時的剖析內容,因此我們要自行控制didStartElement、foundCharacters以及didEndElement這三個事件。

在此稍微說明一下,XML是個階層式的資料,所以資料很有可能長的如下:
<Employee>
    <id>E01</id>
</Employee>

所謂的 didStartElement,代表發現 <Employee>這個 Element,但我們如果要的是<id>這個 element中的 E01資料,則就得請 parser繼續往下找。

foundCharacters則是代表 E01這個字元被找到,我們這裡必需寫程式把它存起來,由於 XML是 unicode以及是文字資料型別,所以要用文字字串或是陣列儲存起來。

最後的 didEndElement則是 </Employee>,也就是 XML中的尾巴這部分,代表整個 XML的結束。

至於我們如何知道頭尾的 element是什麼呢?很簡單,在瀏灠器上看的 demo其實就給了我們資訊,如下圖:

image

是的,也就是我們在didStartElement需要判斷是否值為updateOilResult,如果是的話,就可以開始讀裡面的值,如下圖:

image

在此程式中,我們設定 UpdateOil為 YES,主要是如果你在同一個程式中呼叫多支 web service,負責處理的 method是同一支,所以你要設定像 UpdateOil這樣的旗標,用來說明我已經找到某個 element了,並且把其他的旗標設定為 NO(iphone中是用 YES NO而不是 true與 false)。

然後在 foundCharacters中撰寫程式判斷回傳的結果是否為1,如下圖:

image

由於 xml的文字都是 unicode字串,所以即便是它看起來像數字的0與1,還是要以字串的方式處理。

最後,在 didEndElement中結束這次 XML資料的剖析,如下圖:

image

至此,由 iphone呼叫 web service的程式宣告完成,是不是感覺有點複雜呢?其實以前習慣了 .NET開發,很多動作都包起來,但其實 web service就是一個很簡單的概念,把 SOAP Action用一個信封包起來,利用 HTTP傳送到網路上的 web service,而 SOAP Action裡面已經把呼叫 web service的動作定義好了, web service處理完之後再將 xml回傳結果用一個信封回傳,而應用程式端看自己有沒有需要接收回傳值,再利用 xmlparser負責處理即可,有部分程式是可以直接套用就可以使用的,各位可以參考看看,不用依賴 Jason,畢竟寫原生的 web service好處就是只要概念通,其他應用程式也大概是類似的道理。

image

Tags:

評論 (2) -

joe
joe Taiwan
2015/11/11 下午 06:02:55 #

cool! 學習了~非常實用!

回覆

roger
roger Taiwan
2016/8/2 下午 04:03:36 #

我也曾用objective c寫過XML parsing
但好像打JSON比較簡單哩..
NSJSONSerialization JSONObjectWithData
直接反序列化
不過還是感謝..

回覆

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List