有時候,為了讓數據可以“跨國經營”,尤其是HTTP Web有關的東東,會將數據內容以 XML 或 JSON 的格式返回,這樣一來,不管客戶端平台是四大文明古國,還是處於蒙昧時代的原始部落,都可以使用這些數據。
在WCF中實現將數據以XML或JSON格式返回有Y多種方法,不管你用什么方法,只要得到預期結果就好,米芾說了,筆可以八面出鋒,當然了,人家指的是繪畫。
這里,老周就挑兩種方法來演示,僅供參考,沒有考古價值,建議司馬子長不要把本文收入《史記》。
第一種方法是用到 WebServiceHost 類,它可以自動完成一些與HTTP通信相關的配置,不過,使用該類,要以管理身份運行,不然,會無權限監聽。
首先定義一個 Book 類,稍后咱們會把一個Book實例以XML或JSON數據返回。
public sealed class Book { public string BookName { get; set; } public decimal Price { get; set; } public string BarCode { get; set; } }
然后,很重要一步,就是聲明服務協定,它是個接口,可以對客戶端公開,當然客戶端也可以重新定義。
[ServiceContract] interface IService { [OperationContract] [WebGet(UriTemplate = "getdata?f={format}")] Message GetXml(string format); }
加上ServiceContract特性表明它是服務協定,如果沒有明確指定Name,則它的名字與接口的名字相同;協定接口中,希望向客戶端公開的方法要加上OperationContract特性,否則不會被認為是服務操作,無法被客戶端使用。
服務協定接口允許在服務器和客戶端使用不同定義,只要協定的名稱相同,並且方法的參數和返回值類型和數目相同即可。
WebGet特性指定URI的使用方法,地址為相對路徑,假如基址是http://dog.net/,那么訪問GetXml方法的路徑為 http://dog.net/getdata?f=xml。本來我只想返回XML數據的,所以叫GetXml,后來一想,單返回XML格式的內容也太小氣了,索性弄一個參數,來指定格式,可以傳入xml或json。?f后面的{format}會自動把值傳給方法的format參數,所以,UriTemplate的參數名字不要寫錯,如果寫成 ?f={firmat},那就識別不了參數了。
然后要實現服務,實現協定接口的類型不必向客戶端公開,因為它是在服務器上執行的。
public class MyService : IService { public Message GetXml(string format) { WebOperationContext context = WebOperationContext.Current; Book b = new Book { BookName = "賣女孩的小火柴", Price = 25.2M, BarCode = "2811365801" }; Message msgreturn = null; // 判斷格式 if (format.ToLower() == "xml") { msgreturn = context.CreateXmlResponse<Book>(b); } else { msgreturn = context.CreateJsonResponse<Book>(b); } return msgreturn; } }
這里通過一個很好玩的方法來完成,所以方法返回類型為Message。靜態屬性WebOperationContext.Current可以得到與當前調用的操作協定關聯的上下文對象,即WebOperationContext實例。它公開了一堆方法,名字都是 CreateXXXResponse,其中XXX是啥取決於返回內容,要返回JSON,就調用CreateJsonResponse方法,返回XML就調用CreateXmlResponse方法。
實例化Book對象后,可以傳給帶泛型參數的CreateJsonResponse或CreateXmlResponse方法,把類型參數T指定為Book,就會自動把Book對象序列化,然后返回給客戶端。
最后,在配置文件中給服務設定一個基址,可以在代碼中寫,也可以在配置文件中寫,此處老周選用配置文件,好處是可以動態修改而不必重新編譯應用程序。
<system.serviceModel> <services> <service name="getXmlSample.MyService"> <host> <baseAddresses> <add baseAddress="http://localhost:1888/"/> </baseAddresses> </host> </service> </services> </system.serviceModel>
可能有初學的朋友說WCF的配置文件很難寫,其實啊,是有規律的,你不妨細心研究一下,掌握規律后你會發現配置文件並不難寫。
service的 name 屬性的值就是服務類的Type的名字(類型名,帶命名空間名稱)。
在Main中實例化WebServiceHost。
static void Main(string[] args) { WebServiceHost host = new WebServiceHost(typeof(MyService)); host.Open(); Console.WriteLine("服務已打開。"); Console.Read(); host.Close(); }
注意,傳給構造函數的Type是服務類的類型,與配置文件中service/name的值相同。
以管理員身份運行這個例子,然后打開瀏覽器,輸入http://localhost:1888/getdata?f=xml,回車后,你會看到這樣的內容:

把xml改為json,再看看。

怎么樣,好玩吧。下面老周再演示另一種方法。
這種方法沒使用WebServiceHost,而是使用普通的ServiceHost類來承載服務,可通過WebHttpBinding來得到HTTP交互的支持,不過,不要忘了給終結點配置WebHttpBehavior行為。
同樣,先定義一個類,隨后用來做測試。
[DataContract(Namespace = "http://sample",Name = "student")] public sealed class Student { [DataMember(Name = "stu_id")] public int StuID { get; set; } [DataMember(Name = "stu_name")] public string StuName { get; set; } }
這一次,咱們通過將對象進行XML或JSON序列化的方式生成數據,並轉為字符串返回。服務協定如下:
[ServiceContract] public interface IData { [OperationContract] [WebGet(UriTemplate = "getdata?f={format}")] string GetData(string format); }
和前面差不多,只是返回類型改為string。
下面代碼實現協定接口:
public class MyService : IData { public string GetData(string format) { string res = null; Student stu = new Student { StuID = 3, StuName = "小白" }; using (MemoryStream ms=new MemoryStream()) { XmlObjectSerializer sz = null; if (format != null && format.ToLower() == "xml") { sz = new DataContractSerializer(stu.GetType()); } else { sz = new DataContractJsonSerializer(stu.GetType()); } sz.WriteObject(ms, stu); res = Encoding.UTF8.GetString( ms.ToArray()); } return res; } }
接着,在配置文件中配置一下。
<system.serviceModel> <behaviors> <endpointBehaviors> <behavior name="hb"> <webHttp automaticFormatSelectionEnabled="true"/> </behavior> </endpointBehaviors> </behaviors> <services> <service name="getXmlSample2.MyService"> <endpoint address="http://localhost:2008" binding="webHttpBinding" contract="getXmlSample2.IData" behaviorConfiguration="hb"/> </service> </services> </system.serviceModel>
behaviors節點下可以配置兩種行為——服務行為和終結點行為。此處我們只需配置終結點的行為,需要一個webHttp元素,它映射到 WebHttpBehavior 類。記得要為behavior節點分配名字,隨后在/services/service/endpoint節點下,才能通過behaviorConfiguration屬性來引用前面的behavior。
實現HTTP交互,應使用webHttpBinding。
在配置webHttp行為時,應該把automaticFormatSelectionEnabled的值設置為true,這樣一來,返回給調用方的內容會自動識別格式,其實主要目的是讓返回的字符串中能夠去掉最外層的雙引號。
回到代碼,實例化ServiceHost,然后打開服務。
static void Main(string[] args) { using (ServiceHost host=new ServiceHost(typeof(MyService))) { host.Open(); Console.WriteLine("服務已打開。"); Console.Read(); } }
運行應用程序,在瀏覽中輸入http://localhost:2008/getdata?f=xml,得到結果如下。

然后再輸入http://localhost:2008/getdata?f=json看看。

好了,就演示這兩種方法吧,你願意探索的話,方法是有很多種的。
