2016年9月25日 星期日

在asp.net WebForm當中找個簡單的方法實現非同步檔案上傳

最近由於一些因緣際會,又得回頭寫一點asp.net WebForm相關的東西,但,時代在這5年中實在有了不少的改變,因此一些過去的做法,最近有了不同的實作方式,其實我也是久久沒用怕忘記,紀錄一下。

我們最近碰到一個需求,非常單純,就是希望在網頁上用非同步的方式上傳檔案。

這需求沒啥好說嘴的,對吧。

但環境是這樣的,我們用的開發工具是asp.net WebForm,頁面需要盡可能保持單純,因為我自己不喜歡任何從伺服器端render html到前端的解決方案,因此一開始就盡可能的少用 web control之類的東西。由於現在有jQuery可用,瀏覽器的支援也比當年好了不知多少倍,因此,asp.net AJAX那種龐然大物自然也被排除在選用範圍之外。

為何不用asp.net MVC? 一則因為網站必須和過去開發環境(人員)相容,另外asp.net MVC中的Razor view也會從伺服器端render html到前端,route的對應方式和過去webForm的路徑作法不同,在一個專案裡面同時出現實在太不直覺,因此也不在考慮範圍內。

但專案中我們會用asp.net WebApi,如果需要的話(這表示我們不用Web/WCF Services了)。

簡單的說,就是這雖然用asp.net WebForm技術,但頁面前端盡可能的只有 html 與 js,而後端用C#,盡量不用任何WebControls。OK,背景交代完畢。

怎麼實現,先看前端要怎麼上傳檔案,很簡單,放一個file upload,和一個上傳button,寫一點js做非同步上傳用:

我覺得大部分的程式碼都不需要解釋,留意31行body之後,雖然該頁面是asp.net webform,但除了預設的form tag之外,其他的control我們都是用html而非asp.net web controls,在button click時候,我們呼叫第6行的UploadFileAsync,裡面透過很標準的post方法把用戶選擇的檔案上傳。

就這樣。

那伺服器端怎麼接這個檔案呢? 也容易:
就上面這區區幾行…

ㄟ…我承認,放在Page_Load裡面看起來有點low,但,這是最簡單單純的做法了,整個過程中不需要使用任何第三方套件或工具,頁面也盡可能保持乾淨。

結案,收工。

喔,程式碼在https://github.com/isdaviddong/AspNetWebFormAsyncFileUpload

後記 :

  1. 其實比較有趣的是,透過上面這樣的Code,你很容易猜出asp.net WebForm當中檔案上傳這個機制骨子裡的做法。
  2. github的gist還蠻好用的。
  3. asp.net WebForm用的好,搭配一點js,無須什麼新技術,其實日子也可以蠻好過的。

2016年9月22日 星期四

Microsoft Cognitive Services (4) - 使用Speech API讓你的電腦說話

讓你的電腦說話早已經不是新鮮事了,早期WP7.x的時代,我們就寫過程式碼讓手機說話,適當的採用語音輸出,對於用戶來說也是個不錯的互動體驗。

透過Cognitive Services中的Speech API讓電腦說話,用起來也相當簡單,它可以直接在雲端為你產生你指定的語音,並且將語音檔案binary傳回用戶端。

整體來說,使用該API的方式可參考底下:
Bing Text To Speech API

同樣的,使用時你會用到一組Key,這個Key與先前我們做語音辨識的時候使用的Key相同。呼叫 API前,我們需要先透過這組Key取得一個token (底下是postman呼叫畫面):

取得Token時,請用POST呼叫底下URL :
https://oxford-speech.cloudapp.net/token/issueToken

傳入的body是 :
grant_type=client_credentials&client_id=<Your subscription key>&client_secret=<Your subscription key>&scope=https://speech.platform.bing.com


其中的 Your subscription key 是我們前面說到的 key。

取得後的token應該是類似上圖中一長串的文數字。

接著,請組出底下這樣的XML,這組XML是用來告知Speech API我們要取得什麼語音:
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xml:lang="zh-TW">
<voice name="Microsoft Server Speech Text to Speech Voice (zh-TW, Yating, Apollo)">
哈囉,今天天氣不錯啊
</voice>
</speak>

這組XML是以body的方式傳入http post的呼叫,其URL是:
https://speech.platform.bing.com/synthesize

留意XML中的內容,voice name可讓我們指定語音的語言和類型,可用的內容可以參考底下這裡得知:
https://www.microsoft.com/cognitive-services/en-us/Speech-api/documentation/API-Reference-REST/BingVoiceOutput

你也可以透過底下這邊的工具來組這串XML:
https://www.microsoft.com/cognitive-services/en-us/speech-api

別忘記,呼叫上述http post時必須傳入底下的headers:
Content-Type : application/ssml+xml
X-Microsoft-OutputFormat : raw-8khz-8bit-mono-mulaw
Authorization : Bearer <剛才取得一長串token>

例如(底下是postman呼叫畫面):

也不是很複雜,透過這樣的方式,就能夠取得指定文字的音訊(.wav)檔案囉。

上面是透過測試工具post man來呼叫,如果要透過C#程式碼呼叫,則可參考底下連結:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/6e7f64e4-052c-4753-8128-43b94045064a/mvp-sample-code-with-voice-output-rest-api-in-c?forum=mlapi

2016年9月8日 星期四

關於bot framework (6) - 如何分辨WebChat用戶並保護Secret key

好不容易透過bot framework建立好了一個bot,要讓用戶和我們的bot chatting,最簡單的方式當然就是透過內建的Web Chat。

你會發現,在後台的管理畫面上,有一個內建的Weh Chat:

要啟動該Web Chat,只需要點選上圖中的Edit,並且產生一個secret key即可:

有了這組secret key,你可以直接透過底下這樣的網址,讓不特定用戶來與你建立好的bot聊天:
https://webchat.botframework.com/embed/test20160826?s=x4fT4xmsjNw.cwA.lLc.MfO35JmnXsxKxihkLaMptAlwTqGwOJFP1kLim174nFh8

畫面大致如下,這個Web Chat UI除了可以文字聊天,還可以上傳圖片,其實蠻好用的:

但問題來了,文件上開宗明義地就說,這組secret如果洩漏出去了,那任何人都可以用iframe指令把你的bot embbed在他們家的網頁裡,這或許你不在意,但還有另一個問題。每一個得知這樣的網址連進來的用戶,對談時都是以匿名的方式進來的,如果將來要查詢聊天紀錄,很不方便。

那麼除了用Skype或是FB Messanger來串這個bot,有沒有什麼方式可以解決這個問題呢? 有的,而且還一石二鳥。

首先,你確實不應該用後台產生的這組secret key作為使用WebChat UI的參數,而是該改用一個token。本來的WebChat網址

https://webchat.botframework.com/embed/botName?s=x4fT4xmsjNw.cwA.lLc.MfO35JmnXsxKxihkLaMptAlwTqGwOJFP1kLim174nFh8

應該改為

https://webchat.botframework.com/embed/botName?t=token

這樣的型式。

那這token怎麼來呢,你可以透過底下這個API取得:
https://webchat.botframework.com/api/conversations

當你用POST呼叫上面這組API,在headers中傳入Authorization(value是BotConnector 加上你的secret key),就可以啟用一個新的Conversation,並透過回傳的JSON取得該Conversation的ID與Token,如下圖 postman畫面:

這Conversation的ID與Token能幹啥? 告訴你,大有用途。

首先,你取得token之後,就可以把剛才連結WebChat的網址改成https://webchat.botframework.com/embed/botName?t=token

這樣你就不會洩漏你的bot的secret key了,而每一組token都是有時間限制的,逾時之後就無法使用了。

另外一個很重要的資訊是ConversationID,有了ConversationID我們就可以在用戶從WehChat的UI與bot對談時,從後端WebAPI程式碼當中,分辨出當前對談的人是誰,而不需要用戶非得從skype或FB Messanger進來,才能得知用戶的身分了。這…怎麼說呢?

首先上面這組POST指令,是可以(也應該要)從後端呼叫的,拿asp.net WebForm/MVC來說,你的流程可以是:
  1. 讓用戶先用Forms驗證登入
  2. 透過User.Identity.Name取得用戶的身分(假設用戶登入為David)
  3. 從後端asp.net C#程式碼中呼叫上面的API https://webchat.botframework.com/api/conversations ,來建立新的Conversation
  4. 取得該Conversation的ID與Token
    (一旦取得ConversationID﹐我們就可以記錄該 ConversationId 的對談對象是 David)
  5. 接著,利用剛才取得的token產生一個WebChat對談URL(https://webchat.botframework.com/embed/botName?t=token ),並redirect過去。
  6. 用戶即可在上面 https://webchat.botframework.com/embed/botName?t=token 這個位置與bot對談,對談中我們的後台bot對談邏輯WebApi中取得的activity.Conversation.Id ,就是剛才我們記錄下來的ConversationID,如此一來,就可以關連到用戶是David了。
瞭解了嗎? 透過上面這個POST API,不僅僅可以保護你的secret key,還可以取得新建立的對談的ConversationID,並且關連到與該bot對談的用戶,功能可說是非常大呢~