2019年8月8日 星期四

自訂 Astah Professional 的 Templates Scripting Language

disclaimer

圖片取自:https://jstermask.github.io/anycode/index.html

前言

之前曾試用 Astah Community 就被其強大的功能所吸引,而且期繪製 UML 圖形的(方式/Style) 比較符合 UML OMG 官方組織的規範,即便在我已經慣用 EA 的情況下,我仍然有時候,有些圖形我會使用 Astah 來畫。


問題描述

因為 Astah 是由 Java 所開發,即便 (UML/Professional) 版本支援【Export C#】的 MDA (Model Driven Architecture) 功能,但匯出的 C# 檔案總是與 C# 3.0 之後的語言版本格格不入,因為熟悉 C# 的開發人員都知道,C# 的 get and set accessor 到了 C# 3.0 時代已經加入了 Auto-Properties 的功能,也就是說,我可以將原先比較囉嗦的寫法:

縮短改成如下,這叫做 Auto-Properties

但是,當我們使用 Astah Professional 所提供的 Export C# 功能時,如下 Class Diagram 中的 Account

在我們使用 Export C# 功能匯出 C# 程式碼時(如下視窗可讓我們自由選擇Class)

但美中不足的是,透過 Astah Professional 所產生的 C# Class 檔案中每一個 Properties 卻變成如下:

由此可見,Astah 對於 C# 的支援並不是那麼友善,又或者說,Astah 所支援的 C# 根本還停留在 C# 1.0 的年代,而且不光是 Astah 有這個問題,還有許多 UML Case Tool 對於 C# 語言的支援都不是那麼友善,包括 EA 也是,這我就不一一點名了。

對 C# 支援最完整的還是 Visual Studio 提供的塑模化 Modeling 的功能了,可惜的是官方到了 Visual Studio 2017 時就拿掉了 Modeling 的功能,理由是塑模化的功能很少人用,但這不能當作理由吧?XDDD 因為企業內部真正重要的事情往往在目前的商業議題不重要也無法立即賺到錢,但是往往這是比較重要的。

所幸,在 Astah 裡,不是沒有解決辦法,因為 Astah 所支援的擴充 Plug-In 功能非常強大,官網也提供不少可用的 Plug-In,這也是我從眾多 UML Case Tool 挑選 Astah 的主要原因之一。

因為現有的 Export C# 並無法滿足我們的需求,於是爬文後發現,其實 Astah 有一個 Plug-In名稱為 Any-Code-Generate

他由 jstermask 所開發,正確的來說並不是官方所開發的,AnyCode 的 Github 在這裡:https://github.com/jstermask/anycode ,這個 Plug-In 真正強大的地方在於它還支援一種 Template Scripting Language,它是一種很像 .NET 的 T4 Language 或 ASP 的腳本語言,透過 Scripting Language 你幾乎可以想要 Generate 什麼程式語言就可以產生什麼語言,可謂相當強大。

官方網站已經提供 Java/PHP.. 等語言的 Scripting Language 範本,但是就是沒有 C# 的….. 看樣子有在使用 UML 的還是以 Java 的開發者居多,從 20 年前就是如此,現在似乎也還是如此,這幾乎可以解釋為什麼大部分撰寫 Java 的程式員的系統分析設計的功力都比較好,這是真的是不爭的事實,但這與 Astah 支援 C# 不友善應該也沒有直接關係,這也是我一直以來注重 OOA/OOD 的原因之一,不過.. 當然這是老調重彈了。。。(順便工商服務一下:決戰 OOAD 系列課程-使用UML 線上版現正錄製中… XD)

原歸正傳,參照官方文件,建立【MyTemplate-name.mda】與【MyTemplate-content.mda】這兩個檔案後,

並設定好 Any-Code 的 Template directory 與 Target directory 後,如下圖:

接著,我們可以得到如下的 Java 程式碼:

我們看到,透過 Any-Code 所產生的 Java 程式碼非常的漂亮,這與內建的 Export Java 功能幾乎沒什麼不同,先撇開 Java 的 setter & getter 不說,我們希望有一個 C# 的 Scripting Language 樣板可以套用阿阿阿…. 結果我翻片了 Google 後,居然都沒有人有撰寫 for C# 的 Scripting Language 樣板,心想,不會吧?難道說,都沒有撰寫 C# 的開發人員再用 Astah?啥密?有沒有那麼誇張!?難道都沒有 MDA 的需求嗎?

事到如今,我們只好自己撰寫了,所幸 Scripting Language 也是使用 Java 的語法,本身並不太難,撰寫起來跟 JSP 有點像,於是,我將官網的 MyTemplate-name.mda 的內容副檔名改為 .cs,接著將【MyTemplate-content.mda】修改成如下:

因為大致看了一下語法後,認為不難理解,從程式碼當中,可以看的出來,沒有 <% %> 包起來的部分都是當成字串原封不動的輸出,第一行的 package TempPo.Web 就是 java 當中的 package 概念,而 getFullyQualifiedName() 這個方法應該就是將 Astah 中我們在 (Package/資料夾) 中的階層完整輸出而已,其實早期 UML 真的是 Support Java的,所以在 OMG 的規範下畫圖也都是以 Package 方式來切割 (這不是重點 XD)。所以,這邊對應到 .NET 是 using 的概念,所以我直接改程式。

再來,[<% def atts = c.attributes %>]這段明顯是在取出 Entity 所有的 Attributes,然後跑一段 foreach 將所有 Properties 秀出來,而 C# 的 Auto-Properties 就是在原有 PropertyName 後面接上 { get; set; } ,所以看起來也不難改對吧?

最後,我們來直接看結果好了,一樣執行 Any-Code 的 Generate 的結果我們成功的得到一個 C# 的 Class 如下:

結語:

在 Astah Professional 哩,透過 any<code/> Plug-in 幾乎可以滿足我們所有各種程式語言 MDA 的需求,不愧一套強大的 UML Case Tool。


參考資料:

http://astah.net/features/plugins

https://jstermask.github.io/anycode/index.html

http://astah.net/features/anycode-plugin

https://jstermask.github.io/anycode/documentation/templating-guide.html

https://astahblog.com/2013/02/07/astah_script_plugin/

http://www.runoob.com/java/java-string-substring.html

https://github.com/jstermask/anycode

2019年6月6日 星期四

您的軟體架構夠敏捷嗎?(二)- 持續演進的軟體架構


這次,於 2019/05/05 受新竹敏捷社群總舵主柯仁傑的邀請,在新竹敏捷社群我分享了一個關於 您的軟體架構夠敏捷嗎?的主題,在這個主題當中,我分享了我個人早期多年在專案開發上的系統設計相關經驗外,與最近這五年執行顧問時,替企業規畫與設計軟體架構相關經驗的分享,過程中,與觀眾有幾個共鳴點待我在下方娓娓道來。


軟體的快速交付≠有價值的交付

課程一開始,我提到了在十多年前,我曾待過一家軟體公司,在這個環境中我們嘗試創造出一個 0 缺陷的軟體架構,詳細的內容我在上一篇文章【敏捷的軟體架構設計:可擴展的軟體架構】裡有說明,這裡不再重述。

接著,我提到了現在也是開發流程+開發方法百花齊放的年代,只是 Agile/DevOps 特別為人所知而已,但在這個混亂的年代分常容易讓人無所適從,尤其時初學者,因為你所處的環境有可能已經追不上大環境中的變化與改變的速度了,但是你卻還是有很多東西要學,對吧?我的意思是,最讓人無所適從的倒不是技術的推層出新,慢慢的反而是到底是改怎麼做才是正確的?這部分我們以下在詳盡說明。

先前我曾聽過某大廠的 App 能夠在一天之內交付 20 ~ 30 次的版本,這對一家軟體公司來說,維運與開發之間必須非常的運作與整合完備情況下,再加上工具的熟悉度極高,才有可能將 CI/CD 持續整合+自動化部暑到如此境界,有許多軟體開發商無不卯足全力渴望達成此境界!但是據我所知,大部分大型購物網站、或者對外的訂票系統,事實上,他們在實務上只需要一天上一個至兩個版本便足夠了!如果您需要在一天之內上 20-30 次版的話,通常代表著您的開發流程可能是出了問題,比如:團隊與 User 可能存在著隔閡/開發人員或小組之間沒有共識+不清楚需求就冒然的修改程式碼… 等等。

我在這邊請大家思考另一個面向問題,就是,軟體公司究竟想要什麼?做專案+產品想要的是什麼?就是【獲利】!對吧?做這麼多,改變這麼多,去了解敏捷是什麼!最終目的,就是要賺錢,但是要賺錢,就得先思考如何【獲利】呢?因為你們在進行系統開發時一定常常遇到下面問題:

  • 測試總是花費許多時間?
  • 軟體的修改總是牽一髮動全身?
  • 無法掌控的技術債?失控的技術債?
  • 需求確定後,才可以開始寫程式?
  • 架構設計完成後?才可以開始寫程式?

對了,看到這裡答案就呼之欲出了,公司要賺錢,就是要將『成本』控制在範圍內,不然怎麼賺錢?


價值(Value) vs. 架構(Architecture)

圖(二)、不良的軟體架構就會像手銬一樣會限制住公司的發展

不過,目前許多大企業內部的現狀是,已經存在著許多高度耦合的遺留系統,而這些系統若又存在著不良的軟體架構的話,那麼,這些系統就會像【手銬】一樣,【限制】住公司的業務發展量,好一點的狀況就是拖慢開發速度+專案賠錢,比較不好的狀況就是甚至會【限制住】公司的發展。


你的軟體架構已經設計好了?

在傳統的瀑布式開發裡面,我們可能很常聽到 SD 跟 PG 說,我的架構已經設計好了,你們可以開始寫程式了!以現今的角度來看這其實有點詭異~ 怎麼說呢?如果您有真的認真地了解過敏捷,或者您有真的實行過敏捷,您應該會發現,什麼叫做好了?好了這件事情很弔詭,為什麼我這樣說?從下面兩個面向來看問題:

  • 要怎麼樣設計一種軟體架構來滿足使用者不斷變動的需求?
  • 如果在設計架構之前,就要了解所有的需求,那豈不是代表要先確定所有的需求?

先來看第 一個,本文的上方也有稍微提到,在軟體開發的現代,我們慢慢理解到了一件事情就是,你不可能完全的凍結需求,也就是不太可能凍結使用者的想法,因為有可能使用者沒想清楚、或者是你沒聽清楚但大方向的需求會不變,但需求的細節部分永遠都可能會變所以現今開發人員面臨的一個考驗就是,怎麼設計出一種架構可以滿足使用者不斷的變動的需求,這部分 Clean Architecture 的插件式軟體架構有可能可以解決這樣的問題,但是也別期望太高, 因為不可能 100%,甚至我們能做到 50% 就偷笑了,這我們留到下方的 #軟體架構如何敏捷 Topic 再來談。

再來第二個,傳統的瀑布式的軟體開發方法總是希望需求能夠確定,甚至希望使用者趕快畫押不要再改了,不管你用一種方式開發方法,若需求能固定對軟體開發來說都是好事,但由於這個機會實在非常的低,所以敏捷將專案切割成一個個小階段來進行(稱作Sprint/衝刺),每一個小階段都是增量的開發+大方向不變+透明化+減少浪費,透過每一個衝刺所需完成的代辦項目(PBI)並且,再透過價值來排立優先順序,因此在每一個小階段裡都可以完整地審視一下目前有什麼做錯的地方?優先順序有什麼需要改變的?什麼重要?什麼不重要?也就是說,在每一個小階段裡都是完整的系統分析=>設計=>撰寫程式=>測試=>上版 的完整流程,但是這裡我個人會比較建議採 TDD/ATDD 流程來進行。因為 TDD/ATDD 非常適合進行迭代的開發、尤其是敏捷,前一篇文章 敏捷的軟體架構設計:可擴展的軟體架構 中 也說明了『測試是迭代開發的最佳保護網』,因此 TDD/ATDD 剛好補足這一塊。

記得先前也在一篇文章『您的軟體架構夠敏捷嗎?』也有提到,敏捷與 TDD 之中,雖然不建議一開始就進行大量的分析,但是不代表完全不分析,我們期望實作一個可抽換的架構,而這個架構有可能都只是個 interface 定義而已,而且都還未實作。


軟體架構如何敏捷?

圖(三)、內聚性原則張力圖

OK!那麼,這個時候,其時才真正進入我們本篇的主題,到底?怎麼樣的軟體架構才能被稱作敏捷的軟體架構呢?我相信有些讀者應該也發現了,就是要確保我們目前所做出的是【正確】的軟體,什麼叫做正確的軟體?就是使用者需要的軟體,許多需求分析的工具像是五卡法、User Story Mapping 都可以幫助我們分析需求,但是要真正的釐清需求必須與使用者密切合作才會讓事情更順利許多,因為在敏捷理將業務與客戶均是團隊的成員,這樣做可以確保業務和研發一致加上有效率的敏捷。

然而,架構設計也是一樣,當軟體開發切割成一個個的小階段的時候,你除了必須以【價值】導向的方式來思考並排列在這個衝刺內每一個 Product Backlog,所需要的適應性(演進的/剛好夠用)的軟體架構應該是怎麼樣的?因為在敏捷裡,並沒有『架構師』這角色,因為在敏捷裡面,是由團隊來負責架構,所以我先前才說,敏捷是有一定門檻的。

由於,我們在每一個衝刺裡面,完成一個剛好夠用的架構,常見的設計技巧就是透過 interface 實作可抽換 (Inversion Of Control, IoC) 都是物件導向五大設計模式 SOLID 裡面的概念而已,我們利用介面 interface 來降低彼此的依賴,也利用介面來達到一定的可抽換性,我們希望軟體架構可以含括住需求,但是我們又不希望花太多時間在沒有價值的(功能/方法)上面,所以對外部,我們可能都只有先設計 interface 或 abstract class 而已,如下圖:

圖(四)、【軟體架構】&【使用者需求】的擴張


前面講了這麼多,下面我們來看一個實際的例子。


實務案例:
一個 ATM 自動櫃員機的需求

需求描述:
身為貴銀行的顧客,我可以在各分行的行庫的提款機提取現金。

我只需要插入提款卡,輸入密碼進行身分驗證後,就可以提領現金。


這個需求的 Use Case 分析如下:

Use Case 可當作我們在這裡進行 Domain Modeling 分析時的進入點,如果您使用 DDD (Domain Driven Development) 開發方式時,也可從這裡做為分析的起點。但這邊我嘗試以 OODA 分析來驅動 Domain Modeling 的分析,當我們可以進入 TDD 開發方式時,表示我必須找出我的 Domain Model 與 Target 的 Class,這個 Class 怎麼來的?當然是分析來的,絕對不是隨便找一個,然後事後不斷的 Refactor 系統就會是使用者所想要的系統。

這邊,我們簡單的用五卡法進行分析,因為需求如上方的需求描述裡面所提的,加上 Use Case 分析也完成了,這邊我使用 CARD Board 線上的 User Story Mapping 服務來繪製 User Story Mapping。

有了 User Story 接著團隊就有 Release 的項目(包括:Features/Functional),喔!對了,前面忘了提到,也因為敏捷的思想幾乎改變了軟體開發對於【交付階段】的看法,這個概念也來自【建構微服務】這一本書,系統一開始的建置應該就要考量到【部署】這件事情會更全面,服務本身的(顆粒度/細粒化)也都與容不容易擴展有著密切關係,軟體開發做到最後你會發現,每樣都是相輔相成 + 一環扣一環,一樣都少不了…阿~ 扯遠了…. 我們回頭過來看 User Story,經由 User Story 與 Use Case Diagram 分析可以得到下面的 Domain Conceptual Modeling 概念圖。

註:上方圖形所使用的技巧為 UML 當中透過 Use Case 加上基本的名詞分析法找出的領域模型(Domain Class Diagram),詳細實行方式可參考筆者以前的文章:Visual Studio 2010 塑模化應用程式分析(六)

不過目前的 Domain Conceptual Modeling 還非常不完整對吧?這表示我們 Catch 到的內容無法滿足一個概念的(完整性/可用性),這我在【決戰 OOAD 系列課程】中有說明過。那怎麼辦呢?應該與 Product Owner 討論,釐清,這裡我們假設擁有提款卡的客戶應該是有開戶的顧客,有開戶的顧客,才可以在這個銀行中提領現金,所以有開戶也代表有帳戶,這邊我用【存戶】來表示。

所以,這個時候,我們的 Domain Conceptual Modeling 會更趨於完整。

這裡,我們要先產生可以測試的 Test Case,這裡須來自顧客可以提領現金這件事,而這件事也衍伸並分析出包含了【插入提款卡】、【輸入密碼】、【提領現金】這三件事,輸入密碼執行的是『身分驗證』,稍後補上 Sequences Diagram。

在來,我們有顧客,有帳戶、有存戶、顧客必須先行登入+驗證後,方可提領現金,這些都弄清楚了之後,我們就可以分析並產出下面的 Class Diagram 了。

待續… 實在太長,寫不完 XDDD

下一次,我會將上述的 (interface /領域物件)使用 Sequence Diagram 進行分析後,再使用 EA 的 Generate Code 將介面產生到 Visual Studio 2019 環境之中,實作 Target Class 後,就可以進入 TDD 撰寫紅燈測試了。

2019年4月22日 星期一

敏捷的軟體架構設計:可擴展的軟體架構

敏捷底下的軟體架構

圖片取自:http://m.001zf.com/newshow.php?itemid=696

前一篇,我分享了您的軟體架構夠敏捷嗎?而我寫過許多關於架構設計的相關文章,但今天這一篇,可能是最難寫的一篇?因為,在(確定的需求/沒有 Deadline 的時間壓力下),寫程式並不件難事,對吧?那麼真正難的在哪裡?真正難的是在,有限的時間 與 資源內,發展出(符合客戶需要/為客戶產生價值)的商用軟體,且這個軟體須具備一定的可延展性、擴充性、可維護性,並在企業的可控制的成本範圍內,或者,在敏捷的每一個迭代開發裡,逐漸發展成為客戶所需要的軟體,對吧?軟體公司為企業創造與量身訂做軟體也是為了賺錢,若軟體開發所投注的成本成為無限的話,虧本的生意沒有人會想做的。


傳統的軟體開發產生的架構問題

圖(一)、傳統軟體開發的前身 SDLC (Software/System Development Life Cycle)

SDLC 是早期用以描述一個資訊系統,從無開始規劃、分析、建立、測試、直到最終完成的一個過程。看似無任何問題,事實上,它也運作了幾十年,似乎也確實沒有任何問題,許多團隊也是能夠創造與交付出符合客戶需求的軟體,可是,慢慢的,許多團隊與軟體公司漸漸地發現,當需求變動性高、需求不確定因素高的時候、或者在許多實際的市場機制下,軟體的『開發』與『發展』逐漸與慢慢地跟不上時代的演進 與 市場的變化了。這怎麼說呢?因為當不了解需求、不了解客戶想要的價值時,你所花的(工/成本)絕大部分是浪費的,因為軟體開發越到後期修復的成本是越高的。

以傳統瀑布式開發來說,我得先做完需求分析、才可進行系統的設計,而當系統設計完成後、才可開始進行系統的(程式碼撰寫/Implementation/實作),但問題來了,什麼叫做【系統設計完成】?難道我得在一開始,弄清楚客戶的所有需求?因為系統設計完成、也代表架構設計完成了?如果軟體架構可以在程式碼撰寫前就確定,這不就代表需求必須固定?問題是…. 這是不可能的….. 這其實是一個【雞生蛋、蛋生雞的問題】

圖(二)、雞生蛋、還是蛋生雞?


0 缺陷的架構 = 0 擴展的軟體架構

在早期,曾經有團隊/軟體公司 將所有功能均提供在軟體產品裡,也就是大雜燴的方式,嘗試滿足市場各種不同的需求,筆者很早期待過的軟體公司也還真的經歷過這樣的模式,而在當時,筆者也還真的認定為,這是理所當然的,因為這麼一來,我們的軟體架構只需要被設計一次,如果我們能涵蓋市場裡 70% 的客戶的需求,而我們也能夠接下這些客戶,而不費吹灰之力,就能快速的開發出客戶所需的軟體,因為我們只是把開發好的眾多的模組(Module/Functions)、根據同一個 Domain Known-how 所可能會需要的功能,都加以開發好,並分門別類。再透過抽換、或抽離,客製成目前這個客戶所需的一個軟體。

這樣的方式看似很美好,但是事實上淺藏極大的架構問題,為什麼我這麼說呢?

(1). 使用單一功能滿足所有企業的使用者難以永久滿足… (因為總是會有需要客製的部分)

(2). 功能一定會微調、若為此開立分支(Version Control)將產生另一個災難

(3). 客戶一多,表示你的功能分支越多、這又會產生另一個災難

(4). 軟體架構因為為滿足 A 客戶的某 Function ==> 而導致 B 客戶另一個 Function 失敗

(5). 疊床架屋的軟體終究越來越龐大、每修正一個 Function 或是 擴增一個 Function 都會是一個耗時耗力的過程

(6). 更不用說測試了….

…. 還有說不完的問題…..


軟體架構應該要可以逐步的發展

圖(三)、Implementing Lean Software Development: From Concept to cash

再近代的軟體開發理論裡,包括在『Implementing Lean Software Development: From Concept to cash』的書中,都提到了應該不需要等到軟體架構都完全確定後,才可以開始撰寫程式。且實際的軟體開發中,筆者最近2-3年來實做專案時,嘗試以敏捷方法與迭代方式進行專案的開發,不過筆者以 OOAD/UML 來驅動 Domain Model 的設計,以 Use Case Model 來確定需求的 boundary,但我是搭配 User Story Mapping ,就是用一種方法,一種如何將你最後產出的『用戶活動 (User Activity)』與 最後更加細節的『用戶故事 (User Story)』推展至 Use Case 中,但我不是完全的設計,有些朋友看見 UML 後就會認為會花費許多時間在做文件,其實事實上,我通常只需要半小時就可以畫出一個三角關係的 UML 圖形,只是這個圖形必須夠抽象。有興趣的讀者可參考我另一篇文章『決戰 OOAD 系列(一):使用 UML 分析的黃金三角』,並結合 Clean Architecture 的插件式軟件架構,逐步展現出架構的全貌。詳細關於 Clean Architecture 在實務上的例子,可以參考筆者先前的文章:『從使用者需求、談架構設計(二)- Clean Architecture 一個整潔的架構篇』。

傳統的瀑布式 Waterfall 為人所詬病的就是,當你確定完需求、開始做系統設計、接著開始實作 Programming 時,而這時候,往往已經過度設計了。


測試是迭代開發的最佳保護網

在 『Specification by Example中文版:團隊如何交付正確的軟體』一書中提到,因為敏捷的思想,幾乎改變了整個軟體開發對於【交付階段】的看法,因為我們不可能凍結『變化』、市場隨時會改變,透過『迭代』為基礎,使的 Spec 的實例化變得可行,而且可獲得極大好處,加上將軟體開發切割成多個衝刺(Sprint),要在每一個極短的衝刺時間內、 完成一個交付階段 (MVP, Minimum Viable Product),每一個衝刺所需要完成的代辦項目(PBI)得透過價值來排列優先順序、並消除常見的重工 (Rework) 的問題=漸少浪費,這與先前提到的 Clean Architecture (插件式設計) 避免過度的設計也完全的相互輝映(避免更多浪費與技術債),從價值來決定軟體 Scope 規模。


TDD/ATDD

而然而,這樣就夠了嗎?在極短的時間內交付 MVP 增量開發+根據功能設計勘用與可擴展的軟體架構時,若沒有測試的保護,軟體開發仍然存在極大的風險,即便是敏捷開發也一樣,沒有撰寫測試的軟體,除了測試成本無法降低外,也代表著系統物件的職責容易牽扯在一起,也表示容易設計出系統複雜高的軟體架構,複雜度高也導致軟體不容易維護。所以,結合 TDD 與 ATDD 的開發方法會是迭代開發中,最佳的保護網。

待續…

2019年4月10日 星期三

ASP.NET Blazor 怎麼處理狀態?(二)- 保存預設範本的 Count 值

前言

上一次的文章【ASP.NET Blazor 怎麼處裡狀態?】中,筆者說明了幾種在 Blazor 上保存狀態的常見用法,但是當時筆者無法在 [YourProjectName].Client 的專案裡安裝『Microsoft.AspNetCore.Http』、『Microsoft.AspNetCore.Http.Abstractions』、『Microsoft.AspNetCore.Http.Feature』這三個套件 均無法安裝成功,後來我發現,無法成功是正常的,這因為 [YourProjectName].Client 是執行在 browser 的沙箱(Sand box)裡面,試想,這三個套件都是相依於在沙箱裡,而這個沙箱內又以 Mono Runtime 來執行 .NET Standard,如果 .NET Standard 本身不支援那個 API 也無法執行對吧?更何況又在 browser 的沙箱環境中。這更不用說 Microsoft.AspNetCore.Http.Abstractions 裡還參照了在 Mono Runtime 裡不支援的 advapi32.dll & kernal32.dll 等

就算技術上可行,安全性其實也不允許你在沙箱內部存取外部 OS 資源。

也就是說,上次的那個作法是錯誤的,我們根本就不應該在 [YourProjectName].Client 裡面安裝那三個套件,應該回頭過來思考,我今天的需求是,要從 browser 將 COUNT 內容傳遞到 Server 上,並保存下來!也就是說,我們應該將 [YourProjectName].Client 這樣的專案當作是一個執行在前端browser 中包含 Front-End Framework 的 SPA 應用程式,這麼一來,是不是就清楚多了?因為 Client 是執行在 Browser 中,若不是 Blazor ,傳統 SPA 作法也是透過 JavaScript 執行 Ajax 的 Call Back 呼叫,將 Count 傳遞至 Web Server 上保存下來對吧?所以,Blazor 也會是相同的做法。


專案結構


正確做法是什麼?

(1). WebBlazorStateTest1.Client 的 Counter.cshtml

在 Counter.cshtml 裡,透過 view inject 注入 HttpClient 來撰寫呼叫 Web API 傳遞 currentCount 到後端並保存下來,由於程式碼非常簡單就不多做說明了。


(2). 啟用 MemoryCache


(3). 在 WebBlazorStateTest1.Server 的 SampleDataController 裡增加兩個 API 方法


接著,我們可以在 Counter 頁面得到保存 Count 數的效果如下圖:


但是,這時,如果開另外一個 browser 的話,別的使用者也會看見這個 Count 數,也就是說,它就像個 static 變數一樣,等於是共想於所有使用者,這似乎不是我們想要的,如果我們要每個人可以保存、並有自己的 Count 數值該怎麼做呢?

其實,最簡單的方式,就是用 Session,或者,在 Cache 的 Key 加上 By 登入的 User 的 userId 唯一值,像是 (”_user_id_xxxx”+”_COUNT”)使不同使用者不會重複即可,並將 Session 的 Provider 導向 Redis,以便適用 (Scale-Out/Load Balance )環境中,達到 狀態共享/高效能。


ASP.NET Blazor 系列文章導讀

(一)、ASP.NET Blazor 關鍵報告

(二)、Blazor 怎麼處裡狀態?

(三)、Blazor 怎麼處裡狀態?【保存預設範本的 Count 值】

(四)、Blazor 的 CRUD 應用程式 – Use Entity Framework Core

(五)、Blazor 如何使用自定義的 ApiHostBase?【接續 Clean Architecture 的 API 框架設計 (1)】

(六)、Blazor 如何使用自定義的 ApiHostBase?【接續 Clean Architecture 的 API 框架設計 (2)】

(七)、… 還在想 XDD

什麼是 gRPC(二)- 來撰寫第一個 Hello World 吧!

前言

上一篇 什麼是 gRPC,筆者大致介紹了 gRPC Service 的基本概念,這一次,我們就來小試一下身手,撰寫一個 Hello World (迷之音:嘗試新技術時,總是得先來一個 Hello World ~我不想違背這良好傳統阿阿阿阿)


使用環境

  • Visual Studio 2019
  • .NET Core 3.0.100-preview3-010431


開始進行

撰寫 gRPC 除了先準備好基礎環境、選定一種 作業系統/ 程式語言 Language 外、(Framework/SDK/Runtime)等環境備妥後,就可以開始撰寫,

(1). 開始撰寫 gRPC 第一步就是先定義 .proto 協議了

上一篇筆者提到,gRPC 的 Server 與 Client 必須使用相同的協議才可進行溝通,一般來說,你應該使用 protoc.exe 編譯器先行編譯過 greet.proto 協議檔,並產出 C# 程式碼檔案後才可繼續,而在 Visual Studio 2019 裡,拜 MSBuild 之賜,已經有人預先寫好 .Target 檔案了 (什麼是 MSBuild?什麼是附檔名 .Target 檔案可參考:MSBuild .targets 檔案

筆者先撰寫一個 SayHelloWorld 方法如下:

在協議裡,除了在 service Class 撰寫要公開存取的方法外,必須在提供『傳入訊息型態』、『回傳訊息型態』,這邊我先定義兩個 message,一個是『HelloMyFirstgRPC』、另一個是『HelloMyReply

在撰寫 proto 協議檔時,建議先決定 message 回傳型態與傳入的型態,那麼 Visual Studio 2019 會有 InteillSense 的完整支援。不得不說 Visual Studio 2019 在 .proto 協議編輯上的支援已經算不錯了。

注意:
一般來說,Visual Studio 2019 會在背景裡自動編譯 .proto 協議檔案,但始有可能不會有任何提示,所以您也可以自行使用命令列工具進行手動編譯,如下圖,若編譯失敗會出現錯誤訊息,如下圖顯示 return 關鍵字錯誤:

protoc.exe 編譯器 & 相關 MSBuild Tools 會隨著 NuGet 套件在 Visual Studio 2019 進行自動還原的時候,安裝在你的 User Profile 的 .nuget 快取路徑下:C:\Users\Gelis\.nuget\packages\grpc.tools\1.19.0-pre1

我目前安裝的是 preview 1

我的完整的 protoc.exe 編譯器路徑是:"C:\Users\Gelis\.nuget\packages\grpc.tools\1.19.0-pre1\tools\windows_x64\protoc.exe"

而手動進編譯成功的情況如下:


(2). 撰寫 C# 的伺服器方法

完成 .proto 協議之後,沒有實際的 C# 伺服器方法,程式還是跑不起來的,所以我們必須在 GreeterService.cs 裡,加入一個 SayHelloworld 方法,如下:



(3). 撰寫 Client

完成 Server 端的伺服器方法後,當然就是接著住撰寫 Client 呼叫的程式碼了,Visual Studio 2019 在這裡都有完整的 InteillSense 的支援,不得不再說一次 XD,實在太棒了!

最後,完成的 Client 完整程式碼如下:

如上程式碼,由於是拿 Visual Studio 2019 內建範本來練習,紅色部分是增加的部分。在呼叫遠端方法時,建立 HelloMyFirstgRPC() 類別時,我們傳入的 UserName 就是我們在 greet.proto 協議中所定義的回傳 message 中,我們自己給的,還記得嗎?

到這裡,基本上就完成了。


(4). 測試程式

我們先將 Server 執行起來,再到 "bin\Debug\netcoreapp3.0" 路徑下,執行 "gRPCServer.Client.exe" ,如果沒有任何意外,應該可以將 UserName 傳入至 Server 中,由 Server 的伺服器端方法重新組字串 "test My gRPC"+UserName 並回傳至 Client 的 .NET Core 3.0 的 Console App 並秀出結果 。

執行結果如下:

程式也如預期般運作,如何?是不是非常的容易?


後記:

這雖然不是非常新的協定,目前開發上仍然不是那麼普及,不過在某些大型企業內部已經高效運轉中,雖然的的優勢就是在成為標準之前就已經在許多實務上經過許多考驗,但是面對許多各種(協定/標準)的競爭下,會不會脫穎而出還有待觀察。