ASP.NET Linux部署(2) - MS Owin + WebApi + Mono + Jexus
本文承接我的上一篇博文: ASP.NET 5 Linux部署,那篇文章主要是針對最新的ASP.NET 5的,但在隨后的研究中,我對這種娛樂型的部署依然不是非常滿意,當然其主要原因是因為ASP.NET 5 依然處於RC版本,並不十分成熟. 但可以預見到的是,就算本月ASP.NET 5 RTM版本如期推出,其在Linux上面的開發和部署前景依然不是非常明朗: 特別令人困惑的是,MS在Linux上至今僅僅推出了幾個以開發為目的的簡單服務器實現,難以在其計划中尋覓到類似IIS的完整部署環境,那么所謂的ASP.NET 5的跨平台開發是否只能停留在實驗室水平? 目前乃至今后很長一段時間內(直到ASP.NET 5完全在Linux上站穩腳跟),我們有沒有更好的選擇?下面我將給出我自己的想法.
這里首先聲明一點,ASP.NET Linux部署系列僅針對Linux部署環境,不涉及Windows部署環境.下面還是先給出一些概念以便於大家更好的理解后續的內容.
ASP.NET |
ASP.NET是.NET Framework的一部分,是一項微軟公司的技術,是一種使嵌入網頁中的腳本可由因特網服務器執行的服務器端腳本技術, 本月即將發布的最新版本是版本5,又成為vNext. |
Linux |
Linux是一套免費使用和自由傳播的類Unix操作系統,是一個基於POSIX和UNIX的多用戶、多任務、支持多線程和多CPU的操作系統. 本文中的Linux主要以Ubuntu作為樣例. |
Mono |
mono是指由Novell公司(由Xamarin發起,並由Miguel de lcaza領導的,一個致力於開創.NET在Linux上使用的開源工程. 就目前而言,在Linux上的.NET應用還必須基於Mono來運行. |
Jexus |
Jexus 即 Jexus Web Server,簡稱JWS,是Linux平台上的一款ASP.NET WEB服務器,是目前唯一能夠支持企業級ASP.NET Linux部署的一種方案(其他的服務器方案無類似定位). |
OWIN |
OWIN在.NET Web Servers與Web Application之間定義了一套標准接口,OWIN的目標是用於解耦Web Server和Web Application。基於此標准,鼓勵開發者開發簡單、靈活的模塊,從而推進.NET Web Development開源生態系統的發展。 |
MS Owin |
微軟開發的基於OWIN規范的底層實現,最新版本是3.0.1,其主項目名稱為Kanata |
ASP.NET WebApi |
ASP.NET MVC 4 包含了 ASP.NET Web API, 這是一個創建可以連接包括瀏覽器、移動設備等多種客戶端的 Http 服務的新框架, ASP.NET Web API 也是構建 RESTful 服務的理想平台 |
RESTful |
一種軟件架構風格,設計風格而不是標准,只是提供了一組設計原則和約束條件。它主要用於客戶端和服務器交互類的軟件。基於這個風格設計的軟件可以更簡潔,更有層次,更易於實現緩存等機制。 |
NancyFx |
Nancy 是一個基於 .NET 和 Mono 平台用於構建輕量級基於 HTTP 的 Web 服務。基於 .NET 和 Mono 平台,框架的目標是保持盡可能多的方式,並提供一個super-duper-happy-path所有交互。官方網站 http://nancyfx.org/ |
三種選擇
就.NET路線的Web開發來看,不管何種方式,未來必然是基於OWIN開發的事實已經不可動搖了; 在這個基礎上, 我認為目前在Linux上開發並部署.NET Web應用程序有3個路線可以選擇:
- 底層Owin路線: 選擇MS的底層OWIN實現,配合其他基於OWIN的獨立組件,形成以底層OWIN為核心的自行搭配的輕型構架,這個方案目前已經可以完美部署到Jexus.
- 三方構架路線: 選擇同樣基於OWIN標准的,非MS的三方構架實現, 目前最有潛力,名氣最大的是NancyFx, Nancy框架目前也同樣能較好的部署到Jexus上去.
- 正統vNext路線: 選擇MS正統的下一代ASP.NET 5 (vNext),該版本的底層基於OWIN實現(注意任何老的ASP.NET版本都不是基於OWIN的), 可謂是親兒子; 但目前還沒有發布正式版本,其未來不可預期, 最關鍵的一點是,在Linux上,包括Jexus在內,目前依然沒有完美的基於商業環境的部署服務器環境支持.
就這3個方案而言,我覺得各有利弊: 底層方案需要更多的自行選擇和組裝,但是與任何基於Owin的組件搭配自如; 三方方案面臨生態環境的問題,由於大部分高端的組件都來自MS,能否真正無縫連接需要考驗,自身的生存能力也是問題; 正統方案內容完整,支持強大, 與MS各項技術融合度高,但卻面臨成熟周期問題(時不我待),另外我最不爽的一點是,vNext又一次搞成了鐵索連環船, 連WebApi都和MVC融合了,又給人一種整套推銷的感覺, 有違當初Owin體系的初衷;而最根本的問題是,目前還沒有任何方案給vNext提供一個Linux上的IIS級服務器,沒有好的載體,僅僅是把vNext的Linux部署定義為娛樂這個顯然看不出太大的誠意.
綜上,我目前還是傾向於使用底層Owin方案,目前商業化開發路線是: 基於MS Owin實現,根據需要加入各種MS穩定組件,比如Web API 2.2 OWIN 5.2.3, Identity Owin 2.2.1, SignalR OWIN 1.2.2, OAuth 3.0.1,和其他所有的通用型組件,如EF, Logging, IoC等等; 最終通過Mono和 Jexus架設到Linux環境.
下面我建一步演示如何組裝MS Owin和Web API 2.2, 並把它們部署到Jexus上去.
開發環境VS 2013, Window 7或 8; 部署環境Ubuntu 15.
第一步: 建立項目
首先,在VS 2103中建立一個Class Library項目,注意只要Library項目,這里可以選擇Framework 4.5.2或者4.5.1. 這個項目假設命名為OwinExample.
然后,我們加入這個項目必須的組件,根據上面的描述,我們需要2個組件: MS Owin的核心實現Microsoft Owin和ASP.NET WebApi 2.2 Owin
我們先加入Microsoft Owin
然后加入ASP.NET WebApi 2.2 Owin
第二步: 建立Owin入口代碼
首先,Owin的傳統入口類登場: Startup.cs
using Owin; using System.Web.Http; public class Startup { public void Configuration(IAppBuilder app) { #region WebApi var httpConfig = new HttpConfiguration(); httpConfig.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); //強制設定目前的WebApi返回格式為json httpConfig.Formatters.Remove(httpConfig.Formatters.XmlFormatter); //加載WebApi中間件 app.UseWebApi(httpConfig); #endregion } }
幾個要點:
l Startup中的Configuration寫成類成員方式,而不是靜態方式,是為了和Jexus適配器配合,其實差異不大.
l WebApi的配置寫法和MVC基本類似.
l Startup和Configuration的命名並不是固定的,只是預定俗成而已.
第三步: 建立WebApi代碼
建立DefaultController.cs 為一個默認的WebApi,里面包含一個最簡單的Hello函數.
using System.Web.Http; [AllowAnonymous] public class DefaultController : ApiController { [HttpGet] public string Hello() { return "Hello Owin!"; } }
自此,簡單的MS Owin + WebApi程序架設完畢. 在Owin體系下,我們發現一切都變得非常簡單和清晰.
第四步: 建立Jexus適配器代碼
為了把項目部署到Jexus上去,我們還需要一個非常簡單的適配器類,在項目中加入這個類以后,就能無縫部署到Jexus服務器上去了, 我們把這個代碼命名為Adapter.cs:
/************************************************************************************** * 加載Microsoft.Owin.dll 進行owin編譯的適配器(插件)示例 * ================================================================================== * 目的: * 演示如何將自己的處理方法(中間件)加入到 Microsoft.Owin.dll的處理環節中 * * 使用方法: * 將編譯得到的dll連同Owin.dll、Microsoft.Owin.dll等文件一並放置到網站的bin文件夾中 *************************************************************************************/ #region <USINGs> using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Owin.Builder; #endregion namespace OwinExample { public class Adapter { static Func<IDictionary<string, object>, Task> _owinApp; /// <summary> /// 默認構造函數 /// </summary> public Adapter() { //創建默認的AppBuilder var builder = new AppBuilder(); //創建用戶定義的 Startup類 //這個類中必須有“Configuration”方法 var startup = new Startup(); //調用Configuration方法,把自己的處理函數注冊到處理流程中 startup.Configuration(builder); //生成OWIN“入口”函數 _owinApp = builder.Build(); } /// <summary> /// *** JWS所需要的關鍵函數 *** /// <para>每個請求到來,JWS都把請求打包成字典,通過這個函數交給使用者</para> /// </summary> /// <param name="env">新請求的環境字典,具體內容參見OWIN標准</param> /// <returns>返回一個正在運行或已經完成的任務</returns> public Task OwinMain(IDictionary<string, object> env) { if (_owinApp == null) return null; // 將請求交給Microsoft.Owin對這個請求進行處理 //(你的處理方法已經在本類的構造函數中加入到它的處理序列中了) return _owinApp(env); } } }
這里再次感謝Jexus作者宇內流雲提供的代碼, 出於對原作者的敬意這個代碼除了命名空間以外我一個字母也沒有改,其實也不需要改. 其實大家可以看的出來,這么變態的注釋應該不是我故意去寫的.
自此我們的基於MS Owin和WebApi的迷你版應用開發完成,改為Release模式編譯,我們可以得到如下圖所示的一系列DLL:
就這些DLL就能形成一個WebApi應用嗎?事實就是如此,而且這個應用能很好的部署到Linux環境上去.
第五步: 安裝Jexus環境
這里先聲明下,基於個人的能力所限,只能先給出Ubuntu最新版本的一個部署方案,使用其他版本Linux的兄弟只能麻煩你們自尋門路了.
首先,我們再Ubuntu上面安裝Mono最新版本. 可以參考下面超鏈文章的指引:
http://www.linuxdot.net/bbsfile-3090
然后我們安裝Jexus最新版本. (同樣請參考下面的超鏈)
http://www.linuxdot.net/bbsfile-3500
第六步: 部署到Jexus
部署Jexus網站的常規指導信息,大家可以移步這里:
http://www.linuxdot.net/bbsfile-3084
下面說下我們的特殊部署步驟 (具體Linux命令我就不列舉了):
- 建立網站目錄 /var/www/owinexample, 然后在這個目錄下再建立一個bin目錄.
- 通過各種方式把上面自己開發產生的dll拷貝網站目錄的bin目錄下.
- 建立Jexus網站的配置文件,假設我們命名為 owinexample
其重要內容應該包括以下設置:
# For owinexample
port=88
root=/ /var/www/owinexample
hosts=* # or your.com,*.your.com
OwinMain=OwinExample.dll,OwinExample.Adapter
特別強調的是OwinMain這個必需配置,並且需要對應正確的DLL文件名和Apdater類. 根據前面的描述,我們可以知道我們應用的配置應該是OwinExample.dll, OwinExample.Adapter.
另外, Web.Config文件和其他任何文件在這種構架里面不是必須的.
- 重啟 Jexus 服務
- 打開你的瀏覽器,輸入 http://linuxserverip:88/api/default/hello 就可以看到結果.
注意linuxserverip為部署服務器的IP, 88為我們再Jexus配置中設置的端口, api/default/hello對應我們WebApi的路徑映射,Controller類名和方法名.
結束語
最后還是說下我們這種模式的優勢,劣勢和意義:
優勢: 基於Owin底層,簡單明了穩定,可以融合任何基於Owin的相關技術,擴展性強,可以和Mono, Jexus完美結合,性能最高.
劣勢: 相當於自行組建構架,搭建工作量大, 由於目前沒有獨立的MVC組件,在MVC開發方面缺乏支持(Nancy的一部分MVC構架比如Razor引擎可以獨立移入,但這個方案有待驗證).
這個方案的最終意義在於,結合目前.NET和Linux方向上最具備穩定性和代表性的MONO, MS Owin和 Jexus, 在ASP.NET vNext最終能完美部署到Linux之前,這是最接近於商業生產環境的方案之一.
最后拖一句,這個方案的開發環境可以考慮用TinyFox或者MS Owin Self Host來做宿主. 都可以無縫連接,代碼不需要修改.