2017年1月25日 星期三

丙申年臘月廿九 - 煮咖啡論技術

先說個幾天前發生的小故事,最底下是整理好的年度文章摘要。

可能很多年輕人已經開始不知道,每年的農曆十二月,被稱作臘月。而每逢臘月,則不免讓我聯想到俠客行裡面的『賞善罰惡臘八粥』(如果對這主題有興趣,為了不破壞你的閱讀樂趣,請自行參閱金庸俠客行),我猜這個世代大多數的人,應該完全沒有喝過什麼臘八粥,估計對李白俠客行,可能也陌生的很。

回首2016丙申年,發生了不少事。
因此,在年底不免想找找久未聯繫的三五好友,大家聚聚。

由於大夥都是資訊領域的技術同好,彼此也都在業界耕耘多年(都老了?),但聊起過去種種,卻彷彿就像昨天才發生的事情。然而事實上,這幾年業界幾乎所有的技術都換了一輪,火紅的話題也都翻過了好幾遍。相較之下,我們幾個老朋友們聊到的技術也好、故事也罷,即便還稱不上是歷史,肯定也都已經是往事了。

席間,朋友說到:『技術更迭好像已經是這世代資訊人員的宿命,金庸的俠客行,是1965年出版的,至今已經流傳超過50年,而李白的俠客行,則是1200年前的作品,1200年耶! 這是什麼時間概念? 古人說的『立功、立言、立德』,稱為三不朽,這年代哪還有什麼可以不朽,昨天剛炒熱的技術今天就過時了,更別說寫過的書,才沒幾年就得淘汰,而且越來越快…』另一位朋友笑著說:『你們出的書還可以活個幾年,要絕版了圖書館不小心還能找到,好歹一時也能出個名,像我手上開發出的系統,設計過的架構,估計只要我離職,立馬就會被改的面目全非,要不然就是被直接換掉,根本是屍骨無存』。

這讓我想到俠客行中的一段:『縱死俠骨香,不慚世上英。誰能書閣下,白首太玄經。

時代真的很不同了,如今技術變化太快,潮起潮落可能轉眼間。技術人員手上做的這一切,早晚終究都會過去,也不一定會有人紀念…不過,不管如何,明天太陽依舊會升起,過去的又何必留戀? 每天都是新的,能夠專注在『現在』,才是幸福的事。

我跟朋友們說,我最近第二次看Spencer『禮物』一書的心得:『還記得你人生當中最快樂的一段時間嗎? 那段時間,往往不是我們過的最舒適的時候,也並非是擁有最多掌聲、財富...的時候。

大多數人記憶中最快樂的時光,常常是我們專注在某件事物上、專注在當下的那一段時刻。像是...小時候在公園裡和同伴玩耍不肯回家,深夜時獨自一人寫程式始終不想熄燈,站在講台上底下的人狂舉牌子告訴你超時卻不肯結束...』

我說:『在當下的時候,往往才是人們最快樂的時候...

Spencer在『禮物』這本書裡告訴我們:如果,你的『現在』正擔憂著『未來』的生活(工作)、懊悔著『過去』的境遇或失敗,他要你努力強迫自己,先別管過去和未來,請先專注於現在。

即便我們對未來的掌握度越來越低,但也別讓對過去的懊悔以及對未來的憂慮拿走了你對現在的專注。因為,我們唯一真正擁有的,就只有現在。只有在你專注在這一刻,去體驗它,才能夠慢慢想起以前孩童時期簡單的快樂 -- 那種最初,讓我們每個人寫程式到深夜,不是因為結案或進度的壓力,而只是因為興趣的那種簡單的快樂。

大夥閒聊到這兩年技術的改變與發展,從雲端運算、SaaS帶來的改變、大數據、IoT、最近的Chatbot、人工智慧……最後,我們沒人敢說未來會怎麼發展,這個時代的變化速度,已經遠遠超過我們任何人的預期了…

於是乎,一夥人乾了手中的咖啡….

決定從今年開始,努力練習試著強迫自己,除了憂慮未來,更用心專注於現在。
---------------------------------------------------------------------------------------------------------------
後記 : 底下隨手整理了過去一年的幾個比較重要的系列。今天是丙申年臘月最後一天,過了農曆年,再也沒有任何藉口留戀過去,2017年早已經是新的開始了。

2017年1月24日 星期二

關於LineBot(8) - 發送Template Message

LineBot傳送訊息的形式,除了單純的文字、貼圖、圖片之外,還有一個比較特別的形式,稱之為Template Message,這種形式的訊息本質上是一個選單,長得像是底下這樣:

上面這個是三種Template Message中的一種形式,稱為Buttons Template Message,另外兩種形式是Confirm Template Message(下圖左)與Carousel Template Message(下圖右):

Confirm Template Message好理解,基本上它就是一個確認(confirm)對話框,可以讓用戶選擇Yes/No之類的回答。而Carousel Template Message其實就是多個Buttons Template Message,橫著擺可以左右scroll。

我們先從Buttons Template Message開始看起。

關於Buttons Template Message

我們剛才說過,Buttons Template Message這種形式的訊息本質上是一個選單,包含著一張圖片(下圖1)、一個標題(下圖2)、以及一些文字(下圖3),並且可以設置1-4個選項(下圖4-6,範例中我們只設置了3個):

當你的Bot送出這個訊息給用戶,用戶可以點選底下的選項(上圖4-6的文字),這些選項被稱為Action,這Action也有三種不同的類型,分別是:

  1. MessageAction : 幫用戶說一段指定的文字訊息
  2. UriAction : 直接在Line裡面開啟指定的網頁
  3. PostbackAction : 觸發一個可以你的WebHook收到參數的postback

其中UriAction最容易理解,用戶點選該Action,Line就會直接開啟某個網頁。

而MessageAction可以用來幹嘛? 它可以讓你幫用戶說特定的話,實務上應用時,你可以透過這個機制先設計好一些固定的指令,讓WebHook看到這個指令就能進行相對應的工作(其功能等同於用戶在對話框中說了這個指令)。

而postback則是不出現任何訊息,直接把特定參數傳給WebHook,WebHook就可以進行特定工作。

讓LineBot發送Buttons Template Message

我們看底下這段程式碼,它的功能就是讓LineBot發送Button Template Message:

你會看到我們先在第2-8行建立三個Action(因為是範例,因此每一種一個)。第一個是MessageAction,當用戶點選『點選這邊等同用戶直接輸入某訊息』,Line就會『幫』用戶說『/例如這樣』:

而『點這邊開啟網頁』這個選項則很單純,當用戶點選上圖中該action,就會自動開啟Google首頁。

而上圖中最後一個action,被點選時,WebHook會收到一個postback event,其JSON內容類似像底下這樣:

{"events":[{"type":"postback","replyToken":"d7aooxxo154c6d94oo01xx28coxoxfd04","source":{"userId":"U8x2788OOXX53422082e301b80xb00030","type":"user"},"timestamp":1485251255286,"postback":{"data":"abc=aaa&def=111"}}]}

留意其中的data,就是我們在上面程式碼第8行中指定的postback data,當你的WebHook收到上面這樣的指令,就可以進行相對應的工作。

OK,瞭解了Actions之後,我們繼續回頭看上面的程式碼,我們在第11行建立一個ButtonsTemplate。留意一下第13行的altText,因為並非每一種device都可以顯示Template Message,因此,你可以設定替代文字,這會被用於無法顯示Template Message的場合(例如PC版的Line、手機板的Line訊息預覽畫面、手機的Notification通知畫面…etc.)。

而14,15兩行是標題,這沒什麼,17行則是提供一張大圖的url,Template Message會將你指定的圖顯示出來。程式碼的最後,我們把前面建立好的三個Actions丟給ButtonTemplate物件,然後透過PushMessage指令送出,done.

此範例原始程式碼位於 : https://github.com/isdaviddong/LineBotSdkExample/blob/master/LineBotSdkExample/WebFormExample.aspx.cs

--------------------------------------------
相關課程: http://www.studyhost.tw/NewCourses
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2017年1月15日 星期日

Microsoft Graph API (2) - 使用OAuth進行身分驗證,並取得用戶資訊

我們前面曾經和大家聊過,如果要幾句話說清楚Microsoft Graph API是啥,其實並不很容易,但透過先前的介紹你大概可以知道,Microsoft Graph API身為MS Office 365所有資源存取的API連線入口,負擔著讓開發人員得以輕鬆存取雲端資料(資源)的重要角色,只要你想存取Office 365、OneDrive、OneNote…等各種資源,基本上你就必須與Graph API打交道:

不管用戶採用的是個人帳號(Microsoft Account)或企業帳號(Orgnization Account),MS Graph API讓開發人員可以用單一Endpoint允許各種不同帳號的身分驗證,當然也會依照權限吐出不同的資源。

這一篇我們接著來看,如何透過OAuth連結MS Graph API,並且取得token抓取用戶資料。
(如果讀者對OAuth還不甚了解,請先參考這裡)

建立Microsoft應用程式

首先,若您是開發人員,要使用MS Graph API(或者是要與O365/Onedrive等系統做SSO),你必須先在微軟的站台上建立一個Application,建立的位置在: https://apps.dev.microsoft.com/ ,進入之後會看到底下畫面:

請用您的Microsoft Account登入,您就可以建立一個自己的應用程式:

點選後會出現底下畫面,依照步驟,輸入名稱,按下建立鈕:

建立完應用程式之後,請接著點選『產生新密碼』:

記得保留上面彈出視窗中顯示的密碼,待會我們會使用到(它只會顯示一次,請務必自行保留)。

接著,請在平台這邊選擇新增平台,然後選Web,這是因為我們範例中是透過Web App整合方式來進行Demo,如果你的情境是要在行動裝置上存取Office365(or Onedrive/onenote…etc.)中的資源,當然就選擇行動應用程式:

接著該頁面會要求你輸入重新導向URI,這部分如果不理解其意義以及為何需要,請參考我們以前分享過的OAuth介紹文,底下的URL就是你取得Auth Code的導回網址,由於我們只是要在Local用IIS Express測試,因此我們網址輸入Localhost:

至於port 13555怎麼來的,它是我們在VS2015中建立了一個Web Application Project之後自動產生的,如果你想測試但懶得寫程式,可以拿我在GitHub上面的範例來修改:
https://github.com/isdaviddong/MsGraphApiExample20170115

接著,請至少為您建立的應用程式新增user.read這個權限,如果你想玩其他的權限,可點選下圖的『加入』鈕:

設定完成之後,請按下儲存鈕(請務必保持Live SDK勾選):

撰寫OAuth/SSO登入頁面

完成了上面所有的設定之後,您的應用程式就建立好了,請取得應用程式中的『應用程式識別碼(Client_id)』與『密碼(Client_Secret)』,應該長得像是底下這樣:
Client_id : 98d720db-xxxx-xxxx-xxxx-7430359c1c10  (這是假的)
Client_Secret : teoXXXeJp8bxxxxSO2HjhNG (這當然也是假的)
有了上面的資訊就夠囉。

接著請撰寫底下的頁面(如果你想測試但懶得寫程式,可以拿我在GitHub上面的範例來修改:https://github.com/isdaviddong/MsGraphApiExample20170115):

然後在VS2015的IIS Express中運行此頁面,你會發現點選上圖中的Button之後,會被導引到AAD2.0的登入畫面:

您可以用Microsoft Account或Orgnization Account登入都行,因為Graph API都支援。(但用哪一種帳號登入後面的畫面將會有所不同,我們在本文中的展示是以Microsoft Account登入)

用戶登入之後,系統會跟他要求資訊存取權限:

你會發現上圖(1)的地方就是您建立您的應用程式時,所上傳的圖示,而(2)的地方是您的應用程式名稱,(3)是您跟用戶要的權限 (4)是…就只是一個用戶非點不可的按鈕。

當用戶成功登入之後,網頁會被導回你原先的頁面,但這時,請注意網址列QueryString已經出現了Auth Code:

請取得該Code,我們要用此Code換Token。

後面的動作我用postman示範,取得auth code之後,請對https://login.microsoftonline.com/common/oauth2/v2.0/token這個位置做POST呼叫,並傳入下列參數:

上圖中的(1)是你原本在應用程式以及要求Auth Code的登入URL中所設定的redirect_url(必須都相同),(2)與(3)是一開始我們請你保留的client_id和client_secret,而(4)則是剛才從QueryString取得的Auth Code,成功呼叫之後,你會發現上圖下方API回給我們了Access_token,將其保留起來,該Token就是我們依照權限取得用戶資訊的令牌了。

透過token抓取用戶資訊

拿到token之後你就無敵了,基本上你可以用該token來取得所有用戶授權你抓取的資訊(如果用戶授權你更新,你當然也能修改用戶資訊)。

底下我們依舊用postman來示範,例如,倘若你要取得用戶身分,可以對https://graph.microsoft.com/beta/me這個網址做GET,並傳入底下資訊:
上圖中的Authorization參數當然傳遞我們剛才取得的token,而結果就是上圖下方取得的JSON資訊,你會看到其中有用戶的個人身分資訊。

就這樣,如我你還想取得其他資訊,可以透過哪些API呢? 很多,例如底下是常見的:

更多詳細的資訊可參考 http://graph.microsoft.io/en-us/docs

有沒有發現,當你熟悉了OAuth之後,透過API要取得用戶的資訊其實非常容易。
--------------------------------------------
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2017年1月13日 星期五

asp.net Web開發框架 (7) - 使用Vue.js進行表單雙向繫結

先前我們分別討論過了使用Vue.js進行表格資料渲染以及渲染時動態產生的功能性按鈕之後,接著,我們來看Vue.js在表單上的資料繫結。

範例依舊是我們先前使用的那個:
source code : https://github.com/isdaviddong/AspNetWithVueBinding
測試網址: http://ex20170110-aspnetwithvuebinding.azurewebsites.net/ 
(如果該網站被我不小心殺掉,請FB訊息提醒我,網站裡面的資料由於是共用的,可能會被玩壞或出現詭異的內容,一概與本人無關XD )

看過了先前的介紹之後,你大概已經知道,動態產生的『編輯』鈕:

該按鈕會在用戶點選時,將畫面導入到AddNewOrUpdate.html這個頁面,進行編輯的動作,而首頁上的新增鈕,其實也是將網頁導入到AddNewOrUpdate.html這個頁面。唯一的差異在,如果是按下編輯鈕,該筆紀錄的guid會被帶入:

這個動作怎麼實現的,答案在我們先前進行動態Button渲染時候的Vue instance中的edit method:

這使得如果用戶按下的是新增鈕,AddNewOrUpdate.html這個頁面將不會收到QueryString,若用戶按下的是編輯鈕,則是用戶欲編輯的record的guid。

因此,我們就不難理解AddNewOrUpdate.html這個頁面一開始進入後的javaScript code,就是判斷是否有Guid:

我們把guid保留在12行的變數中,30行之後的document ready,則是判斷是否有guid,如果有,則在36行呼叫LoadData,把該筆資料載入。而不管有沒有資料,31行的SetBinding都會把UI上的HTML表單與記憶中的vd_StudentRec做繫結:

所以你不難猜到,LoadData這個function,在從遠端載入完資料之後,會放到哪一個地方? (別往下看,先想一下…)

答案當然是:

記憶體中的vd_StudentRec,沒錯。其實,上面這段程式碼是為了說明,否則在實務上你把回傳的資料result.Data,直接放入Vue.js的instance就好(vm_student.rec=result.Data),因為vm_student.rec根本就是vd_StudentRec的代理。

好的,資料塞入vm_student.rec,會觸發Binding,Vue.js的Binding Engine會去找HTML UI上的Form_StudentRec:

然後它發現你寫的v-model指令,這表示該欄位要進行雙向繫結(two-way binding),因此,Vue.js engine就會把你繫結的物件vd_StudentRec中的屬性值帶入,這就是畫面上的表單資料會自動呈現的原因。

同樣的,由於是Vue.js是設定雙向繫結,因此進入AddNewOrUpdate.html這個頁面之後,不管是有沒有透過QueryString的參數載入一筆預設的資料,任何表格上使用者的異動都會被反應到記憶體中的vd_StudentRec物件中,因此,當用戶按下畫面上的『新增/更新』鈕:

頁面上的JavaScript程式碼,做的就是把記憶體中的vd_StudentRec物件中的值,透過呼叫後端的AddNewOrUpdate方法,寫回後端資料庫中,程式碼如下:

後端的AddNewOrUpdate方法也很簡單,就是取得傳入的物件,然後判斷一下是否有guid(1),如果沒有,應該是新增(2),如果有,就從資料庫中找出來更新(3):

就這樣而已,相當單純。

以上提到的完整程式碼都在 https://github.com/isdaviddong/AspNetWithVueBinding 請自行參考。

下一篇: asp.net Web開發框架 (8) - 使用krajee進行非同步檔案上傳

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

2017年1月10日 星期二

asp.net Web開發框架 (6) - 在Vue.js動態表格渲染中加上功能按鈕

接續著上一篇,我們這次拿這個WebAPI + Vue.js 的CRUD範例繼續討論。讀者可以點選這邊,看看這個範例的實際執行狀況。(如果該網站被我不小心殺掉,請FB訊息提醒我,網站裡面的資料由於是共用的,可能會被玩壞或出現詭異的內容,一概與本人無關XD )

這個網站的主畫面如下:

上一篇我們大致上說過,這些資料是透過伺服器端以JSON格式傳到前端,並且透過Vue.js的template rendering機制動態顯示出來的。

但我們沒有談到,上圖中每一個row最左邊的編輯/刪除鈕,是怎麼實現的,我們這一篇就來介紹這個部分。

在HTML Tempalte中加上功能按鈕

先前我們看過的HTML樣板,要加上Button很容易,但Button要有對應的功能,則需要透過v-on:click 指令:

你會發現,上面的第4,5兩行,多了兩個Button,就是編輯和刪除鈕,分別是呼叫到edit和remove這兩個javascript function,並且傳入item作為參數,還記得嗎?這個item就是第2行v-for裡面的item in items的那個item,也就是伺服器端傳來的資料集合中的一筆資料。

因此,當用戶點選這兩個Button,實際上會執行到的,就是Vue.js的vm裡面所定義的methods(位於12-22行) :


這個在Vue.js稱之為方法事件處理器。留意上述程式碼的第12-22行,其中的edit、remove,就是按下Vue.js動態渲染出的Button時,會觸發的JavaScript Functions(Methods),由於帶入的參數是item,也就是按下哪一筆資料的Button,就把該筆資料作為參數帶入。因此function裡面的程式碼就不難理解了。

remove method的14-16行會出現confirm(…)視窗,如果用戶確認刪除,則調用Remove(item)這個我們自己寫的JavaScript Function。而19行則是edit method,功能是redirect網頁到AddNewOrUpdate.html,並帶入資料record的Guid作為QueryString參數(由於AddNewOrUpdate.html這個網頁因為同時包含新增與修改兩種功能,比較複雜我們改天討論)。

我們先看14-16行中所呼叫到的Remove(item)這個JavaScript,也就是上述程式碼的26-37行,如果熟悉我們這一系列文章的讀者肯定知道,其中的ExecuteAPI是我們框架提供的JavaScript function,他會呼叫到伺服器端的Remove()這個BO中的C# Method,並傳入guid當作參數。

後端刪除資料的方法

因此我們看後端的C# Code,果然,有一個叫做Remove(Guid guid)的方法:

該方法中的程式碼就是找到guid編號符合的資料,然後刪了它,接著呼叫GetData()這個我們先前介紹過的Method把所有資料以JSON格式回傳給前端,如此這般,達成了資料刪除的功能。

如果你仔細看程式碼,可能會發現,其實前端並沒有拿remove方法回傳過來的JSON,而是自己又呼叫了一次GetData(),為何要這樣寫呢? 這樣不是多呼叫了一次,讓效能變差嗎? 答案是…沒什麼特別原因,就是寫的時候不小心忘了,寫完後又懶得改而已…

所以,整段的重點在於,透過Vue.js做HTML樣板(Tempalte)動態渲染(Rendering)的時候,如果有某些tag需要觸發事件,可以在HTML Template當中直接透過 v-on,以事件處理器的方式,呼叫預先定義在Vue instance當中的Methods,達成所需的效果,就像是我們在上面這個例子中的Remove與edit一樣。

以上提到的完整程式碼都在 https://github.com/isdaviddong/AspNetWithVueBinding 請自行參考。

改天有空我們再繼續討論新增與修改的功能。
下一篇: asp.net Web開發框架 (7) - 使用Vue.js進行表單雙向繫結
--------------------------------------------
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2017年1月5日 星期四

asp.net Web開發框架 (5) - 使用Vue.js進行前端資料繫結顯示(WebAPI版本)

前面寫過了在asp.net WebForms環境下使用Vue.js做DataBinding/UI Template Rendering,這一篇我們把焦點轉回WebAPI的版本。

如果使用前面介紹過的寫法,以WebAPI搭配Vue.js進行SPA Web應用程式開發,那前端的頁面可以是很單純的pure HTML,例如:

先前介紹過的一樣,UI上進行Binding的部分只有60-90這一個區段,透過Vue.js的繫結語法{{item.xxxx}}把每一個屬性的值填入UI,而促使這個Binding生效的js程式碼位於14-21行,也就是SetBinding()這個javascript function。這個SetBinding()建立了vm_StudentInfo這個Vue instance,把HTML UI上的tableBody與vd_StudentInfo這個記憶體物件做了繫結。

因此,每當vm_StudentInfo的items屬性被更新時,Vue就會拿vd_StudentInfo中的數據來更新tableBody區塊中的UI。

而底下這段程式碼(24-31行)則是binding_StudentInfo的items屬性被更新的時機:

也就是畫面上的『Get Data』Button被按下去的時候。會透過ExecuteAPI呼叫伺服器端的WebAPI,因此底下的程式碼被執行(還記得這一大段WebAPI程式碼在幹嘛? 我們曾經在先前詳細的介紹過):

是面這段WebAPI身為服務層,任務就是動態載入並執行相對應的BO,因此進而運行到BO.Health.GetData這個GetData Method:

執行後的結果List<StudentInfo>會透過JSON回傳到前端,被透過Vue 的DataBinding(Template Rendering)機制顯示於螢幕上:

同樣的,按下上圖中的『清空』鈕之後畫面會被清空的原因也很好理解,我們只是把繫結物件的items屬性清空:

因為vm_StudentInfo.items 被設為 undefined(或其他空值),則頁面上顯示的資料就被清空了,就是這麼簡單。

其他的部分我們在上一篇介紹過囉…(先前針對程式碼相關更完整的解釋請參考這裡)

source code : https://github.com/isdaviddong/AspNetWebFormsSpaVueBinding

更完整的WebAPI版本CRUD Source Code:
  https://github.com/isdaviddong/AspNetWithVueBinding

下一篇我們會接著介紹,如何在渲染HTML表格的時候,加上功能按鈕…
--------------------------------------------
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2017年1月2日 星期一

asp.net Web開發框架 (4) - 使用Vue.js進行前端資料繫結顯示(Template Rendering)

弱水三千,為何只取Vue.js?

一直以來,我覺得大部分的開發技術其實也是一種工具,也有生命週期。既然是一種工具,那開發技術當然不能只是拿來學習,而應該是拿來使用的。最近幾年,隨著開發技術的生命週期越來越短,不免讓人開始猶豫該如何選擇。如果你慢慢發現,學習某一門技術的時間並沒有遠低於使用它的時間,那就得回頭重新評估這個工具了…

但,千萬別誤會,我不是叫大家不要花時間去進修,或是減少學習的時間。這年頭,我們比過去以前任何一個時代都需要時時刻刻學習。但,正因為我們的時間越來越珍貴,越來越難以過去的大量快速學習來面對技術的變遷,因為現在不管學得再快,也無法趕上變化的腳步…

莫名其妙講了一堆,好像跟這個主題無關?

非也,我想說的是,最近幾年我在專案中選擇的工具(開發技術)時,都盡可能以不用花太多學習時間的為主。因為工具(技術或框架)最終的目的是幫你節省時間用的,倘若學習成本太高,可能會本末倒置。而這個理由,也恰巧是我們選擇Vue.js作為前端開發框架的原因。

當過去幾年我們在.net環境嘗試建構一個適當的開發架構時,三層式的SPA對我們來說是個能同時滿足行動裝置、Web、以及桌面應用的理想選擇,而要採用何者搭配SPA作為Web前端開發套件呢? 最終,我們選擇了Vue.js。

理由?

  1. 它的程式碼很簡潔,非常輕量級,執行速度也算快,一點都不讓人覺得累贅。
  2. 它很好學,還有中文的文件(唯一的遺憾是簡體),對於已經有前後端程式碼分離、SPA基本概念的人,用起來跟喝水差不多。
  3. 它在資料繫結這個部份的做法非常直覺,MVVM概念的實現很接近以前XAML的作法,同時,它採用的標記語法很簡單,也極不容易破壞HTML版面,和設計師(designer)很好合作。

以上是最主要的這幾點。

Demo的前置準備

我們前面說過Vue.js學起來很簡單,因此我們也不用談什麼初階進階的東西。待會的Demo就直接從伺服器端把一組資料傳到前端,然後透過Vue.js做一個Binding(Template Rendering),以表格的方式把從伺服器端傳來的JSON資料呈現出來。
(若需要完整的CRUD請參考本文最後)

如果你想跟我一起 hands-on 一下,請依照底下的操作步驟做好前置準備,別忘了,我們用的是SPA架構,把以前你熟悉的asp.net WebForms或asp.net MVC都先給擱在一邊吧。

補充: 底下的範例是透過WebForms PageMethod來寫SPA,如果你想看WebAPI的SPA版本,請參考Source code,UI的部分請看index.html,同時原本PageMethod相對應的改成了透過WebAPI呼叫BO,請參考ControllerHealth.cs,而程式碼的說明則建議您先看完這篇之後,再接著看下一篇(WebAPI版)。

  1. 請先建立一個最基本的asp.net 應用程式(請用Empty範本,並勾選WebAPI與WebForms),然後只需直接引入一個Nuget套件isRock.Framework.Web.AllPackages,它會幫你引入其他所有需要的Nuget套件:
  2. 接著,請在頁面上建立一個default.aspx (如果你偏好WebAPI版本的SPA,可參考這邊自行傳換成建立WebApi,或待會看下一篇):
  3. 準備工作先到這邊,接著我們來看如何進行Vue資料繫結。
基本概念

開工前我們扼要說一下基本概念,我們接下來要透過Vue.js做一個最基本的資料繫結,整個動作發生於前端,也就是瀏覽器上(這和Silverlight類似),但和過去asp.net WebForms發生在後端的資料繫結有所不同。

所以你必須先知道一件事情,這裡所謂的資料繫結,指的是瀏覽器內的HTML與Object的繫結。也就是,將『從伺服器端透過AJAX呼叫,被以JSON格式傳遞到瀏覽器之後的JavaScript Object』,與『HTML UI』Template之間的資料繫結。

而非像是過去的asp.net webforms或MVC一樣,在伺服器端進行的資料庫與UI Rendering之間的繫結。

大部分的SPA架構,前端顯示的資料都是從伺服器端以JSON的方式傳到前端,所以我們這裡的資料繫結大多談的都是資料被以JSON格式傳到前端瀏覽器上『之後』的資料繫結。

因此,你必須有幾個概念:

  1. UI上的資料不會『直接』與後端資料庫互動,而是在前端瀏覽器的記憶體內與HTML UI互動。
  2. 資料在繫結前,得先從伺服器端(以JSON格式)傳過來。
  3. 倘若是表單繫結,UI上的資料被用戶修改而有所異動,也只是反應回前端瀏覽器內(記憶體中)的Object,並非直接回寫資料庫。

暫時先知道這些就可以了。

要Demo什麼?

我們先來看,如何從伺服器端取得JSON資料,然後透過Vue.js的template動態Render到HTML上的範例(後面會再介紹表單中的資料雙向繫結)。好的,我們待會要做的事情是這樣,畫面上有一個類似底下這樣的UI:

當按下左上角Get Data按鈕的時候,會從伺服器端撈一堆資料,以JSON的格式傳到前端瀏覽器上,透過Vue.js進行DataBinding,呈現出底下的結果:

如果用戶按下上圖中的清空鈕,則表格資料會清空,就這樣。

如何使用Vue.js的template syntax做HTML動態rendering

好,知道要做什麼之後,我們實際來嘗試一下,請在剛才建立好的aspx頁面的CodeBehind程式碼中,建立底下這個Method :

上面這段後端C#程式碼的主要目的,是建立可以往前端傳送資料、可以被前端JavaScript呼叫的PageMethod,角色如同WebAPI或WebServices一般,但.aspx開發人員很幸運,用上面這樣的寫法就行了。

細看程式碼其實很簡單,28-33行就是準備假資料,如果是正式環境,我會從資料庫抓資料,但因為這只是一個範例,我們不要弄得太複雜。注意我們可以直接在同一個頁面上定義ViewData Class,當然也可以獨立做成一個專案或寫在同一個專案的BO(Business Logic Object)資料夾底下,但對於WebForms開發人員我們很包容,暫時先寫在同一個頁面上就好。

35行的迴圈是計算BMI值,最後在46行回傳給前端JavaScript,就這樣。別問我為何那麼簡單,因為 1.它本來就很簡單 2.上面範例用了我們開發的框架,大部分前端AJAX程式碼以及後端資料回傳的類別都包裝過了。

寫好後端C#,待會接著我們來看前端。

後端的PageMethod負責提供資料,留意上面程式碼25行該PageMethod的宣告以及回傳型別,是public static PageMethodDefaultResult<List<StudentInfo>> GetData() {…},由於框架提供的功能,你可以在前端透過底下這樣的JavaScript直接呼叫後端的GetData()這個PageMethod,作法像是底下這樣:
          CallPageMethod('GetData', null,
              //when success
              function (result) {
                 vm_StudentInfo.items = result.Data;;
              }
           );
透過呼叫CallPageMethod這個function,即可執行伺服器端這個名為GetData的PageMethod(由於該Method不需要任何參數,因此上面第二個參數我們給null),並且在成功呼叫之後,透過callback function取得回傳值result,這個result就是剛才PageMethod的回傳物件PageMethodDefaultResult<List<StudentInfo>>,而result.Data則是PageMethod回傳物件中的List<StudentInfo>,也就是實際上我們在前端需要的ViewModel資料,也就是五筆學生的身高體重與BMI值。

那…這個…

vm_StudentInfo.items = result.Data;

這行程式碼什麼意思呢?別急,我們來看前端頁面上完整的程式碼:

請注意UI的部分只有50行之後,UI進行Template Rendering的部分只有64-94行中間的表格部分,而8-11行則是引用我們會用到的js與css。整段程式碼看過之後,我們來看關鍵的幾個部分。

  1. 首先,該頁面一被載入完畢,41行的Document Ready會先被執行,請留意43行的SetBinding設定。後面45,46只是Hook Button的Click事件而已。
  2. 43行呼叫的SetBinding做了什麼呢? 我們看16-23行。整段內容非常簡單,就是透過Vue做一個資料繫結,繫結什麼? 誰跟誰繫結? 就是頁面上的HTML Template與瀏覽器記憶體中的物件vd_StudentInfo。其中20行的el與21行的data,告訴Vue.js的Rendering/Binding engine,當指向vd_StudentInfo這個記憶體物件的items有所異動時,要自動更新(Rendering)頁面上TableBody這一塊的內容。

     
  3. 我們看TableBody,也就是第64行到94行這一塊div :
     
  4. 由於上面的TableBody區塊,是透過{{…}}這樣的語法所設置了的HTML樣板(Template),因此,每當vm_StudentInfo中,指向vd_StudentInfo的這個data(也就是items)有所異動時,el區塊(也就是TableBody)就會被更新。你可能會疑惑兩件事情,(1) items什麼時候會被異動? 以及 (2) el區塊會被怎麼更新?
  5. 首先,請看45行的Button,他被按下時會觸發26行的GetData,透過CallPageMethod呼叫是伺服器端的GetData方法回傳學生資料JSON到前端,透過result.Data傳回,然後我們丟給binding_StudentInfo.items,對,就是這個動作,更新了items,這解答了上面的(1)這個問題。
  6. el區塊會被怎麼更新呢? 因為我們透過了Vue.js設定的Template語法(也就是那些{{…}}),因此,Vue.js Render Engine發現了items有所異動,就會去拿vd_StudentInfo中的值,更新指定的el區塊(tableBody),也就是64-94行的HTML樣板(Template)。
  7. 更新時,會把vd_StudentInfo帶入items,然後請特別注意76行的<tr v-for="item in items">,這一段Vue的v-for語法,意思是接下來的tr區塊(76-92行),會被重複顯示(Render),重複的次數看items這個array的個數決定…別忘了,items就是vd_StudentInfo,而vd_StudentInfo是從伺服器端傳來的List<StudentInfo>…
  8. 由於伺服器端傳來的資料有五筆,因此這個v-for跑了五次,每一次帶入一個StudentInfo item(留意78,81,84…這幾行的繫結語法{{item.屬性名稱}}),資料被帶入表格,呈現出底下的結果:

沒了,就這樣。

這個Template Rendering與過去XAML當中的Binding Engine作法幾乎完全相同。也就是,透過設定Template語法,上面js程式碼中的new Vue(…),把UI Element與記憶體中的Data Object做一個關聯(繫結),一旦繫結綁定了之後,一端有任何變化,另一端也會跟著變化(在表單中使用的話,可透過v-model設為雙向繫結,容後介紹),而搭配上{{…}}這樣的Template顯示語法,在HTML中可以輕易的帶入要呈現的集合資料或變數。

不僅僅語法非常簡潔,HTML Tag的破壞也極少,這是我喜歡Vue.js的原因,他讓SPA可以輕易實現前端的Template Rendering或Data Binding,並且讓設計師(Designer)與程式設計師(Developer)可以開心的合作。

所以…

目前Vue.js幾乎是我們現在開發SPA時,在前端的首選甚至是唯一選擇。上面這整段程式碼是非常常見的應用,只要稍微熟悉Template Rendering或Data Binding概念,可以很快的pick up整個Vue.js的語法與使用,建議沒有使用過的開發人員可以試試看…

後面,我會抽空繼續介紹更進一步的Binding方式,例如在表格中加上Button按鈕之類的…

source code : https://github.com/isdaviddong/AspNetWebFormsSpaVueBinding

Again: 上面是透過PageMethod來寫,如果你想看WebAPI的版本,請參考上面的程式碼,UI的部分請看index.html,PageMethod則改成了透過WebAPI呼叫BO,請參考ControllerHealth.cs ,並接著看下一篇

更完整的WebAPI版本CRUD Source Code:
  https://github.com/isdaviddong/AspNetWithVueBinding
--------------------------------------------
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2017年1月1日 星期日

一次搞懂OAuth與SSO在幹什麼?

最近的Line NotifyLine Login,以及前一陣子的Microsoft Graph API,全都使用到了OAuth作為用戶身分驗證以及資源存取的基礎。但很多讀者會卡在OAuth的運作流程上,根本的原因是不理解OAuth到底是幹嘛的?其存在的目的為何?以及如何應用?

因此,我想花一個篇幅,盡可能短的介紹一下OAuth與SSO,但,與坊間文章不同的是,我希望從應用情境的角度(而非技術)切入談這件事情,冀望能夠讓開發人員對OAuth有個最基本的認識。

OAuth的背景

我們回頭看Line LoginLine Notify中的例子,OAuth在這邊最簡單的應用情境,就是身分驗證。典型的情境中有幾個角色,分別是:

  1. 網站或App的開發單位 : 也就是各位開發人員
  2. OAuth服務的提供者(Provider) : 也就是Line(或Google、Microsoft…etc.)
  3. 終端用戶(End-User) : 網站使用者、Line使用者、消費者、客戶…etc.

上面這三者的關係是什麼?

當我們建立一個網站(例如Pc Home購物)、或App(例如一個手機遊戲),都非常有可能需要建立一組會員機制,這些機制包含:

  1. 登入(包含身分驗證,帳號、密碼保存…等)
  2. 個資管理(用戶名稱、地址、電話、暱稱、手機…等)

以往,幾乎都是每一個網站自己做一套,但這樣有很多麻煩事,首先用戶要記得很多組帳號密碼,而每一個網站都自己搞一套會員機制,網站開發人員自己也很辛苦,加上最近這幾年大家都很重視個資,網站儲存(保管)了很多帳號密碼與個人資料,總是會有被駭的風險。因此,這十年來,很多大廠開始提供登入(與身分驗證)機制服務。

也就是說,小網站你不用自己做登入和會員管理了,你連過來我這邊,我是大網站,我已經有幾百萬上億的用戶,(例如全台灣都用Line),而且早就做了超級安全的會員管理機制,你這小網站何必自己做會員管理呢?你跟我連結不就得了,我大網站來幫你管理個資,提供你登入的服務,你把會員資料通通存我這裡,用戶也不需要記得很多組帳密,只需要記得我大網站的帳密,一樣可以登入你小網站(或稱為第三方應用)來使用你提供的服務,這樣皆大歡喜。

因此,大家就這麼做了。

但提供這樣服務的大廠越來越多,Google、Microsoft、Yahoo…都提供了這樣的服務,導致小網站為了對使用者更貼心,可能要同時連結上很多這種提供身分服務的大網站,如果每一家連結方式都不同,就很煩。因此,業界就開了幾個會,共同決定了一套工業標準,就是OAuth了。

有哪些功能?

所以你會發現,基本上網站開發人員有兩種身分,一種是OAuth服務的提供者(像是Google、微軟、Line),另一種是OAuth服務的使用者,像是一般的小網站(trello)。而終端用戶只需要在大網站申請過帳號,就可以登入小網站來使用服務。

但,大網站當然不能給你(小網站)用戶的帳號和密碼,否則多麼不安全呢?因此OAuth工業標準讓服務提供者(大網站)透過一種標準的作法,在用戶驗證過身分之後,提供一組會過期的令牌給小網站,這就是token。

小網站拿著這個令牌,就可以跟大網站取得用戶的個資,或是其他需要的資料。小網站也可以拿著這個令牌,跟大網站確認該令牌是否已經到期。

所以,整個流程大概是底下這樣:

由於上述過程中的(2),登入畫面是大網站提供的,因此你小網站不會得知用戶的帳號密碼,大網站只會在登入成功後,把一個具有有效期限的Token傳給你小網站,一旦你需要存取用戶的資料,就拿這個token去跟大網站溝通。

當然,實際上的OAuth操作步驟又更複雜,如果你參考我們前面介紹的Line Login那篇,就會知道,用戶被引導到大網站完成登入之後,你小網站是無法直接取得token的,而是取得一個code,再去用這個code跟大網站換得一個token。為何要多這一道手續?因為,網際網路是個不安全的所在,在網路上傳遞的任何東西,都可能被路上經手的路由器或其他設備給擷取、偽造、變更,因此要確保安全,得更加小心一點。

因此一般的OAuth流程,其實應該長得像是底下這樣(這是微軟Graph API的OAuth Auth Authorization Code Flow流程) :

還有更複雜的、更進階的。

如果大網站除了提供用戶的個資之外,還要可以讓小網站有權限做一些額外的事情,像是變更用戶大頭照、取得用戶上傳的檔案、幫用戶book一個行事曆…這都是Office 365/Google Apps裡面典型的情境,如此一來,終端使用者(end-user)可能就要授權小網站,到底能夠使用該用戶在大網站中多少資料,也就是大網站的用戶要賦予小網站多大的權限,來存取該終端用戶的個資? 這部分,一般稱之為 Permission Scope。

所以,OAuth除了提供登入身分驗證之外,也逐漸開始負擔了網站合作之間的授權管理功能。

好,現在回過頭來看,請參考Line LoginLine Notify這兩篇中的例子,你會發現一開始我們都只是組出一個URL,來取得Authorization Code,這一段取得的code是明碼,走的是http get,透過瀏覽器網址列來傳遞,所以在網際網路上是可以被任何人擷取看到的(因此你當然應該加上SSL),但你會發現接下來小網站取得Authorization Code之後,要透過http post,從後端走另一個路徑去跟大網站換得token,這一段並不是走瀏覽器http get,而是在小網站的伺服器端走另一個https路徑,去跟大網站溝通。由於這一段往往是在背後做的(伺服器端對伺服器端,不會經過用戶端),因此安全性相對高(OAuth也有實作成在前端取token的implicit flow,但走後端相對安全點)。如果從後端換取Token,不管是瀏覽器或用戶本身都無法得知token,就算你的用戶被人在瀏覽器或電腦中安裝了木馬也無法得知,再加上Token還有期限,因此相對安全。

這也是我們前面說的,實務上小網站被導引到大網站完成登入之後,並非直接取得token而是取得一個Authorization Code的原因。

所以你也不難理解,既然Token會到期,就衍生出需要更新(refresh)token、判斷token的有效性、設定Token的生命長度…等相關議題,但在這邊就先不介紹了。

更進一步實現SSO

好的,假設網路世界的身分驗證,都是某一個大網站(例如Google)提供的,而其他服務的小網站(網站A、網站B、網站C…),都使用Google提供的身分驗證服務,那這世界就很單純了,一旦用戶登入了網站B,用著用著,連結到了網站A,還需要重新登入一次嗎? 不需要,因為在網站B已經登入過了,這就是SSO(Single Sign On)在internet上的實現。

一旦OAuth提供者和使用者(也就是大小網站),都有實作這樣的功能,那用戶翱翔於網際網路上時,就只需要記得一組帳號密碼了,這世界多麼美好…

當然,現實世界不是這樣的,你想想,當個大網站將會擁有所有人的個資耶,這意味著什麼呢? 不用大腦想也知道。 所以,只有你想做大網站? 不,每個人都想做。因此只要稍具規模網際網路服務提供者,都希望自己是最大的那個身分驗證提供者。

現在、連Line這個IM界的新玩家(相對What’s app、skype來說,真的算是新的),挾著在亞洲(其實也只有台灣、日本、和韓國…)的超人氣,都開始提供OAuth Provider服務了,你說,Line這家公司它還不夠任性嗎?
#搞懂了OAuth和SSO,不妨接著玩玩Line NotifyLine Login,很好玩唷… Smile
--------------------------------------------
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。