日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

wcf精通1-15

發(fā)布時(shí)間:2023/11/30 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 wcf精通1-15 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第一天 三種Binding讓你KO80%的業(yè)務(wù)

  

  轉(zhuǎn)眼wcf技術(shù)已經(jīng)出現(xiàn)很多年了,也在.net界混的風(fēng)生水起,同時(shí).net也是一個(gè)高度封裝的框架,作為在wcf食物鏈最頂端的我們所能做的任務(wù)已經(jīng)簡(jiǎn)單的不能再簡(jiǎn)單了,

再簡(jiǎn)單的話?cǎi)R路上的大媽也能寫wcf了,好了,wcf最基本的概念我們放在后面慢慢分析,下面我們來(lái)看看神奇的3個(gè)binding如何KO我們實(shí)際場(chǎng)景中的80%的業(yè)務(wù)場(chǎng)景。

?

一:basicHttpBinding

  作為入門第一篇,也就不深入談?wù)刡asic中的信道棧中那些啥東西了,你只需要知道有ABC三個(gè)要素,注意不是姨媽巾哦,如果需要詳細(xì)了解,可以觀賞我以前的系列。在

這里我就不多說(shuō)了,太簡(jiǎn)單的東西沒(méi)意思,先看個(gè)例子簡(jiǎn)單感受了,你只需知道的是basic走的是http協(xié)議就好了,傳輸消息為soap。

1. 契約

1 using System.Runtime.Serialization;2 using System.ServiceModel;3 4 namespace MyService5 {6 [ServiceContract]7 public interface IHomeService8 {9 [OperationContract] 10 int GetLength(string name); 11 } 12 }

2. 實(shí)現(xiàn)類

1 using System;2 using System.Messaging;3 using System.Threading;4 5 namespace MyService6 {7 public class HomeService : IHomeService8 {9 public int GetLength(string name) 10 { 11 return name.Length; 12 } 13 } 14 }

3. 服務(wù)啟動(dòng)

1 using System;2 using System.ServiceModel;3 4 namespace MyService5 {6 class Program7 {8 static void Main(string[] args)9 { 10 using (ServiceHost host = new ServiceHost(typeof(HomeService))) 11 { 12 try 13 { 14 host.Open(); 15 16 Console.WriteLine("服務(wù)開啟!"); 17 18 Console.Read(); 19 } 20 catch (Exception e) 21 { 22 Console.WriteLine(e.Message); 23 } 24 } 25 } 26 } 27 }

4. 配置config文件

<?xml version="1.0" encoding="utf-8" ?> <configuration><system.serviceModel><bindings><netTcpBinding><binding name="IHomeServiceBinding" /></netTcpBinding></bindings><behaviors><serviceBehaviors><behavior name=""><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="true" /></behavior></serviceBehaviors></behaviors><services><service name="MyService.HomeService"><endpoint address="http://127.0.0.1:1920/HomeService" binding="basicHttpBinding" contract="MyService.IHomeService"><identity><dns value="localhost" /></identity></endpoint><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /><host><baseAddresses><add baseAddress="http://127.0.0.1:1920"/></baseAddresses></host></service></services></system.serviceModel> </configuration>

5. 然后通過(guò) servicehost 啟動(dòng)服務(wù)端

using System; using System.ServiceModel;namespace MyService {class Program{static void Main(string[] args){using (ServiceHost host = new ServiceHost(typeof(HomeService))){try{host.Open();Console.WriteLine("服務(wù)開啟!");Console.Read();}catch (Exception e){Console.WriteLine(e.Message);}}}} }

?

好了,到現(xiàn)在為止,服務(wù)端全部開啟完畢,接下來(lái)我們通過(guò)“添加服務(wù)引用”,來(lái)添加對(duì)客戶端的引用

1 using System;2 3 namespace ConsoleApplication14 {5 class Program6 {7 static void Main(string[] args)8 {9 HomeServiceReference.HomeServiceClient client = new HomeServiceReference.HomeServiceClient(); 10 11 var s = client.GetLength("12345"); 12 13 Console.WriteLine("長(zhǎng)度為:{0}", s); 14 15 Console.Read(); 16 } 17 } 18 }

?

麻蛋,就這么簡(jiǎn)單,是的,就這樣簡(jiǎn)單的五步,基于http的通信就這樣被不小心的完成了,真不好意思。

?

二:netTcpBinding

  有了basic的代碼,現(xiàn)在我們要改成tcp通信,這會(huì)通信走的是字節(jié)流,很簡(jiǎn)單,改一下服務(wù)端的config文件就好了,大家也知道這種性能要比basic好。

<?xml version="1.0" encoding="utf-8" ?> <configuration><system.serviceModel><behaviors><serviceBehaviors><behavior name="mxbehavior"><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="true" /></behavior></serviceBehaviors></behaviors><services><service name="MyService.HomeService" behaviorConfiguration="mxbehavior"><endpoint address="net.tcp://localhost:19200/HomeService" binding="netTcpBinding" contract="MyService.IHomeService"><identity><dns value="localhost" /></identity></endpoint><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/><host><baseAddresses><add baseAddress="http://localhost:1920/HomeService"/></baseAddresses></host></service></services></system.serviceModel> </configuration>

?

三:netMsmqBinding

  msmq這個(gè)玩意,我想大家都清楚,一個(gè)物理上的文件,好處呢,你也明白,就是client和service的所有通信都要經(jīng)過(guò)它的手,這樣任何一方出了問(wèn)題,只要

它在就沒(méi)問(wèn)題了。同樣我們把tcp改成msmq也是非常簡(jiǎn)單的,不過(guò)要注意,msmqbinding中是不可以讓契約方法有返回值的。所以我們加上isoneway就好了。

using System.Runtime.Serialization; using System.ServiceModel;namespace MyService {[ServiceContract]public interface IHomeService{[OperationContract(IsOneWay = true)]void GetLength(string name);} }

然后我在mmc上新建一個(gè)消息隊(duì)列,如下:

然后我們?cè)俑膭?dòng)以下配置文件

<?xml version="1.0" encoding="utf-8" ?> <configuration><system.serviceModel><behaviors><serviceBehaviors><behavior name="mxbehavior"><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="true" /></behavior></serviceBehaviors></behaviors><bindings><netMsmqBinding><binding name="msmqbinding"><security mode="None"/></binding></netMsmqBinding></bindings><services><service name="MyService.HomeService" behaviorConfiguration="mxbehavior"><endpoint address="net.msmq://localhost/private/homequeue" binding="netMsmqBinding"contract="MyService.IHomeService" bindingConfiguration="msmqbinding"><identity><dns value="localhost" /></identity></endpoint><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /><host><baseAddresses><add baseAddress="http://localhost:19200/HomeService"/></baseAddresses></host></service></services></system.serviceModel> </configuration>

?

縱觀上面的三種binding,配置起來(lái)何其簡(jiǎn)單,底層的各種通訊協(xié)議貌似對(duì)我來(lái)說(shuō)都是透明的,其實(shí)呢???wcf在底層做了何其多的事情,而我卻沒(méi)有挖掘。。。

這對(duì)碼農(nóng)里說(shuō)也是一種悲哀啊。。。出了問(wèn)題就只能禱告上天。。。下一篇我會(huì)開始深入剖析。

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第二天 告別煩惱的config配置

?

  經(jīng)常搞wcf的基友們肯定會(huì)知道,當(dāng)你的應(yīng)用程序有很多的“服務(wù)引用”的時(shí)候,是不是有一種瘋狂的感覺。。。從一個(gè)環(huán)境遷移到另外一個(gè)環(huán)境,你需要改變的

endpoint會(huì)超級(jí)tmd的多,簡(jiǎn)直就是搞死了人。。。好了,這篇我們來(lái)看看如何最小化配置。

?

一:精簡(jiǎn)service的config配置

  就像上一篇的代碼一樣,我的service端的config配置如下:

1 <?xml version="1.0" encoding="utf-8" ?>2 <configuration>3 <system.servicemodel>4 <behaviors>5 <servicebehaviors>6 <behavior name="mxbehavior">7 <servicemetadata httpgetenabled="true" />8 <servicedebug includeexceptiondetailinfaults="true" />9 </behavior> 10 </servicebehaviors> 11 </behaviors> 12 <services> 13 <service name="myservice.homeservice" behaviorconfiguration="mxbehavior"> 14 <endpoint address="net.tcp://localhost:1920/homeservice" binding="nettcpbinding" contract="myservice.ihomeservice"> 15 <identity> 16 <dns value="localhost" /> 17 </identity> 18 </endpoint> 19 <endpoint address="mex" binding="mexhttpbinding" contract="imetadataexchange" /> 20 <host> 21 <baseaddresses> 22 <add baseaddress="http://localhost:19200/homeservice"/> 23 </baseaddresses> 24 </host> 25 </service> 26 </services> 27 </system.servicemodel> 28 </configuration>

?

  通過(guò)上面的代碼,你應(yīng)該知道在system.servicemodel下的所有節(jié)點(diǎn)都是wcf專屬的節(jié)點(diǎn),所有的節(jié)點(diǎn)數(shù)據(jù)都會(huì)被開啟servicehost這個(gè)監(jiān)聽器時(shí)捕獲到,下面我可以

通過(guò)servicehost這個(gè)監(jiān)聽器的源碼下面找找相關(guān)的讀取config節(jié)點(diǎn)的代碼。

?

?

通過(guò)上面的截圖,你是不是有一種感覺,就是service的底層也是通過(guò)代碼動(dòng)態(tài)的讀取config下面的節(jié)點(diǎn)來(lái)獲取數(shù)據(jù),那就意味著我可以直接將代碼寫入到code中,

對(duì)吧,這樣我就可以把我認(rèn)為該配置的東西配置起來(lái),不該配置的東西全部放到代碼里面去,這樣我的靈活性是不是非常的強(qiáng)大。。。。爽吧,說(shuō)干就干。。。

1 class Program12 {3 static void Main(string[] args)4 {5 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://localhost:19200/HomeService"));6 7 host.AddServiceEndpoint(typeof(IHomeService), new NetTcpBinding(), "net.tcp://localhost:1920/HomeService");8 9 //公布元數(shù)據(jù) 10 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true }); 11 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 12 13 host.Open(); 14 15 Console.WriteLine("服務(wù)已經(jīng)開啟。。。"); 16 17 Console.Read(); 18 } 19 }

?

有人就要說(shuō)了,地址的話肯定不能是寫死的,必須變活,簡(jiǎn)單啊,我就僅僅把ip地址配置到config里面去不就完事了,對(duì)不對(duì)。

<configuration><appSettings><add key ="baseurl" value="http://localhost:19200/HomeService"/><add key ="endpoindurl" value="net.tcp://localhost:1920/HomeService"/></appSettings> 1 class Program12 {3 static void Main(string[] args)4 {5 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri(ConfigurationManager.AppSettings["baseurl"]));6 7 host.AddServiceEndpoint(typeof(IHomeService), new NetTcpBinding(), ConfigurationManager.AppSettings["endpoindurl"]);8 9 //公布元數(shù)據(jù) 10 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true }); 11 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 12 13 host.Open(); 14 15 Console.WriteLine("服務(wù)已經(jīng)開啟。。。"); 16 17 Console.Read(); 18 } 19 }

?

現(xiàn)在看的話,是不是清楚多了,如果你覺得我的代碼比較累贅,你可以封裝成一個(gè)方法,然后就可以動(dòng)態(tài)的配置nettcp,basic,ws*等等對(duì)吧。。。好了,說(shuō)完服

務(wù)端,接下來(lái)我們看看client端如何避免。

?

二:精簡(jiǎn)client的config配置


  就像上一節(jié)那樣,如果我用“服務(wù)引用”的話,vs會(huì)偷偷的用svcutil.exe來(lái)給我們生成一個(gè)proxy類和一個(gè)config文件,proxy類也就是你看到的xxxclient。。。

可惡的是config里面會(huì)給我生成一些亂七八糟的東西,如下圖:

1 <?xml version="1.0" encoding="utf-8" ?>2 <configuration>3 <system.serviceModel>4 <bindings>5 <netTcpBinding>6 <binding name="NetTcpBinding_IHomeService" />7 </netTcpBinding>8 </bindings>9 <client> 10 <endpoint address="net.tcp://localhost:1920/HomeService" binding="netTcpBinding" 11 bindingConfiguration="NetTcpBinding_IHomeService" contract="HomeServiceReference.IHomeService" 12 name="NetTcpBinding_IHomeService"> 13 <identity> 14 <dns value="localhost" /> 15 </identity> 16 </endpoint> 17 </client> 18 </system.serviceModel> 19 </configuration>

?

同服務(wù)器端一樣,如果我用code做掉,是不是非常的爽呢???那可不可以做掉呢? 我們還得看一下proxy的源碼,首先你會(huì)看到其實(shí)所謂的proxy只是一個(gè)繼承

自clientbase的一個(gè)類,如下圖。

?

?

上面的兩幅圖,你會(huì)發(fā)現(xiàn),最后的proxy類是通過(guò)ChannelFactory<TChannel>類來(lái)完成助攻的,那話說(shuō)回來(lái)了,既然底層用了ChannelFactory<TChannel>,

那何不我在代碼里面就用ChannelFactory<TChannel>不是更好嗎???這樣config也省了,對(duì)吧,說(shuō)干就干啦。。。

1 static void Main(string[] args) 2 { 3 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new NetTcpBinding(), "net.tcp://localhost:1920/homeservice"); 4 5 var channel = factory.CreateChannel(); 6 7 var result = channel.GetLength("12345"); 8 }

?

好了,代碼就這么簡(jiǎn)單,現(xiàn)在是不是感覺自己萌萌大啦~~~

?

十五天精通WCF——第三天 client如何知道server提供的功能清單

   ?通常我們?nèi)ゴ蟊=〉臅r(shí)候,都會(huì)找姑娘問(wèn)一下這里能提供什么服務(wù),什么價(jià)格,這時(shí)候可能姑娘會(huì)跟你口述一些服務(wù)或者提供一份服務(wù)清單,這樣的話大

家就可以做到童嫂無(wú)欺,這樣一份活生生的例子,在wcf中同樣是一個(gè)道理,只有client了解service能提供哪些功能,client才可以根據(jù)server提供的功能進(jìn)行

消費(fèi),那問(wèn)題來(lái)了,service怎么把功能提供給client進(jìn)行選擇呢???這個(gè)就是我這一篇要聊的wsdl(web service description language)。。。

?

一:wsdl

   現(xiàn)在你已經(jīng)知道了,wsdl就是server提供給client的清單,那下面問(wèn)題就來(lái)了。server是如何提供的呢???你要是比較仔細(xì)的話,可能會(huì)知道我在上一

篇提到的一個(gè)endpoint,如下截圖。

在上面這幅圖中,你可以看到,Homeservice提供了兩個(gè)端點(diǎn),一個(gè)是“服務(wù)端點(diǎn)“,一個(gè)是“元數(shù)據(jù)端點(diǎn)”。并且你也看到了,元數(shù)據(jù)的端點(diǎn)地址是

http://192.168.16.16:19200/mex,當(dāng)client通過(guò)svcutil訪問(wèn)這個(gè)地址的時(shí)候,就拿到了server能提供的功能清單,然后client就可以根據(jù)這些功能生成一

個(gè)代理文件,然后的然后,就是你懂得,各種啪啪啪,XXXClient。

?

二:眼見為實(shí)

1.見證wsdl

 要想看見wsdl,你只需要通過(guò)http://localhost:19200打開服務(wù)地址、如下圖:

?

然后點(diǎn)擊:http://localhost:19200/?singleWsdl

?

現(xiàn)在你看到的就是server功能清單,太tmd的重量級(jí)了,已經(jīng)完完全全果體在世人前了,下一小節(jié)我們?cè)僭敿?xì)的分析下。

?

2. 見證client端的XXXclient

  剛才我也說(shuō)了,當(dāng)你用vs做“服務(wù)引用”的時(shí)候,svcutil會(huì)根據(jù)http://localhost:19200/mex的地址來(lái)查看wsdl,然后生成代理,下面我們具體來(lái)看一下。

?

?

點(diǎn)擊確定之后,我們就可以看到在?Service References 文件夾下面生成了一個(gè)Reference.cs 文件。

?

然后我們打開Reference.cs,就可以看到一個(gè)繼承于ClientBase的HomeServiceClient。

?

?

三:詳細(xì)分析wsdl文件

  學(xué)wcf,你一定要像svcutil一樣能夠看得懂wsdl。

?

1. 首先看下server提供了一個(gè)Update操作,參數(shù)是一個(gè)id,一個(gè)Student這個(gè)自定義的復(fù)雜類型,同時(shí)返回也是Student這個(gè)

? ? 復(fù)雜類型。

1 namespace MyService 2 { 3 [ServiceContract] 4 public interface IHomeService 5 { 6 [OperationContract] 7 Student Update(int id, Student stu); 8 } 9 }

?

?2. wsdl這個(gè)xml文件,剛才你也看到了,下面我們一個(gè)個(gè)節(jié)點(diǎn)看看

??<1> portType 和 operation節(jié)點(diǎn)

  當(dāng)你看到下面的截圖后,我想你也能猜的出來(lái),portType就是契約(IHomeService),operation就是契約方法(Update),不過(guò)有點(diǎn)意思的是,在operation

下面你看到了一個(gè)input,一個(gè)output,這個(gè)就是所謂的 ”輸入消息“,”輸出消息”,那是什么意思呢??? 也就是說(shuō)client到server的消息叫做“輸入消息”,server到

client端叫做“輸出消息”,到這里你應(yīng)該似乎明白了,我C#中的Update方法是有入?yún)⒑统鰠⒌?#xff0c;然而這映射到wsdl中就是兩條消息,input和output,這個(gè)也就是經(jīng)典

的“請(qǐng)求-響應(yīng)“模式。

?

好了,繼續(xù)往下看,在wsdl:input和wsdl:output中分別有一個(gè)Action屬性,這個(gè)非常有意思,wcf的底層就是通過(guò)這個(gè)地址來(lái)找到對(duì)應(yīng)的方法,比如我們看到的代理

類中的Update方法上面就有這么一段。

?

?<2> message 和 types節(jié)點(diǎn)

  繼續(xù)往下看的話,你會(huì)發(fā)現(xiàn)input和output中還有一個(gè)message屬性,對(duì)應(yīng)的為IHomeService_Update_InputMessage和IHomeService_Update_OutputMessage,

這個(gè)正好是message節(jié)點(diǎn)的引用,如下圖:

從這個(gè)圖中,你可以看到input和output下面都有一個(gè)wsdl:part節(jié)點(diǎn),這個(gè)就是表明input和output中需要攜帶的參數(shù),比如element="tns:Update",就引用了

element中Name=Update的節(jié)點(diǎn),如下圖:

?

好了,最后我再截一張圖,可以看到,傳輸協(xié)議為soap,服務(wù)地址等等。。。然后就沒(méi)什么好說(shuō)的了。

?

?

十五天精通WCF——第四天 你一定要明白的通信單元Message

  轉(zhuǎn)眼你已經(jīng)學(xué)了三天的wcf了,是不是很好奇wcf在傳輸層上面到底傳遞的是個(gè)什么鳥毛東西呢???應(yīng)該有人知道是soap,那soap這叼毛長(zhǎng)得是什么

樣呢?這一篇我們來(lái)揭開答案。。。

?

一:soap到底長(zhǎng)成什么樣子

  為了能看清soap長(zhǎng)的啥樣,我可以用強(qiáng)大的Fiddler來(lái)監(jiān)視一下,突然好激動(dòng)啊!!!

1.Server

1 static void Main(string[] args)2 {3 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://192.168.1.105:19200"));4 5 host.AddServiceEndpoint(typeof(IHomeService), new BasicHttpBinding(), "HomeServie");6 7 //公布元數(shù)據(jù)8 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });9 10 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 11 12 host.Open(); 13 14 Console.WriteLine("服務(wù)已經(jīng)開啟。。。"); 15 16 Console.Read(); 17 }

2.Client

1 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://192.168.1.105:19200/HomeServie")); 2 3 var client = factory.CreateChannel(); 4 5 client.Update("王八蛋");

?

?

現(xiàn)在我想你大概看清楚了這玩意是個(gè)么樣子,一個(gè)建立在xml上面的一種消息格式,根元素是envelope,我知道這叼毛翻譯過(guò)來(lái)就是“信封”,所以就有了”封頭“

和”封體”,就是s:Header 和 s:Body,從這個(gè)soap中你可以看到它忽略了header,然后我們繼續(xù)往下看,還記得Update的意思嗎???如果你讀懂了上一篇,

你應(yīng)該知道這是一個(gè)Action,也就是所謂的input消息。與之對(duì)應(yīng)的就是UpdateResponse這個(gè)output消息,對(duì)吧,還記得xmlns="http://tempuri.org/">嗎?

它就是IHomeService的默認(rèn)命名空間,對(duì)吧。。。

下一個(gè)我們關(guān)注的是Update這個(gè)Action中的<str>這個(gè),你也看得到,這個(gè)就是上圖中Update方法中的str參數(shù),最后我們來(lái)看一下UpdateResponse中

的<UpdateResult xmlns:a="http://schemas.datacontract.org/2004/07/MyService,不知道你是否還記得它就是WSDL中關(guān)于Student的XSD結(jié)

構(gòu),看下圖:

?

好了,wcf中的soap結(jié)構(gòu)我們也大概了解了一下,不知道有沒(méi)有引發(fā)你對(duì)soap更深入的思考呢???

?

二:對(duì)soap的更深入思考

  通過(guò)fiddler觀察,你應(yīng)該也明白了,不管是客戶端還是服務(wù)端,wcf的高層封裝都是僅僅拿出了Envelope中的body節(jié)點(diǎn),而其他節(jié)點(diǎn)對(duì)我們來(lái)說(shuō)好像并

沒(méi)有什么卵用,比如我說(shuō)的Header節(jié)點(diǎn),這么說(shuō)來(lái),Header是不是有點(diǎn)浪費(fèi)呢???那下面有一個(gè)問(wèn)題來(lái)了,wcf在底層用什么來(lái)構(gòu)造消息的呢???下面

我們大概找下client端的源碼。。。

?

通過(guò)上面的圖,你現(xiàn)在應(yīng)該也知道了在.net中其實(shí)tmd的就是message構(gòu)造的,所以我想告訴你的是:既然wcf在底層也是用message來(lái)構(gòu)造的,何不我自己

就來(lái)構(gòu)造message消息呢???豈不美哉???這樣我就可以隨意操作message,對(duì)吧。。。不然wcf這個(gè)高層封裝的叼毛,對(duì)我來(lái)說(shuō)就是一種束縛。。。因

為我已經(jīng)知道了service公布的wsdl,所以我可以輕松構(gòu)造message。。。

?

三:用message來(lái)調(diào)用Server端

? 廢話不多說(shuō),構(gòu)造message你一定要知道下圖中的三點(diǎn):(input這個(gè)Action,契約方式 和 服務(wù)地址)。

?

好了,下面我先來(lái)構(gòu)造數(shù)據(jù)契約,指定服務(wù)契約的命名空間 和 Action在Soap中的名稱

1 [DataContract(Namespace = "http://tempuri.org/", Name = "Update")] 2 class Test 3 { 4 [DataMember] 5 public string str { get; set; } 6 }

然后,我把這個(gè)數(shù)據(jù)契約塞到envelope中的body中,如下:

1 BasicHttpBinding bingding = new BasicHttpBinding();2 3 BindingParameterCollection param = new BindingParameterCollection();4 5 var u = new Test() { str = "王八蛋" };6 7 Message request = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IHomeService/Update", u);8 9 IChannelFactory<IRequestChannel> factory = bingding.BuildChannelFactory<IRequestChannel>(param); 10 11 factory.Open(); 12 13 IRequestChannel channel = factory.CreateChannel(new EndpointAddress("http://192.168.1.105:19200/HomeServie")); 14 15 channel.Open(); 16 17 var result = channel.Request(request); 18 19 channel.Close(); 20 21 factory.Close();

接下來(lái),我們跑起來(lái)看一下,效果咋樣。。。

?

看沒(méi)看到,這個(gè)就是我手工構(gòu)造的Message,是不是太帥了。。。哈哈,太帥的應(yīng)該在后面,剛才也說(shuō)了,既然大家玩的都是Message,而你這個(gè)幾把wcf卻僅僅把

我的message.body拿出來(lái)了,那干脆我直接在契約方法中加message豈不是更好么???自由操作Message還有個(gè)什么好處呢??當(dāng)然啦,我可以在Message的

Header中加一些參數(shù)token,client的ip地址,client的身份,client的時(shí)間等等這些統(tǒng)計(jì)信息,對(duì)吧。。。這樣才是最帥的,好了,說(shuō)干就干,我們修改下server端的

契約方法,只用來(lái)接受Message。

?

server端:

1 public class HomeService : IHomeService2 {3 public Message Update(Message message)4 {5 var header = message.Headers;6 7 var ip = header.GetHeader<string>("ip", string.Empty);8 9 var currentTime = header.GetHeader<string>("currenttime", string.Empty); 10 11 //這個(gè)就是牛逼的 統(tǒng)計(jì)信息。。。 12 Console.WriteLine("客戶端的IP=" + ip + " 當(dāng)前時(shí)間=" + currentTime); 13 14 return Message.CreateMessage(message.Version, message.Headers.Action + "Response", "等我吃完肯德基,再打死你這個(gè)傻逼!!!"); 15 } 16 }

?

client端:

1 namespace ConsoleApplication12 {3 class Program4 {5 static void Main(string[] args)6 {7 BasicHttpBinding bingding = new BasicHttpBinding();8 9 BindingParameterCollection param = new BindingParameterCollection(); 10 11 var u = new Test() { str = "王八蛋" }; 12 13 Message request = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IHomeService/Update", u); 14 15 //在header中追加ip信息 16 request.Headers.Add(MessageHeader.CreateHeader("ip", string.Empty, Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString())); 17 request.Headers.Add(MessageHeader.CreateHeader("currenttime", string.Empty, DateTime.Now)); 18 19 IChannelFactory<IRequestChannel> factory = bingding.BuildChannelFactory<IRequestChannel>(param); 20 21 factory.Open(); 22 23 IRequestChannel channel = factory.CreateChannel(new EndpointAddress("http://192.168.1.105:19200/HomeServie")); 24 25 channel.Open(); 26 27 var result = channel.Request(request); 28 29 channel.Close(); 30 31 factory.Close(); 32 } 33 } 34 35 [DataContract(Namespace = "http://tempuri.org/", Name = "Update")] 36 class Test 37 { 38 [DataMember] 39 public string str { get; set; } 40 } 41 }

?

然后我們用Fiddler監(jiān)視一下結(jié)果:

?

現(xiàn)在一切都如我所愿,好了,我想你也大概明白了這個(gè)神奇的message,也不要忘了它就是wcf的基本通信單元,我要去吃肯德基了。。。。。。

?

十五天精通WCF——第五天 你需要了解的三個(gè)小技巧

?一: 服務(wù)是端點(diǎn)的集合

  當(dāng)你在開發(fā)wcf的時(shí)候,你或許已經(jīng)注意到了一個(gè)service可以公布多個(gè)endpoint,確實(shí)是這樣,在wcf中有一句很經(jīng)典的話,叫做“服務(wù)是端點(diǎn)的集合",就

比如說(shuō)一個(gè)普普通通的服務(wù),它就公布了一個(gè)服務(wù)端點(diǎn),一個(gè)元數(shù)據(jù)端點(diǎn),對(duì)吧。。。

仔細(xì)一想,這個(gè)問(wèn)題就好玩了,既然一個(gè)service可以公布多個(gè)endpoint,而且我還知道wcf中有很多的binding,這些binding對(duì)應(yīng)著很多的傳輸方式,那是不是

說(shuō)我一個(gè)service可以用多種協(xié)議方法對(duì)外公布,比如說(shuō)同時(shí)以nettcp,basic,msmqbinding,udp等方式公布,對(duì)吧,那這樣的話是不是超級(jí)好玩,如果對(duì)方

是非.net程序,那就可以調(diào)用我的basic,如果對(duì)方是.net程序,那是不是可以調(diào)用我的nettcp,對(duì)不對(duì)。。。當(dāng)然啦,wcf無(wú)所不能,這是一個(gè)史上無(wú)比強(qiáng)大的牛

逼框架,牛逼的要死,已經(jīng)逼得程序員只需隨便改幾個(gè)配置就能達(dá)到完全不一樣的效果。。。下面我同時(shí)用nettcp和basic的方式來(lái)同時(shí)公布服務(wù),好了,現(xiàn)在我

們就來(lái)見證奇跡吧。。。

Service:

1 using System;2 using System.Runtime.Serialization;3 using System.ServiceModel;4 using System.ServiceModel.Channels;5 using System.Threading;6 7 namespace MyService8 {9 public class HomeService : IHomeService 10 { 11 public Student Update(Student message) 12 { 13 return new Student() { Name = "一線碼農(nóng)" }; 14 } 15 } 16 17 [DataContract] 18 public class Student 19 { 20 [DataMember] 21 public string Name { get; set; } 22 23 [DataMember] 24 public int Age { get; set; } 25 } 26 }

Host :

1 class Program12 {3 static void Main(string[] args)4 {5 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://192.168.1.105:1920"));6 7 host.AddServiceEndpoint(typeof(IHomeService), new BasicHttpBinding(), "HomeServie");8 9 host.AddServiceEndpoint(typeof(IHomeService), new NetTcpBinding(), "net.tcp://192.168.1.105:1921/HomeServieTcp"); 10 11 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true }); 12 13 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 14 15 host.Open(); 16 17 Console.Read(); 18 } 19 }

Client端:

1 class Program2 {3 static void Main(string[] args)4 {5 //basic 方式6 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(),7 new EndpointAddress("http://192.168.1.105:1920/HomeServie"));8 9 var client = factory.CreateChannel(); 10 11 var result = client.Update(new Student() { }); 12 13 14 //nettcp方式 15 factory = new ChannelFactory<IHomeService>(new NetTcpBinding(), 16 new EndpointAddress("net.tcp://192.168.1.105:1921/HomeServieTcp")); 17 18 client = factory.CreateChannel(); 19 20 result = client.Update(new Student() { }); 21 } 22 }

?

通過(guò)上面的代碼,是不是已經(jīng)發(fā)現(xiàn),我在client端,既可以用basic的方式調(diào)用,又可以用nettcp的方式調(diào)用,這個(gè)技巧是不是感覺wcf無(wú)比強(qiáng)大呢???

?

二:Host寄宿多個(gè)Service

  我們知道wcf的寄宿方式有很多種,有iis,有windowservice,還有簡(jiǎn)單方便的console方式,而默認(rèn)情況下,我們最通常的方法都是一個(gè)service,一個(gè)寄宿,

而其實(shí)呢??? 其實(shí)一個(gè)寄宿host可以承載多個(gè)service,看起來(lái)是不是很好玩,如果說(shuō)你有10個(gè)servcie,現(xiàn)在你只需要用一個(gè)console host就能寄宿起來(lái),廢

話不多說(shuō),我演示一下給你看就好了。

Service:

1 namespace MyService2 {3 [ServiceContract]4 public interface IHomeService5 {6 [OperationContract]7 Student Update(Student message);8 }9 10 [ServiceContract] 11 public interface IFlyService 12 { 13 [OperationContract] 14 Student Fly(Student stu); 15 } 16 }

Host:

1 class Program12 {3 static void Main(string[] args)4 {5 //第一個(gè): 這是Home服務(wù)6 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://192.168.1.105:1920"));7 host.AddServiceEndpoint(typeof(IHomeService), new BasicHttpBinding(), "HomeServie");8 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });9 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 10 host.Open(); 11 12 Console.WriteLine("Home服務(wù)開啟。。。。"); 13 14 //第一個(gè): 這是Fly服務(wù) 15 var host2 = new ServiceHost(typeof(FlyService), new Uri("http://192.168.1.105:1930")); 16 host2.AddServiceEndpoint(typeof(IFlyService), new BasicHttpBinding(), "FlyServie"); 17 host2.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true }); 18 host2.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 19 host2.Open(); 20 21 Console.WriteLine("Fly服務(wù)開啟。。。。"); 22 23 Console.Read(); 24 } 25 }

有沒(méi)有看到,現(xiàn)在兩個(gè)服務(wù)都開啟了,這種方式看起來(lái)是不是很爽呀,否則的話,你需要開啟兩個(gè)Host,這樣的話,我的手續(xù)就精簡(jiǎn)了。。。對(duì)吧。。

?

三: Tcp中的端口共享

   這玩意聽起來(lái)大家都懂,端口共享嘛,不就是兩個(gè)程序共享一個(gè)端口,對(duì)吧,在通常情況下,我們肯定會(huì)認(rèn)為這無(wú)法做到,其實(shí)呢?在Wcf中我們還是可以玩

的,也就是一個(gè)PortSharingEnabled的事!!!如果說(shuō)端口可以共享的話,那我們的service是不是就可以少開辟幾個(gè)端口呢?同樣這也方便我們進(jìn)行service的管

理,下面我給大家繼續(xù)演示一下。。。很好玩的,么么噠

?

可以看到,我的兩個(gè)host都是用1920的端口,并且現(xiàn)在我真的開啟起來(lái)啦。。。。好了,三種技巧都說(shuō)到了,我想你在現(xiàn)實(shí)的wcf開發(fā)中,或多或少的都能接

觸的到,希望對(duì)你有用~~~~

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第六天 你必須要了解的3種通信模式

  

? ? ?wcf已經(jīng)說(shuō)到第六天了,居然還沒(méi)有說(shuō)到這玩意有幾種通信模式,慚愧慚愧,不過(guò)很簡(jiǎn)單啦,單向,請(qǐng)求-響應(yīng),雙工模式,其中的第二種“請(qǐng)求-響應(yīng)“

模式,這個(gè)大家不用動(dòng)腦子都清楚,這一篇我大概來(lái)分析下。

?

一:“請(qǐng)求-響應(yīng)“模式

  ? 如果你看了我上一篇的博文,你應(yīng)該非常清楚這種類似“本地調(diào)用”的方式,wcf同樣也分為“同步”和“異步”兩種,不過(guò)不管是異步還是同步,最終都逃

不過(guò)是“請(qǐng)求-響應(yīng)”這個(gè)事實(shí),對(duì)吧。

?

1: 同步方式

  這種方式我想沒(méi)什么好說(shuō)的,前面幾篇我已經(jīng)說(shuō)的非常清楚了,具體使用方法可以參考我的前面幾篇文章。。。謝啦~~~~

?

2: 異步方式

  通常我們都有這樣的一個(gè)思維,遇到耗時(shí)的東西第一反應(yīng)就想到了多線程,畢竟多線程也是一種負(fù)載均衡,在wcf這種”請(qǐng)求-響應(yīng)“模式,同樣也支持異

步,很神奇吧,而且神奇到可以在“服務(wù)引用“界面上做到一鍵生成,什么???你不信!!!!不信你看。。。

?

然后我非常好奇的看下XXXClient給我們生成的是個(gè)什么代碼。。。

?

通過(guò)client端的proxy代碼,你可以清楚的看到,這雞巴WCF真的不容易,給我們生成了兩種“異步模式”,第一種是最古老的beginXXX,endXXX模式,

還有一種是被Jeffrey Richter 嚴(yán)重鄙視的“事件異步模式”。。。沒(méi)什么好說(shuō)的,截圖一下給大家看看。

?

二:“單向“模式

  很多時(shí)候,我們或許都有這樣的需求,比如說(shuō)訂單提交成功的時(shí)候,我需要給客戶發(fā)送郵件,但是你想想,我發(fā)送郵件這個(gè)任務(wù)只是我訂單流程的

一個(gè)“額外任務(wù)“,也就是說(shuō),它的失敗不應(yīng)該會(huì)阻止我的訂單流程,并且它的邏輯時(shí)間不應(yīng)該會(huì)阻礙我的下單總時(shí)間,對(duì)吧。。。這樣的話,我的訂單時(shí)

間才會(huì)最小化,為了達(dá)到不影響下單總時(shí)間的效果,我的想法就是,client端直接把消息丟給信道就好了,然后不管server端有沒(méi)有真的接收到,處理的

慢不慢,過(guò)的好不好,等等,非常開心的是,這些對(duì)wcf來(lái)說(shuō)真的是小菜一碟,只需要一個(gè)輕輕松松的”IsOneWay=true“屬性就可以了。。。牛逼的要

死。。。還有就是因?yàn)槭菃蜗虻?#xff0c;所以契約方法就沒(méi)有存在返回值的必要了,我說(shuō)的對(duì)吧。。。嘿嘿~~~

1 [ServiceContract] 2 public interface IHomeService 3 { 4 [OperationContract(IsOneWay = true)] 5 void Update(Student message); 6 } 1 namespace MyService2 {3 public class HomeService : IHomeService4 {5 public void Update(Student message)6 {7 Console.WriteLine(message.Name);8 }9 } 10 11 [DataContract] 12 public class Student 13 { 14 [DataMember] 15 public string Name { get; set; } 16 17 [DataMember] 18 public int Age { get; set; } 19 } 20 }

為了驗(yàn)證是否真的是單向通訊,我可以用二種方法驗(yàn)證下。

?

1. wsdl中是否有output這個(gè)message

  通過(guò)下面的圖,我想你看的很清楚了,你再也沒(méi)有找到我們熟悉的“output”這個(gè)message,這就說(shuō)明貌似真的是單向的了,因?yàn)閣sdl就是web服務(wù)的清單。

  

?

2. 使用fillder監(jiān)視一下請(qǐng)求消息

1 class Program 2 { 3 static void Main(string[] args) 4 { 5 HomeServiceClient client = new HomeServiceClient(); 6 7 client.Update(new Student() { Name = "hxc" }); 8 } 9 }

  

正如我在圖中說(shuō)的那樣,非常奇怪,我的IsOneWay模式,竟然在http模式下行不通,但是你要記住,http模式天生就是“請(qǐng)求-響應(yīng)”模式,它完全做不了

單向模式,說(shuō)明白一點(diǎn)就是:“wcf發(fā)現(xiàn)你的bingding不支持單向“的時(shí)候,它并不會(huì)報(bào)錯(cuò),還是用自己天生的”請(qǐng)求-相應(yīng)“模式來(lái)模擬”單向通信“,這就是你

看到的非常奇怪的Http 202這個(gè)http狀態(tài)碼,很多人包括我,都不知道http202 是幾個(gè)意思,沒(méi)關(guān)系,我們百科一下就好了。。。下面框框的里面的字,

已經(jīng)說(shuō)的非常清楚了,感謝感謝。。。

?

三:“雙向“ 模式

  這個(gè)通訊其實(shí)沒(méi)什么好講的,也只有tcp模式才會(huì)天生支持,而http模式天生就不支持,就像上面一樣,如果非要用http來(lái)支持“雙向通訊“,那又是在

坑"wcf"他爹,這樣就會(huì)逼著他爹在底層再建立一個(gè)“請(qǐng)求-響應(yīng)“模式來(lái)支持所謂的”雙向通訊“,而且”雙向通訊“這個(gè)玩意還不如用兩個(gè)單向的”請(qǐng)求-響應(yīng)”模

式或者兩個(gè)“單向模式”來(lái)支持,而且兩個(gè)”請(qǐng)求-響應(yīng)“模式比”雙向通訊“有更大的靈活性,反正我是對(duì)它不感冒,了解一下即可,如果大家比較感興趣,可以

在wcf官網(wǎng)上看一下:https://msdn.microsoft.com/zh-cn/library/ms735119.aspx。

 

? 好了,就說(shuō)到這里,洗洗睡了,晚安~~~~

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第七天 Close和Abort到底該怎么用才對(duì)得起觀眾

?

一:文起緣由

? ? ? ? ? 寫這一篇的目的源自于最近看同事在寫wcf的時(shí)候,用特別感覺繁瑣而且云里霧里的嵌套try catch來(lái)防止client拋出異常,特別感覺奇怪,就比如下面的代碼。

1 public void StartNormalMarketing(int shopId, List<int> marketingIdList)2 {3 4 using (SendEventMarketingService.DistributeServiceClient client = new SendEventMarketingService.DistributeServiceClient())5 {6 try7 {8 9 client.StartByMarketingIDList(shopId, marketingIdList, SendEventMarketingService.MarketingType.NormalMarketing); 10 11 } 12 catch (Exception ex) 13 { 14 LogHelper.WriteLog("常規(guī)營(yíng)銷活動(dòng)開啟服務(wù)", ex); 15 } 16 finally 17 { 18 try 19 { 20 client.Close(); 21 } 22 catch (Exception) 23 { 24 client.Abort(); 25 } 26 } 27 } 28 }

看完上面的代碼,不知道你是否有什么感想?而且我還問(wèn)了同事,為什么try catch要寫成這樣,同事說(shuō)是根據(jù)什么書上來(lái)的什么最佳實(shí)踐,這話一說(shuō),我也不敢輕易

懷疑了,只能翻翻源代碼看看這話是否有道理,首先我來(lái)說(shuō)說(shuō)對(duì)這段代碼的第一感覺。。。

?

1. 代碼特別繁瑣

  我們寫代碼,特別不喜歡繁瑣,上面的代碼就是一例,你try catch就try catch,還在finally中嵌套一個(gè)try catch,真的有點(diǎn)感覺像吃了兩只癩蛤蟆一樣。。。

?

2. 混淆close和abort的用法  

  這種代碼給人的感覺就是為什么不精簡(jiǎn)一下呢???比如下面這樣,起碼還可以少寫一對(duì)try catch,對(duì)吧。

1 public void StartNormalMarketing(int shopId, List<int> marketingIdList)2 {3 4 using (SendEventMarketingService.DistributeServiceClient client = new SendEventMarketingService.DistributeServiceClient())5 {6 try7 {8 9 client.StartByMarketingIDList(shopId, marketingIdList, SendEventMarketingService.MarketingType.NormalMarketing); 10 11 client.Close(); 12 } 13 catch (Exception ex) 14 { 15 LogHelper.WriteLog("常規(guī)營(yíng)銷活動(dòng)開啟服務(wù)", ex); 16 17 client.Abort(); 18 } 19 } 20 }

而且乍一看這段代碼和文中開頭那一段代碼貌似實(shí)現(xiàn)一樣,但是某些人的“最佳實(shí)踐”卻不是這樣,所以確實(shí)會(huì)導(dǎo)致我這樣的后來(lái)人犯迷糊,對(duì)吧。。。反正我就是頭暈,

簡(jiǎn)直就是弄糊涂到什么時(shí)候該用close,什么時(shí)候該用abort。。。

      

二:探索原理

  為了弄明白到底可不可以用一個(gè)try catch來(lái)替代之,下面我們一起研究一下。

?

1. ?從代碼注釋角度甄別

    從類庫(kù)的注釋中,可以比較有意思的看出,abort方法僅僅比close多一個(gè)“立即”,再無(wú)其他,有意思,不過(guò)這對(duì)我來(lái)說(shuō)并沒(méi)有什么卵用,因?yàn)檫@個(gè)注釋太

籠統(tǒng)了,為了讓自己更加徹底的明白,只能來(lái)翻看下close和abort的源代碼。

?

2. ?從源碼角度甄別

  為了方便讓ILSpy調(diào)試Client代碼,現(xiàn)在我決定用ChannelFactory來(lái)代替,如下圖:

1 namespace ConsoleApplication12 {3 class Program4 {5 static void Main(string[] args)6 {7 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>();8 9 try 10 { 11 var channel = factory.CreateChannel(); 12 13 factory.Close(); 14 } 15 catch (Exception ex) 16 { 17 factory.Abort(); 18 } 19 } 20 } 21 }

為了讓大家更好的理解,我把close方法的源碼提供如下:

1 // System.ServiceModel.Channels.CommunicationObject2 [__DynamicallyInvokable]3 public void Close(TimeSpan timeout)4 {5 if (timeout < TimeSpan.Zero)6 {7 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", SR.GetString("SFxTimeoutOutOfRange0")));8 }9 using ((DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose) ? this.CreateCloseActivity() : null) 10 { 11 CommunicationState communicationState; 12 lock (this.ThisLock) 13 { 14 communicationState = this.state; 15 if (communicationState != CommunicationState.Closed) 16 { 17 this.state = CommunicationState.Closing; 18 } 19 this.closeCalled = true; 20 } 21 switch (communicationState) 22 { 23 case CommunicationState.Created: 24 case CommunicationState.Opening: 25 case CommunicationState.Faulted: 26 this.Abort(); 27 if (communicationState == CommunicationState.Faulted) 28 { 29 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 30 } 31 goto IL_174; 32 case CommunicationState.Opened: 33 { 34 bool flag2 = true; 35 try 36 { 37 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 38 this.OnClosing(); 39 if (!this.onClosingCalled) 40 { 41 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this); 42 } 43 this.OnClose(timeoutHelper.RemainingTime()); 44 this.OnClosed(); 45 if (!this.onClosedCalled) 46 { 47 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this); 48 } 49 flag2 = false; 50 goto IL_174; 51 } 52 finally 53 { 54 if (flag2) 55 { 56 if (DiagnosticUtility.ShouldTraceWarning) 57 { 58 TraceUtility.TraceEvent(TraceEventType.Warning, 524292, SR.GetString("TraceCodeCommunicationObjectCloseFailed", new object[] 59 { 60 this.GetCommunicationObjectType().ToString() 61 }), this); 62 } 63 this.Abort(); 64 } 65 } 66 break; 67 } 68 case CommunicationState.Closing: 69 case CommunicationState.Closed: 70 goto IL_174; 71 } 72 throw Fx.AssertAndThrow("CommunicationObject.BeginClose: Unknown CommunicationState"); 73 IL_174:; 74 } 75 }

然后我提供一下Abort代碼:

1 // System.ServiceModel.Channels.CommunicationObject2 [__DynamicallyInvokable]3 public void Abort()4 {5 lock (this.ThisLock)6 {7 if (this.aborted || this.state == CommunicationState.Closed)8 {9 return; 10 } 11 this.aborted = true; 12 this.state = CommunicationState.Closing; 13 } 14 if (DiagnosticUtility.ShouldTraceInformation) 15 { 16 TraceUtility.TraceEvent(TraceEventType.Information, 524290, SR.GetString("TraceCodeCommunicationObjectAborted", new object[] 17 { 18 TraceUtility.CreateSourceString(this) 19 }), this); 20 } 21 bool flag2 = true; 22 try 23 { 24 this.OnClosing(); 25 if (!this.onClosingCalled) 26 { 27 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this); 28 } 29 this.OnAbort(); 30 this.OnClosed(); 31 if (!this.onClosedCalled) 32 { 33 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this); 34 } 35 flag2 = false; 36 } 37 finally 38 { 39 if (flag2 && DiagnosticUtility.ShouldTraceWarning) 40 { 41 TraceUtility.TraceEvent(TraceEventType.Warning, 524291, SR.GetString("TraceCodeCommunicationObjectAbortFailed", new object[] 42 { 43 this.GetCommunicationObjectType().ToString() 44 }), this); 45 } 46 } 47 }

?

仔細(xì)觀察完這兩個(gè)方法,你會(huì)發(fā)現(xiàn)什么呢???至少我可以提出下面四個(gè)問(wèn)題:

?

1:Abort是Close的子集嗎?

  ?是的,因?yàn)槿绻憧炊薈lose,你會(huì)發(fā)現(xiàn)Close只針對(duì)Faulted 和Opened做了判斷,而其中在Faulted的枚舉下會(huì)調(diào)用原生的Abort方法。。。如下圖

?

2:我能監(jiān)視Client的各種狀態(tài)嗎?比如Created,Opening,Fault,Closed等等。。。

   當(dāng)然可以了,wcf的信道老祖宗就是ICommunicationObject,而它就有5種監(jiān)聽事件,這些就可以隨時(shí)監(jiān)聽,懂伐???

1 static void Main(string[] args)2 {3 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:1920/HomeServie"));4 5 try6 {7 factory.Opened += (o, e) =>8 {9 Console.WriteLine("Opened"); 10 }; 11 12 factory.Closing += (o, e) => 13 { 14 Console.WriteLine("Closing"); 15 }; 16 17 factory.Closed += (o, e) => 18 { 19 Console.WriteLine("Closed"); 20 }; 21 22 var channel = factory.CreateChannel(); 23 24 var result = channel.Update(new Student() { }); 25 26 factory.Close(); 27 } 28 catch (Exception ex) 29 { 30 factory.Abort(); 31 } 32 }

?

3:Abort會(huì)拋出異常嗎?

  

從這個(gè)截圖中可以看到非常有意思的一段,那就是居然abort活生生的把異常給吞了。。。骨頭都不給吐出來(lái)。。。真tmd的神奇到家了,想想也有道理,因?yàn)橹挥?/p>

這樣,我們上層的代碼在catch中才不會(huì)二次拋出“未處理異常”了,對(duì)吧,再轉(zhuǎn)念看一下Close方法。

?

從上面圖中可以看到,Close在遇到Faulted之后調(diào)用Abort方法,如果說(shuō)Abort方法調(diào)用失敗,Close方法會(huì)再次判斷狀態(tài),如果還是Faulted的話,就會(huì)向上拋出

異常。。。這就是為什么Abort不會(huì)拋異常,Close會(huì)的原因,所以Close千萬(wàn)不要放在Catch塊中。

?

4. Abort代碼大概都干了些什么

  這個(gè)問(wèn)題問(wèn)的好,要能完美解決的話,我們看下代碼,如下圖,從圖中可以看到,Abort的大目的就是用來(lái)關(guān)閉信道,具體會(huì)經(jīng)過(guò)closeing,abort和closed這

三個(gè)方法,同時(shí),這三個(gè)事件也會(huì)被老祖宗ICommunicationObject監(jiān)聽的到。

?

?

好了,最后我們關(guān)注的一個(gè)問(wèn)題在于下面這條語(yǔ)句是否應(yīng)該放在Try塊中???

1 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:1920/HomeServie"));

很簡(jiǎn)單,我們簡(jiǎn)要的看一下代碼,看里面是否會(huì)有“異常”拋出即可。。。。

?

可以看到,在new的過(guò)程中可能,或許會(huì)有異常的產(chǎn)生,所以最好把try catch改成下面這樣。。。

1 class Program2 {3 static void Main(string[] args)4 {5 ChannelFactory<IHomeService> factory = null;6 try7 {8 factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:1920/HomeServie"));9 10 var channel = factory.CreateChannel(); 11 12 var result = channel.Update(new Student() { }); 13 14 factory.Close(); 15 16 throw new Exception(); 17 } 18 catch (Exception ex) 19 { 20 if (factory != null) 21 factory.Abort(); 22 } 23 } 24 }

?

好了,綜合我上面所說(shuō)的一切,我個(gè)人覺得最好的方式應(yīng)該是上面這樣,夜深了,睡覺了,晚安。

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第八天 對(duì)“綁定”的最后一點(diǎn)理解

  

  轉(zhuǎn)眼已經(jīng)中斷10幾天沒(méi)有寫博客了,也不是工作太忙,正好碰到了端午節(jié),然后最近看天津臺(tái)的愛情保衛(wèi)戰(zhàn)入迷了。。。太好看了,一直都是回味無(wú)窮。。。而且

涂磊老師話說(shuō)的真是tmd的經(jīng)典,然后就這樣耽擱了,好了,話不多說(shuō),這篇我們看看binding中最后一點(diǎn)需要知道的東西。

?

一:信道棧

  我在之前的文章中多次提到信道棧,不知道大家對(duì)它的概念是否有了解,其實(shí)想想也還是蠻簡(jiǎn)單的,既然是棧,那么這個(gè)棧肯定就不止一個(gè)元素了,對(duì)吧,第二個(gè)

的話,既然是棧,那么肯定就遵循FILO的原則,可能你會(huì)說(shuō),這個(gè)還是蠻抽象的,能給個(gè)具體的例子么???恭喜你,wcf中還真有一個(gè)方法CreateBindingElements,

下面我們具體看看。。。

?

1. ?簡(jiǎn)單看看各種binding的棧中都有些什么

  

看到上面的監(jiān)控窗口,是不是有點(diǎn)意思,在BasicHttpBinding的信道棧中有兩個(gè)元素,分別是HttpTransportBindingElement和TextMessageEncodingBindingEl

ement,通過(guò)名字也能很容易的判斷出來(lái),一個(gè)是“http傳輸協(xié)議”,一個(gè)是“文本消息編碼協(xié)議”,然后再看看復(fù)雜一點(diǎn)的WSHttpBinding,你會(huì)發(fā)現(xiàn),他不光有Basic

的所有東西,還包括SymmetricSecurityBindingElement(安全協(xié)議) 和?TransactionFlowBindingElement(事務(wù)流),現(xiàn)在你心中是不是有底了,起碼我知道各

種Binding里面都有些啥,為了更好的理解,我來(lái)畫一張簡(jiǎn)圖。

上面這個(gè)圖,大概也就表達(dá)了我的意思,當(dāng)我們Client在走WSHttpBinding這個(gè)協(xié)議的時(shí)候,Client端的InputMessage會(huì)先走?TransactionFlow,SymmetricSec

urity,TextMessageEncoding,最后走HttpTransport,然后Service端就按照客戶端進(jìn)行“反向處理”,通過(guò)一陣禁臠之后,我們就拿到了安全的OutputMessage。

?

二:BindingElement的跨綁定性

  你要是很仔細(xì)的話,你肯定會(huì)發(fā)現(xiàn),其實(shí)Binding就是一個(gè)預(yù)先默認(rèn)配置好的信道棧,對(duì)不對(duì),你也看到了,每一種Binding都有屬于自己的BindingElements,

恰恰這些Elements是可以跨Binding的,也就是說(shuō)我可以自由組合Elements,這樣是不是可以給我們這些寒酸的碼農(nóng)最大的靈活性,對(duì)吧,舉個(gè)簡(jiǎn)單的例子,

BasicHttpBinding有兩個(gè)綁定元素,其中對(duì)soap消息進(jìn)行的是TextMessageEncoding編碼對(duì)吧,而netTcpBinding對(duì)soap進(jìn)行的BinaryMessageEncoding,

然后你也應(yīng)該知道了,我想做一個(gè)自定義的Binding,其中消息編碼是BinaryMessage,傳輸協(xié)議是HttpTransport,那怎么做呢????

Host文件:

1 class Program12 {3 static void Main(string[] args)4 {5 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://192.168.1.105:1920"));6 7 var customBinding = new CustomBinding();8 9 customBinding.Elements.Add(new BinaryMessageEncodingBindingElement()); 10 customBinding.Elements.Add(new HttpTransportBindingElement()); 11 12 host.AddServiceEndpoint(typeof(IHomeService), customBinding, "HomeServie"); 13 14 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true }); 15 16 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 17 18 host.Open(); 19 20 Console.WriteLine("服務(wù)已經(jīng)開啟!!!"); 21 22 Console.Read(); 23 } 24 }

?

Client調(diào)用:

1 static void Main(string[] args)2 {3 ServiceReference1.HomeServiceClient client = new ServiceReference1.HomeServiceClient();4 5 var result = client.Update("你好");6 7 Console.WriteLine("server value:" + result);8 9 Console.Read(); 10 }

最后我們用Fiddler監(jiān)視一下,最后我們看看,都是些亂碼。

?

這篇就說(shuō)到這里了,希望對(duì)你有幫助,下一篇我們看看WCF中的Behavior,很好玩的哦~~~

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第九天 高級(jí)玩法之自定義Behavior

?

  終于我又看完了二期愛情保衛(wèi)戰(zhàn),太酸爽了,推薦鏈接:http://www.iqiyi.com/a_19rrgublqh.html?vfm=2008_aldbd,不多說(shuō),誰(shuí)看誰(shuí)入迷,下面言歸正傳,

看看這個(gè)很有意思的Behavior。

?

一: Behavior這個(gè)潑婦的厲害

  ? 在前面的文章中,我也清楚的說(shuō)明了整個(gè)wcf通信流,而Behavior這個(gè)潑婦可以在wcf通信流中的任何地方插上一腳,蠻狠無(wú)比,利用的好,讓你上天堂,利用的不

好,讓你下地獄。。。下面讓你看看behavior到底有哪些可以注入的點(diǎn)???先畫個(gè)簡(jiǎn)圖:

上面的圖,大概就是wcf的通信簡(jiǎn)圖,所有藍(lán)色字體都是Behavior注入的點(diǎn),其中Client和Service端都可以注入,如果按照功能分的話,又可以分為“操作級(jí)別”和

”端點(diǎn)級(jí)別“,下面我來(lái)簡(jiǎn)要的分解下。

?

二:端點(diǎn)級(jí)別Behavior

  從圖中你也可以看到,消息檢查器是放在Channel這個(gè)級(jí)別的,也就是說(shuō)它可以監(jiān)視Client和Server的入站請(qǐng)求,也就是說(shuō)所有的請(qǐng)求都需要通過(guò)它轉(zhuǎn)發(fā),如果

這樣的話,那我是不是可以在這個(gè)注入點(diǎn)上自由的修改,變更,攔截入站和出站請(qǐng)求,而且利用這個(gè)特性我還可以做很多的事情,比如日志記錄,記錄統(tǒng)計(jì)等等,下

面我們來(lái)看看這個(gè)怎么使用??? 只需要extends?IEndpointBehavior ?和?IDispatchMessageInspector,然后加入EndpointBehaviors即可。。。

?1.?IDispatchMessageInspector

1 public class MyDispatchMessageInspector : IDispatchMessageInspector2 {3 public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)4 {5 Console.WriteLine(request.ToString());6 return request;7 }8 9 public void BeforeSendReply(ref Message reply, object correlationState) 10 { 11 Console.WriteLine(reply.ToString()); 12 } 13 }

2.?IEndpointBehavior

1 public class MyEndpointBehavior : IEndpointBehavior2 {3 public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)4 {5 }6 7 public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)8 {9 } 10 11 public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 12 { 13 endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MyDispatchMessageInspector()); 14 } 15 16 public void Validate(ServiceEndpoint endpoint) 17 { 18 } 19 }

3. 將MyEndpointBehavior加入到Host中

1 static void Main(string[] args)2 {3 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://127.0.0.1:1920"));4 5 host.AddServiceEndpoint(typeof(IHomeService), new BasicHttpBinding(), "HomeServie");6 7 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });8 9 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 10 11 host.Description.Endpoints[0].EndpointBehaviors.Add(new MyEndpointBehavior()); 12 13 host.Open(); 14 15 Console.WriteLine("服務(wù)已經(jīng)開啟!!!"); 16 17 Console.Read(); 18 }

4. 最后我們看一下服務(wù)方法

1 public class HomeService : IHomeService 2 { 3 public string Update(string message) 4 { 5 Console.WriteLine("我在Action方法:" + message); 6 7 return "my reply!!!"; 8 } 9 }

?

下面看看效果。。。在效果圖中,你應(yīng)該看到了。在我的Action中的方法前后各有一段“入站消息”和“出站消息”,是不是很爽???

?

三:操作級(jí)別Behavior

  從文章開頭的簡(jiǎn)圖中,你應(yīng)該看到了,Operation級(jí)別的Behavior比較多,有“操作啟動(dòng)器(IOperationInvoker)","參數(shù)檢查(IParameterInspector)“,

“消息格式化器(IDispatchMessageFormatter)”等等。。。 為什么說(shuō)等等這個(gè)詞,很簡(jiǎn)單啊,,,其實(shí)還有很多系統(tǒng)內(nèi)置的,既然是Operation,那就必

然是針對(duì)方法的,還記得OperationContract是怎么套在方法上的嗎??? 是特性,對(duì)吧,,,同樣的道理,OperationBehavior也是一樣,那怎么用呢??

同樣也是很簡(jiǎn)單的,繼承幾個(gè)接口即可。。。

?<1>?IParameterInspector 的玩法

? ?其實(shí)沒(méi)什么好說(shuō)的,既然是屬于Operation下面的Behavior,那都是通過(guò)特性注入的,而這個(gè)IParameterInspector,可以做到類似Mvc的Model驗(yàn)證,下面

我做個(gè)簡(jiǎn)單的Action參數(shù)長(zhǎng)度驗(yàn)證(長(zhǎng)度不超過(guò)8個(gè)字符)。

1.?IParameterInspector

1 public class MyIParameterInspector : IParameterInspector2 {3 public int MaxLength { get; set; }4 5 public MyIParameterInspector(int MaxLength)6 {7 this.MaxLength = MaxLength;8 }9 10 /// <summary> 11 /// 出站的操作 12 /// </summary> 13 /// <param name="operationName"></param> 14 /// <param name="outputs"></param> 15 /// <param name="returnValue"></param> 16 /// <param name="correlationState"></param> 17 public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) 18 { 19 20 } 21 22 /// <summary> 23 /// 入站的參數(shù) 24 /// </summary> 25 /// <param name="operationName"></param> 26 /// <param name="inputs"></param> 27 /// <returns></returns> 28 public object BeforeCall(string operationName, object[] inputs) 29 { 30 foreach (var item in inputs) 31 { 32 if (Convert.ToString(item).Length > MaxLength) 33 { 34 throw new Exception("碼單,長(zhǎng)度不能超過(guò) " + MaxLength + " 個(gè)長(zhǎng)度"); 35 } 36 } 37 38 return null; 39 } 40 }

2.?IOperationBehavior

1 public class MyOperationBehavior : Attribute, IOperationBehavior2 {3 public int MaxLength { get; set; }4 5 public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)6 {7 8 }9 10 public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 11 { 12 13 } 14 15 public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 16 { 17 dispatchOperation.ParameterInspectors.Add(new MyIParameterInspector(MaxLength)); 18 } 19 20 public void Validate(OperationDescription operationDescription) 21 { 22 23 } 24 }

3. 在Action在加上MyOperationBehavior 這個(gè) Attribute

1 public class HomeService : IHomeService2 {3 [MyOperationBehavior(MaxLength = 5)]4 public string Update(string message)5 {6 Console.WriteLine("我在Action方法:" + message);7 8 return "my reply!!!";9 } 10 }

4. 然后我在客戶端故意輸入大于5的字符,看看效果怎么樣???

1 public class Program12 {3 static void Main(string[] args)4 {5 HomeServiceClient client = new HomeServiceClient();6 7 client.Update("我故意輸入了很多的字符,哈哈。。。。。");8 9 Console.Read(); 10 } 11 }

5. 最后看看效果圖,可以看到,最終的入站消息會(huì)拋出一個(gè)異常。。。

?

?

<2>?MessageFormatter,IOperationInvoker?的玩法

   剩下的這兩個(gè)玩法都差不多,你只需要extends一下,然后加入到OperationBehavior即可,有了上面的思想,我想下面這些使用起來(lái)都不是問(wèn)題吧。。。

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第十天 學(xué)會(huì)用SvcConfigEditor來(lái)簡(jiǎn)化配置

  

? ? ? ?我們?cè)谕鎤cf項(xiàng)目的時(shí)候,都是自己手工編寫system.serviceModel下面的配置,雖然在webconfig中做wcf的服務(wù)配置的時(shí)候,vs提供大多

數(shù)的代碼提示,但對(duì)于不太熟悉服務(wù)配置的小鳥們來(lái)說(shuō),有些困難,而且一些服務(wù)配置也容易遺漏,大多情況下,我們都是copy一份服務(wù)配置,然

后在服務(wù)配置上面修修改改,對(duì)吧。。。其實(shí)呢,.net給我們提供了一個(gè)強(qiáng)大的scvconfigeditor這個(gè)工具化的軟件來(lái)幫助我們生成wcf的配置,是

不是很神奇???

?

一:工具在何處

  當(dāng)然在無(wú)比牛逼的Microsoft SDK下面啦,在C:\Program Files (x86)\Microsoft SDKs\Windows下面,你會(huì)找到很多的版本,如下圖:

對(duì)吧,你已經(jīng)看到了很多的版本,當(dāng)然啦,我肯定要找最新的啦,一禁臠,我進(jìn)去了v8.0A,如下圖:

C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools

?

你應(yīng)該也看到了,各種牛逼的工具,很眼饞吧,不過(guò)這一篇我們還是看重SvcConfigEditor。

?

二: 如何使用SvcConfigEditor

1. ? 雙擊打開,選擇“文件” => “新建配置”。

?

2. ?然后我們選擇 “新建服務(wù)” => “填寫服務(wù)名”

?

3. ?然后我們給service定義一個(gè)host, 點(diǎn)擊 "主機(jī)" => "新建“ => "填寫基址"。

?

4.??到這一步,你是不是特別想看一看生成的config配置是咋樣的???好啊,滿足你的虛榮心,我們只需要點(diǎn)

? ? ?擊"保存“,選擇一個(gè)路徑即可。。。

  

5. ?好了,你的虛榮心得到滿足了,下面我們來(lái)定義endpoint了,其實(shí)也是非常非常簡(jiǎn)單的, 點(diǎn)擊”終結(jié)點(diǎn)"

? ? => "新建服務(wù)終結(jié)點(diǎn)",然后我們就象征性的填寫一些Address,Contract,Binding即可,如下圖:

?

6. 上面我們就已經(jīng)定義了一個(gè)basichttpbinding了,下一步的話,我們還記得要公布一個(gè)mexhttpbinding,

? ? 這樣我的svcutil才能服務(wù)引用,對(duì)吧,所以方法也是很簡(jiǎn)單,繼續(xù)“新建終結(jié)點(diǎn)”,如下圖:

  

7. 最后我還記得mex需要有一個(gè)behavior,讓http的get可以訪問(wèn),有了這個(gè)神器,同樣簡(jiǎn)單,我們可以

? ? 點(diǎn)擊“高級(jí)” => "服務(wù)行為" => "新建"。

?

8. 最后我們保存來(lái)看一下生成的appconfig是啥樣的???

則么樣???我不需要寫一個(gè)字的config配置就完成了基本的服務(wù)配置,如果你還想玩高級(jí)的,可以自己試著琢磨琢磨SvcConfigEditor。

?

好了,差不多可以睡了,下一篇我們來(lái)研究研究 SvcConfigEditor中的診斷工具,很好玩的啦~~~~~

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第十一天 如何對(duì)wcf進(jìn)行全程監(jiān)控

  說(shuō)點(diǎn)題外話,我們?cè)谕鎍sp.net的時(shí)候,都知道有一個(gè)叼毛玩意叫做“生命周期”,我們可以用httpmodule在先于頁(yè)面的page_load中

做一些攔截,這樣做的好處有很多,比如記錄日志,參數(shù)過(guò)濾,全局登錄驗(yàn)證等等。。。在wcf里面的話也是有類似的功能,第一種就是在

endpoint中加上runtime的behavior,這樣的話就可以先于“服務(wù)方法”做攔截,第二種方法呢,也就是我們這一篇所說(shuō)的全程監(jiān)控,俗稱

”診斷功能”。

?

一:診斷

  我也說(shuō)了,“診斷”這是wcf的一個(gè)專業(yè)術(shù)語(yǔ),意思也就是監(jiān)控wcf的所有動(dòng)向,如果往下說(shuō)的話,可以分為監(jiān)控 wcf的message 和 wcf

本身的服務(wù)狀態(tài)信息和端對(duì)端的流轉(zhuǎn)消息。

1. 端對(duì)端的流轉(zhuǎn)消息

  在玩wcf之前,不知道有多少人熟悉Diagnostics,對(duì)的,它就是.net自帶的日志類,當(dāng)然在這個(gè)年代,記錄日志的組件有很多,比如

log4net,Nlog等等。。。不過(guò)話說(shuō)回來(lái),Diagnostics這個(gè)叼毛用起來(lái)還比較另類,它由“跟蹤源” 和 “監(jiān)聽器”組成。分別就是TraceSource

來(lái)指定跟蹤源,用TraceListener來(lái)指定跟蹤源的監(jiān)聽器,所以理所當(dāng)然,TraceSource的所有蹤跡都會(huì)被TraceListener監(jiān)聽到,下面我們

看看怎么玩。

<?xml version="1.0" encoding="utf-8"?> <configuration><system.diagnostics><sources><source name="System.ServiceModel" switchValue="ActivityTracing"><listeners><add name="mylisteners" type="System.Diagnostics.XmlWriterTraceListener" initializeData="E:\1.txt" /></listeners></source></sources><trace autoflush="true"/></system.diagnostics><system.serviceModel><behaviors><serviceBehaviors><behavior><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="false" /></behavior></serviceBehaviors></behaviors><services><service name="MyService.HomeService"><endpoint address="HomeService" binding="wsHttpBinding"contract="MyService.IHomeService"><identity><dns value="localhost" /></identity></endpoint><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /><host><baseAddresses><add baseAddress="http://192.168.1.107:1920" /></baseAddresses></host></service></services></system.serviceModel></configuration>

?從上面的配置中可以看到,你有沒(méi)有發(fā)現(xiàn)我在配置system.diagnostics的時(shí)候和wcf一點(diǎn)關(guān)系都沒(méi)有,我并沒(méi)有在system.ServiceModel

下對(duì)diagnostics有一丁點(diǎn)的配置,對(duì)吧,這說(shuō)明什么,說(shuō)明“蹤跡跟蹤”功能和wcf一點(diǎn)關(guān)系都沒(méi)有,但卻可以完整的記錄wcf的蹤跡信息,然

后我稍微解釋下listeners節(jié)點(diǎn),在這里我配置了一個(gè)XmlWriterTraceListener的監(jiān)聽器,然后把輸出文件的路徑配置在initializeData屬性下,

其實(shí)都是diagnostics本身的知識(shí)范疇,和wcf一點(diǎn)關(guān)系都沒(méi)有,好了,下面我開啟下程序,看看到底都追蹤到什么?

有沒(méi)有看到,當(dāng)我的服務(wù)啟動(dòng)之后,追蹤信息就全部來(lái)了。。。但是接下來(lái)有一個(gè)問(wèn)題來(lái)了,這個(gè)很雜亂的xml該怎么看才能最舒舒服服的

呢???不用著急啦,wcf同樣給我們提供了一個(gè)叫做SvcTraceView的工具,專門就是用來(lái)查找這個(gè)“蹤跡信息”的,工具的路徑在:

C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools

?

下面的事情就是打開它,附加一下1.txt文件就好了,如下圖:

從左邊的“活動(dòng)圖”中大概可以看到HomeService這個(gè)服務(wù)啟動(dòng)到運(yùn)行經(jīng)歷了一些什么樣的悲慘故事。。。有興趣的話,大家可以自己動(dòng)

手試試?yán)病?/p>

?

2. 監(jiān)控input和ouput的message

  如果要監(jiān)控message的話,我們需要再定義一個(gè)TraceSource 和 TraceListener即可,不過(guò)這次監(jiān)聽的是System.ServiceModel.

MessageLogging跟蹤源,然后在System.ServiceModel下面配置一下message的參數(shù),如下:

1 <?xml version="1.0" encoding="utf-8"?>2 <configuration>3 4 <system.diagnostics>5 <sources>6 <source name="System.ServiceModel" switchValue="ActivityTracing">7 <listeners>8 <add name="mylisteners" type="System.Diagnostics.XmlWriterTraceListener" initializeData="E:\1.txt" />9 </listeners> 10 </source> 11 <source name="System.ServiceModel.MessageLogging" switchValue="ActivityTracing"> 12 <listeners> 13 <add name="messagelogging" type="System.Diagnostics.XmlWriterTraceListener" initializeData="E:\2.txt"/> 14 </listeners> 15 </source> 16 </sources> 17 <trace autoflush="true"/> 18 </system.diagnostics> 19 20 <system.serviceModel> 21 22 <diagnostics> 23 <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtTransportLevel="true" /> 24 </diagnostics> 25 26 <behaviors> 27 <serviceBehaviors> 28 <behavior> 29 <serviceMetadata httpGetEnabled="true" /> 30 <serviceDebug includeExceptionDetailInFaults="false" /> 31 </behavior> 32 </serviceBehaviors> 33 </behaviors> 34 35 <services> 36 <service name="MyService.HomeService"> 37 <endpoint address="HomeService" binding="basicHttpBinding" 38 contract="MyService.IHomeService"> 39 <identity> 40 <dns value="localhost" /> 41 </identity> 42 </endpoint> 43 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 44 <host> 45 <baseAddresses> 46 <add baseAddress="http://192.168.1.107:1920" /> 47 </baseAddresses> 48 </host> 49 </service> 50 </services> 51 52 </system.serviceModel> 53 54 </configuration>

?

這次我準(zhǔn)備來(lái)跑一下客戶端,調(diào)用Server端的Update方法,看看能抓到啥樣的Messsage。

?

?

現(xiàn)在我迫不及待的想用SvcTraceView打開下2.txt,看看都拿到了什么追蹤信息。。。

?

?

好了,這篇我也只是引路式的介紹下SvcTraceView,具體更深入的玩法,大家可以琢磨琢磨,對(duì)了,如果大家想對(duì)Source和Listener的

一些參數(shù)需要進(jìn)一步了解,可以參考下SvcConfigEditor,比如下面這樣,一目了然,你懂的。。。

?

十五天精通WCF——第十二天 說(shuō)說(shuō)wcf中的那幾種序列化

  

  我們都知道wcf是由信道棧組成的,在我們傳輸?shù)膮?shù)走到傳輸信道層之前,先需要經(jīng)過(guò)序列化的過(guò)程,也就是將參數(shù)序列化為message,這篇

我們就來(lái)說(shuō)說(shuō)這里的序列化,蠻有意思的,可能初學(xué)者也明白,在wcf中默認(rèn)的序列化是DataContractSerializer,確實(shí)是這樣,不過(guò)wcf在信道中

其實(shí)不僅僅支持DataContractSerializer,它還支持其他類型的序列化,比如XmlSerializer,NetDataContractSerializer以及DataContractJson

Serializer,下面我們一起來(lái)見證下。

?

1.?XmlSerializer

???要了解XmlSerializer,我們先來(lái)簡(jiǎn)單看看NetDataContractSerializer,在前面的文章中,我也說(shuō)過(guò)DataContract就是將我們的model序列化為

XSD,第二點(diǎn)就是使用DataContract的原則就是你必須在Model上加DataContract,而且在你要序列化的字段上加DataMember。這樣才能夠正確的序列

化,為了演示,我們先看看默認(rèn)的序列化Model會(huì)變成啥樣?

1 [DataContract]2 public class Student3 {4 [DataMember]5 public int ID { get; set; }6 7 [DataMember]8 public string Name { get; set; }9 10 [DataMember] 11 public string SNS { get; set; } 12 }

但是在有些情況下,你可能并不適合用DataContract,比如Model是第三方提供的,那么這個(gè)時(shí)候你的Model可能就不會(huì)有DataContract標(biāo)記,那這樣的

話wcf就無(wú)法進(jìn)行序列化,那我如果非要保證wcf能正常跑起來(lái)的話,還有其他好的辦法嗎???當(dāng)然了,肯定有辦法,這就好比談戀愛一樣,總不能

在一棵樹上吊死吧,沒(méi)人誰(shuí)離不開誰(shuí),也不會(huì)誰(shuí)離開了誰(shuí)會(huì)死,天涯何處無(wú)芳草,男兒何患無(wú)妻,對(duì)吧。Wcf中也一樣,既然DataContract用不了,自

然會(huì)有替代它的人,那這個(gè)人就是XmlSerializer,使用起來(lái)也很簡(jiǎn)單,就是在契約方法上面加上XmlSerializerFormat即可,然后我們把Model的

DataContract全部去掉。

?

是不是很簡(jiǎn)單,下面我們就要驗(yàn)證一下,看看這個(gè)Format是否進(jìn)入到了這個(gè)Operation的Behavior中,

?

從上面的圖中,你也看到了,?XmlSerializerFormat?已經(jīng)被注入到Behavior中,并且是由類XmlSerializerOperationBehavior代為處理。

?

接下來(lái),我們用fiddler監(jiān)視一下,看看Message中的Body是否真的按照XmlSerializer?序列化了。

有沒(méi)有看到,這次Message的Body已經(jīng)和文章開頭處的Message不一樣了。

?

2. NetDataContract

? ? ? ?這個(gè)玩意也沒(méi)什么好說(shuō)的,光從表面上看,它和DataContract唯一不同的地方就是多了一個(gè)Net,所以你大概也能猜到,這個(gè)功能大概和DataCont

ract一樣,只不過(guò)比DataContract多了一個(gè)程序集保存,那這句話是什么意思呢???就是NetDataContract會(huì)把程序集的命名空間和類名都保存到XSD中,

在反序列化的過(guò)程中必須要用同樣的程序集才能解開,其實(shí)不管我們是做SOA或者面向?qū)ο缶幊潭贾v究接口編程,而NetDataContract給你的印象就是面

向?qū)ο缶幊?#xff0c;當(dāng)然這也有好處,比如說(shuō)如果把程序集帶進(jìn)去就好像秘鑰一樣,必須有它才能解開,對(duì)吧,所以導(dǎo)致wcf項(xiàng)目組并不對(duì)NetDataContract感冒

,所以在實(shí)際應(yīng)用上也不建議使用。

?

3.?DataContractJsonSerializer

? ?看到上面這個(gè)帶有Json的字樣,我想大家都知道這玩意是干什么的???沒(méi)錯(cuò),他就是將我們的Model序列化成Json,這在wcf的rest編碼使用的很廣,

如果大家有興趣的話,我在下一篇會(huì)詳細(xì)描述,這里我們先簡(jiǎn)單看一看。

?

好了,這一篇就說(shuō)這些了,洗洗睡了。。。

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第十三天 用WCF來(lái)玩Rest

  

? ? ? ? 在我們玩wcf的時(shí)候,都會(huì)潛意識(shí)的覺得wcf就是通過(guò)soap協(xié)議交換消息的,并且可以在basic,tcp,msmq等等綁定中任意切換,

牛逼的一塌糊涂,但是呢,如果說(shuō)哪一天wcf不再使用soap協(xié)議,而是采用json格式的字符串,是不是有一點(diǎn)顛覆你對(duì)wcf的認(rèn)識(shí)的???

從傳統(tǒng)意義上說(shuō),wcf是非常重量級(jí)的,很明白的一個(gè)例子就是太多太多的配置,尤其是Behavior的配置,而且behavior對(duì)wcf來(lái)說(shuō)又是重

中之重,它對(duì)wcf的擴(kuò)展和性能又是最重要的,可恨的是wcf在binding,behavior,contract之中的配置又是非常非常的保守,可以說(shuō)用

wcf來(lái)玩分布式,這些默認(rèn)配置是完全做不到的,就比如說(shuō)basicbinding的基類HttpBindingBase。

?

抱怨的話我也不說(shuō)了,可能微軟也覺得這個(gè)問(wèn)題是個(gè)不小的問(wèn)題,然后就有了輕量級(jí)的 asp.net web api,你可以看到它和wcf比起來(lái)精

簡(jiǎn)多了,也許讓我們這些碼農(nóng)更加的專注于業(yè)務(wù)吧,既然wcf帶了這玩意,我也得必須約談一下。

?

一:UriTemplate

  要說(shuō)rest,還得先說(shuō)UriTemplate,因?yàn)閣cf用UriTemplate來(lái)做rest中的uri模板匹配,然后用WebInvoke這個(gè)OperationBehavior

插入到wcf的心臟中,說(shuō)的玄乎一點(diǎn),這個(gè)就有點(diǎn)像mvc中的路由匹配機(jī)制,下面我舉個(gè)例子:

?

1. 用UriTemplate來(lái)告知可以監(jiān)視的完整Url

  從下面的圖中,可以看到三個(gè)元素:服務(wù)地址,模板,入?yún)?#xff08;這里面的”1“),這三個(gè)元素組合在一起,就構(gòu)成了完整的remote url,

然后這個(gè)完整的url就是我模板(/User/{id})監(jiān)視的對(duì)象。

?

2. 通過(guò)UriTemplate來(lái)解析url中的參數(shù)。

  既然可以構(gòu)建url,那當(dāng)然可以解析url啦,對(duì)吧,下面這張圖可以很清晰的告知你,當(dāng)外來(lái)的url=http://127.0.1:1920/HomeService

/User/1過(guò)來(lái)的時(shí)候應(yīng)該被哪個(gè)uriTemplate所接收。

?

正是因?yàn)閁riTemplate具有這樣的url構(gòu)建和解析能力,所以wcf就把UriTemplate作為WebInvoke和WebGet這兩個(gè)屬性的參數(shù)來(lái)動(dòng)態(tài)

解析外來(lái)的url,然后根據(jù)這個(gè)url分配到具體的服務(wù)方法上,下面我們具體看一看。

?

二:WebGet,WebInvoke的使用

  剛才也說(shuō)了,WebGet和WebInvoke正是用了UriTemplate,才具有了路由轉(zhuǎn)向的功能,還有就是默認(rèn)返回的是xml,這里就用json

值作為服務(wù)返回的格式

1 [ServiceContract]2 public interface IHomeService3 {4 [OperationContract]5 [WebGet(UriTemplate = "Get/{id}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]6 Student Get(string id);7 8 [OperationContract]9 [WebInvoke(Method = "POST", UriTemplate = "Add", RequestFormat = WebMessageFormat.Json, 10 ResponseFormat = WebMessageFormat.Json)] 11 string Add(Student stu); 12 }

對(duì)了,Rest推薦使用Http協(xié)議中的Get,Post,Delete,Put來(lái)作為CURD的狀態(tài)機(jī)制,然后就是你如果看懂了UriTemplate,那你現(xiàn)在應(yīng)

該知道這個(gè)Template在監(jiān)視什么類型的url。做完了上面的coding,下面我們需要在webconfig中通過(guò)behavior來(lái)指定啟動(dòng)“web編程模型”,

就比如下面這樣。

1 <?xml version="1.0" encoding="utf-8"?>2 <configuration>3 4 <system.diagnostics>5 <sources>6 <source name="System.ServiceModel" switchValue="ActivityTracing">7 <listeners>8 <add name="mylisteners" type="System.Diagnostics.XmlWriterTraceListener" initializeData="E:\1.txt" />9 </listeners> 10 </source> 11 <source name="System.ServiceModel.MessageLogging" switchValue="ActivityTracing"> 12 <listeners> 13 <add name="messagelogging" type="System.Diagnostics.XmlWriterTraceListener" initializeData="E:\2.txt"/> 14 </listeners> 15 </source> 16 </sources> 17 <trace autoflush="true"/> 18 </system.diagnostics> 19 20 <system.serviceModel> 21 22 <diagnostics> 23 <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtTransportLevel="true" /> 24 </diagnostics> 25 26 <behaviors> 27 <serviceBehaviors> 28 <behavior> 29 <serviceMetadata httpGetEnabled="true" /> 30 <serviceDebug includeExceptionDetailInFaults="true" /> 31 </behavior> 32 </serviceBehaviors> 33 <endpointBehaviors> 34 <behavior name="webbehavior"> 35 <webHttp /> 36 </behavior> 37 </endpointBehaviors> 38 </behaviors> 39 40 <services> 41 <service name="MyService.HomeService"> 42 <endpoint address="HomeService" binding="webHttpBinding" behaviorConfiguration="webbehavior" 43 contract="MyService.IHomeService"> 44 <identity> 45 <dns value="localhost" /> 46 </identity> 47 </endpoint> 48 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 49 <host> 50 <baseAddresses> 51 <add baseAddress="http://127.0.0.1:1920" /> 52 </baseAddresses> 53 </host> 54 </service> 55 </services> 56 57 </system.serviceModel> 58 59 </configuration>

?

其實(shí)呢?也就是代碼中的WebHttpBehavior類

?

好了,我現(xiàn)在服務(wù)地址也出來(lái)了:http://127.0.0.1:1920 ,然后服務(wù)方法的template也指定了。只要http.sys監(jiān)控到了template

匹配的url,服務(wù)方法就會(huì)被執(zhí)行,比如我現(xiàn)在在瀏覽器里面輸入:http://127.0.0.1:1920/HomeService/Get/1 ?來(lái)測(cè)試下Get操作。

可以看到,get方法成功了,也正確的匹配了我的服務(wù)方法Get。

1 public class HomeService : IHomeService2 {3 public Student Get(string id)4 {5 return new Student() { ID = Convert.ToInt32(id), Name = "hxc", SNS = "001" };6 }7 8 public string Add(Student stu)9 { 10 return "hello"; 11 } 12 }

?

然后我們看看Add方法,我在HttpWebRequest中模擬測(cè)試如下。

?View Code

?

?

好了,大概就說(shuō)這么多了,如果說(shuō)你不嫌麻煩,你可以用WCF Rest,還有就是不要忘了很多的默認(rèn)配置,如果你覺得太繁瑣,

可以用用asp.net web api。

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——第十四天 一起聊聊FaultException

  

  ?我們?cè)谕鎤eb編程的時(shí)候,可能你會(huì)不經(jīng)意的見到一些http500的錯(cuò)誤,我想你應(yīng)該不會(huì)陌生的,原因你應(yīng)該也知道,服務(wù)器異常嘛,

這時(shí)候clr會(huì)把這個(gè)未處理的異常拋給iis并且包裝成http500的錯(cuò)誤返回到客戶端,就比如下面這樣。

?

?

從這張圖中,我故意輸入了xss字符,然后的然后,web程序自爆異常,其實(shí)我想表達(dá)的意思就是,雖然說(shuō)web程序拋異常了,但不代表iis就

掛了,所以iis還是需要給客戶端做出反饋,這就有了http header,和body信息,同樣的道理,wcf的服務(wù)器異常機(jī)制也是這樣。。。service

拋出了異常,不代表console就掛了,console要做的事情就是把這個(gè)異常包裝起來(lái)丟給調(diào)用方,而wcf是怎么包裝的呢???就是用了這篇所

說(shuō)的FaultException。。。

?

一:FaultException

1. faultexception是干什么的?

  剛才我也說(shuō)了,這個(gè)異常就是wcf來(lái)包裝遠(yuǎn)程錯(cuò)誤的,具體的類含義就是表示“SOAP錯(cuò)誤“,如果你夠細(xì)心的話,你還會(huì)發(fā)現(xiàn)到它有個(gè)屬性

叫Serializable,有了它,這個(gè)叼毛就可以序列化到Soap消息中,對(duì)伐???

?

2. 如果挖出faultexception?

  挖出這個(gè)exception的方法有很多,比如我來(lái)造一個(gè)“除以0”的異常,如下所示:

Service:

1 public class HomeService : IHomeService2 {3 public Student Get(string id)4 {5 //這里必然會(huì)拋出異常。。。6 var result = Convert.ToInt32(id) / Convert.ToInt32("0");7 8 return new Student() { ID = Convert.ToInt32(id), Name = "hxc", SNS = "001" };9 } 10 }

Client:

1 public class Program12 {3 static void Main(string[] args)4 {5 using (HomeServiceClient client = new HomeServiceClient())6 {7 try8 {9 var result = client.Get("1"); 10 } 11 catch (Exception ex) 12 { 13 14 } 15 } 16 } 17 }

?

看到了沒(méi)有,雖然wcf的service已經(jīng)拋出異常了,但是還是被clr用Faultexception包裝起來(lái)了,正如你看到了s:Fault節(jié)點(diǎn),仔細(xì)往下看的話,

你還會(huì)看到faultcode,faultstring,detail等等屬性節(jié)點(diǎn),那下面有個(gè)問(wèn)題就來(lái)了,我們平時(shí)在Client端都習(xí)慣這么寫。

1 using (HomeServiceClient client = new HomeServiceClient())2 {3 try4 {5 var result = client.Get("1");6 }7 catch (Exception ex)8 {9 client.Abort(); 10 } 11 }

但是這么寫有個(gè)什么問(wèn)題呢???就是不管客戶端拋出什么異常,我們都習(xí)慣用基類異常Exception捕獲,但是wcf有一點(diǎn)非常惡心的就是,

它的異常信息非常的少,第一眼根本看不出個(gè)一二三,這是因?yàn)樗械漠惓D愣加庙敿?jí)的exception捕獲,自然你能知道的信息就非常少,

這也很正常,如果你想要更詳細(xì)的信息,你是不是應(yīng)該在Client端寫上更具體的異常捕獲類呢???就比如你現(xiàn)在已經(jīng)知道的FaultException

是因?yàn)榉?wù)器的錯(cuò)誤都是由它處理的。

?

如果現(xiàn)在你按照上圖中所coding的那樣,你是不是對(duì)異常信息可以了解的更深,起碼你知道這個(gè)異常的拋出,絕逼是因?yàn)橥ǖ朗钦5?#xff0c;只是

servcie拋出異常了而已。。。那你可能要問(wèn)了,我這話的言外之意就是還有其他異常類也會(huì)捕獲wcf拋出的異常,對(duì)的,比如說(shuō)你的信道出現(xiàn)

故障,這時(shí)候會(huì)拋出一個(gè)“通信異常(CommunicationException)”。

?

三:如何挖出“通信異常”

   ?挖出這個(gè)異常,也是很簡(jiǎn)單的,現(xiàn)在我們需要使用”會(huì)話級(jí)別“的binding,比如說(shuō)nettcpbinding,wshttpbinding,這里的話,我選擇

后者,因?yàn)槭沁@樣的,第一次服務(wù)器拋異常以后,客戶端和服務(wù)器端通信信道就會(huì)關(guān)閉,如果你在客戶端不重新new一個(gè)client,那么這時(shí)候你

第二次再使用client的話,這個(gè)時(shí)候就會(huì)產(chǎn)生“信道故障“,拋出CommunicationException,而當(dāng)你看到CommunicationException的時(shí)候,

你可以非常有自信的說(shuō),老子的wcf根本就沒(méi)有連接到service,而是在client端就被殺死了。。。下面我演示一下。

?

四:自定義FaultException

  現(xiàn)在你應(yīng)該知道了,只要是Servcie的Exception都會(huì)拋出 FaultException,對(duì)吧,而且你用Fiddler觀察的話,也看的出其中的faultcode

和faultstring貌似都不是很詳細(xì),那我就有一個(gè)想法了,既然wcf會(huì)自己給我包裝個(gè)FaultException,那何不我自己就在發(fā)生異常的時(shí)候自己包

裝一個(gè)自定義的FaultException,然后我可以包裝一些我自己想要告訴客戶端的信息,這樣的話是不是靈活性非常的大呢???想法很不錯(cuò),wcf

也是恩準(zhǔn)這么做的,下面我把service的get方法更改如下,在FaultException中自定義Reason,Code,Action等等自定義信息。

1 public class HomeService : IHomeService2 {3 public Student Get(string id)4 {5 try6 {7 //這里必然會(huì)拋出異常。。。8 var result = Convert.ToInt32(id) / Convert.ToInt32("0");9 10 return new Student() { ID = Convert.ToInt32(id), Name = "hxc", SNS = "001" }; 11 } 12 catch (Exception ex) 13 { 14 var reason = new FaultReason("你這個(gè)戰(zhàn)斗力只有五的渣渣。。。 這么簡(jiǎn)單的錯(cuò)誤都出來(lái)了,搞個(gè)雞巴毛"); 15 16 var code = new FaultCode("500"); 17 18 var faultException = new FaultException(reason, code, "是Get這個(gè)王八蛋"); 19 20 throw faultException; 21 } 22 } 23 }

好了,大概就說(shuō)這么多了,我的目的也很簡(jiǎn)單,在寫wcf的client的時(shí)候,盡量做到異常越具體越好,這樣方便我們盡可能快的排查問(wèn)題,因?yàn)?/p>

wcf的異常信息真的太tmd坑爹了!!!減輕痛苦,從小做起~~~

?

隨筆- 197? 文章- 0? 評(píng)論- 3407?

十五天精通WCF——終結(jié)篇 那些你需要注意的坑

    

? ? ? ? ? 終于一路走來(lái),到了本系列的最后一篇了,這一篇也沒(méi)什么好說(shuō)的,整體知識(shí)框架已經(jīng)在前面的系列文章中講完了,wcf的配置眾多,如果

不加一些指定配置,你可能會(huì)遇到一些災(zāi)難性的后果,快來(lái)一睹為快吧。

?

一: 第一個(gè)大坑 【數(shù)據(jù)傳輸量】

   我們使用wcf的目的,就是用來(lái)進(jìn)行分布式的數(shù)據(jù)交互,既然是交互,就一定要進(jìn)行數(shù)據(jù)交換,可能一些新人并沒(méi)有注意到wcf在數(shù)據(jù)傳輸量上

面做了一個(gè)大小限制,比如我現(xiàn)在要傳輸一個(gè)2m的txt給service,會(huì)出現(xiàn)什么情況???

1 static void Main(string[] args)2 {3 try4 {5 var txt = File.ReadAllText("E:\\1.txt");6 7 HomeServiceClient client = new HomeServiceClient();8 9 client.Get(txt); 10 11 int i = 10; 12 13 } 14 catch (Exception ex) 15 { 16 17 throw; 18 } 19 }

?

可是的可是,我們?cè)谕鎍spnet的時(shí)候,再大的傳輸量都見過(guò),但為什么這玩意就拋異常了呢???下面一個(gè)問(wèn)題就來(lái)了,這個(gè)傳輸默認(rèn)值到底

是多少??? 接下來(lái)我們就用ILSpy翻翻看。

?

可以看到,這個(gè)叼毛玩意居然只有 64k。。。沒(méi)錯(cuò),你看到的就是64k,也就說(shuō)明你的傳輸量不能大于64k,否則請(qǐng)求就會(huì)在client端拒絕,

知道了原因,我們現(xiàn)在就可以這么修改config了。

<bindings><netTcpBinding><binding name="MySessionBinding" maxReceivedMessageSize="2147483647"/></netTcpBinding></bindings>

?

有很多資料在配置這個(gè)坑的時(shí)候,也會(huì)使用MaxBufferSize 和?MaxBufferPoolSize,就是用來(lái)增加緩沖區(qū)和緩沖池的大小。

?

一: 第二個(gè)大坑 【并發(fā)量太低】

  說(shuō)起這個(gè)大坑,還得先從一段代碼說(shuō)起,下面是一段對(duì)服務(wù)進(jìn)行2w次并發(fā)調(diào)用,然后我們看看效果。

public class Program1{static void Main(string[] args){try{for (int i = 0; i < 200000; i++){try{Task.Factory.StartNew((obj) =>{try{HomeServiceClient client = new HomeServiceClient();Console.WriteLine("第 {0} 個(gè)請(qǐng)求開始。。。", obj);client.Get("12312");Console.WriteLine("第 {0} 個(gè)請(qǐng)求結(jié)束。。。", obj);}catch (Exception ex){Console.WriteLine(ex.Message);}}, i);}catch (Exception ex){Console.WriteLine(ex.Message);}}Console.Read();}catch (Exception ex){throw;}}}

?

? ? 從上面你可以看到,當(dāng)并發(fā)數(shù)達(dá)到800左右的時(shí)候,servcie端就開始拒絕client端過(guò)來(lái)的請(qǐng)求了,并且之后的1min的時(shí)間里,client端

開始出現(xiàn)超時(shí)異常,這肯定不是我想看到的,?那有人就要說(shuō)了,我的并發(fā)達(dá)到800多很正常啊,如果提高這個(gè)并發(fā)呢???其實(shí)在wcf里面

有一個(gè)叫做ServiceThrottlingElement綁定元素,它就是用來(lái)控制服務(wù)端的并發(fā)數(shù)。

?

這三個(gè)屬性的大概意思,我想大家都看的明白,不過(guò)有點(diǎn)奇怪的是,這三個(gè)屬性的默認(rèn)值 和 ILSpy中看到的不一樣。。。

?

也懶的研究源碼了,不管怎么樣,反正這三個(gè)屬性值都是int類型的,所以我將他們?cè)O(shè)置為int.maxValue就好了。

<system.serviceModel><behaviors ><serviceBehaviors ><behavior name="nettcpBehavior"><serviceMetadata httpGetEnabled="false" /><!--是否在錯(cuò)誤中包含有關(guān)異常的詳細(xì)信息--><serviceDebug includeExceptionDetailInFaults="True" /><serviceThrottling maxConcurrentCalls="2147483647" maxConcurrentInstances="2147483647" maxConcurrentSessions="2147483647" /></behavior></serviceBehaviors></behaviors><bindings><netTcpBinding><binding name="MySessionBinding" /></netTcpBinding></bindings><services><service behaviorConfiguration="nettcpBehavior" name="MyService.HomeService"><endpoint address="net.tcp://127.0.0.1:19200/HomeService" binding="netTcpBinding"bindingConfiguration="MySessionBinding" contract="MyService.IHomeService" /><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /><host><baseAddresses><add baseAddress="http://127.0.0.1:1920" /></baseAddresses></host></service></services></system.serviceModel>

?

然后我們?cè)侔殉绦蚺芷饋?lái)看一看。。。

?

? ? ? 現(xiàn)在你可以發(fā)現(xiàn)并發(fā)早已突破800了,不過(guò)你要記住,如果并發(fā)數(shù)太多,容易造成系統(tǒng)資源耗盡,導(dǎo)致崩潰,這時(shí)候負(fù)載均衡就來(lái)

了,對(duì)吧,wcf需要修改的配置還有很多,正因?yàn)閣cf框架龐大,很多默認(rèn)配置不符合生產(chǎn)需求,所以大家在工作中需要注意,這個(gè)系列

就到此打住了,希望對(duì)你有幫助。

轉(zhuǎn)載于:https://www.cnblogs.com/kingCpp/p/4705931.html

總結(jié)

以上是生活随笔為你收集整理的wcf精通1-15的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

国产黄免费看 | 亚洲一区精品二人人爽久久 | 97超碰中文 | 亚洲婷婷综合色高清在线 | 日韩久久精品一区二区 | 日韩免费久久 | 久久综合操 | 欧美色图视频一区 | 国产精品18久久久久久vr | 青青久草在线 | 4438全国亚洲精品在线观看视频 | 成人不用播放器 | 毛片在线播放网址 | 国产麻豆剧传媒免费观看 | 免费视频 三区 | 精品在线视频播放 | www.国产精品 | av三级av | 麻豆国产精品va在线观看不卡 | 欧美精品一区二区性色 | 久草综合在线观看 | 日韩激情小视频 | 欧美日韩不卡一区二区三区 | 日韩av快播电影网 | 久久国内精品视频 | 国产精品久久一区二区三区, | 国产一区二区免费看 | 波多野结衣在线观看一区二区三区 | 碰天天操天天 | 日本深夜福利视频 | 黄在线| 国产91免费在线观看 | 天天草网站 | av在线免费在线 | 国产粉嫩在线观看 | 91久久国产露脸精品国产闺蜜 | 久久中文字幕视频 | 久久综合之合合综合久久 | 香蕉视频啪啪 | 天天射天| 在线观看亚洲电影 | 久久乐九色婷婷综合色狠狠182 | 国产精品美女久久久 | 成人亚洲免费 | 国产精品丝袜在线 | 久久a国产 | 久久午夜色播影院免费高清 | 国产精品99免费看 | 国产无遮挡猛进猛出免费软件 | 久久视了 | 亚洲一级片在线观看 | av直接看 | 91丨九色丨勾搭 | 婷婷国产视频 | 激情婷婷欧美 | 国产精品久久久久久久久久直播 | 国产一二三四在线视频 | 成人久久 | 狠狠狠狠狠色综合 | 欧美亚洲国产一卡 | 国产精品一区二区久久 | 天堂av免费看 | 国产xxxx做受性欧美88 | 久草在线中文视频 | 天天做天天爱天天综合网 | 免费日韩视| 中文日韩在线视频 | japanesexxxhd奶水| 亚洲精品理论片 | 亚洲人久久久 | 亚洲永久字幕 | 五月天.com | 99精品在线直播 | 亚洲人成在线观看 | 久草在线资源观看 | 国产中文字幕在线看 | 尤物97国产精品久久精品国产 | 天天操伊人 | 夜色在线资源 | 九九热视频在线播放 | 四虎成人精品在永久免费 | 亚洲精品午夜久久久久久久 | 毛片网在线| 97超级碰碰碰视频在线观看 | 成人9ⅰ免费影视网站 | 国产一区电影在线观看 | 成人免费共享视频 | 99久热在线精品视频成人一区 | 国产欧美日韩一区 | 中文字幕一区二区三区四区久久 | 久久久首页 | 免费视频久久久 | 玖玖精品在线 | 欧美激情综合色综合啪啪五月 | 久草在线观看视频免费 | 免费观看9x视频网站在线观看 | 国产精品露脸在线 | 最新超碰| 婷婷综合av | 久久激情久久 | 国内外成人免费在线视频 | 国产免费大片 | 久久九九网站 | 伊人中文网 | 免费看黄20分钟 | 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | 在线观看日本高清mv视频 | 久在线观看视频 | 成人h在线观看 | 久久精品最新 | 99国产一区 | 亚洲成人国产 | 欧美一级免费在线 | 亚洲综合在线观看视频 | 国产自在线 | 精品黄色片 | 亚洲激情在线播放 | 婷婷色中文网 | 欧美午夜理伦三级在线观看 | 天天干天天拍天天操 | 免费亚洲婷婷 | 视频 国产区 | 欧美日韩国产一区二 | 色综合久久88色综合天天免费 | 亚洲一区二区三区在线看 | 久草视频在线看 | 激情综合狠狠 | 99精品在线免费在线观看 | a一片一级| 亚洲不卡在线 | 国内视频一区二区 | 国产高清免费 | 精品国产一区二区三区久久久蜜月 | 视频在线观看国产 | 97精品国自产拍在线观看 | 日韩电影中文,亚洲精品乱码 | 欧美怡红院 | 最新av在线播放 | 91麻豆精品 | 日韩久久精品一区二区三区下载 | 亚洲精品免费观看视频 | 国内丰满少妇猛烈精品播放 | 欧美日韩视频 | 久青草影院 | 国产成人av免费在线观看 | 日韩啪啪小视频 | 在线观看福利网站 | 99热九九这里只有精品10 | 欧美做受高潮 | 91在线入口| 五月婷婷在线视频 | www久久久 | 欧美极品少妇xbxb性爽爽视频 | 一区二区三区不卡在线 | 国产精品国产三级国产aⅴ9色 | 免费av看片 | 欧美9999| 天天操天天色天天射 | 中文字幕色播 | 久久久一本精品99久久精品 | 三级大片网站 | 韩国av在线播放 | 免费一级片观看 | 成人小电影在线看 | 丝袜av一区 | 国产在线a视频 | 亚洲欧美日韩一区二区三区在线观看 | 中文在线a√在线 | 久99视频 | 尤物97国产精品久久精品国产 | 国内一级片在线观看 | 一级片色播影院 | 国内精品国产三级国产aⅴ久 | 免费看的黄色片 | 久久精品艹| 精品久久久999 | 国产色道| 97色婷婷成人综合在线观看 | 娇妻呻吟一区二区三区 | 午夜视频在线观看一区二区三区 | 欧美日韩亚洲一 | 人人射人人插 | 午夜精品久久久 | 久久久久成人免费 | 国产一区二区在线免费播放 | 在线视频91 | 99久久免费看 | 亚洲 欧洲av| 欧美成人在线免费观看 | 欧美精品在线一区二区 | 日韩电影在线观看一区 | 色综合亚洲精品激情狠狠 | 亚洲国产精品成人综合 | 最新国产精品久久精品 | www.777奇米| 国产精品久久久久久69 | 91亚洲网站 | 久久韩国免费视频 | 日b视频国产 | 99久久99久久综合 | 亚洲欧美一区二区三区孕妇写真 | 欧美最猛性xxxx | 亚洲色图av | 中文字幕 国产专区 | 黄色国产精品 | 人人dvd| 色www免费视频 | 一区二区视频在线观看免费 | 97色婷婷成人综合在线观看 | 国产一级不卡毛片 | 免费在线观看毛片网站 | 丰满少妇高潮在线观看 | 日本xxxxav| 国产高清专区 | 欧美日韩在线网站 | 亚洲天天综合 | 亚洲国产剧情 | 日本中文字幕在线看 | 在线免费视频a | 丁香六月在线观看 | 日本在线观看一区二区 | 日韩免费不卡av | 成人黄色在线 | 日韩精品一区二区三区外面 | 日本中文字幕在线看 | 四虎成人精品永久免费av九九 | 国产麻豆精品免费视频 | 国产很黄很色的视频 | 中文字幕黄网 | 免费a级毛片在线看 | 中文伊人 | 欧美网站黄色 | 国产91综合一区在线观看 | 日韩一区精品 | 国产精品一区二区视频 | 91麻豆精品国产自产在线 | 免费观看mv大片高清 | 97麻豆视频 | 天天干婷婷 | 精品夜夜嗨av一区二区三区 | 久久国产乱 | www.色综合.com | 欧洲精品码一区二区三区免费看 | 亚洲区二区 | 99精品视频在线观看视频 | 国产高清av免费在线观看 | 天天爽人人爽夜夜爽 | 国产喷水在线 | 天天av在线播放 | 久久免费黄色 | 激情欧美国产 | 99 精品 在线 | 人人澡人人爽 | 免费开视频 | 中文字幕中文字幕在线中文字幕三区 | 国产精品大全 | 日韩二区三区在线观看 | 午夜久久福利影院 | 久久国产成人午夜av影院宅 | 99国产一区二区三精品乱码 | 五月婷婷.com | 亚洲高清资源 | 91丨九色丨蝌蚪丨对白 | 黄色大全在线观看 | 色婷婷久久| 夜色资源站wwwcom | 99久久久久成人国产免费 | 国产在线欧美日韩 | 午夜精品久久久久久久久久久久久久 | 欧美片一区二区三区 | 人人精品 | 中文在线亚洲 | 91av原创| 国产在线观看免费 | 91av蜜桃 | 九九热中文字幕 | 色在线国产 | 亚洲精品久久久蜜桃直播 | 成人免费看片98欧美 | 国产中文字幕一区二区 | 日本公妇在线观看高清 | 欧美一级片免费 | 亚洲动漫在线观看 | 最近免费中文字幕大全高清10 | 日韩www在线 | 91丨porny丨九色 | 国产福利在线免费观看 | 在线国产一区二区三区 | 欧美一级片播放 | 久久精品视频在线观看免费 | 国产黄在线免费观看 | 制服丝袜一区二区 | 香蕉影院在线观看 | 欧美日韩亚洲第一 | 国产乱视频| 欧美一级片在线播放 | 91福利视频免费观看 | 国产高清久久久 | 91精品视频在线免费观看 | 中文字幕一区二区三区精华液 | 亚洲国产无 | 国产成人av一区二区三区在线观看 | 午夜精品一区二区三区在线视频 | 在线观看中文字幕亚洲 | 天天综合网天天 | 久久婷婷网 | 91在线视频一区 | 99国内精品久久久久久久 | 亚洲在线色 | 日韩中字在线 | 中文在线www | 国产无套精品久久久久久 | 在线观看免费91 | 日产乱码一二三区别免费 | 中文字幕日韩一区二区三区不卡 | 天天射色综合 | 亚洲精品一区二区精华 | 丁香视频| 国产日产在线观看 | 97av精品| 人人爱夜夜操 | 成人中文字幕av | .国产精品成人自产拍在线观看6 | 婷婷久久国产 | 在线观看黄色的网站 | 在线色视频小说 | 免费在线观看91 | 国产第一福利 | 免费黄在线看 | 国产精品欧美久久 | 久久久久区 | 激情在线免费视频 | 亚洲日韩中文字幕在线播放 | 欧美精品免费一区二区 | 国产精品永久在线 | 99视频99 | 99这里有精品 | 五月天综合激情 | 91亚洲国产成人 | 欧美日韩在线观看视频 | 色婷婷综合在线 | 黄色av电影免费观看 | 狠狠干激情 | 免费国产一区二区视频 | 日本在线精品视频 | 九九视频网站 | 久久久亚洲网站 | 五月开心六月伊人色婷婷 | 91麻豆精品国产91久久久无限制版 | 久久久免费精品 | 精品v亚洲v欧美v高清v | 婷婷色伊人 | 色婷婷久久久 | 亚洲精品欧美视频 | 欧美精品一区二区三区四区在线 | 国产字幕av | 国产黄色大片免费看 | 国产免费嫩草影院 | 久久视频在线免费观看 | 五月天激情电影 | 99国产视频在线 | 欧美日韩二三区 | 亚洲精品在线观 | 日本精品视频在线播放 | 久久高清免费观看 | 免费观看成年人视频 | 一本一本久久a久久精品综合 | 国产精品久久电影网 | 国产精品免费在线视频 | 成人资源在线播放 | 欧美黑吊大战白妞欧美 | 天天爽天天碰狠狠添 | 夜夜躁狠狠燥 | 日韩精品一区不卡 | 国产精品观看在线亚洲人成网 | 欧美中文字幕第一页 | 中文字幕在线电影 | 午夜电影一区 | 国产中文字幕网 | 久久久久国产成人精品亚洲午夜 | 国产精品久久久久久久久久久杏吧 | 天天干天天操天天操 | 综合精品在线 | 夜夜躁狠狠躁日日躁视频黑人 | 国产午夜在线观看 | 亚洲精品国产精品乱码不99热 | 免费影视大全推荐 | 久久综合之合合综合久久 | 女人18毛片90分钟 | 91九色porny在线 | 日韩在线视频播放 | 亚洲国产婷婷 | 亚洲人成人天堂h久久 | 免费观看全黄做爰大片国产 | 91在线一区二区 | 色网站免费在线观看 | 在线观看成年人 | 西西人体www444 | 99久久久久成人国产免费 | 中文字幕乱码亚洲精品一区 | 国产成人一区二区啪在线观看 | 97人人澡人人添人人爽超碰 | 国产香蕉视频在线观看 | 日本在线视频一区二区三区 | 在线观看视频精品 | 国产福利91精品张津瑜 | 91久久丝袜国产露脸动漫 | 97超碰资源总站 | 色操插| 国产免费xvideos视频入口 | 黄色免费国产 | 在线观看免费视频 | 久久九精品 | 国产成人综合图片 | 96国产在线 | 激情久久五月 | 成人在线视频免费观看 | 日本中文在线 | 99免在线观看免费视频高清 | 久久在线免费观看视频 | 婷婷色在线播放 | 99电影456麻豆 | 国产不卡免费视频 | 久久久久久久久爱 | 国内精品在线观看视频 | 亚洲午夜在线视频 | 99国产在线视频 | 日韩精品一区二区三区视频播放 | 在线看v片成人 | 久久草av| 日日爽日日操 | 免费三级av | 波多野结衣亚洲一区二区 | 在线免费av网站 | 美女视频国产 | 丁香婷婷色月天 | 国产免费又粗又猛又爽 | 免费av在 | 国产电影一区二区三区四区 | 高清不卡毛片 | 亚洲 在线| 99在线高清视频在线播放 | 成人精品一区二区三区中文字幕 | 久久99国产精品免费网站 | 国产精品二区在线 | 久久99国产综合精品 | 久久久久久久久久久福利 | 久草在线免费资源站 | 国产精久久久 | 中文字幕av免费在线观看 | 国产成人一区二区三区免费看 | 午夜精品久久久久久久久久 | 超碰在线最新网址 | 黄色网址a| 欧美成人播放 | 天海翼一区二区三区免费 | 中文字幕在线高清 | 超碰国产在线观看 | 色综合五月 | 日韩在线观看的 | 免费a视频| 久久9视频| 欧美日韩免费在线观看视频 | 国产一级黄 | 五月激情久久 | 国产一区二区在线视频观看 | 91一区二区三区在线观看 | 精品视频资源站 | 久久在线视频在线 | 福利视频第一页 | 亚洲综合在线观看视频 | 91最新网址在线观看 | 久久国产精品一区二区三区 | 日本在线精品视频 | 成人黄色电影在线观看 | 国产一区二区观看 | 99这里只有精品99 | 成人资源在线观看 | www蜜桃视频| 久久99精品视频 | 精品自拍av | 91香蕉国产在线观看软件 | 中文字幕在线观看第一区 | av在线短片 | 欧美日韩视频在线播放 | 午夜精品一区二区三区视频免费看 | 在线视频 你懂得 | 亚洲资源一区 | 很黄很污的视频网站 | 国产91小视频 | 久草五月| 在线看av网址 | 91免费在线播放 | 婷婷激情综合 | 国产剧情一区二区在线观看 | 日韩在线二区 | 久久久wwww| 国产裸体无遮挡 | 91最新在线观看 | 久久久久久久久综合 | 久久久免费观看视频 | 亚州欧美视频 | 在线免费成人 | 欧美午夜久久 | 精品国产黄色片 | 在线黄色av| 97超碰在线播放 | 91免费高清在线观看 | 日日夜夜狠狠操 | 欧美一区三区四区 | 高清中文字幕 | 欧美国产三区 | 久热国产视频 | 国产成人区 | 欧美午夜剧场 | 亚洲 欧洲 国产 日本 综合 | 在线成人中文字幕 | 一本一本久久a久久精品综合小说 | 夜夜嗨av色一区二区不卡 | 人人精久 | 九月婷婷人人澡人人添人人爽 | 久久免费黄色大片 | 亚洲 欧美 另类人妖 | 日本精品二区 | 久久99精品视频 | 成人久久18免费网站图片 | 久久久久久中文字幕 | 天堂av网址 | 国产精品成人品 | 国产成人福利在线观看 | 日本中文字幕在线 | 色黄视频免费观看 | 黄色av免费 | 黄色毛片在线观看 | 久久久久久福利 | 精品国产伦一区二区三区观看方式 | 欧美小视频在线观看 | 九色精品在线 | 婷婷在线综合 | 成人久久免费 | 精品国产日本 | 亚洲区另类春色综合小说 | 久久免费精品视频 | www成人精品 | 人人爽人人插 | 中国一级片在线播放 | 99精品国产一区二区三区不卡 | 日日草夜夜操 | 久久亚洲影视 | a视频在线看| 亚洲国产免费 | 91精品国自产拍天天拍 | 亚洲国产精久久久久久久 | 久久r精品 | 精品国产乱子伦一区二区 | 黄色软件网站在线观看 | 五月丁香| 最近最新中文字幕视频 | 国产精品久久久久久久久久久久久久 | 精品一区二区在线免费观看 | 国产高清精品在线 | 中文 一区二区 | 精品人人爽 | av高清一区二区三区 | 国内精品久久久久久中文字幕 | 麻豆视频91| 高清不卡一区二区三区 | 精品久久久免费视频 | 免费看的黄网站 | 国产精品自产拍在线观看蜜 | 日韩动漫免费观看高清完整版在线观看 | 日韩免费三区 | 色五月情| 国产精品一区二区三区在线 | 久久久国产精品人人片99精片欧美一 | 日韩黄在线观看 | 国产很黄很色的视频 | 999久久久久久 | 日韩在线观看不卡 | 18av在线视频| 黄网站大全 | 日韩av在线一区二区 | 国产一在线精品一区在线观看 | 中文字幕欧美激情 | 91精品国产99久久久久 | 99久久精品久久久久久清纯 | 久久综合精品一区 | 日日夜夜精品免费观看 | 欧美成人精品在线 | 美女视频一区二区 | 久久在线免费 | 日韩精品不卡在线 | 这里有精品在线视频 | 中国一区二区视频 | 国产精品久久电影观看 | 蜜臀aⅴ国产精品久久久国产 | 亚洲综合欧美激情 | 成人黄色大片 | 777久久久| 国内久久视频 | 国产精品99久久久久久久久久久久 | 麻豆免费视频观看 | 日韩欧美国产视频 | 国产黄色网 | 久久精品亚洲精品国产欧美 | 日本精品久久 | 五月激情综合婷婷 | 成人午夜精品福利免费 | 天天综合网天天 | 亚洲男男gaygay无套同网址 | 久久av中文字幕片 | 婷婷丁香国产 | 久99久中文字幕在线 | 国产黄在线播放 | 亚洲码国产日韩欧美高潮在线播放 | 国产一区二区高清视频 | 久精品视频免费观看2 | 欧美色精品天天在线观看视频 | 久久人人爽人人爽人人片av软件 | www免费看| 国产美女在线精品免费观看 | 国产成人一区在线 | 成人av视屏 | 少妇高潮流白浆在线观看 | 成人一级电影在线观看 | 高清一区二区三区 | 亚洲aⅴ免费在线观看 | 在线观看成人国产 | 最新av网址在线 | 亚洲人成网站精品片在线观看 | 国产精品99免费看 | 天天综合网在线观看 | 久久精品美女 | 欧美精品日韩 | 操天天操 | 久久精品91久久久久久再现 | 玖玖在线看 | 精品a视频 | 日本久久免费视频 | 亚洲精品乱码久久久久久蜜桃欧美 | 久久99国产精品久久99 | 国产成人精品综合 | 亚洲伦理中文字幕 | 久久国产综合视频 | 精品一区二区三区久久久 | 99九九免费视频 | 精品久久久久久国产偷窥 | 天天色综合三 | 日韩av视屏 | 在线日韩 | 日本成人中文字幕在线观看 | 久久免费播放视频 | 在线免费观看视频一区二区三区 | 中文字幕在线视频国产 | 亚洲欧洲国产视频 | 91精品推荐 | a级国产乱理伦片在线播放 久久久久国产精品一区 | 黄色av免费 | 免费观看av | www.天天射.com| 天天色天天上天天操 | 国产做爰视频 | 久久99国产精品久久99 | 五月婷色 | 国产九九九视频 | 婷婷激情5月天 | 又黄又爽的视频在线观看网站 | 91探花视频 | 久久国产欧美日韩 | 国产一级在线免费观看 | 91av在线视频免费观看 | 日本中文一区二区 | 91视频一8mav | 国产精品手机播放 | 98涩涩国产露脸精品国产网 | 国产在线一卡 | 国产精品福利一区 | 久久污视频 | 天天干夜夜爽 | 久久99国产视频 | 怡红院av久久久久久久 | 青青草久草在线 | 久草在线看片 | 999久久久精品视频 日韩高清www | 99精品偷拍视频一区二区三区 | 国产精品成人久久久 | 天天干,天天射,天天操,天天摸 | 玖玖玖精品 | 99超碰在线播放 | 免费看的黄色的网站 | 亚洲精品乱码久久久久久蜜桃动漫 | 91九色成人蝌蚪首页 | 国产亚洲精品精品精品 | 国内揄拍国内精品 | av一级免费 | 成年人黄色免费视频 | 精品福利视频在线 | 免费在线观看一区二区三区 | a一片一级 | 最近能播放的中文字幕 | 国产精品久久久久久久久久久久 | 99久久99久久精品国产片果冰 | 激情伊人五月天 | 久久五月婷婷丁香社区 | 久草综合视频 | 四虎小视频 | 国产精品视频内 | 国产精品麻豆99久久久久久 | 久久久精品福利视频 | 在线观看免费福利 | 99国产视频| 亚洲色图色 | 美女网站久久 | 97天天干| 国产在线黄色 | 久久电影网站中文字幕 | 色黄久久久久久 | 欧美日韩啪啪 | 色偷偷88888欧美精品久久 | 日韩.com | 日本中文字幕在线播放 | 四虎永久国产精品 | 日本护士撒尿xxxx18 | 久久久久久久久久久久影院 | 国产在线视频一区 | 成人资源在线播放 | 96视频免费在线观看 | 日韩欧美视频在线免费观看 | 少妇bbbb揉bbbb日本 | 国产精品久久久久毛片大屁完整版 | a在线免费| 久久一区二区三区四区 | 99久免费精品视频在线观看 | 亚洲国产最新 | 国产夫妻性生活自拍 | 九九九在线观看视频 | 91精品久久久久久久久久入口 | 中字幕视频在线永久在线观看免费 | 久草在线免费新视频 | 久久福利国产 | 久久最新 | 日韩久久片 | 天天天天射 | 成年人视频在线免费 | av高清网站在线观看 | 亚洲第一伊人 | 国际av在线| 欧美性高跟鞋xxxxhd | 三上悠亚一区二区在线观看 | 韩国一区在线 | 日韩区视频 | av片子在线观看 | 日本最新一区二区三区 | 国产免费又爽又刺激在线观看 | 久久精品日韩 | 中文字幕一区二区三区在线观看 | 99精品一级欧美片免费播放 | 在线a视频 | 久久久久女人精品毛片 | 人人涩 | 九色福利视频 | 手机在线免费av | 天天色天 | 永久免费的av电影 | 亚洲九九影院 | www免费视频com━ | 精品一区二区久久久久久久网站 | 国产精品小视频网站 | av在线免费网 | 日本论理电影 | 国产亚洲精品成人av久久影院 | 婷婷激情影院 | 天堂av在线网 | 欧美激情另类文学 | 热热热热热色 | 日韩高清免费在线 | 精品人妖videos欧美人妖 | 国产成人精品电影久久久 | 欧美巨大荫蒂茸毛毛人妖 | 最新的av网站 | 国产成人精品国内自产拍免费看 | 丁香网五月天 | 成人免费观看网站 | 日韩精品一区二区在线观看 | 豆豆色资源网xfplay | 久久人人爽人人爽人人片 | 亚洲专区 国产精品 | 免费看三级黄色片 | 天天干天天拍天天操天天拍 | 成年人免费在线 | 亚洲激情av | 国产黄色免费电影 | 人人看看人人 | 久久精品三 | 亚洲精品久久久久久久不卡四虎 | 久久一区二 | 人人草在线观看 | 午夜精品久久久久久久久久久久 | 91女人18片女毛片60分钟 | 久草网在线视频 | 香蕉视频在线播放 | 91色亚洲 | 97精产国品一二三产区在线 | 午夜色大片在线观看 | 日本最新一区二区三区 | 日韩av网页| 美女久久久久久久久久 | 亚洲视频免费在线 | 五月婷激情 | 欧美永久视频 | 少妇按摩av | 日韩在线免费电影 | 天天av在线播放 | 啪嗒啪嗒免费观看完整版 | 国产精品免费高清 | 亚洲在线免费视频 | 日本黄色免费电影网站 | 中文字幕日韩高清 | 99久久精品免费看 | 91精品国产乱码在线观看 | 日韩免费高清在线 | 91精品婷婷国产综合久久蝌蚪 | 久久人91精品久久久久久不卡 | 国产专区一 | 中文字幕色站 | 日韩成片 | 99视频免费观看 | 亚洲专区在线播放 | 亚洲激情国产精品 | 国产999精品久久久久久绿帽 | 国产最新视频在线观看 | 久久人人97超碰精品888 | av免费在线免费观看 | 在线观看黄色小视频 | 国内精品中文字幕 | 国产精品久久久久久久久软件 | 国产99久久精品一区二区永久免费 | 97成人精品视频在线播放 | 国产成人精品免费在线观看 | 国产一级二级三级在线观看 | av一区在线播放 | av电影亚洲| 亚洲成人精品在线观看 | 久久综合电影 | 全久久久久久久久久久电影 | 亚洲精品综合在线 | 91麻豆精品国产自产在线 | 三级av在线播放 | 精品久久网站 | 黄色成人小视频 | 国产一区视频免费在线观看 | 色网站在线 | 日韩专区在线播放 | 中文字幕免费久久 | 亚洲欧美国产精品 | 色综合天天视频在线观看 | 99久久婷婷国产综合精品 | 99视频偷窥在线精品国自产拍 | 午夜视频久久久 | 亚洲二级片| 亚洲国产精彩中文乱码av | 婷婷av网 | 久久福利精品 | 中文字幕欧美日韩va免费视频 | 国产小视频国产精品 | 久久黄色小说 | 国产精品久久久久亚洲影视 | www.狠狠操 | 波多野结衣一区三区 | 欧美日韩中文国产一区发布 | 精品视频成人 | 日韩久久精品一区二区 | 毛片二区 | 亚洲高清视频在线观看免费 | 黄色录像av | 久久精品三 | 婷婷六月久久 | 久久伊人精品一区二区三区 | 久青草视频在线观看 | 91九色视频网站 | 成年人免费在线观看网站 | 国产日韩在线视频 | 亚洲国产日韩一区 | 玖玖999| 在线观看深夜福利 | 狠狠操精品 | 国产在线91在线电影 | 国产成人精品综合久久久久99 | 夜夜干天天操 | 456免费视频 | 久久人人97超碰com | 欧美日本中文字幕 | 91久久精品一区二区二区 | 亚洲免费一级电影 | 91毛片在线观看 | 久久国产香蕉视频 | 久久影院精品 | 欧美久久久久久久久久久 | www.888.av| 免费观看www视频 | 久久久久国产一区二区三区 | av黄色免费在线观看 | 天堂视频一区 | 中文字幕美女免费在线 | 永久免费看av | 91在线免费看片 | 欧美性色黄大片在线观看 | 中文字幕在线观看视频网站 | 日本资源中文字幕在线 | 日韩成人免费在线 | 天天碰天天操 | 精品一区二区在线看 | 日韩精品视频免费 | 波多野结衣理论片 | 国产精品99久久久久久大便 | 精品九九九九 | 免费美女久久99 | 五月天激情视频在线观看 | 国产一区二区三区四区大秀 | 日韩久久影院 | 美女精品 | 国产福利一区二区在线 | 免费进去里的视频 | 精品在线二区 | 亚洲 欧美 另类人妖 | 久久se视频 | 中文字幕在线视频国产 | 国产一卡二卡在线 | 久久这里只有精品首页 | 久久亚洲欧美日韩精品专区 | 亚洲精品综合一区二区 | 91禁看片 | 最新的av网站 | 日日夜夜精品网站 | 中文国产成人精品久久一 | 毛片随便看 | 日韩美av在线 | 久久久久国产精品午夜一区 | 我要色综合天天 | 狠狠色噜噜狠狠狠合久 | 中文字幕在| 国产精品精品国产色婷婷 | 久视频在线 | 久久久久亚洲精品成人网小说 | 国产精品九色 | 人人狠狠综合久久亚洲 | 国产一区二区在线播放 | 国产一区二区手机在线观看 | 亚洲精品国产精品国 | 中文字幕一区二区三区四区在线视频 | 亚洲欧美国产视频 | 狠狠色丁香久久婷婷综合丁香 | 日本黄色大片儿 | 麻豆一精品传二传媒短视频 | 天天爽网站 | 最近中文字幕在线播放 | 99日韩精品 | 久久久香蕉视频 | 91成版人在线观看入口 | 中文字幕在线观看免费观看 | 在线国产日本 | 西西人体www444 | 色99网| 欧美精品被 | 久草97| 在线观看黄污 | 国产一区二区观看 | 日韩一区二区三区高清在线观看 | 狠狠综合久久av | 国产精品美女免费 | 玖玖视频免费在线 | www.亚洲黄色| 成片免费观看视频 | 波多野结衣电影一区二区三区 | 狠狠精品| 欧美日韩国产区 | www.久艹| av在线播放一区二区三区 | 午夜av色 | 最新高清无码专区 | 国产精久久久久久妇女av | 国产欧美综合在线观看 | 国产九九在线 | 国产精品手机看片 | av中文字幕在线观看网站 | 成人精品在线 | 久久久国产一区 | 在线亚洲播放 | 香蕉色综合 | 69av在线播放 | 色视频网站免费观看 | 狠狠狠色狠狠色综合 | 黄色av高清 | av色一区 | 国产成人久久精品77777综合 | 中文亚洲欧美日韩 | 国产中文字幕一区二区三区 | 三级在线视频观看 |