wcf精通1-15
十五天精通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最基本的概念我們放在后面慢慢分析,下面我們來看看神奇的3個(gè)binding如何KO我們實(shí)際場(chǎng)景中的80%的業(yè)務(wù)場(chǎng)景。
?
一:basicHttpBinding
作為入門第一篇,也就不深入談?wù)刡asic中的信道棧中那些啥東西了,你只需要知道有ABC三個(gè)要素,注意不是姨媽巾哦,如果需要詳細(xì)了解,可以觀賞我以前的系列。在
這里我就不多說了,太簡(jiǎn)單的東西沒意思,先看個(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. 然后通過 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ù)端全部開啟完畢,接下來我們通過“添加服務(wù)引用”,來添加對(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)過它的手,這樣任何一方出了問題,只要
它在就沒問題了。同樣我們把tcp改成msmq也是非常簡(jiǎn)單的,不過要注意,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,配置起來何其簡(jiǎn)單,底層的各種通訊協(xié)議貌似對(duì)我來說都是透明的,其實(shí)呢???wcf在底層做了何其多的事情,而我卻沒有挖掘。。。
這對(duì)碼農(nóng)里說也是一種悲哀啊。。。出了問題就只能禱告上天。。。下一篇我會(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)直就是搞死了人。。。好了,這篇我們來看看如何最小化配置。
?
一:精簡(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>?
通過上面的代碼,你應(yīng)該知道在system.servicemodel下的所有節(jié)點(diǎn)都是wcf專屬的節(jié)點(diǎn),所有的節(jié)點(diǎn)數(shù)據(jù)都會(huì)被開啟servicehost這個(gè)監(jiān)聽器時(shí)捕獲到,下面我可以
通過servicehost這個(gè)監(jiān)聽器的源碼下面找找相關(guān)的讀取config節(jié)點(diǎn)的代碼。
?
?
通過上面的截圖,你是不是有一種感覺,就是service的底層也是通過代碼動(dòng)態(tài)的讀取config下面的節(jié)點(diǎn)來獲取數(shù)據(jù),那就意味著我可以直接將代碼寫入到code中,
對(duì)吧,這樣我就可以把我認(rèn)為該配置的東西配置起來,不該配置的東西全部放到代碼里面去,這樣我的靈活性是不是非常的強(qiáng)大。。。。爽吧,說干就干。。。
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 }?
有人就要說了,地址的話肯定不能是寫死的,必須變活,簡(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ì)吧。。。好了,說完服
務(wù)端,接下來我們看看client端如何避免。
?
二:精簡(jiǎn)client的config配置
就像上一節(jié)那樣,如果我用“服務(wù)引用”的話,vs會(huì)偷偷的用svcutil.exe來給我們生成一個(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類是通過ChannelFactory<TChannel>類來完成助攻的,那話說回來了,既然底層用了ChannelFactory<TChannel>,
那何不我在代碼里面就用ChannelFactory<TChannel>不是更好嗎???這樣config也省了,對(duì)吧,說干就干啦。。。
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ù),什么價(jià)格,這時(shí)候可能姑娘會(huì)跟你口述一些服務(wù)或者提供一份服務(wù)清單,這樣的話大
家就可以做到童嫂無欺,這樣一份活生生的例子,在wcf中同樣是一個(gè)道理,只有client了解service能提供哪些功能,client才可以根據(jù)server提供的功能進(jìn)行
消費(fèi),那問題來了,service怎么把功能提供給client進(jìn)行選擇呢???這個(gè)就是我這一篇要聊的wsdl(web service description language)。。。
?
一:wsdl
現(xiàn)在你已經(jīng)知道了,wsdl就是server提供給client的清單,那下面問題就來了。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通過svcutil訪問這個(gè)地址的時(shí)候,就拿到了server能提供的功能清單,然后client就可以根據(jù)這些功能生成一
個(gè)代理文件,然后的然后,就是你懂得,各種啪啪啪,XXXClient。
?
二:眼見為實(shí)
1.見證wsdl
要想看見wsdl,你只需要通過http://localhost:19200打開服務(wù)地址、如下圖:
?
然后點(diǎn)擊:http://localhost:19200/?singleWsdl
?
現(xiàn)在你看到的就是server功能清單,太tmd的重量級(jí)了,已經(jīng)完完全全果體在世人前了,下一小節(jié)我們?cè)僭敿?xì)的分析下。
?
2. 見證client端的XXXclient
剛才我也說了,當(dāng)你用vs做“服務(wù)引用”的時(shí)候,svcutil會(huì)根據(jù)http://localhost:19200/mex的地址來查看wsdl,然后生成代理,下面我們具體來看一下。
?
?
點(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)你看到下面的截圖后,我想你也能猜的出來,portType就是契約(IHomeService),operation就是契約方法(Update),不過有點(diǎn)意思的是,在operation
下面你看到了一個(gè)input,一個(gè)output,這個(gè)就是所謂的 ”輸入消息“,”輸出消息”,那是什么意思呢??? 也就是說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的底層就是通過這個(gè)地址來找到對(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ù)地址等等。。。然后就沒什么好說的了。
?
?
十五天精通WCF——第四天 你一定要明白的通信單元Message
轉(zhuǎn)眼你已經(jīng)學(xué)了三天的wcf了,是不是很好奇wcf在傳輸層上面到底傳遞的是個(gè)什么鳥毛東西呢???應(yīng)該有人知道是soap,那soap這叼毛長(zhǎng)得是什么
樣呢?這一篇我們來揭開答案。。。
?
一:soap到底長(zhǎng)成什么樣子
為了能看清soap長(zhǎng)的啥樣,我可以用強(qiáng)大的Fiddler來監(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,我知道這叼毛翻譯過來就是“信封”,所以就有了”封頭“
和”封體”,就是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ù),最后我們來看一下UpdateResponse中
的<UpdateResult xmlns:a="http://schemas.datacontract.org/2004/07/MyService,不知道你是否還記得它就是WSDL中關(guān)于Student的XSD結(jié)
構(gòu),看下圖:
?
好了,wcf中的soap結(jié)構(gòu)我們也大概了解了一下,不知道有沒有引發(fā)你對(duì)soap更深入的思考呢???
?
二:對(duì)soap的更深入思考
通過fiddler觀察,你應(yīng)該也明白了,不管是客戶端還是服務(wù)端,wcf的高層封裝都是僅僅拿出了Envelope中的body節(jié)點(diǎn),而其他節(jié)點(diǎn)對(duì)我們來說好像并
沒有什么卵用,比如我說的Header節(jié)點(diǎn),這么說來,Header是不是有點(diǎn)浪費(fèi)呢???那下面有一個(gè)問題來了,wcf在底層用什么來構(gòu)造消息的呢???下面
我們大概找下client端的源碼。。。
?
通過上面的圖,你現(xiàn)在應(yīng)該也知道了在.net中其實(shí)tmd的就是message構(gòu)造的,所以我想告訴你的是:既然wcf在底層也是用message來構(gòu)造的,何不我自己
就來構(gòu)造message消息呢???豈不美哉???這樣我就可以隨意操作message,對(duì)吧。。。不然wcf這個(gè)高層封裝的叼毛,對(duì)我來說就是一種束縛。。。因
為我已經(jīng)知道了service公布的wsdl,所以我可以輕松構(gòu)造message。。。
?
三:用message來調(diào)用Server端
? 廢話不多說,構(gòu)造message你一定要知道下圖中的三點(diǎn):(input這個(gè)Action,契約方式 和 服務(wù)地址)。
?
好了,下面我先來構(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();接下來,我們跑起來看一下,效果咋樣。。。
?
看沒看到,這個(gè)就是我手工構(gòu)造的Message,是不是太帥了。。。哈哈,太帥的應(yīng)該在后面,剛才也說了,既然大家玩的都是Message,而你這個(gè)幾把wcf卻僅僅把
我的message.body拿出來了,那干脆我直接在契約方法中加message豈不是更好么???自由操作Message還有個(gè)什么好處呢??當(dāng)然啦,我可以在Message的
Header中加一些參數(shù)token,client的ip地址,client的身份,client的時(shí)間等等這些統(tǒng)計(jì)信息,對(duì)吧。。。這樣才是最帥的,好了,說干就干,我們修改下server端的
契約方法,只用來接受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)的集合",就
比如說一個(gè)普普通通的服務(wù),它就公布了一個(gè)服務(wù)端點(diǎn),一個(gè)元數(shù)據(jù)端點(diǎn),對(duì)吧。。。
仔細(xì)一想,這個(gè)問題就好玩了,既然一個(gè)service可以公布多個(gè)endpoint,而且我還知道wcf中有很多的binding,這些binding對(duì)應(yīng)著很多的傳輸方式,那是不是
說我一個(gè)service可以用多種協(xié)議方法對(duì)外公布,比如說同時(shí)以nettcp,basic,msmqbinding,udp等方式公布,對(duì)吧,那這樣的話是不是超級(jí)好玩,如果對(duì)方
是非.net程序,那就可以調(diào)用我的basic,如果對(duì)方是.net程序,那是不是可以調(diào)用我的nettcp,對(duì)不對(duì)。。。當(dāng)然啦,wcf無所不能,這是一個(gè)史上無比強(qiáng)大的牛
逼框架,牛逼的要死,已經(jīng)逼得程序員只需隨便改幾個(gè)配置就能達(dá)到完全不一樣的效果。。。下面我同時(shí)用nettcp和basic的方式來同時(shí)公布服務(wù),好了,現(xiàn)在我
們就來見證奇跡吧。。。
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 }?
通過上面的代碼,是不是已經(jīng)發(fā)現(xiàn),我在client端,既可以用basic的方式調(diào)用,又可以用nettcp的方式調(diào)用,這個(gè)技巧是不是感覺wcf無比強(qiáng)大呢???
?
二:Host寄宿多個(gè)Service
我們知道wcf的寄宿方式有很多種,有iis,有windowservice,還有簡(jiǎn)單方便的console方式,而默認(rèn)情況下,我們最通常的方法都是一個(gè)service,一個(gè)寄宿,
而其實(shí)呢??? 其實(shí)一個(gè)寄宿host可以承載多個(gè)service,看起來是不是很好玩,如果說你有10個(gè)servcie,現(xiàn)在你只需要用一個(gè)console host就能寄宿起來,廢
話不多說,我演示一下給你看就好了。
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 }有沒有看到,現(xiàn)在兩個(gè)服務(wù)都開啟了,這種方式看起來是不是很爽呀,否則的話,你需要開啟兩個(gè)Host,這樣的話,我的手續(xù)就精簡(jiǎn)了。。。對(duì)吧。。
?
三: Tcp中的端口共享
這玩意聽起來大家都懂,端口共享嘛,不就是兩個(gè)程序共享一個(gè)端口,對(duì)吧,在通常情況下,我們肯定會(huì)認(rèn)為這無法做到,其實(shí)呢?在Wcf中我們還是可以玩
的,也就是一個(gè)PortSharingEnabled的事!!!如果說端口可以共享的話,那我們的service是不是就可以少開辟幾個(gè)端口呢?同樣這也方便我們進(jìn)行service的管
理,下面我給大家繼續(xù)演示一下。。。很好玩的,么么噠
?
可以看到,我的兩個(gè)host都是用1920的端口,并且現(xiàn)在我真的開啟起來啦。。。。好了,三種技巧都說到了,我想你在現(xiàn)實(shí)的wcf開發(fā)中,或多或少的都能接
觸的到,希望對(duì)你有用~~~~
?
隨筆- 197? 文章- 0? 評(píng)論- 3407?十五天精通WCF——第六天 你必須要了解的3種通信模式
? ? ?wcf已經(jīng)說到第六天了,居然還沒有說到這玩意有幾種通信模式,慚愧慚愧,不過很簡(jiǎn)單啦,單向,請(qǐng)求-響應(yīng),雙工模式,其中的第二種“請(qǐng)求-響應(yīng)“
模式,這個(gè)大家不用動(dòng)腦子都清楚,這一篇我大概來分析下。
?
一:“請(qǐng)求-響應(yīng)“模式
? 如果你看了我上一篇的博文,你應(yīng)該非常清楚這種類似“本地調(diào)用”的方式,wcf同樣也分為“同步”和“異步”兩種,不過不管是異步還是同步,最終都逃
不過是“請(qǐng)求-響應(yīng)”這個(gè)事實(shí),對(duì)吧。
?
1: 同步方式
這種方式我想沒什么好說的,前面幾篇我已經(jīng)說的非常清楚了,具體使用方法可以參考我的前面幾篇文章。。。謝啦~~~~
?
2: 異步方式
通常我們都有這樣的一個(gè)思維,遇到耗時(shí)的東西第一反應(yīng)就想到了多線程,畢竟多線程也是一種負(fù)載均衡,在wcf這種”請(qǐng)求-響應(yīng)“模式,同樣也支持異
步,很神奇吧,而且神奇到可以在“服務(wù)引用“界面上做到一鍵生成,什么???你不信!!!!不信你看。。。
?
然后我非常好奇的看下XXXClient給我們生成的是個(gè)什么代碼。。。
?
通過client端的proxy代碼,你可以清楚的看到,這雞巴WCF真的不容易,給我們生成了兩種“異步模式”,第一種是最古老的beginXXX,endXXX模式,
還有一種是被Jeffrey Richter 嚴(yán)重鄙視的“事件異步模式”。。。沒什么好說的,截圖一下給大家看看。
?
二:“單向“模式
很多時(shí)候,我們或許都有這樣的需求,比如說訂單提交成功的時(shí)候,我需要給客戶發(fā)送郵件,但是你想想,我發(fā)送郵件這個(gè)任務(wù)只是我訂單流程的
一個(gè)“額外任務(wù)“,也就是說,它的失敗不應(yīng)該會(huì)阻止我的訂單流程,并且它的邏輯時(shí)間不應(yīng)該會(huì)阻礙我的下單總時(shí)間,對(duì)吧。。。這樣的話,我的訂單時(shí)
間才會(huì)最小化,為了達(dá)到不影響下單總時(shí)間的效果,我的想法就是,client端直接把消息丟給信道就好了,然后不管server端有沒有真的接收到,處理的
慢不慢,過的好不好,等等,非常開心的是,這些對(duì)wcf來說真的是小菜一碟,只需要一個(gè)輕輕松松的”IsOneWay=true“屬性就可以了。。。牛逼的要
死。。。還有就是因?yàn)槭菃蜗虻?#xff0c;所以契約方法就沒有存在返回值的必要了,我說的對(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
通過下面的圖,我想你看的很清楚了,你再也沒有找到我們熟悉的“output”這個(gè)message,這就說明貌似真的是單向的了,因?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 }
正如我在圖中說的那樣,非常奇怪,我的IsOneWay模式,竟然在http模式下行不通,但是你要記住,http模式天生就是“請(qǐng)求-響應(yīng)”模式,它完全做不了
單向模式,說明白一點(diǎn)就是:“wcf發(fā)現(xiàn)你的bingding不支持單向“的時(shí)候,它并不會(huì)報(bào)錯(cuò),還是用自己天生的”請(qǐng)求-相應(yīng)“模式來模擬”單向通信“,這就是你
看到的非常奇怪的Http 202這個(gè)http狀態(tài)碼,很多人包括我,都不知道http202 是幾個(gè)意思,沒關(guān)系,我們百科一下就好了。。。下面框框的里面的字,
已經(jīng)說的非常清楚了,感謝感謝。。。
?
三:“雙向“ 模式
這個(gè)通訊其實(shí)沒什么好講的,也只有tcp模式才會(huì)天生支持,而http模式天生就不支持,就像上面一樣,如果非要用http來支持“雙向通訊“,那又是在
坑"wcf"他爹,這樣就會(huì)逼著他爹在底層再建立一個(gè)“請(qǐng)求-響應(yīng)“模式來支持所謂的”雙向通訊“,而且”雙向通訊“這個(gè)玩意還不如用兩個(gè)單向的”請(qǐng)求-響應(yīng)”模
式或者兩個(gè)“單向模式”來支持,而且兩個(gè)”請(qǐng)求-響應(yīng)“模式比”雙向通訊“有更大的靈活性,反正我是對(duì)它不感冒,了解一下即可,如果大家比較感興趣,可以
在wcf官網(wǎng)上看一下:https://msdn.microsoft.com/zh-cn/library/ms735119.aspx。
? 好了,就說到這里,洗洗睡了,晚安~~~~
?
隨筆- 197? 文章- 0? 評(píng)論- 3407?十五天精通WCF——第七天 Close和Abort到底該怎么用才對(duì)得起觀眾
?
一:文起緣由
? ? ? ? ? 寫這一篇的目的源自于最近看同事在寫wcf的時(shí)候,用特別感覺繁瑣而且云里霧里的嵌套try catch來防止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 }看完上面的代碼,不知道你是否有什么感想?而且我還問了同事,為什么try catch要寫成這樣,同事說是根據(jù)什么書上來的什么最佳實(shí)踐,這話一說,我也不敢輕易
懷疑了,只能翻翻源代碼看看這話是否有道理,首先我來說說對(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)致我這樣的后來人犯迷糊,對(duì)吧。。。反正我就是頭暈,
簡(jiǎn)直就是弄糊涂到什么時(shí)候該用close,什么時(shí)候該用abort。。。
二:探索原理
為了弄明白到底可不可以用一個(gè)try catch來替代之,下面我們一起研究一下。
?
1. ?從代碼注釋角度甄別
從類庫的注釋中,可以比較有意思的看出,abort方法僅僅比close多一個(gè)“立即”,再無其他,有意思,不過這對(duì)我來說并沒有什么卵用,因?yàn)檫@個(gè)注釋太
籠統(tǒng)了,為了讓自己更加徹底的明白,只能來翻看下close和abort的源代碼。
?
2. ?從源碼角度甄別
為了方便讓ILSpy調(diào)試Client代碼,現(xiàn)在我決定用ChannelFactory來代替,如下圖:
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è)問題:
?
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活生生的把異常給吞了。。。骨頭都不給吐出來。。。真tmd的神奇到家了,想想也有道理,因?yàn)橹挥?/p>
這樣,我們上層的代碼在catch中才不會(huì)二次拋出“未處理異常”了,對(duì)吧,再轉(zhuǎn)念看一下Close方法。
?
從上面圖中可以看到,Close在遇到Faulted之后調(diào)用Abort方法,如果說Abort方法調(diào)用失敗,Close方法會(huì)再次判斷狀態(tài),如果還是Faulted的話,就會(huì)向上拋出
異常。。。這就是為什么Abort不會(huì)拋異常,Close會(huì)的原因,所以Close千萬不要放在Catch塊中。
?
4. Abort代碼大概都干了些什么
這個(gè)問題問的好,要能完美解決的話,我們看下代碼,如下圖,從圖中可以看到,Abort的大目的就是用來關(guān)閉信道,具體會(huì)經(jīng)過closeing,abort和closed這
三個(gè)方法,同時(shí),這三個(gè)事件也會(huì)被老祖宗ICommunicationObject監(jiān)聽的到。
?
?
好了,最后我們關(guān)注的一個(gè)問題在于下面這條語句是否應(yīng)該放在Try塊中???
1 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:1920/HomeServie"));很簡(jiǎn)單,我們簡(jiǎn)要的看一下代碼,看里面是否會(huì)有“異常”拋出即可。。。。
?
可以看到,在new的過程中可能,或許會(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 }?
好了,綜合我上面所說的一切,我個(gè)人覺得最好的方式應(yīng)該是上面這樣,夜深了,睡覺了,晚安。
?
隨筆- 197? 文章- 0? 評(píng)論- 3407?十五天精通WCF——第八天 對(duì)“綁定”的最后一點(diǎn)理解
轉(zhuǎn)眼已經(jīng)中斷10幾天沒有寫博客了,也不是工作太忙,正好碰到了端午節(jié),然后最近看天津臺(tái)的愛情保衛(wèi)戰(zhàn)入迷了。。。太好看了,一直都是回味無窮。。。而且
涂磊老師話說的真是tmd的經(jīng)典,然后就這樣耽擱了,好了,話不多說,這篇我們看看binding中最后一點(diǎn)需要知道的東西。
?
一:信道棧
我在之前的文章中多次提到信道棧,不知道大家對(duì)它的概念是否有了解,其實(shí)想想也還是蠻簡(jiǎn)單的,既然是棧,那么這個(gè)棧肯定就不止一個(gè)元素了,對(duì)吧,第二個(gè)
的話,既然是棧,那么肯定就遵循FILO的原則,可能你會(huì)說,這個(gè)還是蠻抽象的,能給個(gè)具體的例子么???恭喜你,wcf中還真有一個(gè)方法CreateBindingElements,
下面我們具體看看。。。
?
1. ?簡(jiǎn)單看看各種binding的棧中都有些什么
看到上面的監(jiān)控窗口,是不是有點(diǎn)意思,在BasicHttpBinding的信道棧中有兩個(gè)元素,分別是HttpTransportBindingElement和TextMessageEncodingBindingEl
ement,通過名字也能很容易的判斷出來,一個(gè)是“http傳輸協(xié)議”,一個(gè)是“文本消息編碼協(xié)議”,然后再看看復(fù)雜一點(diǎn)的WSHttpBinding,你會(huì)發(fā)現(xiàn),他不光有Basic
的所有東西,還包括SymmetricSecurityBindingElement(安全協(xié)議) 和?TransactionFlowBindingElement(事務(wù)流),現(xiàn)在你心中是不是有底了,起碼我知道各
種Binding里面都有些啥,為了更好的理解,我來畫一張簡(jiǎn)圖。
上面這個(gè)圖,大概也就表達(dá)了我的意思,當(dāng)我們Client在走WSHttpBinding這個(gè)協(xié)議的時(shí)候,Client端的InputMessage會(huì)先走?TransactionFlow,SymmetricSec
urity,TextMessageEncoding,最后走HttpTransport,然后Service端就按照客戶端進(jìn)行“反向處理”,通過一陣禁臠之后,我們就拿到了安全的OutputMessage。
?
二:BindingElement的跨綁定性
你要是很仔細(xì)的話,你肯定會(huì)發(fā)現(xiàn),其實(shí)Binding就是一個(gè)預(yù)先默認(rèn)配置好的信道棧,對(duì)不對(duì),你也看到了,每一種Binding都有屬于自己的BindingElements,
恰恰這些Elements是可以跨Binding的,也就是說我可以自由組合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)視一下,最后我們看看,都是些亂碼。
?
這篇就說到這里了,希望對(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,不多說,誰看誰入迷,下面言歸正傳,
看看這個(gè)很有意思的Behavior。
?
一: Behavior這個(gè)潑婦的厲害
? 在前面的文章中,我也清楚的說明了整個(gè)wcf通信流,而Behavior這個(gè)潑婦可以在wcf通信流中的任何地方插上一腳,蠻狠無比,利用的好,讓你上天堂,利用的不
好,讓你下地獄。。。下面讓你看看behavior到底有哪些可以注入的點(diǎn)???先畫個(gè)簡(jiǎn)圖:
上面的圖,大概就是wcf的通信簡(jiǎn)圖,所有藍(lán)色字體都是Behavior注入的點(diǎn),其中Client和Service端都可以注入,如果按照功能分的話,又可以分為“操作級(jí)別”和
”端點(diǎn)級(jí)別“,下面我來簡(jiǎn)要的分解下。
?
二:端點(diǎn)級(jí)別Behavior
從圖中你也可以看到,消息檢查器是放在Channel這個(gè)級(jí)別的,也就是說它可以監(jiān)視Client和Server的入站請(qǐng)求,也就是說所有的請(qǐng)求都需要通過它轉(zhuǎn)發(fā),如果
這樣的話,那我是不是可以在這個(gè)注入點(diǎn)上自由的修改,變更,攔截入站和出站請(qǐng)求,而且利用這個(gè)特性我還可以做很多的事情,比如日志記錄,記錄統(tǒng)計(jì)等等,下
面我們來看看這個(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)”等等。。。 為什么說等等這個(gè)詞,很簡(jiǎn)單啊,,,其實(shí)還有很多系統(tǒng)內(nèi)置的,既然是Operation,那就必
然是針對(duì)方法的,還記得OperationContract是怎么套在方法上的嗎??? 是特性,對(duì)吧,,,同樣的道理,OperationBehavior也是一樣,那怎么用呢??
同樣也是很簡(jiǎn)單的,繼承幾個(gè)接口即可。。。
?<1>?IParameterInspector 的玩法
? ?其實(shí)沒什么好說的,既然是屬于Operation下面的Behavior,那都是通過特性注入的,而這個(gè)IParameterInspector,可以做到類似Mvc的Model驗(yàn)證,下面
我做個(gè)簡(jiǎn)單的Action參數(shù)長(zhǎng)度驗(yàn)證(長(zhǎng)度不超過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)度不能超過 " + 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即可,有了上面的思想,我想下面這些使用起來都不是問題吧。。。
?
隨筆- 197? 文章- 0? 評(píng)論- 3407?十五天精通WCF——第十天 學(xué)會(huì)用SvcConfigEditor來簡(jiǎn)化配置
? ? ? ?我們?cè)谕鎤cf項(xiàng)目的時(shí)候,都是自己手工編寫system.serviceModel下面的配置,雖然在webconfig中做wcf的服務(wù)配置的時(shí)候,vs提供大多
數(shù)的代碼提示,但對(duì)于不太熟悉服務(wù)配置的小鳥們來說,有些困難,而且一些服務(wù)配置也容易遺漏,大多情況下,我們都是copy一份服務(wù)配置,然
后在服務(wù)配置上面修修改改,對(duì)吧。。。其實(shí)呢,.net給我們提供了一個(gè)強(qiáng)大的scvconfigeditor這個(gè)工具化的軟件來幫助我們生成wcf的配置,是
不是很神奇???
?
一:工具在何處
當(dāng)然在無比牛逼的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)該也看到了,各種牛逼的工具,很眼饞吧,不過這一篇我們還是看重SvcConfigEditor。
?
二: 如何使用SvcConfigEditor
1. ? 雙擊打開,選擇“文件” => “新建配置”。
?
2. ?然后我們選擇 “新建服務(wù)” => “填寫服務(wù)名”
?
3. ?然后我們給service定義一個(gè)host, 點(diǎn)擊 "主機(jī)" => "新建“ => "填寫基址"。
?
4.??到這一步,你是不是特別想看一看生成的config配置是咋樣的???好啊,滿足你的虛榮心,我們只需要點(diǎn)
? ? ?擊"保存“,選擇一個(gè)路徑即可。。。
5. ?好了,你的虛榮心得到滿足了,下面我們來定義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可以訪問,有了這個(gè)神器,同樣簡(jiǎn)單,我們可以
? ? 點(diǎn)擊“高級(jí)” => "服務(wù)行為" => "新建"。
?
8. 最后我們保存來看一下生成的appconfig是啥樣的???
則么樣???我不需要寫一個(gè)字的config配置就完成了基本的服務(wù)配置,如果你還想玩高級(jí)的,可以自己試著琢磨琢磨SvcConfigEditor。
?
好了,差不多可以睡了,下一篇我們來研究研究 SvcConfigEditor中的診斷工具,很好玩的啦~~~~~
?
隨筆- 197? 文章- 0? 評(píng)論- 3407?十五天精通WCF——第十一天 如何對(duì)wcf進(jìn)行全程監(jiān)控
說點(diǎn)題外話,我們?cè)谕鎍sp.net的時(shí)候,都知道有一個(gè)叼毛玩意叫做“生命周期”,我們可以用httpmodule在先于頁面的page_load中
做一些攔截,這樣做的好處有很多,比如記錄日志,參數(shù)過濾,全局登錄驗(yàn)證等等。。。在wcf里面的話也是有類似的功能,第一種就是在
endpoint中加上runtime的behavior,這樣的話就可以先于“服務(wù)方法”做攔截,第二種方法呢,也就是我們這一篇所說的全程監(jiān)控,俗稱
”診斷功能”。
?
一:診斷
我也說了,“診斷”這是wcf的一個(gè)專業(yè)術(shù)語,意思也就是監(jiān)控wcf的所有動(dòng)向,如果往下說的話,可以分為監(jiān)控 wcf的message 和 wcf
本身的服務(wù)狀態(tài)信息和端對(duì)端的流轉(zhuǎn)消息。
1. 端對(duì)端的流轉(zhuǎn)消息
在玩wcf之前,不知道有多少人熟悉Diagnostics,對(duì)的,它就是.net自帶的日志類,當(dāng)然在這個(gè)年代,記錄日志的組件有很多,比如
log4net,Nlog等等。。。不過話說回來,Diagnostics這個(gè)叼毛用起來還比較另類,它由“跟蹤源” 和 “監(jiān)聽器”組成。分別就是TraceSource
來指定跟蹤源,用TraceListener來指定跟蹤源的監(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>?從上面的配置中可以看到,你有沒有發(fā)現(xiàn)我在配置system.diagnostics的時(shí)候和wcf一點(diǎn)關(guān)系都沒有,我并沒有在system.ServiceModel
下對(duì)diagnostics有一丁點(diǎn)的配置,對(duì)吧,這說明什么,說明“蹤跡跟蹤”功能和wcf一點(diǎn)關(guān)系都沒有,但卻可以完整的記錄wcf的蹤跡信息,然
后我稍微解釋下listeners節(jié)點(diǎn),在這里我配置了一個(gè)XmlWriterTraceListener的監(jiān)聽器,然后把輸出文件的路徑配置在initializeData屬性下,
其實(shí)都是diagnostics本身的知識(shí)范疇,和wcf一點(diǎn)關(guān)系都沒有,好了,下面我開啟下程序,看看到底都追蹤到什么?
有沒有看到,當(dāng)我的服務(wù)啟動(dòng)之后,追蹤信息就全部來了。。。但是接下來有一個(gè)問題來了,這個(gè)很雜亂的xml該怎么看才能最舒舒服服的
呢???不用著急啦,wcf同樣給我們提供了一個(gè)叫做SvcTraceView的工具,專門就是用來查找這個(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即可,不過這次監(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)備來跑一下客戶端,調(diào)用Server端的Update方法,看看能抓到啥樣的Messsage。
?
?
現(xiàn)在我迫不及待的想用SvcTraceView打開下2.txt,看看都拿到了什么追蹤信息。。。
?
?
好了,這篇我也只是引路式的介紹下SvcTraceView,具體更深入的玩法,大家可以琢磨琢磨,對(duì)了,如果大家想對(duì)Source和Listener的
一些參數(shù)需要進(jìn)一步了解,可以參考下SvcConfigEditor,比如下面這樣,一目了然,你懂的。。。
?
十五天精通WCF——第十二天 說說wcf中的那幾種序列化
我們都知道wcf是由信道棧組成的,在我們傳輸?shù)膮?shù)走到傳輸信道層之前,先需要經(jīng)過序列化的過程,也就是將參數(shù)序列化為message,這篇
我們就來說說這里的序列化,蠻有意思的,可能初學(xué)者也明白,在wcf中默認(rèn)的序列化是DataContractSerializer,確實(shí)是這樣,不過wcf在信道中
其實(shí)不僅僅支持DataContractSerializer,它還支持其他類型的序列化,比如XmlSerializer,NetDataContractSerializer以及DataContractJson
Serializer,下面我們一起來見證下。
?
1.?XmlSerializer
???要了解XmlSerializer,我們先來簡(jiǎn)單看看NetDataContractSerializer,在前面的文章中,我也說過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就無法進(jìn)行序列化,那我如果非要保證wcf能正常跑起來的話,還有其他好的辦法嗎???當(dāng)然了,肯定有辦法,這就好比談戀愛一樣,總不能
在一棵樹上吊死吧,沒人誰離不開誰,也不會(huì)誰離開了誰會(huì)死,天涯何處無芳草,男兒何患無妻,對(duì)吧。Wcf中也一樣,既然DataContract用不了,自
然會(huì)有替代它的人,那這個(gè)人就是XmlSerializer,使用起來也很簡(jiǎn)單,就是在契約方法上面加上XmlSerializerFormat即可,然后我們把Model的
DataContract全部去掉。
?
是不是很簡(jiǎn)單,下面我們就要驗(yàn)證一下,看看這個(gè)Format是否進(jìn)入到了這個(gè)Operation的Behavior中,
?
從上面的圖中,你也看到了,?XmlSerializerFormat?已經(jīng)被注入到Behavior中,并且是由類XmlSerializerOperationBehavior代為處理。
?
接下來,我們用fiddler監(jiān)視一下,看看Message中的Body是否真的按照XmlSerializer?序列化了。
有沒有看到,這次Message的Body已經(jīng)和文章開頭處的Message不一樣了。
?
2. NetDataContract
? ? ? ?這個(gè)玩意也沒什么好說的,光從表面上看,它和DataContract唯一不同的地方就是多了一個(gè)Net,所以你大概也能猜到,這個(gè)功能大概和DataCont
ract一樣,只不過比DataContract多了一個(gè)程序集保存,那這句話是什么意思呢???就是NetDataContract會(huì)把程序集的命名空間和類名都保存到XSD中,
在反序列化的過程中必須要用同樣的程序集才能解開,其實(shí)不管我們是做SOA或者面向?qū)ο缶幊潭贾v究接口編程,而NetDataContract給你的印象就是面
向?qū)ο缶幊?#xff0c;當(dāng)然這也有好處,比如說如果把程序集帶進(jìn)去就好像秘鑰一樣,必須有它才能解開,對(duì)吧,所以導(dǎo)致wcf項(xiàng)目組并不對(duì)NetDataContract感冒
,所以在實(shí)際應(yīng)用上也不建議使用。
?
3.?DataContractJsonSerializer
? ?看到上面這個(gè)帶有Json的字樣,我想大家都知道這玩意是干什么的???沒錯(cuò),他就是將我們的Model序列化成Json,這在wcf的rest編碼使用的很廣,
如果大家有興趣的話,我在下一篇會(huì)詳細(xì)描述,這里我們先簡(jiǎn)單看一看。
?
好了,這一篇就說這些了,洗洗睡了。。。
?
隨筆- 197? 文章- 0? 評(píng)論- 3407?十五天精通WCF——第十三天 用WCF來玩Rest
? ? ? ? 在我們玩wcf的時(shí)候,都會(huì)潛意識(shí)的覺得wcf就是通過soap協(xié)議交換消息的,并且可以在basic,tcp,msmq等等綁定中任意切換,
牛逼的一塌糊涂,但是呢,如果說哪一天wcf不再使用soap協(xié)議,而是采用json格式的字符串,是不是有一點(diǎn)顛覆你對(duì)wcf的認(rèn)識(shí)的???
從傳統(tǒng)意義上說,wcf是非常重量級(jí)的,很明白的一個(gè)例子就是太多太多的配置,尤其是Behavior的配置,而且behavior對(duì)wcf來說又是重
中之重,它對(duì)wcf的擴(kuò)展和性能又是最重要的,可恨的是wcf在binding,behavior,contract之中的配置又是非常非常的保守,可以說用
wcf來玩分布式,這些默認(rèn)配置是完全做不到的,就比如說basicbinding的基類HttpBindingBase。
?
抱怨的話我也不說了,可能微軟也覺得這個(gè)問題是個(gè)不小的問題,然后就有了輕量級(jí)的 asp.net web api,你可以看到它和wcf比起來精
簡(jiǎn)多了,也許讓我們這些碼農(nóng)更加的專注于業(yè)務(wù)吧,既然wcf帶了這玩意,我也得必須約談一下。
?
一:UriTemplate
要說rest,還得先說UriTemplate,因?yàn)閣cf用UriTemplate來做rest中的uri模板匹配,然后用WebInvoke這個(gè)OperationBehavior
插入到wcf的心臟中,說的玄乎一點(diǎn),這個(gè)就有點(diǎn)像mvc中的路由匹配機(jī)制,下面我舉個(gè)例子:
?
1. 用UriTemplate來告知可以監(jiān)視的完整Url
從下面的圖中,可以看到三個(gè)元素:服務(wù)地址,模板,入?yún)?#xff08;這里面的”1“),這三個(gè)元素組合在一起,就構(gòu)成了完整的remote url,
然后這個(gè)完整的url就是我模板(/User/{id})監(jiān)視的對(duì)象。
?
2. 通過UriTemplate來解析url中的參數(shù)。
既然可以構(gòu)建url,那當(dāng)然可以解析url啦,對(duì)吧,下面這張圖可以很清晰的告知你,當(dāng)外來的url=http://127.0.1:1920/HomeService
/User/1過來的時(shí)候應(yīng)該被哪個(gè)uriTemplate所接收。
?
正是因?yàn)閁riTemplate具有這樣的url構(gòu)建和解析能力,所以wcf就把UriTemplate作為WebInvoke和WebGet這兩個(gè)屬性的參數(shù)來動(dòng)態(tài)
解析外來的url,然后根據(jù)這個(gè)url分配到具體的服務(wù)方法上,下面我們具體看一看。
?
二:WebGet,WebInvoke的使用
剛才也說了,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來作為CURD的狀態(tài)機(jī)制,然后就是你如果看懂了UriTemplate,那你現(xiàn)在應(yīng)
該知道這個(gè)Template在監(jiān)視什么類型的url。做完了上面的coding,下面我們需要在webconfig中通過behavior來指定啟動(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ù)地址也出來了: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 ?來測(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?
?
好了,大概就說這么多了,如果說你不嫌麻煩,你可以用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á)的意思就是,雖然說web程序拋異常了,但不代表iis就
掛了,所以iis還是需要給客戶端做出反饋,這就有了http header,和body信息,同樣的道理,wcf的服務(wù)器異常機(jī)制也是這樣。。。service
拋出了異常,不代表console就掛了,console要做的事情就是把這個(gè)異常包裝起來丟給調(diào)用方,而wcf是怎么包裝的呢???就是用了這篇所
說的FaultException。。。
?
一:FaultException
1. faultexception是干什么的?
剛才我也說了,這個(gè)異常就是wcf來包裝遠(yuǎn)程錯(cuò)誤的,具體的類含義就是表示“SOAP錯(cuò)誤“,如果你夠細(xì)心的話,你還會(huì)發(fā)現(xiàn)到它有個(gè)屬性
叫Serializable,有了它,這個(gè)叼毛就可以序列化到Soap消息中,對(duì)伐???
?
2. 如果挖出faultexception?
挖出這個(gè)exception的方法有很多,比如我來造一個(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 }?
看到了沒有,雖然wcf的service已經(jīng)拋出異常了,但是還是被clr用Faultexception包裝起來了,正如你看到了s:Fault節(jié)點(diǎn),仔細(xì)往下看的話,
你還會(huì)看到faultcode,faultstring,detail等等屬性節(jié)點(diǎn),那下面有個(gè)問題就來了,我們平時(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è)什么問題呢???就是不管客戶端拋出什么異常,我們都習(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拋出異常了而已。。。那你可能要問了,我這話的言外之意就是還有其他異常類也會(huì)捕獲wcf拋出的異常,對(duì)的,比如說你的信道出現(xiàn)
故障,這時(shí)候會(huì)拋出一個(gè)“通信異常(CommunicationException)”。
?
三:如何挖出“通信異常”
?挖出這個(gè)異常,也是很簡(jiǎn)單的,現(xiàn)在我們需要使用”會(huì)話級(jí)別“的binding,比如說nettcpbinding,wshttpbinding,這里的話,我選擇
后者,因?yàn)槭沁@樣的,第一次服務(wù)器拋異常以后,客戶端和服務(wù)器端通信信道就會(huì)關(guān)閉,如果你在客戶端不重新new一個(gè)client,那么這時(shí)候你
第二次再使用client的話,這個(gè)時(shí)候就會(huì)產(chǎn)生“信道故障“,拋出CommunicationException,而當(dāng)你看到CommunicationException的時(shí)候,
你可以非常有自信的說,老子的wcf根本就沒有連接到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ò)誤都出來了,搞個(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 }好了,大概就說這么多了,我的目的也很簡(jiǎn)單,在寫wcf的client的時(shí)候,盡量做到異常越具體越好,這樣方便我們盡可能快的排查問題,因?yàn)?/p>
wcf的異常信息真的太tmd坑爹了!!!減輕痛苦,從小做起~~~
?
隨筆- 197? 文章- 0? 評(píng)論- 3407?十五天精通WCF——終結(jié)篇 那些你需要注意的坑
? ? ? ? ? 終于一路走來,到了本系列的最后一篇了,這一篇也沒什么好說的,整體知識(shí)框架已經(jīng)在前面的系列文章中講完了,wcf的配置眾多,如果
不加一些指定配置,你可能會(huì)遇到一些災(zāi)難性的后果,快來一睹為快吧。
?
一: 第一個(gè)大坑 【數(shù)據(jù)傳輸量】
我們使用wcf的目的,就是用來進(jìn)行分布式的數(shù)據(jù)交互,既然是交互,就一定要進(jìn)行數(shù)據(jù)交換,可能一些新人并沒有注意到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í)候,再大的傳輸量都見過,但為什么這玩意就拋異常了呢???下面一個(gè)問題就來了,這個(gè)傳輸默認(rèn)值到底
是多少??? 接下來我們就用ILSpy翻翻看。
?
可以看到,這個(gè)叼毛玩意居然只有 64k。。。沒錯(cuò),你看到的就是64k,也就說明你的傳輸量不能大于64k,否則請(qǐng)求就會(huì)在client端拒絕,
知道了原因,我們現(xiàn)在就可以這么修改config了。
<bindings><netTcpBinding><binding name="MySessionBinding" maxReceivedMessageSize="2147483647"/></netTcpBinding></bindings>?
有很多資料在配置這個(gè)坑的時(shí)候,也會(huì)使用MaxBufferSize 和?MaxBufferPoolSize,就是用來增加緩沖區(qū)和緩沖池的大小。
?
一: 第二個(gè)大坑 【并發(fā)量太低】
說起這個(gè)大坑,還得先從一段代碼說起,下面是一段對(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端過來的請(qǐng)求了,并且之后的1min的時(shí)間里,client端
開始出現(xiàn)超時(shí)異常,這肯定不是我想看到的,?那有人就要說了,我的并發(fā)達(dá)到800多很正常啊,如果提高這個(gè)并發(fā)呢???其實(shí)在wcf里面
有一個(gè)叫做ServiceThrottlingElement綁定元素,它就是用來控制服務(wù)端的并發(fā)數(shù)。
?
這三個(gè)屬性的大概意思,我想大家都看的明白,不過有點(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è)侔殉绦蚺芷饋砜匆豢础!!?/p>
?
? ? ? 現(xiàn)在你可以發(fā)現(xiàn)并發(fā)早已突破800了,不過你要記住,如果并發(fā)數(shù)太多,容易造成系統(tǒng)資源耗盡,導(dǎo)致崩潰,這時(shí)候負(fù)載均衡就來
了,對(duì)吧,wcf需要修改的配置還有很多,正因?yàn)閣cf框架龐大,很多默認(rèn)配置不符合生產(chǎn)需求,所以大家在工作中需要注意,這個(gè)系列
就到此打住了,希望對(duì)你有幫助。
轉(zhuǎn)載于:https://www.cnblogs.com/kingCpp/p/4705931.html
總結(jié)
- 上一篇: .NET 类型(Types)的那些事
- 下一篇: 多维DP UVA 11552 Fewes