程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF從理論到實踐(15):響應變化

WCF從理論到實踐(15):響應變化

編輯:關於.NET

本文目的

需求變化是軟件開發過程中的一大難題,我們經常扼腕歎息:面對變化,我們的軟件為何如此不堪一擊?我們常常在眾多需求變化導致的功能爆炸中疲於奔命,甚至迷失自我!這到底為什麼?面對"擁抱變化"這種得吶喊,我們的感受應該是震耳欲聾,還是振聾發聩?如果你仍在困惑,可以來看一看WCF是如何擺脫這種困境的!

序幕

小王效力於北京的一家系統集成公司,該公司內部有一個WCF服務為各個部門所共用,小王便是WCF服務的開發和維護人員。起初大家在一個辦公樓工作,共用一個局域網,WCF運行的非常好,小王也因此獲得了公司上下的一致好評。此時他們的WCF的使用狀態如下圖所示:

起初小王以為公司都在一個局域網之中,考慮到性能,WCF最早采用的是NetTcpBinding的綁定方式,契約部分是根據自己的業務需要開發的, 而他為服務公布的最早的地址為:net.tcp://127.0.0.1:6547/Service。他最早是用代碼方式將服務托管到一個Console程序中的,托管代碼如下:

ServiceHost host = new ServiceHost(typeof(ServiceLib.Service));
NetTcpBinding bind = new NetTcpBinding();
Uri address = new Uri("net.tcp://127.0.0.1:6547/Service");
host.AddServiceEndpoint(typeof(Contracts.IService), bind, address);

而此時大家所使用的客戶端代碼均為:

NetTcpBinding bind = new NetTcpBinding();
EndpointAddress address = new EndpointAddress("net.tcp://127.0.0.1:6547/Service");
Proxys.IService ws = new Proxys.ServiceClient(bind, address);

這樣一種情況下,小王的WCF服務與各個部門之間可謂是其樂融融。可好景不長。各位看官,請看下文:

使用范圍擴大

隨著近幾年公司業務的持續發展,公司在唐山的業務量非常大,所以在唐山成立了一個辦事處,而該辦事處同樣需要使用小王的WCF服務,可原本出乎小王意料的事情發生了:唐山辦事處和公司總部處於不同的網絡,如果還使用tcp這種傳輸方式,就不適用了。公司頭們為這事也挺犯愁,本來以為還要勞煩小王大改一通,沒想到小王卻說:"小意思,馬上解決問題!"他首先和公司網絡管理人員聯系,將WCF服務所在主機配置1個公網IP為202.120.120.3,然後再托管程序的代碼中增加幾行

BasicHttpBinding bind = new BasicHttpBinding();
Uri address = new Uri("http:// 202.120.120.3:80/Service");
host.AddServiceEndpoint(typeof(Contracts.IService), bind, address);

然後將客戶端程序場景中的代碼修改如下:

BasicHttpBinding bind = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http:// 202.120.120.3:80/Service");
Proxys.IService ws = new Proxys.ServiceClient(bind, address);

然後將托管程序重新發布了一下。而將修改之後的客戶端部署到辦事處一台服務器上面,經過測試,新的客戶端運行正常,而總部那些客戶端也沒受任何影響。由此可見,雙方相安無事,小王也松了一口氣,原本另大家比較頭疼的變化問題便迎刃而解了。下面是使用范圍變化之後,WCF服務與客戶端的工作情況:

停電了,殃及池魚

昨天請假了,今天興致勃勃來上班,沒想到剛來,卻被經理劈頭蓋臉的數落了一頓:" 昨天停電,來電後,你的服務沒有啟動,打你電話也不接,下次注意亞!",小王抓抓了頭皮,不好意思的笑笑說:"好,我馬上想辦法,防止出現類似問題",回到座位上,小王就想到了用iis來替代console作宿主,這樣機器重新啟動後,服務便會自動加載,可轉念一想,不對,iis支持http的訪問方式,而且基地址必須和服務所在網站地址一致,我們局域網內部采用的是tcp,排除了iis,小王很快就想到了windows service,恩,就它了。所以問題也便成了下圖所示的情形:

經過查證,小王先弄明白了下面的原理:

不僅如此,在不同宿主中寄宿的方法也一致:都是采用ServiceHost來進行托管。知道上面的知識,小王將原本Console宿主中 的托管代碼拷貝到Windows服務的代碼中,只不過,Console中托管代碼寫在Main方法,而Windows Service寫在OnStart方法中。

秀才遇見兵

原本只是公司內部使用的WCF服務,前段時間也開放給了公司的幾個大的合作商,和他們的平台作整合,前幾家,合作的非常好,小王正津津樂道之時,卻遇到了一個刺頭,他是公司一個非常重要的合作商,但要求也非常特殊,服務中原本有個數據契約,用於描述公司訂單,契約的定義如下:

舊版本數據協定

[DataContract]
public class Order
{
private string _orderID;
[DataMember]
public string OrderID
{
get
{
return _orderID;
}
set
{
_orderID = value;
}
}
private string _content;
[DataMember]
public string Content
{
get
{
return _content;
}
set
{
_content = value;
}
}
}

而且其他的合作商,對此都沒有任何的異議,小王將代理已經發出去10幾家了,可現在遇到這位要求必須再上面的基礎上再提供訂單的創建時間,小王打電話過去,和他解釋:"目前我們的系統已經被很多廠商使用,而且別人的代理目前也運行的很好,你的這個需求是正確的,但我們如果修改數據契約會影響其它客戶端的使用,請理解",本以為自己苦口婆心的解釋,人家會買賬,誰想,對方根本不聽解釋,一個勁地說:"這是我們的需求,必須的,必須的!"。氣得小王直想摔電話。可"用戶是上帝,胳膊扭不過大腿麼",後來一高人指點道:"WCF在設計的時候已經考慮到了版本管理的問題,這種問題已經非常容易解決,你可以用IExtensibleDataObject",經查閱還真有此類問題的解決方案,小王將上面的契約代碼更改如下:

新版本數據協定

[DataContract]
public class Order:IExtensibleDataObject
{
private string _orderID;
[DataMember]
public string OrderID
{
get
{
return _orderID;
}
set
{
_orderID = value;
}
}
private string _content;
[DataMember]
public string Content
{
get
{
return _content;
}
set
{
_content = value;
}
}

private ExtensionDataObject _exData;
public ExtensionDataObject ExtensionData
{
get
{
return _exData;
}
set
{
_exData = value;
}
}

private DateTime _createTime;
public DateTime CreateTime
{
get
{
return _createTime;
}
set
{
_createTime = value;
}
}
}

然後新生成一個代理,發給了刁蠻用戶,而其他客戶的代理版本卻不用任何變動。新的用戶的代理運行和很正常,而老的也很正常,真爽!小王此時方體會到WCF的強大之處。

凡是符合下面的變動情形的,均可視為非重大更改:

更改成員名稱,且將DataMemberAttribute的Name屬性和舊版本保持一致

大多數添加和移除數據成員的操作

將成員的特性IsRequired從True更改為False

實現IExtensibleDataObject接口

更改枚舉成員名稱,但用EnumMemberAttribute將協定名稱和老版本保持一致

大多數數據集合的更改

服務也會累麼?

問題是一個接一個,解決完上面的幾個問題沒多長時間,這個WCF又有新問題了,現在客戶端越來越多,很多客戶反映,最近服務端很不穩定,有時還連接不上去,小王檢察了半天業務代碼,發現沒有問題,而且之前人數少得時候,運行的挺好的亞,此時他經過仔細的查閱,終於找到了一些用的信息:WCF為了改善性能,是有限流(Throttling)措施的。主要包括三種

maxConcurrentCalls:最大並發數,默認為16

maxConcurrentSessions:最大的會話數,主要針對於PerSession的情況,默認為10

maxConcurrentInstances:最大實例數,默認為Int.MaxValue

默認的設置比較保守,最大並發數僅為16,非常容易造成排隊或者超時現象。修改或者添加限流也非常簡單,只需要在服務的配置中修改或者增加ServiceBehavior中的

<serviceThrottling maxConcurrentCalls="16" maxConcurrentSessions="10" />

後記

擁抱變化,擁抱變化,我們口號喊得非常響亮,可為什麼面對變化的時候,我們有時會暴跳如雷呢?一邊罵客戶bt,一邊還要通宵達旦的加班來完成工作呢?問題的原因不在於用戶,不在於變化本身,更多的是我們一味的將一堆垃圾改造成另外一堆垃圾,要想真正解決問題,做好架構,做好基礎是關鍵。我們常常因為時間,人力等因素,剎不住車似的的制造garbage,卻忘記了什麼叫細節,什麼叫品質。無論針對產品還是市場,當前更重視不是你做了多少,而是做了多少有意義的事情,多少別人沒有做過或者做不了的事情。品質,細節,ThinkPad,Google。總之我會毫不猶豫地轉向WCF,因為它有品,也更能適應變化

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved