天天看點

WebService開發

一、什麼是WebService:

簡單通俗來說,就是企業之間、網站之間通過Internet來通路并使用線上服務,一些資料,由于安全性問題,不能提供資料庫給其他機關使用,這時候可以使   用WebService服務提供。

二、建立WebService

建立WebService之後,我們就可以在檔案裡寫傳回資料的方法了。

三、傳回資料的四種形式

筆者水準有限,隻列出這四種資料的傳回形式:

(1)直接傳回DataSet對象

(2)傳回DataSet對象用Binary序列化後的位元組數組

(3)傳回DataSetSurrogate對象用Binary序列化後的 位元組數組

(4)傳回DataSetSurrogate對象用Binary序列化并Zip 壓縮後的位元組數組

理論上來說,網絡傳輸位元組與傳輸時間,應該是遞減的,其中,(3)(4)種方法需要引用微軟提供的開源元件  下載下傳位址:http://support.microsoft.com/kb/829740/zh-cn

下面展示這四種傳回資料的代碼,其中(1)是其三種方法的根本,都要得到一個DataSet作為根本,然後來做各種轉換壓縮的操作:

view source

print?

1

1

[WebMethod(Description =

"直接傳回DataSet對象"

)]

2

public

DataSet GetDataSet()

3

{

4

string

connStr = System.Configuration.ConfigurationManager.ConnectionStrings[

"conn"

].ToString();

5

SqlConnection conn =

new

SqlConnection(connStr);

6

string

sql =

"select * from china_city"

;

7

conn.Open();

8

SqlDataAdapter sda =

new

SqlDataAdapter(sql, conn);

9

DataSet ds =

new

DataSet(

"China"

);

10

sda.Fill(ds);

11

conn.Close();

12

return

ds;

13

}  

14

15

[WebMethod(Description =

"直接傳回DataSet對象,并用Binary序列化後的位元組數組"

)]

16

public

byte

[] GetDataSetBytes()

17

{

18

DataSet ds = GetDataSet();

19

BinaryFormatter ser =

new

BinaryFormatter(); 

//序列化對象

20

MemoryStream ms =

new

MemoryStream(); 

//記憶體流

21

ser.Serialize(ms, ds);

22

byte

[] buffer = ms.ToArray();   

//位元組流

23

return

buffer;

24

}  

25

26

[WebMethod(Description =

"直接傳回DataSetSurrogate對象,并用Binary序列化後的位元組數組"

)]

27

public

byte

[] GetDataSetSurrogateBytes()

28

{

29

DataSet ds = GetDataSet();

30

DataSetSurrogate dss =

new

DataSetSurrogate(ds);

31

BinaryFormatter ser =

new

BinaryFormatter(); 

//序列化對象

32

MemoryStream ms =

new

MemoryStream(); 

//記憶體流

33

ser.Serialize(ms, dss);

34

byte

[] buffer = ms.ToArray();   

//位元組流

35

return

buffer;  

36

37

}  

38

39

[WebMethod(Description =

"直接傳回DataSetSurrogate對象,并用Binary序列化後并且ZIP壓縮的位元組數組"

)]

40

public

byte

[] GetDataSetSurrogateZipBytes()

41

{

42

DataSet ds = GetDataSet();

43

DataSetSurrogate dss =

new

DataSetSurrogate(ds);

44

BinaryFormatter ser =

new

BinaryFormatter(); 

//序列化對象

45

MemoryStream ms =

new

MemoryStream(); 

//記憶體流

46

ser.Serialize(ms, dss);

47

byte

[] buffer = ms.ToArray();   

//位元組流

48

byte

[] bufferZip = ComPress(buffer);

49

return

buffer;

50

}

51

//壓縮方法

52

public

byte

[] ComPress(

byte

[] data)

53

{

54

try

55

{

56

MemoryStream ms =

new

MemoryStream();

57

Stream zipStream =

null

;

58

zipStream =

new

GZipStream(ms, CompressionMode.Compress,

true

);

59

zipStream.Write(data, 0, data.Length);

60

zipStream.Close();

61

ms.Position = 0;

62

byte

[] compressed_data =

new

byte

[ms.Length];

63

ms.Read(compressed_data, 0,

int

.Parse(ms.Length.ToString()));

64

return

compressed_data;

65

}

66

catch

67

{

68

return

null

;

69

}

70

}

我們可以在浏覽器中檢視下WebService的效果,如圖,在這個頁面中,有提供四個方法,這四個方法就是上述我們寫的四個傳回資料的方法了,點選方法即可傳回相應的資料,這樣,我們資料提供方的代碼就可以寫好了,接下來,我們寫調用資料的方法!

四、調用資料

用戶端WebService程式

1

private

void

button1_Click(

object

sender, EventArgs e)

2

{

3

com.dzbsoft.www.Service1 ds =

new

com.dzbsoft.www.Service1(); 

//new出WebService對象

4

DateTime dtBegin = DateTime.Now;

5

DataSet dataSet = ds.GetNorthwindDataSet();

6

this

.label1.Text =

string

.Format(

"耗時:{0}"

, DateTime.Now - dtBegin);

7

binddata(dataSet);

8

}

9

private

void

button2_Click(

object

sender, EventArgs e)

10

{

11

com.dzbsoft.www.Service1 ds =

new

com.dzbsoft.www.Service1();

12

DateTime dtBegin = DateTime.Now;

13

byte

[] buffer = ds.GetDataSetBytes();

14

BinaryFormatter ser =

new

BinaryFormatter();

15

DataSet dataSet = ser.Deserialize(

new

MemoryStream(buffer))

as

DataSet;

16

this

.label2.Text =

string

.Format(

"耗時:{0}"

, DateTime.Now - dtBegin) +

"  "

+ buffer.Length;

17

binddata(dataSet);

18

}

19

private

void

button3_Click(

object

sender, EventArgs e)

20

{

21

com.dzbsoft.www.Service1 ds =

new

com.dzbsoft.www.Service1();

22

DateTime dtBegin = DateTime.Now;

23

byte

[] buffer = ds.GetDataSetSurrogateBytes();

24

BinaryFormatter ser =

new

BinaryFormatter();

25

DataSetSurrogate dss = ser.Deserialize(

new

MemoryStream(buffer))

as

DataSetSurrogate;

26

DataSet dataSet = dss.ConvertToDataSet();

27

this

.label3.Text =

string

.Format(

"耗時:{0}"

, DateTime.Now - dtBegin) +

"  "

+ buffer.Length;

28

binddata(dataSet);

29

}

30

private

void

button4_Click(

object

sender, EventArgs e)

31

{

32

com.dzbsoft.www.Service1 ds =

new

com.dzbsoft.www.Service1();

33

DateTime dtBegin = DateTime.Now;

34

byte

[] zipBuffer = ds.GetDataSetSurrogateZipBytes();

35

byte

[] buffer = UnZipClass.Decompress(zipBuffer);

36

BinaryFormatter ser =

new

BinaryFormatter();

37

DataSetSurrogate dss = ser.Deserialize(

new

MemoryStream(buffer))

as

DataSetSurrogate;

38

DataSet dataSet = dss.ConvertToDataSet();

39

this

.label4.Text =

string

.Format(

"耗時:{0}"

, DateTime.Now - dtBegin) +

"  "

+ zipBuffer.Length;

40

binddata(dataSet);

41

}

42

private

void

binddata(DataSet dataSet)

43

{

44

this

.dataGridView1.DataSource = dataSet.Tables[0];

45

this

.label5.Text =

"共計:"

+ dataSet.Tables[0].Rows.Count +

"條記錄"

;

46

}

在資料傳回的方法中,我們使用了資料的壓縮,是以,在調用方這邊,需要進行解壓,代碼:

1

用戶端UnZipClass程式

2

public

static

class

UnZipClass

3

{

4

public

static

byte

[] Decompress(

byte

[] data)

5

{

6

try

7

{

8

MemoryStream ms =

new

MemoryStream(data);

9

Stream zipStream =

null

;

10

zipStream =

new

GZipStream(ms, CompressionMode.Decompress);

11

byte

[] dc_data =

null

;

12

dc_data = ExtractBytesFromStream(zipStream, data.Length);

13

return

dc_data;

14

}

15

catch

16

{

17

return

null

;

18

}

19

}

20

public

static

byte

[] ExtractBytesFromStream(Stream zipStream,

int

dataBlock)

21

{

22

byte

[] data =

null

;

23

int

totalBytesRead = 0;

24

try

25

{

26

while

(

true

)

27

{

28

Array.Resize(

ref

data, totalBytesRead + dataBlock + 1);

29

int

bytesRead = zipStream.Read(data, totalBytesRead, dataBlock);

30

if

(bytesRead == 0)

31

{

32

break

;

33

}

34

totalBytesRead += bytesRead;

35

}

36

Array.Resize(

ref

data, totalBytesRead);

37

return

data;

38

}

39

catch

40

{

41

return

null

;

42

}

43

}

44

}

在上例中,調用四個方法的效果是一樣的,唯一不同的是,傳輸過程中,資料量大小和傳輸時間的差異。

============2=============

效率調用問題,是以,我回說說如何實作同步與異步調用 webservice,如果說得哪裡不對或者不好的地方,歡迎大家評論指導。

首先,什麼是同步,什麼是異步呢?打個比方來說,小明和小 華,互相打架,小明打了小華3下之後,小華才能打回小明,這叫同步,如果,小華勇敢點,在小明打了第一下開始做出反擊,也打回小明,這叫異步。 也就是說,隻能等待另外一個作業進行完才能進行下一個操作的叫同步,在另外一個作業進行的同時也進行其他操作,叫異步。

先建立一個webservice

1

using

System;

2

using

System.Web;

3

using

System.Web.Services;

4

using

System.Web.Services.Protocols;

5

6

[WebService(Namespace =

"http://tempuri.org/"

)]

7

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

8

//若要允許使用 ASP.NET AJAX 從腳本中調用此 Web 服務,請取消對下行的注釋。

9

// [System.Web.Script.Services.ScriptService]

10

public

class

GetWebService : System.Web.Services.WebService

11

{

12

13

[WebMethod]

14

public

string

HelloWorld()

15

{

16

int

res = 0;

17

for

(

long

i = 0; i < 1000000000; i++)   

//循環10億次,目的是模仿大批量操作,這裡至少需要數秒的操作以便看出異步的效果

18

{

19

res++;

20

}

21

return

" Hello World"

;

22

}

23

24

}

webservice建立好了,建立一個winform項目,引入webservice,我在引入webservice的時候,差點被坑爹了,原來。VS裡是提供

Add Service References 和 Add Web References

這兩種,其實就是年代遺留下來的問題。web引用是2.0版本的,而服務引用是3.5版本的,微軟為了保持向前相容的特性,也保留了這兩種方法,分别可以看這裡

添加web引用和添加服務引用有什麼差別?Add Service References 和 Add Web References 有啥差別?

項目右鍵 添加服務引用,如果你用的是VS2008,菜單可能是添加web引用。

如果是本地做學習測試之用的,浏覽器浏覽你建立的webservice,得到URL,如果是使用網絡上的webservice,這裡則輸入給予的URL位址,點選前往即可,

再看看左下角的進階按鈕嗎?點選進階吧!!

把生成異步操作(必須勾上,不然沒有異步方法)勾上,生成消息合同也需勾上,看到左下角的添加WEB引用了嗎?這就是基于.NET Framework2.0 的。點選确定即可完成引入webservice。

兩種不同版本的引入webservice也将造成代碼的不同,是以,為了說明這個問題,我們也把2.0的引入方法也說明一下。

2.0的引入方法更加簡潔,如果你在看浪曦的webservice視訊教程,肯定很熟悉這個界面。我個人也是比較喜歡這種方法的。

編寫代碼

1

localhost.GetWebService webservice =

new

localhost.GetWebService();

//通過2.0的添加WEB引用需要這種方式new出webservice對象      

2

3

ServiceReference1.GetWebServiceSoapClient getWebService =

new

ServiceReference1.GetWebServiceSoapClient();

//通過添加服務引用需要這種方式new出webservice對象

4

5

//同步調用webservice

6

private

void

btnSyn_Click(

object

sender, EventArgs e)

7

{

8

string

res = webservice.HelloWorld();

9

this

.textBox1.Text +=

"完成了"

;

10

this

.textBox1.Text += res + System.Environment.NewLine;

11

}

12

13

//異步調用webservice

14

private

void

btnAsyn_Click(

object

sender, EventArgs e)

15

{

16

//給HelloWorld方法注冊調用完成時執行的方法AsyncHelloWorldComplete

17

webservice.HelloWorldCompleted +=

new

localhost.HelloWorldCompletedEventHandler(AsyncHelloWorldComplete);

18

//開始異步調用

19

webservice.HelloWorldAsync();

20

this

.textBox1.Text +=

"完成了"

+ System.Environment.NewLine;

21

}

22

23

//完成webservice操作時會執行的方法

24

void

AsyncHelloWorldComplete(

object

sender, localhost.HelloWorldCompletedEventArgs e)

25

{

26

string

res = e.Result;

27

this

.textBox1.Text += res + System.Environment.NewLine;

28

}

代碼說明:

1、HelloWorld方法:同步直接調用webservice的方法,傳回結果時輸出“成功了”加上傳回的結果;

2、webservice.HelloWorldAsync() :開始異步調用webservice

3、HelloWorldCompleted是webservice為我們提供委托調用,意思是将操作完成時執行的操作給參數中的方法執行,本例給了AsyncHelloWorldComplete方法執行;

執行效果:運作本例程式,你會發現,同步調用方法中,“完成了”這句話會與執行結果“Hello World”一起輸出,在webservice還沒執行完成的時候,小華不會打小明;

而異步調用方法中,“完成了”這句話先是輸出到文本框中,等了數秒之後,再顯示“Hello World”。這就是同步與異步調用webservice的差別了

如果需要在WebForm中異步調用,需要在頁面屬性中設定可以異步:Async=”true”

============================3======================

在前兩講裡,我已經向大家示範了如何使用WebService、同步, 異步調用WebService,而在實際開發過程中,可能會有多個WebService接口供你選擇,而在程式執行過程中才決定使用哪一個 WebService的情況,而以前的情況往往是添加指定的web引用調用WebService,而這一講中,會講述動态調用WebService,也就是知道WebService的位址而不用使用添加引用的方法來調用WebService。

淺談WebService開發(一)

淺談WebService開發二(同步與異步調用)

首先貼出整個架構的示意圖(圖檔來自浪曦),其中ServiceHelper類包括下面所示的五個步驟。

首先實作ServiceHelper類,代碼如下:

1

using System.Collections.Generic;

2

using System.Linq;

3

using System.Text;

4

5

using System.IO;

6

using System.Configuration;

7

using System.CodeDom;

8

using System.CodeDom.Compiler;

9

using System.Net;

10

using System.Web.Services;

11

using System.Web.Services.Description;

12

using Microsoft.CSharp;

13

14

namespace

InvokeWebService

15

{

16

public

static

class

WebServiceHelper

17

{

18

/// <summary>

19

/// 動态調用WebService

20

/// </summary>

21

/// <param name="url">WebService位址</param>

22

/// <param name="methodname">WebService方法名</param>

23

/// <param name="args">參數清單</param>

24

/// <returns>傳回object</returns>

25

public

static

object InvokeWebService(string url, string methodname, object[] args)

26

{

27

return

InvokeWebService(url,

null

, methodname, args);

28

}

29

/// <summary>

30

/// 動态調用WebService

31

/// </summary>

32

/// <param name="url">WebService位址</param>

33

/// <param name="classname">類名</param>

34

/// <param name="methodname">WebService方法名</param>

35

/// <param name="args">參數清單</param>

36

/// <returns>傳回object</returns>

37

public

static

object InvokeWebService(string url, string classname, string methodname, object[] args)

38

{

39

string @

namespace

=

"ServiceBase.WebService.DynamicWebLoad"

;

40

if

(string.IsNullOrEmpty(classname))

41

{

42

classname = WebServiceHelper.GetClassName(url);

43

}

44

//擷取服務描述語言(WSDL)

45

WebClient wc =

new

WebClient();

46

Stream stream = wc.OpenRead(url +

"?WSDL"

);

47

ServiceDescription sd = ServiceDescription.Read(stream);

48

ServiceDescriptionImporter sdi =

new

ServiceDescriptionImporter();

49

sdi.AddServiceDescription(sd,

""

,

""

);

50

CodeNamespace cn =

new

CodeNamespace(@

namespace

);

51

//生成用戶端代碼類代碼

52

CodeCompileUnit ccu =

new

CodeCompileUnit();

53

ccu.Namespaces.Add(cn);

54

sdi.Import(cn, ccu);

55

CSharpCodeProvider csc =

new

CSharpCodeProvider();

56

ICodeCompiler icc = csc.CreateCompiler();

57

//設定編譯器的參數

58

CompilerParameters cplist =

new

CompilerParameters();

59

cplist.GenerateExecutable =

false

;

60

cplist.GenerateInMemory =

true

;

61

cplist.ReferencedAssemblies.Add(

"System.dll"

);

62

cplist.ReferencedAssemblies.Add(

"System.XML.dll"

);

63

cplist.ReferencedAssemblies.Add(

"System.Web.Services.dll"

);

64

cplist.ReferencedAssemblies.Add(

"System.Data.dll"

);

65

//編譯代理類

66

CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);

67

if

(

true

== cr.Errors.HasErrors)

68

{

69

System.Text.StringBuilder sb =

new

StringBuilder();

70

foreach (CompilerError ce

in

cr.Errors)

71

{

72

sb.Append(ce.ToString() + System.Environment.NewLine);

73

}

74

throw

new

Exception(sb.ToString());

75

}

76

// 生成代理執行個體并調用方法

77

System.Reflection.Assembly assembly = cr.CompiledAssembly;

78

Type t = assembly.GetType(@

namespace

+

"."

+ classname,

true

,

true

);

79

object obj = Activator.CreateInstance(t);

80

System.Reflection.MethodInfo mi = t.GetMethod(methodname);

81

return

mi.Invoke(obj, args);

82

}

83

84

/// <summary>

85

/// 得到URL中的WebService名稱

86

/// </summary>

87

/// <param name="url">URL位址</param>

88

/// <returns>如http://wwww.baidu.com/service.asmx 則傳回service</returns>

89

private

static

string GetClassName(string url)

90

{

91

string[] parts = url.Split(

'/'

);

92

string[] pps = parts[parts.Length -

1

].Split(

'.'

);

93

return

pps[

];

94

}

95

}

96

}

然後,我們可以建立1個WebService,看看是如何動态調用的:

1

private

void

button1_Click(

object

sender, EventArgs e)

2

{

3

string

url =

"http://localhost:2697/Service1.asmx"

; //用于做測試的WebService

4

object

b = InvokeWebService.WebServiceHelper.InvokeWebService(url,

"HelloWorld"

,

null

);

5

MessageBox.Show(b.ToString());

6

}