快速了解 ASP.NET 5 與 MVC 6 懶人包系列 (一)

這次釋出的 Visual Studio 2015 還是有許多讓人驚豔的地方,我想讓微軟開發人員覺得變動最大的莫過於就是 Open Sources 與 跨平台了 這兩個部分。剛開始可能無法接受,但最後你可能也只能擁抱這樣的改變,其實多了解現在 Open Source 的市場大家都在玩些什麼?這對開發人員,不失為一件好事,因為這樣你會學得更多,會覺得,世界真的很寬廣。然後到最後你會發現,其實 Open Source 才是最大的市場。

前言

前一陣子,大約半年前,隨著微軟在 ASP.NET vNext 中,預告了未來會擁抱開放式平台,且 ASP.NET 並邁向真正的跨平台。直到最近 Visual Studio 2015 Preview/CTP 的推出,隨著推出的 ASP.NET 5 造成了一些小轟動,因為在 ASP.NET 5 不光只是專案結構上的改變,也是架構上的改變,比如(開放、跨平台),如果你真的想讓你的應用程式走向真正的跨平台,那麼您一定要了解什麼是 ASP.NET 5 ,以及他的目標是什麼?

 

全新平台 Visual Studio 2015

目前你可以下載 Visual Studio 2015 CTP 5 來體驗 ASP.MVC 6 與整個 IDE 工具在開發發環境上的增強,其中一個亮點就是 Timeline Tool (時間軸工具)。Timeline Tool 讓你在 Visual Studio 2015 中,執行你的應用程式時,輕易掌握住你的應用程式的 CPU使用量、磁碟使用量 (I/O)、網路使用量 等等,如果你應用程式是 WinForm 或 WPF 應用程式的話、甚至可以監控的你應用程式的 UI Thread 的使情況。

 

要使用 Timeline Tool 可以在 Visual Studio 2015 選單選擇 Analyze –>  Start Diagnotis tools without debugging 先會出現如下畫面讓您選擇要進行分析的目標、可使用的分析工具等,如下:

image

Timeline Tool 目前並不支援 Web 專案,所以你如果在 Change Target 的地方,選擇 ASP.NET 類型的專案

SNAGHTML7add3f

那麼你就只剩下 Network 與 Performance Wizard 兩個可以選擇。另外,他也不是只能針對開啟的專案才可以進行分析,它甚至可以對已經安裝在你系統裡的 Store App ,或是在執行的 Store App 進行分析。

如下、選擇安裝的 App 畫面:

SNAGHTML7cfd6f

Timeline 分析畫面如下:

image

 

再來就是 Diagnostics Tools (偵錯工具),在 Visual Studio 2015 CTP 5 中,只要按下 F5 執行你的應用程式,就會出現新的 Diagnostics Tools (偵錯工具),

  • 它可以和 IntellTrace 搭配使用

也就是說,你可以在 IntellTrace 的模式下,同步查看 Diagnostics Tools 視窗。

  • Memory Usage (記憶體使用量)

你可以在偵錯時,監控你應用程式內部記憶體的使用量,是否有 Memory Leaks 的情況,甚至是 Dump Memory 下來,這些在以前都是得要依靠另外安裝 Microsoft Debug Tools 才做得到的,現在都在 Visual Studio 中就提供這些功能。

  • CPU Usage (CPU 使用量)

同樣的,透過這個工具,可以允許您以圖形化的方式查看你每一行 Code 所使用到的 CPU 資源。甚至單步執行,查看你每一行程式碼的Total CPU (%) 使用百分比,或是 CPU 花費時間 Total CPU (ms)。

image

圖片取自 http://blogs.msdn.com/b/visualstudioalm/archive/2015/01/16/diagnostic-tools-debugger-window-in-visual-studio-2015.aspx

 

為什麼要重新設計 ASP.NET?

之所以會重新設計 ASP.NET 是因為這麼多年以來,.NET Framework 不斷地一直增加功能,而許多應用程式不見得都會使用到 .NET Framework 的所有功能,而且目前的設計似乎如果要使用.NET Framework 來撰寫、或是執行 ASP.NET 的應用程式時,就得在系統中安裝.NET Framework,微軟認為,未來,如果開放會是主流,那麼 .NET Framework 也不該與作業系統綁得太緊,更不應該內建在 Windows 裡,也就是說 .NET Framework 如果要成為開放式的執行環境,那麼他得先 Open Source,先 Open Source 才能來談要達到真正的跨平台,因為除了執行在 Windows 外,也要可以執行在 Unix、Linux、MAC OS、Mobile 平台,或是輕易地放置到雲端,或是其他你想的到的作業系統,如果要做到這樣,那 .NET Framework 就應該要可以很易於被安裝。

 

註:因為擔心先前筆者上方文章誤導讀者以為 .NET Core 得先 Open Source 才能跨平台,因此在這加上註解,一般來說 .NET Core 就算沒有 Open Source 一樣可做到跨平台,所以跨平台與 Open Source 是兩件事情,而微軟先跨平台是因為這樣才能吸引其他平台的高手進來,這麼一來,就更有機會移植到各種 Devices 中。

 

基於這些因素,因此微軟重新設計 ASP.NET,並稱為第 5 版的 ASP.NET 5,其他的修改如下:

  • 沒有 GAC 了,因為其他作業系統不會有這個機制,也不該因為這個機制限制了 .NET Framework 的擴展、跨平台能力
  • 因此是真正的跨平台
  • 移除掉原本與Windows & IIS 綁的太緊的組件 (如:System.Web、System.Draw、System.InterOp 等)
  • 組件都可以抽換,應用程式可以安裝自己有使用到的 .NET Framework 就可以了
  • 易於在雲端上擴展、甚至針對雲端最佳化 (.NET Core)
  • Run Any Host, Any Platform
  • 稱為 ASP.NET 5,而 ASP.NET 5 內部使用 DI 相依性注入的方式,有使用到的功能才放進來 (連 MVC 本身也都是被注入進來的)
  • 改進了 ASP.NET 的管線模式,原本依據 Request 選擇對應 Filter 來執行,現在只有有安裝進來的管線才會被執行 (完全支援 OWIN)
  • 使用新的 Roslyn (羅斯林) 編譯器,在 Visual Studio 下,自動在背景編譯完成,你只要刷新瀏覽器
  • 走向開源 (Open Source)
  • 為了吸引開源 Open Source 的開發者,因此引進 Bower & Grunt

 

ASP.NET 5 跟 MVC 6 有什麼關係?

所謂的 ASP.NET 5 就是 ASP.NET 的下一版,為什麼這這樣說呢?這要要從 ASP.NET 的歷史開始說起,從.NET Framework 1.0 在 2002 推出時,當時稱為 ASP.NET 1.0,所以目前的 .NET Framework 4.51 所以目前的 ASP.NET 可稱為是 ASP.NET 4.51,他後面的版號其實是跟著 .NET Framework 版本編號走的,因此下一版本的 ASP.NET 微軟就為 ASP.NET 5 。

 

在 ASP.NET 5 中,他已經與原本的 ASP.NET 並不相容,就如同上方所提的改進,且目前在 ASP.NET 5 中只有 MVC 6 的框架,所以目前的 ASP.NET 5 即等於一個新的 MVC 6 框架。在這個框架中目前也還不支援 WebForm 的框架 (未來應該會放置進來,不過與 System.Web 綁得太死的 WebControl 有可能會被移除),因為就算是 MVC 它的要求 (Request) 管線模式也不相容於先前的 ASP.NET MVC 5。但原先的 ASP.NET MVC 5 都可以直接運作在 .NET Full CLR 之中,不需要考慮升級的問題。但注意喔,是 Full .NET CLR,不是真正跨平台的 Core CLR 喔,待會會解釋他們之間的不一樣。

 

所以 ASP.NET 5 是一種開發、執行模型的轉變 (目前是 CTP Community Technical Preview 社群預覽版)

 

ASP.NET 5 的專案結構

有安裝 Visual Studio 2015 CTP 的朋友應該就會發現 ASP.NET 5 的專案結構很不一樣,原本你所熟悉的 web.config 不見了,當然有其他取而代之的項目 project.json & config.json,這是為了支援目前廣泛的 Open Source 的作法。

 

下圖為一個 ASP.NET 5 的專案結構:

image

這個專案檔附檔名改用 *.kproj,在這新結構中,新增了如下項目:

  • Dependency
    • NPM

NPM 是 (Node Package Manager) 的縮寫,這是 Node.js 的套件管理員,如果你是前端工程師應該很熟悉這個東西,因為 bower & grunt 得透過它來進行打包與安裝前端 CSS 與 JS 檔案的作業。

    • Bower

管理前端套件的設定檔案,詳細的可參考下面 整合 Bower 與 Grunt 說明。

  • wwwroot

存放所有網站使用到的靜態檔案,如:圖片、CSS、JavaScript 檔案,要改放置在這裡,這解決了以往程式檔案與靜態檔案放在一起的問題。

  • References

原本的 NuGet 也還是存在,但改由 project.json 管理套件相依性。所以原本的 Reference 視窗在 ASP.NET 5 的專案結構中不能使用。

  • bower.json & gruntfile.json

可參考下方關於 『整合 Bower 與 Grunt』章節。

  • project.json

在 ASP.NET 5 裡主要以 project.json & config.json 來取代 web.config,只不過 project.json 是定義專案使用到的組件相依姓,所以原本在 Reference 視窗裡做的事情,改由在 project.json 裡定義,所以並不表示就不需要 NuGet 了,因為實際的組件還是由 NuGet 來安裝,當你在 project.json 裡的 dependency 區段裡敲 "" 雙引號時,就會有 IntelliSense,這時所帶出的,就是你 NuGet 裡面有安裝的套件。而當你輸入完所需套件後,你會發現 References 節點會出現 (Restore....) 字樣,此時在工具列的 [Build] 底下的項目都會變成灰色不能使用,所以此時也無法 [編譯] 或是 [執行],必須直到它安裝完成後,才可以使用。

image

另外,就是定義專案的環境、Root 位置:

image

與要排除的項目有哪一些:

image

還有 Host 掛載的方式,命令 command:

image

然後是指定使用的 framework:

image

因為這裡只是指定使用哪一個組件,所以不必給內容,只要給定 key 即可。這邊的例子是同時指定 ASP.NET 5.0 和 ASP.NET Core 5.0 的組件,也是目前 Visual Studio 2015 CTP 開新專案時預設的設定,您也可以移除掉某一個,那麼就表示單使用該組件。

  • config.json

image

就是以往在 web.config 裡設定的 ConnectionString 與 AppSettings 都在這裡進行設定。

為什麼會改成這樣的結構呢?主要也是因為擁抱 Open Source 的關係,這些 project.json/*.json 在 Node.js 都已經行之有年,為了吸引這些開發人員來使用微軟的開發工具,於是微軟將這些功能都加入到 Visual Studio 中。

 

  • package.json

在 Node.js 裡面最方便的功能莫過於可以直接利用官方的 NPM(Node Package Manager)工具,從網路上把別人已經開發好的模組抓回來用。這樣的模組交換平台加快了開發人員的開發速度,讓開發者可以全心全意專注於當前應用的開發工作,不必理會套件彼此之間的相依性。

建立 package.json 有幾種方式:

  • 可使用 npm init 這個指令可以產生基本的 package.json 檔案。
  • 或使用 Visual Studio 建立

image

也就是說,現在在 Visual Studio 2015 裡,也可以建立 package.json 檔,直接管理 Project 的相依性以及所使用到的套件了。所以通常,你只要定義好 package.json,再使用以下命令:

npm install

就會幫你將所有相依套件一次裝好,省下很多功夫。

 

整合 Bower 與 Grunt

什麼是 Bower 與 Grunt 呢?只在使用 Microsoft Visual Studio 的開發人員可能會不知道,在其他平台 (如:MAC、Linux) 的前端工程師應該就相當清楚,所謂的 Bower 是 Twitter 所推出的一種解決管理、打包 Web Package 、與相依性的工具,什麼是 Web Package 呢?舉凡網頁裡面使用到的 .js/JavaScript、CSS (以下簡稱Web Package) 檔案 等,都算是他打包管理的對象,那麼你可能會說,那跟 NuGet Package 有什麼不一樣?的確,NuGet Package 也可以打包這些前端的 .js 與 .css 檔案,還可以打包後端執行的 Package。那為什麼需要呢?因為 Bower 與 Grunt 是廣大的 Open Source 用戶經常使用的 Web Package 打包方式,為了吸引其他平台的開發者的青睞,吸引他們來使用微軟的開發更具,因此微軟將 Bower 與 Grunt 加入到 Visual Studio 中,希望讓廣大的 Open Source 用戶有熟悉的感覺,另一方面,由於原本的 NuGet Package 只針對 Visual Studio 專案結構上的改變,所以簡單的說,為了讓 ASP.NET 變得更 Open,所以才改變了 ASP.NET 原有的專案結構,才有 project.json、 config.json 的出現。

 

更詳細關於 Bower 相關資訊可到官網:http://bower.io/

image

 

底下筆者介紹如何安裝 Bower,要安裝 Bower 需要 npm 執行引擎,而 npm 是 Node.js 的套件(package)管理工具,所以您必須先安裝 node.js,安裝好 node.js 後 npm 工具就包含在其中了。

 

首先

1. 到 Node.js 官網下載 for Windows 的 msi 安裝檔

image

 

2. 使用 Node.js command prompt 來安裝 Bower

(1). 以管理員來開啟 Node.js command prompt

image

(2). 使用下面命令

npm install bower –g

安裝過程如下:

SNAGHTML1766fa6

3. 安裝 GitHub for Windows 與 Git on Windows

由於 Bower 在安裝 Web Package 套件時,是從 Github 下載 Web Package 的,也就是說,其他人預先包裝好的 Web Package 是放在 Github 上的,所以如果要可以正常的下載並安裝 Bower 的套件,必須要在您的系統中安裝 Github。

Github for Windows 可到官網下載:https://windows.github.com/

image

當 Github for Windows 安裝起來後,還得需要安裝一個東西,就是 Git for Windows ,因為 Github 內並不含 Git 的命令列工具,關於Git 的命令列工具可到 https://msysgit.github.io/ 下載。

image

同樣是 MSI 安裝檔案。

SNAGHTML30dfd06

安裝完畢後,我們就可以再測試一下 bower 這套工具了。

當我們建立一個空的 ASP.NET 5 的專案時,裡面可能沒有 bower.json 這個檔案,這時我們就可以使用下面命令。

bower init

image

完成後,專案裡就會出現 bower.json 這個檔案了。

image

而剛剛產生的 bower.json 只有簡單的 name, version, description, authors 等相關資訊。

image

那麼 bower 到底怎麼用呢?這個時候,我們可以稍微修改一下 bower.json 的內容,如下:

image

這時,我們在 Node.js command prompt 底下,在專案的資料夾下,再輸入如下命令:

bower install

image

這時我們就可以在畫面中看見我們剛才貼在 bower.json 裡,相依的 Bootstrap & jQuery 等套件被安裝進來了。

 

PS:

另外如果還是出現找不到 Git 命令的訊息的話,那麼你可能需要手動將 "C:\Program Files (x86)\Git\bin" 這個路徑加入到系統的環境變數中。

 

如上命令正常執行結束後,回到 Visual Studio 2015 的畫面裡,在 Solution Explorer 的視窗下,會發現,在 Dependency 的節點下面,會看見多了 Bower 的資料夾,下面也出現我們剛剛在 bower.json 中指定要安裝的套件。

image

4. 安裝 Grunt 套件

什麼是 Grunt 呢?

Grunt 是一個以 Node.js 為基礎所開發的命令列工具,只要經過適當的設定之後,它可以幫助程式開發人員將一些重複性的工作自動化,減輕開發者與開發團隊的負擔。

Grunt 跟以前傳統的 Makefile 類似,但以前使用 Makefile 的時候,使用通常使用者必須自己安裝相關的開發程式(像 CoffeeScriptMocha 等),但是在 Windows 環境下,要安裝的東西可能更多。

所謂的 Grunt 主要處理前端網頁應用程式開發問題,例如精簡 CSS 程式或網頁的大小、編譯 CoffeeScript、unit test、linting 等,舉凡一般性的重複動作多半都可以使用這個工具來處理,並且將這些工作由 task 來依序處理。但這些 task 要可以工作,你必須在 package.json 定義好需要的 Grunt 的 Plug-In 套件,如下:

image

再使用 npm install 的命令將 Plug-In 安裝進來即可。安裝進成功後,回到 Visual Studio 的方案總管理可以看見多了一個 NPM 節點,所有已經安裝好,可使用的 Plug-In 會顯示在 NPM 節點下面。如下圖:

image

如何執行 grunt task 輸出 .js/.css 呢?有兩種方式:

  • 使用 grunt 命令

如果您系統中無法使用 grunt 命令,那麼您可以必須先安裝進來,跟前面安裝 bower 一樣,因為 Grunt 也是建構在 Node.js 上頭,所以要使用 Grunt 的話,需要透過 npm 來安裝 grunt-cli 這個程式就可以使用命令工具了。

安裝的方式如下:

SNAGHTML7bc36d0

如上,這樣的指令就可以將 grunt 命令與相關的套件安裝進來。

有了 grunt 命令,我們可以開始來建立 gruntfile.js 的設定檔案,你可以在透過 Visual Studio 2015 來建立基本的 gruntfile.js 檔案,然後填入以下內容。

image

如上 grunt.initConfig 的設定是表示 (打包/壓縮) 後的 .js 與 .css 的存放位置,下方的 grunt.registerTask("default", ["bower:install"]); 是表示註冊一個 default 的 task,要執行這個 task 只要在專案目錄下出入 grunt ,如下:

SNAGHTML1b6a035

那麼它會將 (打包/壓縮) 後的 .js 與 .css 放置在 wwwroot\lib 資料夾下面。

  • 使用 Task Runner Explorer

開啟在 Visual Studio 2015 的選單 View –> Other Windows –> Task Runner Explorer ,點選左邊的 tasks\bower\install,左邊隨即會出現 task 執行的狀況,並告訴你輸出到哪一個位置。

image

實際到這路徑下就發會發現,就如同 gruntfile.js 設定的一樣,在 wwwroot\lib 自動建立壓縮完成的 .js 與 .css 檔案。

image

如上 jquery 的部分點進去看就可以看見 *min.js 檔案。

 

ASP.NET 5 的執行環境

就如前面所說,以往 .NET Framework 包山包海,每當需要一個縮小版的執行環境,就得推出一個精簡版的 .NET Framework,如之前的 Silverlight、Windows Phone 等,就是一個例子。

如下圖、各個版本的 .NET Framework:

SNAGHTML1869234

因為原有的 .NET Framework 包山包海,有時候我只是需要用到 .NET Framework 裡面的某一個功能,但我卻得在執行環境中安裝龐大的 .NET Framework ,這就造成每當我想執行在一個平台,那我就得再做另一套執行平台,而且當我有修復一些 Bug,那就得在所有 .NET Framework 都生一個 HotFix,但這不是長久之計,也造成一些問題。於是微軟從新思考這些問題而發展了一個新的執行環境,也就是 .NET Core CLR。這個執行不只是跨不同的 Windows 平台,它是真正可以移植到 Linux、Max OS 等,又能夠兼顧最小的  .NET Framework 的核心,因為 .NET Core CLR 將 .NET Framework 變成 Package,可讓應用程式量身訂做 .NET Framework,只安裝需要的 Package 進來,因此夠維持一個最精簡執行環境。

 

如下圖、在  .NET Core CLR 上面,.NET Framework 就像 Package 一般,只安裝有使用到的:

image

 

在探討 ASP.NET 5 的執行環境之前,我們必須先來探討什麼是 K?所謂的 K 就是微軟發展來管理 .NET Core CLR 的工具。

所謂的 K 可分為下面三種:

  • KVM (K Version Manager)

所謂的 KVM 就是 K 的版本管理工具,負責(管理、更新)各種版本 KRE 的管理工具,因為同一台可以安裝各種版本的 KRE 執行環境,可同時支援 x86/x64 與 .NET CLR/.NET Core CLR 等。

當我們執行如下命令可以查詢目前系統中有安裝那些 KRE 版本:

kvm list

SNAGHTML307d78a

  • KRE (K Runtime Emvironment)

為 .NET Core CLR 的執行環境,通常由它來帶起實際上的 CLR 來執行,而 KRE 只是個 .cmd 檔案

SNAGHTML1e9d90f

實際上背後是由 KLR.EXE 來負責。而 KLR 會帶起一個載入器 Loader,由應用程式的 project.json 內指定的 Runtime 來決定運行的平台。

image

如果 Loader 的對象是 ASP.NET 5 的應用程式,那麼再交由對應的 Host Services 來(執行/掛載)該應用程式。

如要安裝 KRE 你得先安裝 KVM,安裝 KVM 可透過 PowerShell 命令來安裝,或是在命令提示字元裡執行:

   1:  @powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"

執行結果如下:

image

接著,才可以安裝 KRE,使用下面命令:

kvm install latest

image

這時候,就可以使用 kvm 的命令了,如下,我們可以這樣來查看目前系統有安裝那些 KRE 的版本。

SNAGHTML1e9d90f[6]

另外,K 還有一個特異功能,我們只要在資料夾放置兩個檔案,一個 project.json 與程式碼檔案 program.cs

image

然後執行命令:

k run

SNAGHTML31d918d

你會發現程式碼不用編譯居然就可以執行了。其實它背後是呼叫 Rosyln Compiler 進行編譯的,因為 KRE 幫我們做了許多事情,包含應用程式的編譯,相依偵測與執行環境建置的工作,因此開發人員不需要煩惱這些,我們只要確定專案的 project.json 的資訊充份即可。

而 K 的安裝目錄當然就是 KRE 的安裝目錄,路徑在你的 UserProfile 的資料夾下面 C:\Users\[你的名稱]\.kre\packages\KRE-CLR-x86.1.0.0-beta2\bin

image

整個 x86 版 的 KRE 你會發現它其實並不大,才 7.83M 而已。

k.cmd 其實就是個批次檔,內容如下:

   1:  @Echo OFF
   2:  SETLOCAL
   3:  SET ERRORLEVEL=
   4:  :: K [command] [args]
   5:  ::   command :  Required - Name of the command to execute
   6:  ::   args : Optional - Any further args will be passed directly to the command.
   7:  
   8:  :: e.g. To compile the app in the current folder:
   9:  ::      C:\src\MyApp\>K build
  10:  
  11:  IF "%K_APPBASE%"=="" (
  12:    SET "K_APPBASE=%CD%"
  13:  )
  14:  
  15:  "%~dp0klr" --appbase "%K_APPBASE%" %K_OPTIONS% "Microsoft.Framework.ApplicationHost" %*
  16:  
  17:  exit /b %ERRORLEVEL%
  18:  ENDLOCAL

先幫你設定好環境參數、%path% 路徑、Microsoft.Framework.ApplicationHost 的位置 等,最後一樣帶起 KLR來執行。

  • KPM (K Package Manager)

所謂的 KPM 就是一個套件管理工具,雖然在 Visual Studio 中,伺服器端的套件還是以 NuGet 為主,但 KPM 它以更好,更直覺的方式來管理 NuGet 套件。

 

另外,前面我們提到的 ASP.NET 5 專案,當發佈出去的時候,目錄的結構與原本的 ASP.NET 截然不同。

image

其中有兩個主要資料夾:

  • approot

主要放置網頁專案的 原始碼、與 Package, 所謂的 Package(需要一起部署的 .NET Framework ,這裡就會發現,.NET Framework 變成套件了,除了可針對網站量身訂做之外,表示 web 也可以帶著走了。

如果到 Package 資料夾下,會發現連以前最原始的 .NET Framework 現在都被編譯持獨立的套件 Package

SNAGHTML325679

  • wwwroot

除了靜態檔案外,而 KLR 會帶起一個載入器 Loader 檔案也在這裡。

image

 

然後,在 Publish 的資料夾下,你應該有注意到一個 web.cmd 批次檔,您可以直接執行它,執行後就會以 KLR.EXE 帶起 Host,若成功起動便顯示 Started 字樣,如下:

SNAGHTML3143b99

這時開啟瀏覽器,直接可執行此 ASP.NET 5 的應用程式,如下:

SNAGHTML3165011

 

OK,本篇就先到這裡,下一篇,筆者再介紹 ASP.NET 5 的 MVC 6 有哪些新增功能,以及如果真的需要將 MVC 5 移轉至跨平台的 MVC 6 該如何進行。


 

簽名:

學習是一趟奇妙的旅程

這當中,有辛苦、有心酸、也有成果。有時也會有瓶頸。要能夠繼續勇往直前就必須保有一顆最熱誠的心。

軟體開發之路(FB 社團)https://www.facebook.com/groups/361804473860062/

Gelis 程式設計訓練營(粉絲團)https://www.facebook.com/gelis.dev.learning/


 

如果文章對您有用,幫我點一下讚,或是點一下『我要推薦,這會讓我更有動力的為各位讀者撰寫下一篇文章。

非常謝謝各位的支持與愛護,小弟在此位各位說聲謝謝!!! ^_^