2008年11月,我在博客園開通了我的賬號,並在博客園發表了本身的第一篇博客。固然,我寫博客也不是從2008年纔開始的,在更早時候,也在CSDN和系統分析員協會(以後名爲「希賽網」)我的空間發佈過一些與編程和開發相關的文章。從入行到如今,我至始至終樂於與網友分享本身的所學所得,但願會有更多的同我同樣的業內朋友可以在事業上取得成功,也算是爲咱們的軟件事業貢獻本身的一份力量吧,這也是我在博客園建博客時候的願景:專業、求是、解惑。所以,我在撰寫博客文章的時候,都是以客觀嚴謹的態度來闡述技術知識,並儘量地以更好的內容組織形式來提升文章的可讀性,同時儘量地回答網友的提問。有不少博客園的粉絲跟我提過意見,有的說個人博客更新太慢,也有的說我有些系列文章有爛尾現象,對於粉絲們的提問,我只有一個回答,那就是業餘時間太有限,我沒有辦法憑靠本身一我的的力量,在有限的業餘時間裏,在保證文章品質的前提下,爲社區提供愈來愈多的支持。在這一點上,我選擇的是寧缺毋濫:寧肯發佈週期變長,也不但願把沒有質量的文章分享出來。另外一方面,我也發佈了不少開源項目,有些項目屬於我本身一些我的小工具的代碼備份,也有一些項目,好比Apworks、Byteart Retail、WeText,甚至是個人新博客daxnet.me的源代碼項目daxnet-blog,都在個人Github Repo裏。說實話我真的沒有時間把每一個項目中的細節技術以博客的方式一一介紹清楚,所以,通常我基本完成了本身比較滿意的開源項目時,我都會寫一篇博客來介紹項目的內容和所使用的技術,同時引導讀者直接克隆個人項目代碼進行參閱,或者直接folk(不用太擔憂許可協議問題,除了Raspkate項目以外,其它絕大部分項目都是MIT或者Apache的許可協議)。總而言之,無論形式如何,我始終沒有放棄過最初的願景。前端
也是出於這樣的堅持,我但願可以更好地組織個人博客文章,甚至是其它的一些原創做品,以更爲集中和高效的方式爲讀者提供更好的學習交流體驗,一直以來我都想過搭建屬於本身的博客服務,我也通過了不少嘗試。早在2012年,我使用Word Press在一個國外站點創建過博客系統,但是後來由於國外服務供應商的緣由,網站沒能繼續維持下去,以後我也通過好幾回的嘗試,包括使用BlogEngine.NET等開源項目,但是也都沒能作好。出於對技術的熱衷與追求,這一次,我終於下定決心,使用本身所學的知識,依託微軟的.NET平臺,開發並部署了我本身的新博客系統:【http://daxnet.me】。git
首先簡要介紹一下目前的站點功能吧。右圖就是本站的主頁效果,我作得很簡潔,沒有用太多花哨的圖片,也沒有用走馬燈。明眼人一看就知道這是基於ASP.NET MVC而開發的Web應用程序,使用了Bootstrap。不錯,基本答對!須要強調的是,這個博客站點以及後端的RESTful服務,所有都是基於ASP.NET Core完成的,.NET Core運行時版本爲1.1.0,運行在Docker容器中。哎,說着說着又到技術上了,功能還沒介紹完呢。說到功能,目前功能很簡單:主頁列出了我本身原創或者翻譯的全部文章,讀者能夠註冊用戶賬號,註冊用戶能夠發表評論,也能夠在用戶管理頁面中更改本身的暱稱。好了,目前功能就這麼多,別看功能少,我但是前先後後陸陸續續花了2個月的時間,才作到目前這個樣子。固然,我會繼續更新這個站點,讓它的功能變得更加完善。github
提到ASP.NET Core,有沒有吊起你的技術胃口呢?不用着急,接下來我就介紹一下整個站點中各部分的技術選型,看完後,或許你會知道爲何我花了2個月的業餘時間,才整出來這麼個簡單的玩意兒。web
整個網站所採用的全部基礎設施所有運行在微軟雲(Windows Azure)中,使用了部分託管資源,以及一些非託管的Azure VM。大體狀況以下:算法
有人會問:爲何使用了非託管的Azure VM環境運行應用系統?我也考慮過這個問題,理論上講,基於雲的系統架構最好選用託管的PaaS服務,這樣不只能夠獲得純自然的高可用性(包括災備,好比AWS的跨AZ部署,某些服務跨區域的可用性,以及負載均衡),並且還能夠獲得專業的技術支持。只有當存在老系統向雲遷移的需求,並須要迎合老系統的特定運行環境要求時,才考慮使用IaaS服務。雖然虛擬機等這些資源是由Azure負責建立並運行的,在這一層面Azure能夠保證虛機的可用性,但虛機內部運行的任何程序的狀態,以及所使用的數據,Azure等雲服務是無從得知的,對這部分東西的監控也會變得很麻煩。出於安全考慮,一般雲服務供應商是不會,也不該該得到相似虛機內部的客戶程序的運行數據的,使用虛擬機服務所產生的程序運行風險,客戶須要本身承擔。這也就是著名的責任共擔原則。sql
看起來用虛擬機運行應用不是太靠譜嘛,然而我卻選擇這麼使用了。有幾個緣由:數據庫
理由夠充分吧?微軟Windows Azure提供的這些服務都很贊,我沒選不是說它們很差用,而是出於本身的實際狀況考慮:編程
OK,從總體架構上看,個人選擇便是如此而已,這樣的選擇固然不必定徹底正確,但我以爲至少合適,僅供參考。下面附上本站點的總體架構圖。後端
做幾點註解:緩存
接下來,回到代碼上,我向你們介紹一些框架的技術選型,以及幾個ASP.NET Core可用的開源庫項目。
現在的前端技術突飛猛進,各類Javascript的框架和JSX的技術,使得前端開發變得更加方便高效,所得到的用戶體驗也變得愈來愈好。例如Angular JS(包括1和2兩個版本)、React + Redux、Knockout.JS、Backbone等等。在實際項目中,咱們也運用了這其中絕大部分技術,然而,在個人這個博客系統中,我沒有使用單頁面應用的解決方案,而是繼續使用前端Razor+後端C#代碼的方式,對啦,這就是ASP.NET Core MVC!我沒有使用任何MVVM的框架,只是簡單地使用了Bootstrap和jQuery,對我來講,這樣選擇的緣由有如下幾個:
固然,爲了實現一些特定的功能,我仍是選用了一些開源代碼和框架,現給你們大體介紹一下。
首頁實現了博客文章的服務端分頁,每次僅向服務器請求有限量的數據。分頁控件是本身寫的一套算法實現的,並套用了Bootstrap的pager樣式,實現了響應式用戶體驗。分頁控件使用了ASP.NET Core MVC中新的Tag Helper技術,從算法上根據每頁的大小和總博客數量,對頁號進行分段處理,使得整個分頁功能有個很好的用戶體驗。
驗證碼的生成在經典的ASP.NET應用程序中可以很是容易地實現。經典ASP.NET應用程序基於Full .NET Framework,運行於Windows的IIS上,依賴於Windows的圖形庫,能夠很方便地產生圖片。然而,ASP.NET Core應用程序則徹底不一樣,爲了實現跨平臺,就沒法使用System.Drawing命名空間下的類型(固然你能夠指定你的ASP.NET Core應用程序使用net45,可是這樣沒法跨平臺)。在這裏我使用了CoreCompact.System.Drawing這個庫,能夠經過nuget搜索到 。它會依賴於Microsoft.Win32.Primitives庫,這個庫定義了一些與Drawing相關的數據結構,可是沒有提供任何圖形庫的實現。有興趣的讀者不妨一試。
沒什麼好說的,使用了著名的CKEditor做爲編輯器,固然,我選擇性地啓用/禁用了某些功能。
使用了著名的Alex Gorbatchev的SyntaxHighlighter,博客園也是使用的這個庫,不過我用的可能不是最新版本。
在每篇博客文章後面會顯示網友的回覆內容。這些內容會顯示回覆時間與當前時間的關係信息,好比:
上圖顯示這則回覆內容是發表於25天前的。可別小看了這個部分的實現,我是採用了一個叫作Humanizer的庫。這個庫頗有意思,它能提供一些很是實用的API,好比給它一個英文名詞,它能夠返回複數形式;給它一個日期,它能返回一個更貼近人類天然語言的表述。它還有不少其它的有趣的功能,你們能夠去了解一下。
博客系統支持使用Windows Live Writer發佈博客,它經過Shawn Wildermuth提供的WilderMinds.MetaWeblog實現了MetaWeblog API。經過Windows Live Writer能夠直接將站點添加到賬號中:
基本上前端所使用的一些技術和第三方框架就如上所述。下面來看看後臺的一些技術選型。
正如上所述,新博客系統後臺使用Azure SQL Database,也就是託管的SQL Server關係型數據庫。爲何選擇SQL Server而不選擇MongoDB等目前流行的NoSQL方案?做爲一個博客網站,我沒有找到選擇NoSQL的理由,Azure上也有託管的MongoDB服務,僅管它是委託由Bitnami負責運維的。另外一方面,雖然我選擇了Azure SQL Database,但我沒有使用任何第三方的數據訪問框架,沒有使用ORM,包括目前流行的Dapper。沒有選擇ORM的理由,一方面感受ORM在這個場景裏仍是過重,另外一方面,截止我進行技術選型時,Entity Framework Core沒法知足個人需求,至少它沒法從領域模型的角度去支持多對多的映射。那爲什麼又沒有選擇Dapper呢?主要緣由仍是同樣:沒法知足個人需求。原生的Dapper類庫須要寫一些SQL腳本,雖然輕量了,但失去了對代碼重構的支持,Dapper.Contrib增長了一些更友好的API,但仍然沒法知足本身的需求。
幾番思考,我決定本身寫一個小框架,既能夠支持本身定義的簡單領域模型,又能夠支持基於Lambda的語法、支持數據庫事務、支持異步API、支持多種類型的關係型數據庫。這個小框架的代碼位於DaxnetBlog.Common.Storage命名空間下,使用了一些很是巧妙的技巧,好比,開發者可使用Lambda表達式來定義查詢條件,框架會經過ExpressionVisitor(訪問者模式)將Lambda表達式轉換成SQL語句。下面的代碼正是這個框架的使用代碼:
var rowsAffected = await this.storage.ExecuteAsync(async (connection, transaction, cancellationToken) => { var account = (await this.accountStore.SelectAsync(connection, acct => acct.UserName == userName, transaction: transaction, cancellationToken: cancellationToken)).FirstOrDefault(); if (account == null) { throw new ServiceException(HttpStatusCode.NotFound, Reason.EntityNotFound, $"未能找到賬號名稱爲{userName}的用戶賬號。"); } account.DateLastLogin = DateTime.UtcNow; return await this.accountStore.UpdateAsync(account, connection, acct => acct.UserName == userName, new Expression<Func<Account, object>>[] { acct => acct.DateLastLogin }, transaction, cancellationToken); });
這段代碼用於更新指定賬號名稱的用戶的登陸時間,代碼中沒有穿插SQL語句,而是使用Lambda表達式進行表述。代碼中storage對象指代關係型數據庫的實體,而accountStore則表示對某種實體(在此處是賬號實體)的存儲,有點像領域驅動設計中的Repository的概念。這樣的設計是爲了實現職責分離:accountStore不會依賴於storage(也就是關係型數據庫類型)的實現。
不管是前端仍是後端,我都使用了Serilog做爲日誌框架,並將日誌推送到Seq系統。具體作法我會在另外的博客文章中詳細介紹,在此就很少介紹了。下圖就是本博客的日誌輸出,爲了省錢,在Docker容器啓動時,經過環境變量將日誌級別設置爲Warning。
很少說,Swagger。具體實現方式我也會在另外的文章中介紹。
暫時未使用緩存,下一步會增長。
好了,整個博客的架構以及先後端技術大概就介紹這麼多,若是要深刻技術實踐的每個細節,我想,估計幾個系列文章都講不完。仍是如本文最開始的時候所述,博客代碼開源,你們能夠學習交流。從此我仍然會爭取多寫一些文章來介紹相關技術。
固然會!博客園一直是我與你們交流的主要場所,未來也是。能夠理解,爲了向你們提供更多高質量的「乾貨」,博客園對博主們所發文章都會有一些限制,博客主題行文也會有一些約束。做爲我本人來講,在博客這種形式下,我或許應該能夠以更多的方式來表現個人技術生涯,甚至是本身的一些對生活中事物的思考,這或許對他人的技術發展也會是一種啓發,在得到你們的反饋和回覆之後,我也能繼續提升本身。與這些相關的內容,我會發表在本身的博客中,固然,我想,我本身的博客仍然會以技術類文章爲主吧。
目前這個新博客顯示了我曾經在博客園發表的博客(固然只是爲了充數,使得主頁不顯得那麼單調,全部圖片中仍是保留博客園的連接)。我打算給這個新博客定下三個月的試運營階段,這個過程準備考察一下系統的運行情況,並總結一下微軟Azure雲的使用心得,固然最重要的是衡量一下本身可否支付得起運營的這筆開銷。整個試運營階段我還會繼續往系統加入更多功能。
若是運營失敗,也請你們多多包涵,權當是我爲社區多貢獻了一個開源項目吧。
本文首先闡述了我對社區貢獻的一些實際狀況,並由此引出我本身全手工打造的基於ASP.NET Core實現的博客系統;接下來介紹了這個系統的總體架構和部署,以及先後端的一些技術選型;最後對你們可能提出的問題進行了簡要解答。立刻又要進入新的一年了,也快到了本身MVP Renew的時間,不管Renew是否成功(去年貢獻量感受不是過高),我仍將繼續堅持爲社區多作貢獻,真正作到「專業、求是、解惑」。