http://www.cnblogs.com/sxwgf/archive/2011/07/10/something-about-webservice.html
今天早上起來,想談談.NET中的WebService,當然我不想講什麼是 WebService,或者怎麼用WebService,因為那個大家 随便Google一下前100頁都能找到答案。今天我想來分享一下我在用WebService中的一些技巧(至少我認為是技巧,還有點成就感),希望能給 大家以後在用WebService時一點幫助和啟發吧。
一、問題誕生 -- 大部分解決方案的背後總是一些頭痛的問題
很早以前就用過傳說中的WebService,但一直是用正常的思路在用:建立WebService項目-->寫Web服務方法--> 在項目中添加Web引用-->調用Web方法。這樣貌似很好,非常符合規範,在一段時間内效果也還可以,但漸漸的随着項目的擴大和同時參與項目的人 員增多,就越來越覺得這種正常的方法很是不爽,為什麼呢?我每次修改WebService端(添加、删除Web方法,以及修改方法名稱),在引用端我都要 更新WebService引用,其實是就是更新WSDL檔案,很是煩人。
二、化分為合 -- 傳說分久必合,合久必分
好吧,既然增加、删除、修改web方法名都會引起WSDL的更新,那麼我們索性用一個統一的方法來作為webservice的通路入口吧,然後内部用switch case來區分調用哪個方法,先貼代碼吧,再來簡單講講:
統一通路接口IRemoteCall:
public interface IRemoteCall
{
byte[] GeneralCall(string methodName, params byte[] param);
}
然後定義一個WebService并實作以上接口(以前還沒真在webservice上實作過接口,哈哈):
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class BlogService : System.Web.Services.WebService, IRemoteCall
[WebMethod(EnableSession = true)]
public byte[] GeneralCall(string methodName, params byte[] param)
switch (methodName)
case "LoadBlog":
long blogId = Serializer.DeserializeToObject<long>(param);
BLLBlogArtical ba = new AppBlog().LoadBlog(blogId);
return Serializer.SerializeToBinary(ba);
case "DeleteBlog":
//To Do Your Code
return null;
這裡為什麼要定義接口IRemoteCall呢,主要是為接下來統一調用webservice服務的,所有實作這個接口的webservice類都可以通 過GeneralCall來完成調用,待會将webservice通路器的時候會具體講到,這裡主要講講這個switch case。
這裡我們定義了一個統一的通路入口
byte[] GeneralCall(string methodName,params byte[] param)
意思是:傳入要調用的方法名稱以及序列化後的參數,傳回序列化後的結果。這裡為了統一資料,我們均對參數和傳回值都序列化成byte數組,即用Serializer.SerializeToBinary(object)來實作,這樣所有調用就都統一了格式。
有人可能會提出質疑,這樣方法名稱都已字元串形式是不是會顯得難看,而且字元串容易出錯,還沒有智能提示?那也好解決,我們可以把方法名稱定義成const常量就可以了。這裡我對webservice的一個态度是:webservice層就是完成轉接和排程工作的,它僅僅起到承接的作用,用了他可以将服務任意分布,是以裡面是沒有任何邏輯的(邏輯都是被封裝在其他dll中的),最多是一些資料轉換,是以我采用了這種模糊接口的方式。
三、自定義webservice通路器,爽死用戶端
上面我們完成了webservice端的工作,接下來就來實作用戶端對webservice的靈活調用,這裡上面定義的那個IRemoteCall就起到作用了,首先我們定義一個webservice通路器類RemoteCaller,代碼如下:
View Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Web.Services.Protocols;
using SharedLib_403;
namespace ITIvy.Shared.RemoteCaller
/// <summary>
/// 遠端接口通路器
/// </summary>
public class RemoteCaller
private string _MethodName;
private byte[] _ParamByte;
private IRemoteCall _Caller;
private ArrayList _Params;
/// 參數清單
public ArrayList Params
get { return _Params; }
set { _Params = value; }
/// 序列化後的參數
public byte[] ParamByte
get { return _ParamByte; }
set { _ParamByte = value; }
/// 遠端服務方法名稱
public string MethodName
get { return _MethodName; }
set { _MethodName = value; }
/// 遠端服務調用接口
public IRemoteCall Caller
get { return _Caller; }
set { _Caller = value; }
/// 構造
/// <param name="caller">Webservice遠端接口</param>
public RemoteCaller(IRemoteCall caller)
_Caller = caller;
_Params = new ArrayList();
/// 調用遠端接口
/// <param name="methodName">方法名稱</param>
/// <param name="param">參數對象</param>
/// <returns></returns>
public byte[] Call(string methodName, object param)
try
_MethodName = methodName;
_ParamByte = Serializer.SerializeToBinary(param);
return _Caller.GeneralCall(_MethodName, _ParamByte);
catch (Exception ex)
if (ex is SoapException)
throw new Exception(((SoapException)ex).Detail["Message"].InnerText);
else
throw ex;
/// <param name="param">參數清單</param>
public byte[] Call(string methodName, ArrayList param)
_Params = param;
_ParamByte = Serializer.SerializeToBinary(_Params);
/// <param name="param">參數對象數組</param>
public byte[] Call(string methodName, params object[] param)
foreach (object obj in param)
_Params.Add(obj);
public byte[] Call()
if (string.IsNullOrEmpty(_MethodName))
throw new Exception("遠端方法不能為空!");
/// <typeparam name="T">傳回值類型</typeparam>
public T Call<T>()
byte[] resultByte = Call();
return Serializer.DeserializeToObject<T>(resultByte);
public T Call<T>(string methodName, ArrayList param)
byte[] resultByte = Call(methodName, param);
public T Call<T>(string methodName, object param)
byte[] resultByte = _Caller.GeneralCall(_MethodName, _ParamByte);
public T Call<T>(string methodName, params object[] param)
這個通路器主要是定義了一系列通路接口的重載,利用了c#的泛型更加使接口簡單了。哈哈,這個類就能讓我們實作一句話調用webservice,相 當簡潔。注意裡面的IRemoteCall屬性,就是隻要傳入實作了該接口的類,就都可以通過該通路器來通路webservice。如何使用該類呢,下面 給一個例子吧:
IRemoteCall Caller = new BlogService.BlogService();
BLLBlogArtical bllArtical = new RemoteCaller(Caller).Call<BLLBlogArtical>("LoadBlog", id);
抱歉,說錯了,要兩句話來調用,但是這裡少去了很多資料轉換的工作,因為有了泛型,呵呵,而且我可以在RemoteCaller這個通路器類中做很多工作,比如異常處理,權限驗證等等。
四、總結 -- 寫了這麼多不總結可不行
這個實作方法的核心在于用IRemoteCall接口來規範webservice類的實作方式均為統一GenerateCall,然後 webservice類中通過switch case來将所有方法整合在一起,避免頻繁更新WSDL的麻煩,最後用戶端利用IRemoteCall定義一個webservice通路器類 RemoteCaller來提供統一的webservice通路。小技巧,呵呵,請大家笑納,有什麼不對的地方請指出...
不好意思,上面引用的那個SharedLib_403中有序列化和反序列化的代碼,一時忘記貼出來了,現在補上:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
namespace SharedLib_403
public class Serializer
/// 把對象序列化成二進制流
/// <param name="obj">需要序列化的對象</param>
public static byte[] SerializeToBinary(object obj)
if (obj == null)
MemoryStream stream = new MemoryStream();
new BinaryFormatter().Serialize(stream, obj);
stream.Position = 0L;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Close();
return buffer;
/// 把二進制流反序列化成對象
/// <param name="bytes">需要反序列化的二進制流</param>
public static object DeserializeToObject(byte[] bytes)
object obj = null;
if (bytes != null)
MemoryStream stream = new MemoryStream(bytes);
obj = new BinaryFormatter().Deserialize(stream);
return obj;
/// <typeparam name="T">對象類型</typeparam>
public static T DeserializeToObject<T>(byte[] bytes)
object obj = DeserializeToObject(bytes);
return (T)obj;
本文轉自cnn23711151CTO部落格,原文連結:http://blog.51cto.com/cnn237111/617461 ,如需轉載請自行聯系原作者