天天看點

采訪ServiceStack的項目上司Demis Bellot——第1部分(網摘)

ServiceStack是一個開源的、支援.NET與Mono平台的REST Web Services架構。InfoQ有幸與Demis Bellot深入地讨論了這個項目。在這篇兩部分報道的第1部分中,我們主要談論了ServiceStack項目建立的原動力,以及項目中的各種設計方案選擇。

InfoQ: 你是否認為微軟對服務的實作方式有什麼問題?ServiceStack又是怎樣解決這些問題的呢?

Demis: 有一些問題是由于微軟一直以來自認為良好的架構設計的方式所造成的常見問題,另一些問題的根源是由于微軟的設計總是傾向于滿足設計器優先的工具,并且試圖為使用設計器作為向導的開發者提供一套熟悉的API,而這種設計傾向造成了一些副作用:

  • 在服務API設計時提倡用C#進行遠端過程調用(RPC)的方法調用,這導緻了非常細粒度(chatty)的設計,并且産生了許多特定于用戶端的API。
  • 企圖将脆弱的、臃腫的、低效并且過于複雜的SOAP以及WS-*序列化格式進行标準化。
  • 試圖通過繁重的人為抽象、UI設計器以及各種大型工具達到簡化終端使用者開發的目的。
  • 為了嘗試給開發者展現一個人為定制的服務端對象模型,建立了繁重的抽象API。
  • 試圖通過一個共享的抽象對象模型将所有網絡終結點(endpoint)統一起來。
  • 過度使用XML配置與代碼生成。
  • 沒有預先考慮可測試性與性能。

RPC方法簽名

由于微軟過于追求為開發者提供一套熟悉的RPC API,并在VS.NET中提供豐富的UI工具(例如“添加服務引用”對話框)以保證上手的簡易性,其代價就是推廣了遠端服務中的各種反模式,從長期來看将導緻不必要的不協調與脆弱性。不幸的是,微軟長期以來在其釋出的每個web service架構中都持續使用這種設計方式,這種方式提倡建立RPC服務API的設計方式,造成了開發者在意識中将遠端服務也當作本地方法一樣調用。這種結果的害處是多方面的,遠端服務意味着它包裝了一個外部依賴,對它的調用要比本地方法慢上幾百萬倍,并且更容易受外界的影響而發生錯誤。将隐式的服務契約與服務端RPC方法簽名綁定在一起,就意味着你的API服務契約和服務端的實作緊密耦合在一起了。由于沒有規定一個定義良好的邊界,導緻了糟糕的關注分離,并且出現了将繁重的ORM資料模型通過網絡傳回給用戶端的糟糕實踐。從定義上來說,這種資料模型的關系型結構與循環式關系對于資料遷移對象(DTO)來說并非一種好的選擇,它使調用可能偶爾會失敗。這種方式還将隐式的服務契約與你的底層關系型資料庫(RDBMS)資料模型耦合在一起,這樣在進行修改時就會産生額外的沖突。而且遠端API與調用它們的服務端網站是無連接配接的,而這些調用的方法在用戶端代理部署後也會不斷地演化。理想的架構應該能夠提倡可演化的、靈活的API設計,以避免在服務端改變時産生運作時錯誤。

這些有一張關于WCF提倡的細粒度的RPC API方式與ServiceStack所鼓勵的基于消息的API方式的不同之處的對比圖。此外,這個用ServiceStack重寫Web API的入門教程的示例則展示了基于消息的API如何減少細粒度調用,增加了服務的可重用性。

ServiceStack采用了Martin Fowler所推薦的遠端服務最佳實踐,是以避免了之前困擾着.NET web service開發者的很多潛在問題:

遠端門面

遠端門面提倡使用基于消息的、粗粒度的批量調用接口。它能夠将通信次數減至最低,并促進了建立更少但是可用性更好、并且支援版本化的服務接口。ServiceStack采取了基于消息的設計確定開發者始終建立粗粒度的API設計。

資料遷移對象(MSDN)

資料遷移對象要求使用特定用途的POCO以建立web service響應的資料格式。ServiceStack一直鼓勵使用DTO,它本身與它的實作完全解耦,并且存在于一個沒有外部依賴也不需要具體實作的程式集中。這種政策允許将定義服務端的服務類型共享給所有.NET用戶端,因而提供了一個端到端的類型化API,并且無需使用代碼生成。

網關(Gateway)(MSDN)

網關的作用是将所有服務端通信包裝起來,隐藏在一個顯式定義并且可重用的用戶端網關之後。這種最佳實踐和代碼生成的代理(例如WCF)有所不同,後者将代碼生成的類型與底層的服務用戶端揉合在一起,使得生成結果難以模拟(mock)、測試以及替換為不同的實作,也經常導緻對現有服務的改變會造成用戶端代碼的編譯錯誤。這一點對ServiceStack來說很少會成為問題,因為它能夠重用通用的服務用戶端,是以在接口方面唯一需要改變的東西僅限于類型本身而已。并且由于基于消息的設計的優勢,無論新增或移除任何功能都不會影響到現有的用戶端。

ServiceStack在它的通用并且可重用的類型化.NET服務用戶端采用了網關模式。我們同時支援Silverlight、JavaScript、Dart甚至是MQ(消息隊列)的用戶端。讓所有.NET服務用戶端都共享相同的接口,這使測試(通過注入或者寫日志方式)變得簡單,而且能夠友善地在JSON、XML、JSV、MessagePack以及ProtoBuf等現有的用戶端之間進行切換,而無需改動應用程式的代碼。這就允許你在開發時使用類似于JSON這樣便于調試的文本格式,随後在部署建構時切換為使用.NET上速度最快的二進制格式,例如Message Pack或ProtoBuf,以降低資料傳輸量并實作最高的性能。

SOAP Web Services

以目前的情況來看,SOAP這種技術是不應該繼續存在的,或者說應該僅僅限制在那些它還能夠帶來一些好處的地方使用。它的存在本身就是基于一個錯誤的假設,即為了實作資料的互交換性,必須表現出複雜性,要盡可能的嚴格與明确,這使得基于它的所有現實都必須實作一個複雜的schema以進行通信。而事實上,之與相對設計方式反而被證明是正确的,如果使用了類似于JSON、CVS、Protocol Buffers、MessagePack、及BSON等最小化并且靈活的格式,就會大大減少實作的障礙與複雜性,結果的生成會更快,互操作性與版本能力也會更強。

我總是覺得這件事很難想象,盡管SOAP是建立在HTTP基礎之上的,但它的設計者們在開發出WSDL時似乎完全沒有吸取那些寶貴的經驗。WSDL所引入的類型、消息、操作、端口、綁定以及服務這些概念真的能夠取代HTTP中簡單的URL辨別符,以及Accept/Content-Type這些頭資訊嗎?我覺得這一點也不難判斷啊。

雖然它名為SOAP(簡單對象通路協定),但它既不簡單,也不是什麼對象通路協定,而且對于開發服務來說,它在許多方面都顯示出它是個糟糕的選擇,例如:

  • 臃腫而緩慢——通常各種尺寸與性能名額評比中都會作為反例出現。
  • 脆弱——對命名空間、字段、枚舉或類型的改變都會造成運作時異常。
  • 在程式設計時難以使用——它本身不能夠自然地映射為任何對象類型系統,在與應用程式代碼進行轉換時經常造成各種沖突。
  • 違反了HTTP——HTTP對于分布式通路提供了簡單的謂詞(verb),例如GET方法應該是無副作用的,是以可以被緩存在用戶端以及中間伺服器(例如代理)上。而由于每個SOAP請求都是一個HTTP POST方法,它就無法利用HTTP中最主要的一項好處。
  • 可通路性糟糕——一個SOAP消息在本質上就是為了傳送定制的XML内容體與SOAP頭的一個抽象容器。這種方式很糟糕,因為抽象消息格式需要花費你更多的精力去實作通路與序列化,同時為你的資料提供了弱類型的通路。而且它限制了隻有能夠收發SOAP消息的用戶端才能夠通路你的服務。由于它實在無法提供任何有意義的價值,許多Web API已經不再把響應封裝在消息容器内,而是簡單地将序列化的JSON與XML按原樣輸出,這種實踐被稱為POX/J(Plain Old XML)。
  • 複雜 – SOAP、WSDLs、UDDI、WS-*帶來了不必要的複雜性。最終恐怕隻有這些規格說明的參與者(或者SOAP架構開發者)能夠良好地了解整個WS-*系列技術,以及使用那些它們曾經打算正式采用的一些大型複雜架構去以最好的方式去實作它了。
  • 鼓勵代碼生成——由于它的複雜性,如果不使用SOAP架構及代碼生成的代理,一般來說是難以手工實作SOAP的。

由于SOAP明顯背離了服務的核心優勢,是以它能夠流行起來實在是一個令人吃驚的事實。我曾有許多年為政府項目與大型企業開發服務的經驗,很不幸的是其中的許多項目都有一個必需實作的要求,即把他們的服務暴露為SOAP終結點。不過許多網際網路公司與專注于創造價值的創業公司都不太會使用這門技術了,他們更多地選擇建立簡單的HTTP API,傳回單純的XML或者JSON格式的響應。

雖然在多數情況下SOAP是一個糟糕的選擇,但ServiceStack還是為你建立的服務提供了對SOAP終結點的支援,因為如今仍然有許多現存的企業系統隻能夠與SOAP終結點進行通信。這一點也和ServiceStack的核心目标相一緻,即為你的服務提供最大化的功能性、可通路性以及連接配接方式。

SOAP在設計上是一種非常脆弱的格式,如果某個服務稍稍偏離了WSDL,而用戶端又是由這個WSDL生成的,那你通常就會看到運作時錯誤的發生。雖然在靜态類型系統中,快速失敗被視為一種優勢,但對于遠端服務來說就不是一種理想的方式了,因為你通常希望能夠實作向前相容與向後相容,是以服務端的API改變不會破壞現有的用戶端。這一目标顯然被WCF忽略了,它提倡RPC方法簽名、SOAP格式以及代碼生成,這可以說是當今的所有web service實作技術中最為脆弱的組合了。

SOAP與Protocol Buffers

将SOAP與Google的Protocol Buffers進行一下對比是很有趣的,它是Google推出的一種簡單的接口描述語言(IDL),Google在其内部的所有RPC協定與檔案格式中幾乎都使用了該技術:

  • 它比SOAP小了好幾倍,而速度要快上幾個數量級
  • 它使用了一種簡單的領域特定語言(DSL)來定義基于消息的API
  • 使用.proto檔案來定義類型,對于程式設計語言來說在程式設計角度上非常适合
  • 包括了對多版本管理的實作
  • 為Python、Java與C++提供了原生的用戶端與服務端綁定

MessagePack RPC以及用于開發Facebook的Apache Thrift是另外兩個流行的開源選擇,它們都提供了快速的,簡單的IDL,并且為多數主流平台提供了綁定。

雖然是由不同的公司開發,但以上每個IDL都比SOAP更簡單、快速并且易于使用。從SOAP的規格說明書的厚度來看,它應該是由委員會所開發的,但顯然完全沒有考慮過性能,大小以及易于實作。

JSON

雖然在大小與性能方面有優勢,但Protocol Buffers與MessagePack都有一個問題,即它們使用了二進制格式。由于基于文本的格式與協定更易于建立、維護及調試,它們經常成為整個開放web的更流行的選擇。近年來,在基于文本的資料互交換格式上的赢家顯而易見是JSON,這是一個簡單的、緊湊的自描述文本格式,它的主要優勢是能夠在所有支援JavaScript的浏覽器上進行直接應用,隻需使用浏覽器内置的“eval()”語句就能夠立即将其轉換為JavaScript對象了。由于它的流行性,主流浏覽器如今都加入了對JSON的原生支援,它們為eval()方法提供了一個更安全的替代方案,可以在老浏覽器上提供一個基于JavaScript的備選實作方式。如果想更多的了解JSON以及它的好處,我推薦你去看看Douglas Crockford這個有趣的演講——“Heresy & Heretical Open Source”。

由于它的普遍性、功能多樣并且易于使用,JSON在多數平台上都得到了原生的支援,并且很快地成為了開發Web API的首選資料格式,尤其是使用在Ajax用戶端的時候。

從我自身的經驗來看,我認為JSON對于實作服務是一種優秀的格式。它是一種更精簡、靈活、容忍度高并且适應性更強的格式,并且它易于建立、調用以及調試,比起SOAP減少了沖突并提高了生産力。當我們開始ServiceStack項目時,JSON的唯一問題就是.NET Framework自帶的序列化器比XML序列化器還要慢。出于對性能上的嚴謹态度,我們并不願意接受這點不足,是以我們釋出了我們自己實作的序列化器,它比任何其它.NET JSON序列化器都要快上3倍以上,并且比.NET Framework中的任何序列化器(包括二進制序列化器)都要快上2.5倍以上。

繼承了JSON保持體積最小的精神,我們也開發了JSV格式,它類似于JSON,但使用了CVS風格的轉義功能,使得它比JSON略微加快,更精簡并且更便于人類閱讀,它不僅能夠用于.NET與.NET服務的互動,而且能夠用以解析查詢字元串,在ServiceStack的GET請求中是能夠允許傳遞複雜的對象圖的。

ServiceStack與WCF方式

雖然WCF與ServiceStack在實作方式上是完全不同的服務架構,但它們卻有着非常類似的目标。ServiceStack在建立服務上采取了一種非常面向服務的方式,它的設計經過了做好,能夠以最大程度重用的方式達到服務的實作。通過代碼優先、類型化設計的方式,我們能夠為你的服務提供更強大的智能推斷,以允許你自動地生成XSD、WSDL檔案,自動生成中繼資料頁,并且自動暴露預定義的路徑。每個新加入的功能、特性、終結點與Content-Type都是圍繞着你的現有模型建立的,并且不需要任何額外的操作以及對應用程式代碼的任何改動就可以立即獲得新功能。我們将這種方式了解為從一個代碼優先的模型開始,作為最權威的部分,随後再将其功能暴露出來。

WCF的目标也是提供一個服務架構,以支援在多種終結點上運作服務,但他們站在一個不同的視角,并且為所有網絡終結點提供了一個統一的抽象,你必須對服務進行配置以綁定到終結點。作為WCF的主要目标之一,他們是少數幾個在最終實作中對WS-*系列技術提供了深入支援的架構。

我們最終的目标都是提供一個易于使用的服務架構,我們隻是在如何取得簡便性上有着完全不同的想法。

簡便性與處理複雜性

WCF看起來比較喜歡繁重的抽象,用複雜的運作時XML配置進行管理,以及用大型工具為開發者提供端到端的連接配接能力。這個抽象層包含了許多複雜的技術:經過抽象的人工服務端對象模型很複雜、配置很複雜、WSDL很複雜、SOAP/WS-*也很複雜。最終結果是,為了對這些主題有一個良好的了解,對每個主題都需要看好幾本書才行。

抽象

有一種陳舊的觀念認為處理複雜性的解決之道就是添加更高層的抽象。這種方式的問題在于,隻有這種抽象的設計很完美,它才能夠顯出效果。(例如程式設計語言比機器代碼更合适)否則當你遇到了一些預料之外的行為,或者是配置、整合與互操作性上的問題是,你需要去了解在這些抽象層之下到底發生了什麼。在這種情況中添加更多的抽象實際上隻會增加開發者必須去熟悉的概念,以及當他們針對進階别抽象層進行開發時額外的認知。這也使得了解你的代碼庫更加困難,因為你必須了解每一個之下都發生了些什麼。WCF的服務端對象模型是全新的、并且不夠自然,這進一步放大了問題,新的開發者們對此一無所知,因為這種模型是獨一無二的,并且它完全沒有對服務或HTTP領域中的概念知識作出任何指導。是以當開發者們之後轉而使用最好的服務架構時,他們從WCF中學到的東西完全沒有用武之地。與其投入時間去閱讀那些如何使用WCF的書籍,還不如把時間花在學習HTTP與TCP/IP上,因為即使你轉而使用其它web service架構,這些知識依然能起到作用,它們是完全獨立于程式設計語言或平台的。

從技術實作的層面來說,過多的抽象會導緻不必要的性能負擔,并且這種性能問題很難優化。因為當你嘗試直接與底層API打交道時,這些抽象會産生阻礙以及各種強制性的阻力。而我們的方式是隻在絕對必要時才會添加抽象,例如我們的IHttpRequest與IHttpResponse封裝對于為ASP.NET與自托管的HttpListener提供一個通用的API就是必需的。相比起添加抽象層的方式,我們更傾向于添加一些非強制性的特性,它們隻是将一些底層接口與一些常見功能包裝起來,以實作DRY。這種方式帶來的好處就是允許終端使用者自由地調用各種方式,并在他們自己開發的類庫中加入自己定義的功能增強,以促進他們實作精益的、DRY以及可讀性良好的代碼庫。暴露底層API能夠確定我們保持架構的靈活性,使用者可以通過多種方式進行通路而得已完整地控制系統的輸出,也因為使用者可以定制傳回的響應,是以他們不會受到任何限制,而得已控制傳回的每一個位元組。

WCF的抽象

WCF為服務采取了一種統一的方式,它促進所支援的所有終結點都标準化為一個單一的人為抽象模型。這種方式也遇到了抽象的通用原則所産生的副作用,即一個統一的抽象模型要為每一種試圖抽象化的實作承擔所有的複雜性,因而它們隻能夠處理各種終結點的特性的交集部分,而且為每個結終點實作最低程度的通用功能。結果就是生成了一個不完整的外部API,并且由于抽象的存在阻礙了對底層終結點的通路,使得這種API的可通路性與可配置能力都大大削弱了。

要徹底了解WCF的功能需要強大的技術能力,需要你投入巨大的精力研究各種技術資源。但本質上來看這種精力投入是一種浪費行為,因為WCF與其它平台上的一些采用了标準方式開發的架構相比,生産力與功能都有所欠缺。對于終端使用者來說,哪怕是為了稍稍掌握一些WCF的使用經驗,也需要投入大得多的精力。出于以上原因,我不希望看到有人去使用類似于WCF之類的架構,或者是它那種統一的終結點的抽象方式。由于它的複雜性與龐大的技術實作細節,我也很懷疑它是否能夠保持演化,以适應新的開發範式或是服務開發模式。我懷疑WCF會遭受到與WebForms相同的命運,退化為一個過時的技術,最終被微軟下一代架構取而代之。

除了現有的REST、SOAP、MQ以及RCON之外,我們也計劃為ServiceStack加入更多的終結點。但由于我們采取了一種基于約定的方式,我們會避免使用繁重的配置。我們所采用的基于消息的設計方式會避免使用大型工具,并簡化必須實作的外部接口部分。首先從C#開始,逐漸移植其它語言,這使得終端使用者可以立即使用新功能,而無需任何額外的投入。我們的松耦合架構不存在統一的抽象模型,這可以允許我們加入互不沖突的新終結點與特性,而不會為現有的元件帶來強制的複雜性。

總而言之,我們提供了一個特性完整、性能更好并且更易于了解的服務架構,它的代碼庫也更加精益和靈活,并且使用它進行開發和維護所需的技術投入要小的多。

繁重的配置

WCF所推崇的另一個概念是XML配置,而這也是我們無法苟同的,它妨礙了測試,并且需要投入更多精力進行維護。隻有你的應用程式中真正可配置的部分才應該放在你的應用配置檔案中,定義及組織你的服務依賴應該交給代碼去做,這種方式的額外優點在于它便于調試,而且可以在編譯時靜态地進行驗證。WCF需要大量的配置,在ServiceStack中建立一個完整的應用程式所需的代碼量比起一個的WCF Service所需的XML WCF 配置還要小。如果把配置資訊放在IOC(控制反轉)這一怪,那代碼會更幹淨與整潔,因為它直接就可以引用你所需的特性的.NET API了。

大型工具

大型工具的問題在于,當你打算在其中嘗試些新功能,或者是某些不在其設計初衷裡的功能時,它就無能為力了。也就是說你成為了這個工具的奴隸,隻能提供一些它所支援的功能。而且架構一旦進行了重寫,大型工具就無法繼續使用,因為它們所提倡的繁重的、複雜的代碼庫是很難演化或者是重構的。我推測這就是微軟為什麼總是重寫新的服務架構,而不是改進現有的架構的原因。也是為什麼Web API不能夠重用MVC現有的抽象方式,并且不支援SOAP的緣故,盡管它們都采用了相同的RPC API設計方式,并且它的自托管功能選項也是基于WCF建立的。

由于ServiceStack是基于ASP.NET的最底層建立的,是以它提供了對ASP.NET MVC良好的內建能力,也能夠友善地重用MVC中許多元件現有的功能實作,例如Authentication filter attribute、Caching與Session provider等等。你也可以在MVC中友善地調用ServiceStack服務,比起C#方法直接調用隻是稍稍麻煩一點。

ServiceStack的複雜性

ServiceStack與WCF相反,它看起來要簡單許多。例如ServiceStack的架構隻要一頁紙就能畫下。啟用它隻需在web.config中加入一行,告訴ASP.NET将所有請求轉發給ServiceStack即可。

約定與人為的複雜性

ServiceStack與微軟開發類庫與架構所采用的方式,其觀念上的最大不同或許就是在如何最好地處理複雜性這一點上了。微軟傾向于明确性,XML方式的可配置能力,引入繁重的抽象層(為了前瞻性而支援所有潛在的用例),依賴于抽象層将簡單的面向使用者的門面經過改頭換面後暴露出去,為了友善使用設計器工具及新手開發者進行優化。微軟的主要動力是為開發者提供一個熟悉的程式設計模型,并且通過使用大型工具來簡化模型的上手難度。從WebForms中就可以看出這一點,它為WinForm開發者提供了一個基于事件的程式設計模型來開發網站,WCF則讓開發者使用傳統的C#方法與接口方式去建立遠端服務。它們采取的方式通常會導緻完成功能需要投入大量的技術精力去研究巨大的代碼庫。

與之相反,我們将大型的代碼庫當作代碼的最大敵人,并且避免引入人為的複雜性,這是我們的主要目标之一。比方說我們強烈反對引入新概念、抽象或程式設計模型。我們崇尚小巧的低級别接口,它與底層領域1對1進行映射,以實作靈活性的最大化,減少沖突,并且在需要進一步定制化時将轉換的複雜性降至最低。通過可重用的工具類與擴充方法保證了DRY與進階别的功能。我們采取一種代碼優先的開發模型,通過代碼去捕捉使用者意願的本質,這促進了一種更優雅、不妥協的設計方式,避免了使用設計器工具時所帶來的轉換的複雜性。我們的所有類庫都使用POCO,以獲得最大的可重用性,并且我們内置的轉換器可以簡化在領域特定模型中進行轉換所需的精力。

我們為使用者展現了一種基于消息設計的最佳實踐,為從頭開始開發的服務提供了一種最優的方式。服務就是普通的C#類,無需關注任何終結點的問題,因為這種依賴是可以自動解析的,這種方式會促使使用者采用良好的代碼實踐。

約定以及減少對外部知識的了解是我們處理複雜性最好的武器。相比明确的指定實作方式,更好的辦法是提供一個基于約定的預設行為,使它按預計的方式運作。這就讓使用者不必一定要學習你的架構API,因為我們可以假定預計的标準行為的結果,并允許我們随時提供更多的能力,比方說,它能夠自動支援外部所調用的所有内置終結點與格式。你也可以讓你的服務傳回任意的響應,它會自動序列化為所請求的Content-Type。

達成簡單性

我們相信,達成簡單性的最好方式就是在第一時間避免各種複雜性,我們采取了以下方式:

  • 去除了各種不必要的部分與堆積的抽象——而是直接基于ASP.NET基本的IHttpHandler接口所建立。
  • 約定勝于配置——所有實作了IService的服務都會被自動加載,并且随時使用。
  • 合理的預設表現——ServiceStack可直接被外部調用,無需進一步的配置。
  • 支援全部特性——所有内置的格式與終結點都預設可用,預定義的約定路由也自動可用,但也可以通過配置關掉它。
  • 自動探索——ServiceStack包含了一個中繼資料頁面,列舉了全部的服務、所處的路由、XSD及WSDL等等。
  • 未引入新的構造函數——ASP.NET開發者能夠立即了解如何定制化HTTP請求與響應。
  • 以C#語言開發——以C#語言開發,并且以無沖突的方式添加新特性,是以在普通的開發過程中就能夠立即應用這些新特性了。
  • 追求生産力——在ServiceStack中的每個請求DTO都必須是唯一的,它允許你在調用服務時隻提供請求DTO的名稱與内容就可以了。
  • 圍繞POCO開發功能——你可以在ServiceStack中使用同一個POCO作為DTO、OrmLite、Data Model、Cache、Session以及Config等等。
  • 使用基于消息的設計——比起RPC方法簽名,綁定至一個單一的模型更易于實作和推斷。
  • 靈活——提供一系列Custom Filter以及可以插入實作的事件鈎子,以此定制Request與Response管道中每一階段的行為。

避免大型工具與代碼生成

我們并不喜歡代碼生成,因為我們相信它為項目帶來了不必要的麻煩,我們也反對在開發工作的核心部分依賴于任何大型工具。

由于你的ServiceStack服務的服務契約在設計上是由你的請求與響應DTO維護的,我們就能夠提供一個類型化的端到端的API,隻需要你用來建立服務的那些類型以及那些通用的、可重用的.NET用戶端就可以了。這允許我們為任何.NET上的服務架構提供一個最簡潔的、類型化的以及端到端的API。

可測試性

基于WCF的設計方式以及它對配置的嚴重依賴,看起來WCF在設計時完全沒有考慮到可測試性。而這一點是ServiceStack的核心目标之一,我們預設提供了一個内置的(并且可重寫的)IOC容器,鼓勵在一開始就遵循良好的開發實踐。開發一個服務隻需實作一個不包括任何方法的IService接口,或者從其它現有的Service類、或ServiceBase類繼承即可,這些類都是可獨立測試的,并且完全可以mock。這一系列努力的成果就是,你所實作的單元測試可以用作XML、JSON、JSV以及SOAP的內建測試。我們所提供的自托管HttpListener類型使得進行記憶體中的內建測試非常友善。

性能

性能是ServiceStack的首要目标之一,我們将性能視為最重要的特性。基于消息的設計提倡更少的網絡調用,我們也很小心地保證隻暴露那些運作快速的面向使用者的API。一般情況下我們不接受來自外部的貢獻代碼,因為它們會包含速度較慢的代碼。我們對自己的實作是全力以赴的,我們沒有使用任何運作時的反射或者正規表達式比對,而是采用其它更快的解決方案。

最快的序列化格式

我們開發并維護着.NET上最快的JSON、JSV以及CSV文本序列化器,同時允許以插件的方式使用Message Pack與Protocol Buffers這兩個.NET上最快的二進制序列化器。

豐富的Caching Provider

由于緩存是建立高性能服務不可或缺的技術,我們提供了一個豐富的Caching Provider模型,包含了對各種記憶體緩存、Redis、Memcached、Azure以及Amazon背景的實作。緩存API會保證使用最優化的格式,比方說,如果用戶端支援,我們會将壓縮後的JSON輸出緩存起來,并在之後發生調用時直接将緩存中的内容輸出到響應流中,這就保證了托管代碼能産生最快的響應速度。

修複了.NET中的性能問題

每次我們找出微軟的類庫中的瓶頸時,我們都會使用更快速的實作去替代它。我們已經實作了自己的JSON序列化器,作為插件的Gzip和Deflate壓縮類庫,并且提供了自己的Session實作,它能夠與以上任意一種Caching provider相配合使用,它的出現也避免了困擾ASP.NET開發者已久的嚴重性能問題。

為最快的分布式NoSQL資料庫提供最好的用戶端

出于我們對開發高性能服務的技術追求,我們為最快的分布式NoSQL資料庫Redis開發并維護着一個.NET上最好的C# Redis用戶端。

time waits for no one

如果,您認為閱讀這篇部落格讓您有些收獲,不妨點選一下右下角的 【

推薦

】 按鈕。

因為,我的寫作熱情離不開您的肯定支援。

感謝您的閱讀,如果您對我的部落格所講述的内容有興趣,請繼續關注我的後續部落格。