2019年9月12日 星期四

中秋節前的最後一天

在中秋前失去工作,我想不會是一件讓人愉快的事情。

阿伯是我們辦公室樓下停車場的管理員,從我們承租這邊的第一天,他就在那個管理亭裡。我認識他快十年了,他永遠穿著一樣的黃色上衣,不管是颱風天還是大豔陽,總是守在那個售票亭裡,度過他的每一天。

小停車場車位很容易客滿,但我從來不用擔心,因為我可以在上班遲到時在路上打電話給他,請他偷偷幫我留一個車位。抑或是,讓我在早已經客滿的停車場稍微併排一下,如果真擋到了人,他會機警地打電話到我手機上給我…,呵呵,這顯然是一個非常人治的停車場,但是我很喜歡。

他數鈔票找零錢的時候,總會喃喃自語1,2,3,4...,認真的一張一張數過三次,這年頭這樣傳統的人已經很少見,可能是他永遠一個人在停車亭,我每次進出時,他總會試圖跟我聊天,哪怕只是一兩句閒聊或八卦。

然而,今天他告訴我,九月中之後,大樓管理人員要把停車場換成自動售票裝置(而且還順便漲價),因此,這個亭子不再需要他了。

我知道這是早晚的事,在自動化的潮流之下,會有人失去自己的工作,我一直都知道,因為我們或多或少也算是這個自動化浪潮的某種推手。

我們熱愛自動化、講求效率,我們也知道在這過程中,某些人的工作會被影響,某些人的生活或許會因此改變,只是...這些人一直離我很遠,因此我平常可以毫不在意地,轉身專注於如何為客戶提供最新的技術,如何幫助客戶降低成本,甚至是減少人力。

但在心裡我知道,總有一天,我們都會是自動化浪潮底下失去些甚麼的人。或許,失去的不是工作,也或許,失去的不只是工作...

我不知道阿伯準備好了沒有,甚至,我也不知道自己準備好了沒有。

但我想,中秋節回來之後,當我聽到自動柵欄的語音時,或許我會想念起阿伯一張一張數鈔票找零的聲音、滔滔不絕的八卦,以及親切的問候、和售票亭裡面孤獨的身影。

2019年8月20日 星期二

使用IoC與DI有何意義? (二) asp.net core中的DI服務

看過了前面的介紹,在瞭解了DI的背景需求與前提,以及採用介面來降低對特定物件實作的相依性之後,我們接著來看,怎麼使用asp.net core中的DI服務進行功能抽換。

事實上,早在約莫十年前,坊間就有很多DI框架或套件,例如我之前上課介紹過的Unity Application Block,他是一組DI Container(容器)套件,可以幫助我們更輕易地實現動態注入。而asp.net core則是把DI設計為服務,讓我們在程式碼當中,也可以輕易享有相關的功能。

在軟體開發的領域當中,你慢慢會發現到,真正困擾你的不是寫(新)程式,而是改(舊)程式。在我們開發系統的過程當中,我們會希望盡可能維持原始程式碼的不改變,就能夠加入新功能。原因很簡單,拿先前提過的例子,你只是想要修改薪資計算公式,而不是換掉整套HR系統,然後你剛才接手這個系統不久,這時候你不會想看完這套HR系統的整套原始程式碼,才能增加一個小小的薪資計算公式。

另外,你很有可能碰到運氣更差的狀況,就是你手邊根本沒有原始程式碼。

你不過就只是想改一下薪資計算的公式啊?(因為政府剛調整了最低薪資…)

記得Martin Fowler在重構一書中說過這麼一段話:

你回頭想,果真是如此,如果程式碼寫得夠好,你根本不需要看完所有程式碼,甚至也無須擁有整套程式碼,就能夠依照需求在系統中添加新功能。

所幸,前面我們已經為動態注入奠定好了基礎,請看底下這個Razor Page頁面: (我們之所以從前面的Console App改用Razor Page,是為了要展示asp.net core中的DI之故,請務必看過前面這篇才能理解底下情境)

上面這個Razor Page的執行結果如下:

計算出的薪資是 28800,問題來了,OnGet(…)程式碼當中沒有看到誰去new了那個計算薪資的SalaryFormula類別啊? 莫非是從建構子(上面程式碼第4行)傳入的? 是的,你猜對了。

整個asp.net core框架都支援套DI服務,不管是WebAPI、一般的Controller、或是Razor Page的PageModel,都可以在建構子當中加上特定介面作為參數(例如上面第4行),這時候,asp.net core的DI服務框架,會幫你自動注入你事先指定好的類別實作物件。這就是asp.net core提供的DI『服務』。

如此一來,我們透過asp.net core在開發整套系統時,程式碼就可以砍斷對特定類別實作的依賴,實現動態抽換(注入)的效果了。

那到底,是在哪邊指定要用哪一個類別實作的呢? 就是那鼎鼎大名的Startup.cs:


你會發現,就是在Startup.cs當中,我們指定了HR.ISalaryFormula介面未來的實作採用的是HR.SalaryFormula這個類別(第7行),這使得 PageModel 的建構子被asp.net core系統new起來的時候,會自動帶入(注入)HR.SalaryFormula物件的實體(.net core自動幫我們new的)作為參數,然後就實現了後續薪資計算的功能: (12-14行)

而有朝一日,我們想換掉這個公式的時候怎麼做呢? 容易,只需要在Startup.cs 當中換成另一個同樣是繼承自ISalaryFormula所實作出的類別即可:

嘩啦,如此一來,整套系統所有使用到薪資計算的地方都不需要做任何修改,單單只需要在Startup.cs 當中設定(註冊),就可以決定系統中每一個用到的薪資計算的地方採用的是哪一個計算公式類別。

這就是注入的好處,也是DI所帶來的可抽換性。

剛才你看到的是薪資計算公式,但更多我們常用的情境是處理資料庫的Data Context物件、處理日誌紀錄的Logging物件、處理通知的Notification物件…凡此種種,透過DI的設計就可以輕易的替換了,甚至asp.net core已經內建了不少實作。

未來你要把原先發mail的Notification改成發LINE訊息嗎? 你想把原先寫到檔案系統的Log改成送到雲端嗎? 都沒問題,只需要實作出符合相對應介面的類別,然後在Startup.cs 中以DI服務進行註冊即可,系統中其他的程式碼會自動被注入(.net core採用建構子注入),替換成你註冊的類別實作。

這一整個功能的實現,都源自於一開始我們談到的IoC,砍斷針對類別實作的相依,換成以介面設計的方式來實踐。

很有趣是吧,先消化一下。接著我們要來談談,為什麼DI能夠有助於提高可測試性,以及如何連程式碼都不要改,只需要透過『設定』,就可以為系統注入不同的類別實作…
-----------------------------

本文內容來自於『團隊開發與架構設計實務』課程,我們最近要開課囉,依照過去經驗這門課幾乎都是秒殺,如果你需要預先保留席次,請點選這裡登記唷。

若您要詢問問題,或是需要即時取得更多相關訊息,可按這裡加入FB專頁。
若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2019年8月19日 星期一

使用IoC與DI有何意義? (一) 它到底是甚麼?

其實我們在好幾年前,已經談過DI(Dependency Injection)這個議題。當時這類議題被視為進階的開發概念,但如果你最近開始使用 .net core,大概已經發現DI如今已變成.net core中的基本要求。

事實上,從事教育訓練這麼多年的觀察下來,不難發現其實還是有相當多的開發人員不真的很明白,到底DI對於軟體開發有何意義? 它能帶來什麼價值?

這一篇希望能夠用一個具體的實例,對初學者解釋到底什麼是DI,以及它能帶來的效益。

結論

先說結論,對開發人員來說,使用DI能夠帶來 提高可測試性(testability) 以及 提高可擴充性的價值(效益)。

在 asp.net core當中DI如今已是基本方案,asp.net core 以服務(DI Services)的形式把DI這個機制實現在框架當中。讓開發人員不管是用 razor page, MVC, 或是其他開發方式,都可以(幾乎是必須)採用DI服務。

我們很久以前就說過,『框架』本身其實就是一種限制、一種引導,誘導開發人員往某一種方向去開發程式。而如今 asp.net core 把DI納作框架的一部分,就是在引導開發人員在開發時走向某一個路線。

什麼路線呢? 就是高可測試性以及高可擴充性,如果兩相比較,我覺得asp.net core中的DI可以為開發人員實現高可測試性這個目的的可能性大概會更高一些,估計是因為最近幾年,unit test已經成為開發領域的某種潮流。

什麼是物件相依性

但不管如何,.net core已經把DI視為基礎,而你要理解這一切,得先搞清楚什麼是物件的相依性。

我常在上架構設計課程時說,職責分離這個設計概念很容易理解,誰都知道不同職責的模塊或物件就該分離,問題是怎麼決定誰的職責是甚麼? 到底誰又該跟誰分離? 等到有一天你真的開始設計,就會發現理解是一回事,真的明白到能夠動手設計又是另一回事…

看個例子,我們先來了解一下背景需求。

我們打算為企業建構一個薪資計算的功能,已知薪資計算會依據三個參數,分別是本月上班時數(WorkHours),時薪(HourlyWage),以及請假時數(PrivateDayOffHours)。

也就是說,倘若Eric本月上班 19天,每天8小時,時薪200,本月請假1天,每請假一天倒扣200元,則Eric的薪資為:

Eric薪資= (19x8) x 200 – (1 x 8) x 200 = 30400 – 1600 = $28800

為了實現這個功能,我們的設計了底下這樣的程式,它包含一個主程式和兩個類別,我們先看類別的部分:

我們來談談上面這兩個類別的職責,為什麼計算薪資該分成兩個類別? 為何不能寫成一個? 如果把上面SalaryFormula中計算薪資的Execute Method直接放入SalaryCalculator裡面作為內建的程式碼(Calculate的一部分),不是讓程式碼簡單的多了嗎?

的確,但關鍵就在『需求』。由於考量到這是一個套裝軟體,將來會賣到不同的企業,每一個企業計算薪資的具體公式可能不同,我們希望未來計算薪資的公式可以『抽換』,最理想的狀況是,賣給不同的企業,可以抽換不同的模組。

請記得,最終職責的決定其實往往取決於『需求』。

因此,之所以把計算薪資設計成兩個類別,就是考量到上面這樣的背景需求。我們區分成兩個類別,一個是計算薪資的SalaryCalculator類別,另一個則是薪資計算公式SalaryFormula類別。SalaryFormula是薪資計算的公式,它具體決定了薪資怎麼計算。而SalaryCalculator這個類別則是負責『計算』這個動作,但不管具體算法為何。

這兩個類別設計好了之後,我們再來看主程式如下:

你會發現主程式裡面new了一個SalaryCalculator類別來計算薪資,並且傳入SalaryFormula()物件實體作為參數。好了,問題來了。這整段程式碼有什麼缺點?

沒錯,從原始需求的角度來看,薪資計算的公式若想要可以動態調整,依照先前SalaryCalculator.cs的程式碼,由於類別SalaryCalculator會倚賴SalaryFormula類別的實作(SalaryCalculator.cs 16行相依於36行的SalaryFormula類別的具體實作,因為傳入的參數型別寫死了是SalaryFormula類別),未來這套軟體賣給了另一家公司,倘若想要改變薪資計算的公式,勢必得翻出原始程式碼(48行)來改寫SalaryFormula的實作才行。

砍斷針對具體實作的相依

好,知道問題在哪之後,我們來看怎麼調整? 其實很簡單,請回想起你熟悉的物件導向程式設計中的介面(interface)。請注意最大的改變在11,16,36,55行:

上面這段是修改後的類別,你會發現最大的差異在於55-59行增加了一個介面ISalaryFormula,該介面是類別SalaryFormula的抽象定義,而類別SalaryFormula(36-50)行則是ISalaryFormula的實作。

另外一個重要的修改是16行的SalaryCalculator(…)方法,傳入的物件的型別從SalaryFormula改為ISalaryFormula,如此一來,未來只要是符合ISalaryFormula介面所實作的類別,都可以當作參數傳入。

這一個修改動作,就在改變SalaryCalculator類別對於SalaryFormula類別的相依性,從原先針對類別實作的相依,改為對介面(抽象)相依。這樣做有什麼好處? 砍斷對具體實作的相依性,才能夠為將來系統能夠動態抽換計算公式而鋪路…我們接著往下看。

做了這樣的修改之後,未來倘若我們希望改變薪資的具體計算方式,我們無須修改整套程式碼,只需要再建構一個新的薪資計算類別,然後修改主程式即可(你如果一直往後看,未來只需要透過『設定』,連主程式都無須修改):

注意上面的程式碼當中,主程式有兩段6-9行與12-16行,本質上這兩段code幾乎完全一樣,唯一的差別是new SalaryCalculator(…)類別時傳入建構子的參數有所不同,一個是計算員工的公式類別實作,一個是計算老闆的公式類別實作。

你會發現由於老闆請假不扣薪(26行),因此即便參數完全一樣,但計算出的結果有所不同:

到這邊,我們已經為了動態抽換鋪好了基礎,接著我們來看,如何在ASP.NET Core中透過DI Services實現動態抽換。

-----------------------------

本文內容來自於『團隊開發與架構設計實務』課程,我們最近要開課囉,依照過去經驗這門課幾乎都是秒殺,如果你需要預先保留席次,請點選這裡登記唷。

若您要詢問問題,或是需要即時取得更多相關訊息,可按這裡加入FB專頁。
若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2019年7月18日 星期四

使用C#開發LINE Bot(32) – .net core 2.2 WebHook 範例

前面我們談過了如何在 .ner core環境上透過 LineBotSDK發送訊息。我們今天來看如何建立一個WebHook…

我們先看執行結果:

當你跟bot說hello的時候,他會echo你hello,當你說 /show ButtonTempalte的時候,他會reply一個tempalte訊息,當你傳送貼圖的時候,它會回你一個貼圖。

我們來看WebHook的程式碼:

剛才我們說到依照用戶傳來的訊息,回覆相對的訊息的部分,是在27-78行,其中回覆文字訊息的部分是29-57行。你會看到我們在程式碼當中,透過bot物件採用ReplyToken回覆訊息。

回覆多則訊息

比較值得注意的地方是,我們回覆訊息的程式碼其實統一寫在76行,回覆的物件是responseMsgs,這是一個訊息的集合。裡面至多可以放5則訊息。而前面程式碼當中的判斷與回覆,其實只是把準備要回覆的訊息加入這個responseMsgs物件中。這樣的寫法比較理想,因為依照LINE的規格,ReplyToken只能使用一次,如此做法可以在程式碼的單一地方一次性的處理回覆,比較好管理,不容易發生replyToken使用多次的錯誤。

另外,程式碼最上面的5,6兩行,是從json檔案中取得appSetting,這是.net core新的做法,請讀者測是這個範例時,也要記得開啟appsettings.json置換當中的token與admin user ID:

程式碼的18-23行,其實就是取得LINE傳來的http body,並且透過我們的SDK Parsing成為ReceivedMessage物件,其中就包含了用戶跟我們LINE Bot對談傳來的訊息,後面25行LineEvent的操作我覺得我們的讀者應該就不陌生了。

小結

總的來說,使用.net core開發LINE Bot現在已經相對算是成熟很多了,我們的SDK目前也已經全面支援,不管是發送(push)/回覆(reply)文字或template訊息基本上都沒有甚麼問題。

而整段程式碼與過去最大的不同之處,大概只有取得config環境變數的作法稍有不同,完整的程式碼已經在Github上等你,請直接clone或fork下來使用即可,不用客氣。

如果你要測試,無須安裝VS 2019,使用MAC+VS Code開發也是很好的選擇,參考前面介紹過的做法,透過dotnet run指令執行之後,搭配ngrok來運作即可測試使用。

完整的程式碼請參考Github:  https://github.com/isdaviddong/LineBotSdkDotNetCoreWebExample

Hope it helps.

-----------
最新實體課程:http://www.studyhost.tw/NewCourses/LineBot
線上課程:https://www.udemy.com/line-bot/
電子書:http://studyhost.blogspot.tw/2017/12/line-bot.html
LineBotSDK:https://www.nuget.org/packages/LineBotSDK
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2019年7月14日 星期日

使用C#開發LINE Bot(31) – .net core 2.2 Web範例

一路上都有不少朋友問過:『LineBotSDK怎麼還不支援 .net core呢?』 我總是回答『手邊事情太多,一直沒時間啊…』不過,老是跟人說:『你永遠有時間做你認為重要的事…』我自己卻拿沒時間當藉口,似乎有點牽強…

該怎麼說呢,總之,我覺得目前看起來, .net core 2.2 似乎是一個挺好的起跑點,所以,我們準備全面開始支援 .net core囉。

SDK

關於LineBotSDK的 .net core套件,前幾天已經跟朋友們介紹過了,我們剛更新了一個 beta3 的版本,幾乎已經可以當作正式版使用了,nuget package 可以參考底下網址:
https://www.nuget.org/packages/LineBotSDK/2.0.0-beta3

這包package可以直接支援 .net framework 與 .net core,所以不管你用哪一種開發技術(只要是 .net)你都只需要直接引用就好。所有的API都在同樣的namespace底下,如果你想把source code從WebForm轉成 .net core,也完全不用改API的用法。

razor page 範例

很久以前我就說過,上了 .net core之後,我自己大部分的專案選擇用razor pages來開發Web專案(少部分用 .net core mvc,箇中原因有機會再慢慢談,不過,.net core的WebAPI依舊是要的),所以,底下這個部分我們會直接介紹一個使用 .net core 2.2 razor pages開發以及透過 .net core WebAPI來做LINE Bot WebHook的範例。

不管你用的是MAC或是PC,不管使用VS 2019或VS Code,你都可以直接在command line底下建立一個資料夾,然後執行底下指令,clone github上的專案…

git clone https://github.com/isdaviddong/LineBotSdkDotNetCoreWebExample.git

當然,別跟我說你沒安裝 Git 和 dotnet SDK

執行後你應該會看到類似底下這樣的輸出:

Cloning into 'LineBotSdkDotNetCoreWebExample'...
remote: Enumerating objects: 29, done.
remote: Counting objects: 100% (29/29), done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 29 (delta 6), reused 22 (delta 3), pack-reused 0
Unpacking objects: 100% (29/29), done.
Checking connectivity... done.

接著,請用底下指令進入到包含 .sln 的資料夾

cd LineBotSdkDotNetCoreWebExample
cd main

然後執行底下指令(請確定您有安裝 .net sdk 2.2)

dotnet build

你應該會看類似底下這樣的回應:

Microsoft (R) Build Engine for .NET Core 15.9.20+g88f5fadfbe 版
Copyright (C) Microsoft Corporation. 著作權所有,並保留一切權利。

  正在還原 D:\test\linebottest\LineBotSdkDotNetCoreWebExample\main\main\main.csproj 的封裝...
  正在安裝 System.Composition.TypedParts 1.0.31。
  正在安裝 System.Composition.Convention 1.0.31。
  正在安裝 System.Composition.Runtime 1.0.31。
  正在安裝 System.Composition.AttributedModel 1.0.31。
  正在安裝 System.Composition.Hosting 1.0.31。
  正在安裝 System.Composition 1.0.31。
  正在安裝 System.Linq.Parallel 4.3.0。
  正在安裝 Microsoft.CodeAnalysis.Workspaces.Common 2.8.0。
  正在安裝 Microsoft.CodeAnalysis.CSharp.Workspaces 2.8.0。
  正在安裝 Microsoft.VisualStudio.Web.CodeGeneration.Design 2.2.3。
  正在安裝 Newtonsoft.Json 12.0.2。
  正在安裝 Microsoft.VisualStudio.Web.CodeGenerators.Mvc 2.2.3。
  正在安裝 NuGet.Frameworks 4.7.0。
  正在安裝 Microsoft.VisualStudio.Web.CodeGeneration 2.2.3。
  正在安裝 Microsoft.VisualStudio.Web.CodeGeneration.Contracts 2.2.3。
  正在安裝 Microsoft.VisualStudio.Web.CodeGeneration.Utils 2.2.3。
  正在安裝 Microsoft.VisualStudio.Web.CodeGeneration.Templating 2.2.3。
  正在安裝 Microsoft.VisualStudio.Web.CodeGeneration.Core 2.2.3。
  正在安裝 Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore 2.2.3。
  正在安裝 LineBotSDK 2.0.0-beta3。
  正在產生 MSBuild 檔案 D:\test\linebottest\LineBotSdkDotNetCoreWebExample\main\main\obj\main.csproj.nuget.g.props。
  正在產生 MSBuild 檔案 D:\test\linebottest\LineBotSdkDotNetCoreWebExample\main\main\obj\main.csproj.nuget.g.targets。
  D:\test\linebottest\LineBotSdkDotNetCoreWebExample\main\main\main.csproj 的還原於 32.02 sec 完成。
  main -> D:\test\linebottest\LineBotSdkDotNetCoreWebExample\main\main\bin\Debug\netcoreapp2.2\main.dll
  main -> D:\test\linebottest\LineBotSdkDotNetCoreWebExample\main\main\bin\Debug\netcoreapp2.2\main.Views.dll

建置成功。
    0 個警告
    0 個錯誤

經過時間 00:00:47.74

完成後,接著可以用底下指令進入到包含 .csproj 的資料夾

cd main

然後執行

dotnet run

如果沒有意外,你應該會看到底下回應

Hosting environment: Production
Content root path: D:\test\linebottest\LineBotSdkDotNetCoreWebExample\main\main
Now listening on: http://localhost:5000
Now listening on: https://localhost:5001
Application started. Press Ctrl+C to shut down.

這時候你就可以開啟browser,輸入 http://localhost:5000
會看到底下網頁:

只需要在上面輸入你的 channel access token 與 userID,就可以測試發訊息給特定 user囉…

Razor Pages

.net core 的Razor Pages Web專案我們將主程式碼放在 Pages資料夾底下的 index.cshtml與index.cshtml.cs。先來看index.cshtml的部分:

<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <script>
    </script>
</head>
<body>
    <h3>LINE Bot - Send Message Test</h3>
    <div class="row" style="margin:10px">
        <div class="col-12">
            <form method="POST">
                @Html.AntiForgeryToken()
                <div class="card">
                    <div class="card-body">
                        <label>LINE Bot Channel Access Token:</label>
                        <textarea class="form-control" name="txbToken" rows="2">@Model.txbToken</textarea>
                        <label>To User ID:</label>
                        <input class="form-control" name="txbUserId" value="@Model.txbUserId" />
                        <div class="row">
                            <div class="col-6">
                                <label>Message:</label>
                                <input class="form-control" name="txbMessage" value="@Model.txbMessage" />
                                <button type="submit" asp-page-handler="SendMessage">Send Message</button>
                            </div>
                            <div class="col-6">
                                <label>sticker:</label>
                                <input class="form-control" name="txbStickerPkgId" value="@Model.txbStickerPkgId" />
                                <input class="form-control" name="txbStickerStkId" value="@Model.txbStickerStkId" />
                                <button type="submit" asp-page-handler="SendSticker">Send Sticker</button>
                            </div>
                            <label>
                                RESULT (JSON) :  @Model.result
                            </label>
                        </div>
                    </div>
                </div>
            </form>
        </div>
    </div>
</body>
</html>

在razor pages裡面,大部分程式碼都是很單純的HTML,無需太多解釋,只有 27 和 33行的兩個Submit Button,我們用到了 .net core razor 的 asp-page-handler 這個attribute。這個attribute它會讓按鈕觸發後端相對應的OnPost_____() 方法,所以你會看到我們後端的程式碼是這樣寫的…

        public void OnPostSendMessage()
        {
            if (string.IsNullOrEmpty(txbToken) ||
                string.IsNullOrEmpty(txbUserId) ||
                string.IsNullOrEmpty(txbMessage))
            {
                this.result = "cannot push message due to missing information...";
            }
            else
            {
                var bot = new isRock.LineBot.Bot(this.txbToken);

                var ret = bot.PushMessage(this.txbUserId, this.txbMessage);
                this.result = ret;
            }
        }
        
        public void OnPostSendSticker()
        {
            if (string.IsNullOrEmpty(txbToken) ||
                    string.IsNullOrEmpty(txbUserId))
            {
                this.result = "missing data...";
            }
            else
            {
                var bot = new isRock.LineBot.Bot(this.txbToken);

                var ret = bot.PushMessage(
                    this.txbUserId,
                    new isRock.LineBot.StickerMessage(this.txbStickerPkgId, this.txbStickerStkId)
                    );
                this.result = ret;
            }
            return;
        }

第1行和第18行的兩個method,分別對應到前端button按下後的功能,你會發現裡面就是很單純的透過LineBotSDK來發送訊息,如此這般,就完成囉…

關於WebHook

這個範例不只支援訊息發送,當然還有訊息的接收,我們先把sample code放在GitHub分享給大家了,下一篇我們再來談談 WebHook 的部分…

-----------
最新實體課程:http://www.studyhost.tw/NewCourses/LineBot
線上課程:https://www.udemy.com/line-bot/
電子書:http://studyhost.blogspot.tw/2017/12/line-bot.html
LineBotSDK:https://www.nuget.org/packages/LineBotSDK
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2019年7月4日 星期四

使用PowerShell刪除Azure訂閱中沒有任何資源的資源群組

先前提到,在我棄明投暗開始改用CLI之後,Windows世界裡的PowerShell我當然不可能不去碰。對PowerShell來說,我應該算是新手(資訊界非常有趣,每隔一段時間你就會自動升級為新手,偶而享受一下可以亂做一些蠢事的新手禮遇其實還挺不錯)。

而對新手來說,認識某一種工具或技術的第一件事情,當然就是拿它來弄出一個自己需要的解決方案。PowerShell對我最大的用途當然是控制Azure訂閱,而第一個讓我想幹的解決方案就是,殺光…空著的資源群組。

不知道你有沒有跟我一樣的問題,你知道,Microsoft很大方地給開發人員Azure Free trial帳號、visual studio dev essentials、上課的Azure Pass…等諸多Azure資源。這導致我有非常多的Microsoft Account(MSA)、每個Account底下有非常多的Subscription,每個Subscription底下有一堆常常移動過來移動過去的Resource Group…箇中原由就暫且不表(內行人一定知道)…

當我把Resource Group在subscription之間移來移去的過程中,總是會留下很多空的Resource Group,這很煩、很難看、很難管…

所以我閒暇之餘常常從Azure Portal進去,一個一個Resource Group點進去看看裡面有沒有Resource(這很白癡,對,我知道…)如果是空著的話我就刪除它…很久很久以前我就知道這樣很蠢,根本不是辦法…應該要寫個script去處理它…

但一來沒空二來我內心掙扎不想碰CLI,所以連帶PowerShell也不太動手…好啦,現在我洗心革面棄明投暗之後,第一件解決自己問題的PowerShell巨作,當然就是寫一個刪除empty resource group的script…

寫完之後的結果如下:

由於用到了PowerShell的az Module,如果你要拿去玩耍的話,請記得使用底下指令安Az Module:

Install-Module -Name Az –AllowClobber

相關資訊可以參考: https://docs.microsoft.com/zh-tw/powershell/azure/install-az-ps?view=azps-2.4.0

如果你用PowerShell ISE執行的話,刪起來還蠻過癮的…

要不要拿去試試看? Enjoy it :)

不負責任聲明…

對了,請特別留意,別忘了上面這段code是新手之作,一出手就用 Remove-AzResourceGroup 指令移除整個 resource group,萬一有bug導致發生誤刪resource group的慘案發生,請千萬不要回來找我

2019年6月23日 星期日

怎麼回事?我怎麼會重新愛上CLI的?

當你有一定的年紀之後,話就會愈說愈小聲。雖然我清楚地明白這個道理,但每次發生在自己身上時總是印象深刻。

常看這個blog的人應該都知道,我不太喜歡CLI(Command-Line Interface),除了因為現在的圖形化介面其實大多都做得很完善,加上我從小討厭背指令,實在記不得要完成某個動作的時候,該在鍵盤上敲下什麼…而且更主要的原因是,我經歷過那個只有CLI沒有GUI(Graphical User Interface)的年代,那個時代的工程師天天跟黑底白字(或綠字)的螢幕為伍,花上數小時在鍵盤上敲打著別人看起來完全沒有意義的文字…

我也不例外,副作用之一當然是練就了超快的打字速度…但其實頗為辛苦。所以當GUI出現的時候,我和很多那個年代的工程師一樣,是大聲頌揚大力鼓吹的,並且對CLI棄之如敝屣。

一晃眼30多年過去了…

最近這幾年,CLI居然又成為主流,我在心理上其實很難立刻接受。(你會發現人的既定印象與觀念有時真的很死板,一旦形成後,無法改變到難以想像的地步)我始終認為,只要在有設計良好的GUI的前提下,我根本沒什麼理由需要跟以前一樣一天到晚用力敲打鍵盤!

直到…

最近因為上課的關係,需要實現『金絲雀佈署』,這導致我常常需要一口氣建立兩三個Web Site Slot,並且在不同的slot分別各自佈署網站(這還只是暖場)。然後,為了實現金絲雀,我必須要先在第一個網站佈署新版,然後透過Web App的traffic management改變流量,把10%流量導入第一個站台,依此類推,直到最後一個站台佈署完新版…

第一次,我用Azure Web UI用到覺得很X。

當我發現,過程中我少做(或做錯)了一個步驟,導致設定配置有錯誤的時候,為了讓整個Lab環境乾淨且順暢一點,我發現我得要重來 >_<。

佈署到第三輪之後,我開始覺得這樣在網頁上用滑鼠點來點去實在不行。

就在這一刻,我竟然毫不猶豫的打開了powershell:

其實過去就安裝過了azure cli,所以我隨手把建立網站的指令打了進去,不夠確定的話還可以請AI神燈阿拉丁幫忙查詢(在上面,有看到嗎,哈)…後來發現,我與其這樣一行一行打,不如用VS Code編輯。接著開了VS Code,想到印象中有一個azure cli套件,可以有intellisense的功能,還可以在VS Code裡面直接run Azure CLI,所以我把套件裝了起來…

然後沒兩下我寫完了重建Web Site和Slot的指令,來回測試之下,一口氣重複做了近10次上面這個Lab…建立resource group, 建立網站, 建立slot, 佈署三個網站,再佈署新版,切換流量,測試,刪除resource group…

做到第五次時候我懂了(其實我早就懂了,只是不想承認),這些動作沒有CLI不行。

我不可能在網頁上連續操作10次這些動作,首先步驟很容易搞混,隨便順序上的錯誤就可能讓結果不同。其次,使用GUI我得要等網頁的回應時間,它比起CLI根本慢太多,再來,這些動作要在課堂上帶著學員跟著step by step一起做,用GUI大概得多花個半小時,但CLI只需要給學員指令碼就行…

這還只是做十次,如果,我是IT維運人員,每天都要做個十幾次呢?我能用GUI嗎?不,我會瘋掉…終於,我徹底接受必須使用CLI的原因了。

其實,我早就知道CLI的優點,只是我不常碰到那些情境吧。咦? 再仔細想想,我真的碰不到這些情境嗎? 我發現,我過去其實是下意識地有點刻意避開那些會讓我用到CLI的情境,好讓自己維持一個繼續討厭CLI的理由!!!

我突然發現,我或許不是因為覺得它不好用而討厭它,我可能是為了想繼續討厭它而下意識的選擇不去用…人的大腦還真是詭異啊。

直到有一天,環境逼著我非翻出這個解決方案,我才承認,這個過去被我討厭的對象,其實非但並不討厭,而且還能夠在許多關鍵時刻幫上我的忙…然而我僵化的既定印象,卻讓我把這個解決方案一直排除在選項之外…

這根本是我自己天大的損失。

轉念一想,一個CLI是如此,其實生活當中許多事情不也是如此嗎?自己討厭的那群同事、那些政黨、那個該死的OOXX…是不是其實也是我刻意選擇的價值判斷? 是不是他們現在的真實的狀況其實也早跟我過去在腦袋裡植入的既定印象有所不同?如果,我能讓(強迫)自己更客觀一點,是不是或許能夠更早發現對方的優點,以及我可以和對方合作的機會?

想到這裡,我更無懸念的繼續用VS Code把Lab剩下的指令打完…『或許明天中午,去找那個很久沒說話的同事吃個飯吧...』我心裡這樣想著。

Related Posts Plugin for WordPress, Blogger...

熱門文章