-
Notifications
You must be signed in to change notification settings - Fork 1
/
content.json
1 lines (1 loc) · 456 KB
/
content.json
1
{"meta":{"title":"E.K TechThinking","subtitle":"Tech & Thinking & DevOps & Azure & VSTS","description":"Azure,Teams,雲端架構,製造業,DevOps,程式開發,MVP,架構設計,C#,SQL,javascript,html,css,微軟,MVC,Server,寫","author":"Edward kuo","url":"http://edwardkuo.imas.tw"},"pages":[{"title":"個人蒐集的網站","date":"2016-06-30T20:48:33.000Z","updated":"2017-07-28T09:07:06.816Z","comments":true,"path":"Link/Link.html","permalink":"http://edwardkuo.imas.tw/Link/Link.html","excerpt":"","text":"Bootstrap 資源 Bootstrap Case Bootstrap Form Builder Bootstrap官網 Bootswatch Pingendo 網路資源 Google Analytics 圓角產生器 圖庫 Iconfinder Microsoft MVA MSDN Visual Studio MarketPlace MS DevOps blog"},{"title":"Edward.Kuo","date":"2017-08-13T15:33:11.358Z","updated":"2017-08-13T15:33:11.358Z","comments":true,"path":"about/about.html","permalink":"http://edwardkuo.imas.tw/about/about.html","excerpt":"","text":"架構不是設計出來,是迭代出來的;沒有最完美架構,只有最適宜的架構 本身在竹科打滾十多年,從RD到MIS扮演過不同的角色,在不同的角色中學習用不同觀點看待軟體開發流程,本身不僅熱愛技術,也喜愛探索產業各種Knowhow與流程,在需求與技術中探尋合適的解決方案,思考適合產業架構的設計,近來,研究企業如何導入DevOps核心價制於開發流程中,讓DevOps會更適用於企業IT現狀的模式 經歷 任職某外商公司 資訊主管 好朋友工坊 資訊顧問 財團法人福榮融合教育推廣基金會 資訊義工 雲林科技大學工業工程與管理系課程委員會 委員 Study4.TW 社群講師 曾任職友達光電 資訊處 工程副理 曾任均豪精密機械 LCD研發處 課長 獲獎 Microsoft® MVP MVP 社群活動突出貢獻獎 Certified Scrum Developer Certified Scrum Master Certified Product Owner 講課 Microsoft Teams記者會 Speaker Visual Studio Everywhere 講師 Global Microsoft Azure Bootcamp 講師 Microsoft Community Rising Star appraise 中國第十屆五金工業設計大賽 評委 國立東華大學 全球供應鏈管理講師 國立雲林科技大學 全球供應鏈管理暨生產排程規劃講師 漢翔航空工業 全球生產排程規劃講師","keywords":"Edward kuo,Kingston,MVP,Study4"},{"title":"整理個人愛用的Sublime外掛套件","date":"2016-05-31T20:48:33.000Z","updated":"2016-11-22T15:55:34.000Z","comments":true,"path":"sublime/Sublime.html","permalink":"http://edwardkuo.imas.tw/sublime/Sublime.html","excerpt":"","text":"因為工作需要,開始做一些Font-End的工作,雖然,Visuao Stduio已經非常好用,但是,就前端工程師來說用的比較多還是Sublime,Sublime好用這裡就不做介紹,我們知道它是一個輕量化的編輯軟體,很多功能都是你需要時候才透過Plugin方式來安裝,若是,你安裝Plug-in套件,這東西就跟筆記本沒啥兩樣,所以,外掛選用就變成是一件重要的東西。諷刺的是,若是外掛裝多,這東西也就龐大,當然效能也就變慢了,一個好的方式就是下載免安裝版本的sublime,依照在不同工作需求去產生不同的sublime執行資料夾,避免同一個sublime裝太多套件變慢了 紅框為可攜帶版本,也就是說套件裝好後,可以任意攜帶到其他電腦繼續使用,不需要重裝套件 要安裝套件時候,記得必須先安裝Package install panel套件,安裝方法可以參考 http://packagecontrol.io/installation 陸陸續續整理一些不錯的套件給大家使用,若是有好的套件也歡迎推薦給我 ChinesOpenConvert 主要是做繁體與簡體轉換,除了文字轉換,還會針對慣用語的轉換,慣用語轉換的準確度還算可以 SASS & SCSS 要用SASS寫CSS的話,兩個語法在原本sublime是沒有支援,必須額外安裝。不過,可以依照自己愛用哪一種語法去開發,安裝其中一個就可以 Html-CSS-JS Prettify 支援HTML & CSS & JS排版的套件,透過它可以美化程式版型,在使用之前,電腦必須安裝Node.JS,它是基於Node.jS下的運作的套件未安裝前的格式美化後的樣式 sidebarenhancements 讓Sublime的側邊功能加強原本有的功能只有下面這樣,功能看起來少少的安裝完畢後,可以發現側邊欄位的功能變成很多了 ConvertToUTF8 預設sublime並不支援utf8,避免後續出現亂碼,這套件幾乎是必須安裝的 Emmet 讓我們可以快速產生Html Tag的套件,透過這套件可以簡化很多打字的力氣例如:你只要在空白頁面打入 ! + Tab,就會出現下面圖樣,Tag都幫你做好了又或是你要打槽狀的Html Tag,可以這樣打div>p>span + Tab,這語法其實不需死記,因為這語法其實就是跟撰寫CSS是相同的,只要會撰寫CSS就可以快速建立這樣結構 更多語法可以參考http://docs.emmet.io AutoFileName 當我們在使用一些Tag需要用到資料夾內的各個檔案路徑時候,會自動幫我們顯示出來這樣好處在於,可以快速找到我們要的檔案,也可以省掉打一些路徑的時間"},{"title":"我的Slideshare","date":"2017-12-07T20:48:33.000Z","updated":"2017-12-06T15:44:36.646Z","comments":true,"path":"slideshare/slideshare.html","permalink":"http://edwardkuo.imas.tw/slideshare/slideshare.html","excerpt":"","text":"微信公眾號運營 AzureBootcamp 中國Azure 使用經驗 Vsts + microsoft teams 建構企業的Devops 建構Devops流水線工具的另一個選擇"}],"posts":[{"title":"查詢Microsoft Teams群組中儲存檔案的容量","slug":"Devops/TeamsFileSize","date":"2017-12-12T16:00:00.000Z","updated":"2017-12-13T08:20:41.116Z","comments":true,"path":"paper/2017/12/13/Devops/TeamsFileSize/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/12/13/Devops/TeamsFileSize/","excerpt":"","text":"首先感謝微軟技術團隊提供支援,協同解決 當大家開始習慣使用Microsoft Teams時候,就會開始把習慣透過群組方式分享檔案給團隊成員, Office 365雖然有提供每個帳號1TB的Onedrive空間,但是,對於公用的空間卻是有限制的,其計算方式1TB+Account個數x0.5G,換句話說如果公司人數1000人,共用的空間大小則是1.5G。而這1.5G會被SharePoint和Microsoft Teams所儲存的檔案大小給瓜分。所以,感覺很多,但其實也不太夠用。 此外,Microsoft Teams是一個很獨特的工具,因為前端看見是Teams,但其實背後隱藏技術卻是被架構在SharePoint、Skype for Buinsess…等Office 365內的服務之上,所以,Microsoft Teams的檔案管理背後其實是被SharePoint管理,所以,當我們建立一個新的群組,等於是在Office 365上面建立一個SharePoint Web Site,只是在SharePoint Admin管理介面中看不到這些群組 這時候,就必須Teams的管理上真的還不夠人性化,在SharePoint Admin看不到,且在Office 365後台也沒有相關資訊,對於管理者來說真的不夠方便,不過,目前最差狀況就是還可以透過PowerShell管理,至少是還是有解決方式 安裝SharePoint Powershell模組 既然要透過PowerShell管理,就必須先安裝相關管理模組,才能與Office 365連線溝通,首先必須下載SharePoint Online 管理命令介面,下載套件網址https://www.microsoft.com/zh-tw/download/details.aspx?id=35588 查詢Teams空間使用狀況 這邊使用的PowerShell語法,基本上就是管理Office 365用的語法,如前面所說,Teams群組其實背後是SharePoint,所以,語法上等同於查詢SharePoint使用檔案空間狀況,下面逐步撰寫相關查詢語法 建立Office 365連線,執行後會跳出帳號密碼輸入框,輸入密碼即可12345#Format :XXXXXX@BBB.onmicrosoft.com\"$AdminName =\"Office 365管理者帳號\"$O365Connection = Get-Credential -UserName $AdminName -Message \"Enter Office 365 Admin Credentials\"$O365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $O365Connection -Authentication Basic -AllowRedirectionImport-PSSession $o365Session 2.連線到SharePoint Admin Portal123$SPAdminUrl =\"https://BBB-admin.sharepoint.com/\"Connect-SPOService -Url $SPAdminUrl -Credential $O365Connection$TeamsGroups = Get-UnifiedGroup -ResultSize Unlimited Get-UnifiedGroup主要是列出所有群組列表,可以再放其他參數了解該群組的細節 3.列出群組使用的檔案大小1234567891011121314151617$TeamsResult=@() ForEach ($TeamsGroups in $TeamsGroups){ If($TeamsGroups.SharePointSiteUrl -ne $null) { $TeamsGroupSite=Get-SPOSite -Identity $TeamsGroups.SharePointSiteUrl $TeamsResult += [PSCustomObject] @{ GroupName = $TeamsGroups.DisplayName SiteUrl = $TeamsGroupSite.Url StorageUsed_inMB = $TeamsGroupSite.StorageUsageCurrent StorageUsed_inGB=$TeamsGroupSite.StorageUsageCurrent/1024 StorageQuota_inGB = $TeamsGroupSite.StorageQuota/1024 WarningSize_inGB = $TeamsGroupSite.StorageQuotaWarningLevel/1024 } $Sum +=$TeamsGroupSite.StorageUsageCurrent }} 群組的SharePoint網址格式都會是https://BBB.sharepoint.com/sites/Name 限制Teams群組空間大小 限制群組空間大小,是採用MB計算,空間計量設定有兩個地方,一個是警示容量大小,一個是可用容量大小,警示容量顧名思義就是當使用到警示容量會有提示功用,所以,設定容量限制時候,可用容量不可以小於警示容量,不然會出現錯誤,如果要自行設定容量大小,必須先在SharePoint的設定功能去變更網站集合儲存空間管理,必須改為手動 1.變更警示容量大小1Set-SPOSite -Identity https://BBB.sharepoint.com/sites/groupname -StorageQuotaWarningLevel 5120 2.變更容量大小1Set-SPOSite -Identity https://BBB.sharepoint.com/sites/groupname -StorageQuota 6000 使用上面兩行指令就可以變更容量大小了,如果想知道每個群組的設定值,也可以使用下面方式1Get-SPOSite -Identity https://BBB.sharepoint.com/sites/groupname |fl StorageUsageCurrent, StorageQuota,StorageQuotaWarningLevel 以上方式是目前唯一可以去管理Teams方式,希望之後可以把這些指令併入到原本O365平台內管理,此外,這邊另一個不好地方,就是用戶如果自行建立群組,是會被設定預設大小,所以,管理者必須定期掃描哪些是新建立群組,那些群組還沒有被限制空間大小,不然,哪邊某一個群組放上大量檔案,把共用空間用光,就會讓其他群組無法上傳檔案了 參考資料 1.管理網站集合的儲存限制2.https://technet.microsoft.com/zh-tw/library/mt238272(v=exchg.160).aspx","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"VSTS整合資安工具Fortify達成自動化","slug":"Devops/VSTSFority","date":"2017-12-03T16:00:00.000Z","updated":"2017-12-05T16:17:20.681Z","comments":true,"path":"paper/2017/12/04/Devops/VSTSFority/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/12/04/Devops/VSTSFority/","excerpt":"","text":"在資安逐步被重視的年代,企業會導入更多資安相關工具,除了本身伺服器或網路層的工具外,近年也針對程式碼進行安全性的掃瞄,目前其中市面上比較熱門的工具之一就是HPE Fortify,他本身可掃描的程式碼種類很多。在開發者端,可以透過Visual Studio的Plug in方式,安裝在Visual Studio,如果你又有Fortify Center的登入權限,便可以從Center將資安團隊設定好的規則下載下來,透過企業訂好的資安政策去掃描自己的程式碼,完畢之後,可以選擇把報告上傳到Center或是在本地自己觀看,掃描後的結果,不過,這邊我建議是上傳到Center中,可讀性會比較高,報表內容比較好看得懂 既然要走DevOps,當然除了在開發工具安裝外,也會希望在CI時候,也可以把資訊安全檢測的這一段給自動化,目前,VSTS可以透過外掛套件將Fortify整合進來,其套件名稱為Micro Focus Fortify,在 點我 來下載安裝 安裝Fortify 這邊為什麼要多安裝Fortify這步驟,因為,雖然說套件可以幫忙做到自動化,但是它底層其實是必須先有Fortify核心,然後再透過PowerShell指令驅動它,然後進行程式碼的靜態掃描。今天如果是透過地端VSTS Agent來建置,建議是手動先把它安裝好,雖然,這個Plug in有提供Fortify Static Code Analyzer Installation,其中有些設定必須要有Admin權限,所以為了省掉這中間的麻煩,還是先手動安裝好 安裝HPE Fortify SCA其實不難,主要在於必須設定裡面的資訊。 第一步找到HPE_Security_Fortify_SCA_and_Apps_17.10_windows_x64.exe進行安裝,有買這產品的人,因該都會有這一個檔案,不過,這一個版本目前不支援掃描ASP.NET Core,必須等到HPE_Security_Fortify_SCA_and_Apps_17.20_windows_x64.exe才可以針對ASP.NET Core掃描。另外,會自動幫你安裝IDE的Plug in,不過,目前似乎不支援Visual Studio 2017版本,2017必須額外安裝Plug in。 第二步安裝過程到了一半,會請你輸入Software Security Center的URL,就看自己企業內部架設的Software Security Center網址填入進去就可以,SSC網址會類似這樣: https://XXX.XX.XX.XX/SSC,到這邊看似已經完成,不過,會建議先用Command方式測試是否可以上傳fpr檔案,如果,無法上傳檔案,就必須找出哪邊出問題,不然,到時候VSTS也沒有辦法自動化完成上傳檔案,當然,如果不需要上傳檔案到SSC,就可以不用管它 如果遇到憑證問題,必須執行下面指令,必須先跟SSC管理員取得.cer檔案,並匯入到環境中,才不會發生憑證問題,造成無法連線123set "FORTIFY_HOME=C:\\Program Files\\HPE_Security\\Fortify_SCA_and_Apps_17.10"set "JAVA_HOME=%FORTIFY_HOME%\\jre""%JAVA_HOME%\\bin\\keytool" -importcert -trustcacerts -alias ussca -file "C:\\yourSCAInstallLocation\\ussca.cer" -keystore "%JAVA_HOME%\\lib\\security\\cacerts" -storetype JKS -storepass changeit 如果單機上測試都沒有問題,接下來就可以進行自動化部分,另外,在fortify中有一個fortify.license的SCA檔案,也要一併放到可以被VSTS Agent讀到的位置,因為在設定後續的Fortify Task會使用到這個檔案 在fortify安裝資料夾中找到fortifyclient.bat,用這個測試上傳fpr是否有問題 設定VSTS內Fortify Task 安裝完畢Micro Focus Fortify套件後,可以看到這些相關的TASK 要掃描程式碼,選Fortify Static Code Analyzer Assessment這個來用就可以,主要設定可以分三大塊 基本參數設定 主要設定SCA License檔案位置,和每次產生fpr檔案的命名規則 Build設定 這邊設定是要編譯程式的類型,在17.1版只有分.NET & ‘Java’版本兩種,且還不能編譯.NET Core,不過,據說下一個版本會擴充更多可編譯的類型,然後,在選擇專案位置,這邊有一個比較奇怪地方,就是如果上面有一個TASK已經做過Build,在這裡把Run Build取消,就會發生失敗狀況,所以,這邊還是必須把Run Build打勾,才可以順利進行下去。在17.1版如果是.NET程式,還是仰賴MSBuild進行,所以,編譯那一台機器上必須可以執行MSBuild Scan 掃描類型可以分成Cloud和Local,在企業端大部分都是選擇Local Scan,就可以開始進行掃描的動作,這部分會執行時間相當長,所以,建議可以用定時執行Definitons方式 上傳fpr設定 當掃描完畢之後,就會產生.fpr檔案,這時候就必須上傳到SSC Server。此時必須先設定SSC的End Point位置,設定主機屬性如下 Connection Name : 給定這服務一個名稱 Server URL : 格式會是https://XXXX.XXX.XXX.XXX/ssc User Name : 登入SSC的帳號 Password : 登入SSC的密碼再來設定對應到SSC的Application Name和Version,這邊的Application Name和Version必須和SSC上面註冊是一致的才可以,換句話說,必須在SSC註冊一個Application和它的版本 完成以上步驟,就可以自動化的SCAN,同時上傳掃描後的檔案了","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"Study4.TW Study4Love - 與大師對談 活動","slug":"Other/StudyLove","date":"2017-11-21T14:59:31.000Z","updated":"2017-11-21T16:48:02.087Z","comments":true,"path":"paper/2017/11/21/Other/StudyLove/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/11/21/Other/StudyLove/","excerpt":"","text":"活動時間: 1/06/2018 9:00:00 AM活動地點: 台大管理學院1號館/台北市大安區基隆路四段144巷 No. 52 邀請了高達 15 位講師,分享他們的專業知識和經驗,在一整天的議程中,您將可以盡情地享受 IT Infrastructure、Dev、Agile、DevOps、Azure、Database、AI…等相關的議題,無論您是初學者、轉換跑道者還是資深的技術人員,這裡皆有適合您的議程。共同學習,提出問題與講師交流,藉此精進您的開發技能。 技能範圍從容器開發、DevOps到MR都有,重量級講師盡出,不來太可惜了 活動頁面 http://study4.tw/Activity/Details/12","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"有參照外部元件如何在VSTS建立.Net Core Package","slug":"Devops/VSTSCore","date":"2017-11-09T16:00:00.000Z","updated":"2017-11-10T03:16:48.067Z","comments":true,"path":"paper/2017/11/10/Devops/VSTSCore/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/11/10/Devops/VSTSCore/","excerpt":"","text":"在先前一篇的[用VSTS建立.Net Core的Package],建立屬於.Net Core的Nuget Package,其中在Path to csproj or nuspec file(s) to pack是沒有辦法放.nuspec檔案的,但是,原本在.nuspec有一個標籤可以把外部dll包進Package123<files> <file src=\"lib\\XXX.dll\" target=\"lib\\netstandard2.0\" /></files> 不過,目前VSTS上面那個Dotnet Task無法讀取.nuspec檔案,就導致無法把外部參考的dll一起打包,而在介面上也找不到可以加入的地方。其實,在頁簽上面設定,都會被記錄到csproj檔案中在csproj有下面tag包住的資訊就跟在Package頁簽上面看到是相同的資訊123<PropertyGroup>....</PropertyGroup> 既然這樣,那樣也是因該可以在這邊加入我想要的打包外部dll設定才對,畢竟,在這裏面的屬性其實是對應到.nuspec的標籤的,找了半天,最後可以下面語法加入到csproj中123456<ItemGroup> <_PackageFiles Include=\"lib\\XXX.dll\"> <BuildAction>None</BuildAction> <PackagePath>lib\\netstandard2.0\\</PackagePath> </_PackageFiles></ItemGroup> 第一行_PackageFiles是說在專案資料夾中,你把外部的dll放在那個地方,需要去那邊抓到這個dll,第三行PackagePath是把dll放到package內那個地方,就.Net Core來說目前必須放到netstandard2.0資料夾內,所以,就必須設定把dll搬移到這邊 這樣設定好之後,再重新跑一次CI,就可以完美的把外部dll也打包進去了,雖然可以解決目前這問題,最好方法還是可以正常讀取.nuspec檔案","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"Application Insights + Logic App + Microsoft Teams 整合","slug":"Azure/AIappTeams","date":"2017-10-15T16:00:00.000Z","updated":"2017-10-16T14:04:01.949Z","comments":true,"path":"paper/2017/10/16/Azure/AIappTeams/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/10/16/Azure/AIappTeams/","excerpt":"","text":"Application Insights可以讓我們去設定監控某些指標,當這些指標有發生異常時候,就會發送Alert通知,讓我們隨時知道發生的狀況或是是否有異常發生 我們通常會設定是屬於Exception類的訊息,且這對於開發或是維運人員來說才可以立即進行處理,同時也是屬於DevOps環節的一塊,不過,透過Mail方式收到資訊內容就會像下圖這樣呈現方式,就這樣內容來說只知道有發生問題,但是無法知道問題點是甚麼,是否要做立即性的的處理,且若想要知道更細節的資訊,還必須回到Azure內查詢,才可以知道是到底是發生甚麼錯誤 若是使用手機去查看時候,更就會感到不方便。先前有實作一篇Azure Application Insights發Alert訊息到Slack,可以透過Logice App利用Application Insights的Webhook作為發送管道,雖然,可以放入比”Mail”還多的資訊,但明顯還是不夠,這時候就可以利用Logice App屬於Application insights的功能,這目前還在Preview版本,透過這個的Application insights Task就可以在訂定更多細節的資訊 Logic App流程設計 在這次設計上,只需要三個步驟就可以讓Application Insights蒐集到Exception送到Microsoft Teams Channel,算是很簡單了 RecurrenceRecurrence主要是設定間隔一段時間確認Application Insights內的資料,可以依照需求決定時間點 Run Analytics Query在Logice App的Application Insights Task共有兩種Application insights Query & Application insights for Visualize Application insights Query : 透過分析語法取得想要的資料,呈現方式是表格型態 Application insights for Visualize : 意思如同上面一樣,只是採用圖表方式呈現 因為Logice App會與Application Insights做資料串接,所以,我們必須讓Logic App可以與Application Insights溝通,因此,要設定Connection Info Connection Name : 定義連線資訊名稱 Application ID : Application Insights的Application Key,可以在下圖找到 API Key:在同一個畫面中,選擇建立API金鑰,就可以得到 設定完以上資訊,就可以讀取到Application Insights資料,之後,就採用Application insights Query這個Task,要使用語法可以先在Application Insights Analytics去跑跑看自己寫的語法是否可以運作,下面為這次實作的語法,主要是抓取資訊類型是屬於exception的 123456789101112131415exceptions| where timestamp>ago(180s)| where (itemType == 'exception' )| project timestamp=timestamp+8h,s=now()+8h,client_Type ,outerType ,outerMethod ,outerMessage ,outerAssembly,operation_Name ,details ,customDimensions,ApplicationName=tostring(customDimensions["ApplicationName"]),user_Id 上面查詢語法的每個欄位,之後都可以當作傳送的資訊欄位 Microsoft Teams設定好取得Application Insights資料後,再來就是設定綁定到Microsoft Teams,在Task中找到Microsoft Teams 要將資訊POST到Teams的Channel,所以選擇Post Message 前面有提到,透過Application Insights Query的資料欄位,都可以作為傳遞訊息的欄位,所以,可以看見Parameter都是剛剛查詢出來的欄位,然後,就可以在Message組合自己想要收到的資訊,因為是Application Insights Query查詢到的資料,所以,可以完整呈現出Application Insights蒐集的資訊 Team ID : 就是在Teams上的群組 Channel ID : 就是Teams群組中的頻道基本上只要跟Teams綁定後,這兩個資訊可以用選的,不需要人工Key,希望在Teams中的訊息有html格式,可以用Html的Tag去編排,如下圖 另外,在發送資料時候,Logic App會用迴圈方式一筆一筆將資料推送到Teams 整個流程如下 總結 Logic App功能越來越強大,整合越來越Microsoft SaaS的服務,對於企業來說可以省掉整合的成本與時間,但是,採用排程方式並不是最好的,最好的方式還是用觸發會比較好,又因為觸發沒有辦法找到詳細資訊,所以,目前怎樣運用就自行評估,不過,也許後續有可以透過參數方式丟給Application Insights Query,這樣就可以透過觸發方式去運作","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"用VSTS建立.Net Core的Package","slug":"Devops/donetVSTS","date":"2017-10-12T16:00:00.000Z","updated":"2017-10-13T16:19:08.650Z","comments":true,"path":"paper/2017/10/13/Devops/donetVSTS/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/10/13/Devops/donetVSTS/","excerpt":"","text":"我們知道使用VSTS中的Packages Manager可以建立企業或是私有的Nuget Server,在一般.Net Framework下,可以用下面幾個步驟建立Nuget的Package,其中使用到的是MSBuild做編譯,再用Nuget指令打包成Package 不過,今天若是也這樣對.Net Core專案進行封裝,雖然會成功,但是,當在.Net Core專案下載來用時候,就會出現你使用了.Net Framework,不能使用在.Net Core專案中,請使用XXXXX字樣,主要原因是在編譯時候,單純使用MSbuild的Task,會被使用.Net Framework進行編譯封裝所造成的問題,網路上有人說可以採用/t:package方式克服,不過,既然使用了.Net Core,就改用.Net Core方式做CI & CD吧 .Net Core專案檔設定 首先啟用的專案類型是.Net Core Libray 之前在.Net Framework時期專案,因為封裝成Nuget Package,必須透過.nuspec檔案把元件資訊填入,這樣別人才可以知道這個元件用途以及相關資訊,在.Net Core專案底下,已經可以省略這個檔案了,因為,要把這些需要填入資訊已經納入專案檔中了,在專案按右鍵找到屬性設定 針對整個專案設定部分,會多出一個Package頁簽,會發現填入的資訊跟.nuspec檔案內容是大同小異,只是這邊已經被限定好欄位了,上面有兩個需要打勾的,基本上是不需要去勾選 VSTS Build設定 在Build設定中,基本的完整流程如下: Nuget Restore在Nuget Task,要注意的就是它的Task Version,記得一定要選到最新版本,若是有Nuget.config檔案,也記得要放上去 donet Builddonet Task這裡如果只是單純Build .Net Core專案倒是不需要注意Task版本,但是,如果要封裝Package,記得選到最新版本,目前版本最新是2 Preview,因為在最新版本才會有Pack的指令,這裡的Path to project專案路徑,不能用選的,必須要用手敲入,記得不能打錯路徑,不然會失敗 donet pack重頭戲是在這邊,搞定這個搞超久,再提一次,記得選到最新版本,不然會找不到Pack指令 此外,這邊有一個小坑,就是在Path to csproj or nuspec file(s) to pack提到可以使用.nuspec檔案作為Package的資訊檔案,但是,當我指定.nuspec檔案時候,就會出現不支援標籤,不知道這是preview造成還是其他問題,唯一可以確定是.nuspec檔案格式是沒問題的,所以,就指定.csproj,前面有提到,在.Net Core已經可以把封裝資訊放入專案檔,用處就是在這裡要被使用的。此外,我喜歡用Buil Number來作為Package版本號,也在Automatic package versioning中選用使用環境變數作為版號,而環境變數就是使用Build.BuildNumber 另一個要提醒的是這邊先不要把Do Not Build打勾,話說前面不是已經有Build過嗎?因該不需要再Build,這裡的Build主要是要做封裝用,所以還是必須要Build一次。 到這裡基本上就大功告成,後面兩個Task,主要是把封裝檔案上傳到發布區域,等待後面的發行 VSTS Release 到這裡只需要用一個Task就可以進行發佈到團隊的Packages中 只要選擇Nuget Publish,把相關資訊田入就可以,唯一要注意是要選擇4.0版本的Nuget指令 以上就能完成在VSTS針對.Net Core的CI / CD 了,有一些眉眉角角必須多踏過,不然還真的跑不出來,所以,不管是.Net Framework或是.Net Core都可以自動化封裝成Nuget Package","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"VSTS新版Agent要多.proxy設定檔","slug":"Devops/VSTSAgent2","date":"2017-10-02T16:00:00.000Z","updated":"2017-10-13T15:14:13.982Z","comments":true,"path":"paper/2017/10/03/Devops/VSTSAgent2/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/10/03/Devops/VSTSAgent2/","excerpt":"","text":"在使用VSTS Agent 2.115版本時候,在企業內部使用是沒甚麼問題,不過,最近升級到2.123版後,地端與雲端就失聯,就無法進行連線,到_diag資料查看Log,發現會卡在最後連線驗證地端權限時候,一直發生Timeout然後Agent就發生Exception,導致怎樣都無法與雲端溝通,如果再倒回2.115版又可以連線,真是太神奇 仔細研究一下,因為企業內部必須透過Proxy才能連線,在舊版的Agent,因為會自動去吃在IE內的Proxy設定值,所以,沒有問題,但是,到新版的Agent,似乎就不是這樣,它在對外連線,基本上就不走Proxy,直接對外連線,就會導致無法連線,就發生了TimeOut,要解決這個辦法,就是在Agent目錄下新增一個.proxy的檔案,用Powershell執行下列指令 1echo http://proxy server name:80 | Out-File .proxy 這樣Agent在執行時候,就會透過Proxy連線到外面,如果,你的Proxy需要設定帳號密碼,就必須在環境變數中加入下面資訊 12$env:VSTS_HTTP_PROXY_USERNAME = "proxyuser" $env:VSTS_HTTP_PROXY_PASSWORD = "proxypassword" 就可以解決了","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"讓訪客也加入到你的Microsoft Teams團隊中,但...","slug":"Devops/TeamsGuest","date":"2017-09-11T16:00:00.000Z","updated":"2017-09-13T01:31:11.643Z","comments":true,"path":"paper/2017/09/12/Devops/TeamsGuest/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/09/12/Devops/TeamsGuest/","excerpt":"","text":"Microsoft Teams一個值得高興的更新,就是Microsoft Teams可以支援外部訪客加入Teams團隊中了,原先,要使用Teams的成員,必須具備O365帳號且還必須同一個組織或是公司下的O365帳號才可以一起使用Teams,現在這些非原本在同個組織下的O365帳號或,都會被當作訪客登入到Teams,首先,先來看用訪客身分登入後,訪客會具備那些權限 不過,雖然可以邀請訪客登入,但是,這邊有一個前提就是邀請者本身必須是O365管理員或是該群組的管理員,可以邀請訪客登入。不然,無法邀請訪客的加入。現在只是讓帳號本身是其他O365才可以,未來據說可以連Windows live ID也可以用 Office 365設定 Microsoft Teams預設沒有開放給訪客使用,如果要啟動這功能,必須到Office 365管理者平台去設定Microsoft Teams的功能 在Teams設定中找到Settings by user/license type,找到選項是來賓,從這邊可以看出來,這設定預設是無法被授權給外來訪客的,所以,我們必須要開啟它 一旦打開之後,就可以指定的群組中,加入你想要邀請的人的Email,不過,目前這邊設定有一點奇怪,就是先設定好要被邀請方的Mail,就會送邀請信給被邀請方,但是,有時候會消失,必須等被邀請方認證過後,再去加一次才會成功 這時候我們可以在被邀請方的Email看到作為訪客字樣,被邀請方就可以用這Email當作帳號登入Teams了,當然,在O365的使用者管理中,就可以看到這組Mail被歸納到來賓使用者了 被邀請方 訪客部分,不要以為對方把你邀請加入Teams後,就可以直接打開Teams,輸入Email就可以登入唷。這樣會收到你沒有權限登入的畫面,必須先到你收到邀請的那封Email中,點擊裡面的連結 就會開啟Teams網頁版,第一次登入時候,會要求你建立你的登入密碼。這些手續完成後,才可以進入到Microsoft Teams。另外,作為訪客身分登入是無法改動自己暱稱的。 現階段測試不知道是哪邊權限整合上問題,基本上無論使用Desktop程式登入或是透過https://teams.microsoft.com網站登入都會收到下面訊息 但是透過邀請信的link就可以登入,我想邀請信中連結中的變數因該是會把資訊帶入到登入認證中,但是,目前Desktop程式這部分似乎還有問題,沒有辦法很順利登入","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"解決json檔案放在Azure Storage導致發生CORS","slug":"Azure/StorageCORS","date":"2017-09-07T16:00:00.000Z","updated":"2017-09-08T01:04:04.404Z","comments":true,"path":"paper/2017/09/08/Azure/StorageCORS/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/09/08/Azure/StorageCORS/","excerpt":"","text":"把前端的一些靜態檔案像是css、js…之類的放到Azure Storage,然後,讓網站去參照Storage路徑下載靜態檔案,基本上這樣並無太大問題,不過,做多國語系時候,使用到i18n這個套件,裡面會利用translation.json檔案做多國語系,誰知道這樣使用下卻發生了這個錯誤訊息 CORS not enabled or no matching rule found for this request 通常遇到這問題,我們會去web.config去設定CORS的屬性,來避開這錯誤,不過,針對這個檔案似乎無效,它依然出現這樣錯誤資訊 因此,發現在Storage有一個設定,叫做CORS,看名字就知道顧名思義,因該是針對CORS進行處理,進入這個設定功能後,我們只要設定好CORS規範,基本上就可以解決CORS問題(基本上因該是連Web.config都可以不用設定) 設定CORS Rule 設定這規範其實很簡單的,它是針對每個Host Name去做設定,只要按下Add,就可以看到旁邊設定畫面 看到這畫面要怎樣設定呢,其實最簡單方法就是利用F12取得原本失敗檔案的Header資訊,分別填入就可以,參考資訊如下圖藍色框的欄位 Allowed Origins=Origin Allowed Verbs=Access-Control-Request-Method Allowed Headers=x-requested-with Exposed Headers=x-requested-with 透過以上對應關係,只要把資訊放入就可以,若是要更進階一點,針對Allowed Header & Exposed Headers,若是要包括更多的資訊,可以用星號省略後面的資訊,只要符合前面字樣就可以,設定會像是這樣x-requested*,只要是x-requested開頭的,都是符合這規則。 這樣設定完畢後,就輕鬆解決CORS問題了","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"解決註冊VSTS的npm平台無法下載npmjs.com套件","slug":"Devops/VSTSNPM2","date":"2017-09-01T16:00:00.000Z","updated":"2017-09-02T15:40:55.953Z","comments":true,"path":"paper/2017/09/02/Devops/VSTSNPM2/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/09/02/Devops/VSTSNPM2/","excerpt":"","text":"在前一篇的[在VSTS中建立npm套件管理平台]介紹說可以在VSTS內建立NPM套件平台,因為,VSTS建立的NPM套件管理平台是屬於私人的,所以,會有註冊憑證的動作,不過,這樣做下去之後,卻發生一個問題,如果今日我們是要從原本NPM官網下載套件,就會發生這樣錯誤 其實這錯誤就是因為在.npmrc設定檔中註冊是VSTS NPM套件路徑,而原本NPM平台上套件又不在VSTS,導致會發生失敗,如果不是上面錯誤,也會發生找不到Package路徑問題。要解決這問題,可以去開啟VSTS Package中的Upstream sources功能,下圖這個要把它Enable起來 它的原理其實就是安裝時候,會先到VSTS Package裡面去找是否有符合你要安裝的Package,如果沒有,就會自動往npmjs.com再去找 這樣就可以安裝好在npmjs.com上面的套件了,這時候,會發現在VSTS的NPM套件平台上可以看到團隊套件有來自npmjs.com的都會被Cache在這上面 如果擔心找不到自己建立的Source,可以透過filter去搜尋this feed,就可以找到自記建立的套件列表","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"用Chocolatey安裝Docker CLI","slug":"Docker/DockerCLI","date":"2017-08-11T14:59:31.000Z","updated":"2017-08-11T15:26:06.542Z","comments":true,"path":"paper/2017/08/11/Docker/DockerCLI/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/08/11/Docker/DockerCLI/","excerpt":"","text":"一般想要在個人電腦或是Windows Server 2016玩Docker,前者可以安裝Docker for Windows,後者啟用Window Server的Container,這樣就可以開始使用Docker指令,不過,今日只是想在某台電腦透過Docker -H去執行Remote具有Container的機器,是否還需要完整安裝上述所提的功能才能使用Docker Command呢? 答案是可以不需要在電腦上安裝Docker for Windows或是啟用Container,就可以執行Docker了,只需要安裝Docker CLI就可以。Docker CLI網路上版本還不少,但我目前使用Chocolatey Package Manager來安裝Docker CLI,感覺上還不錯,且安裝又方便簡單 1.首先用PowerShell來安裝Chocolatey,PowerShell需要用Admin執行1iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 2.安裝好Chocolatey,就透過它幫我們安裝docker CLI吧,通常這個步驟也是使用Powershell執行,不過,我發現執行後會卡住,改用Command Line就沒問題,如果有問題可以改用cmd試試看1choco install docker 因為目的是想要透過本身的機器去操作遠端的Docker,所以,前提必須記得去改遠端Docker的daemon.json檔案,要加入下面這行1\"hosts\": [\"tcp://0.0.0.0:2375\", \"npipe://\"] 這行目的主要是說我們可以透過Port2375進行連線,當然雙邊的防火牆記得要開啟Port23753.完畢後就下達重啟動指令就可以1Restart-Service docker 這樣就可以讓這台機器具有Docker指令了","categories":[],"tags":[{"name":"Docker","slug":"Docker","permalink":"http://edwardkuo.imas.tw/tags/Docker/"}],"keywords":[]},{"title":"在VSTS中建立npm套件管理平台","slug":"Devops/VSTSNpm","date":"2017-08-09T16:00:00.000Z","updated":"2017-09-02T12:14:23.279Z","comments":true,"path":"paper/2017/08/10/Devops/VSTSNpm/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/08/10/Devops/VSTSNpm/","excerpt":"","text":"在之前有介紹透過VSTS的Packages可以自建團隊的Nuget套件管理平台,在Packages中不只是可以建立Nuget套件的管理平台,如果,今日是前端人員或是非.NET人員,想要用npm指令來裝前端套件,VSTS是否可以做npm套件的管理平台呢?答案是可以,VSTS的Packages同時支援Nuget和npm套件管理,就讓我們來建立一個npm packages管理平台吧。 自動化建立npm package 在VSTS的Feed本身就同時支援Nuget和npm,換句話說可以在同一個Feed URL同時存在兩種套件管理,不過,並不建議這樣混合使用,畢竟這樣使用會造成套件本身管理的混亂。還是建議把兩種不同屬性的Package分別建立不同的Feed。要建立Feed只需要選擇建立就可以,很簡單的 只需要填入Feed名稱就可以建立成功,建立成功後去點選Connect to Feed,可以看到裡面有Nuget和npm兩種設定方式 透過VSTS自動化建置npm package的流程比建置Nuget package簡單許多了,今日若是要透過VSTS自動化建置,上圖中的設定可以暫時不需要管它,後續如果是在Clinet進行,則必須要做一些相關設定才有辦法,先來說講最簡單的,使用VSTS建置npm package。 因為npm主要是封裝前端的元件,基本上都不太需要做到編譯的動作,當然如果今天是用SCSS需要編譯成CSS才給人家用,這樣就需要增加編譯動作,不然,只要將整個專案進行封裝就可以。在封裝的前提必須在專案檔加入package.json檔案,這檔案主要是針對Package做說明,與Package.config有異曲同工之妙 關於package.json說明 The most important things in your package.json are the name and version fields. Those are actually required, and your package won’t install without them. The name and version together form an identifier that is assumed to be completely unique. Changes to the package should come along with changes to the version. 關於package.json格式,可以透過npm init建立123456789101112131415161718192021{ \"name\": \"my_package\", \"description\": \"\", \"version\": \"1.0.0\", \"description\": \"\", \"main\": \"index.js\", \"scripts\": { \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\" }, \"repository\": { \"type\": \"git\", \"url\": \"https://github.com/ashleygwilliams/my_package.git\" }, \"keywords\": [], \"author\": \"\", \"license\": \"ISC\", \"bugs\": { \"url\": \"https://github.com/ashleygwilliams/my_package/issues\" }, \"homepage\": \"https://github.com/ashleygwilliams/my_package\"} 有了這檔案,只需要去VSTS進行設定就可以,因為,沒有Build的動作,基本上在VSTS Build就等於Release了。所以,這邊只需要添加一個npm Task即可 設定npm Task 建立好Task後,就是把相關設定設定完畢就可以 Command : 可以選擇install,publish和Custom,這邊選擇publish Working folder with package.json : 如果package.json在Root就不用填寫,不然就選擇該檔案所在的資料夾 Registry location : 註冊你的npm package在哪個地方,如果是在VSTS內,則選用Registry I Select here,一但選用這個,下面的target就可以選擇在你VSTS上面的Feed URL了 以上屬性設定完成後,就可以讓她自動化去封裝了,同時也會自動化佈署到我們自己的Feed內,建置完成後就可以看到Feed那邊多出了npm package了另外,如果每次要佈署時候,沒有去更改package.json中的version號碼,會發生佈署失敗,主要原因是它不會去覆蓋原本舊版本,必須要進版才可以,不然會發生錯誤,如果不想這樣麻煩,也可以使用Version Assemblies套件做自動化進版 安裝VSTS中的npm package 既然我們已經可以用npm封裝好了,再來就是要能去使用它,因為,VSTS上的是屬於私人或是團隊的,並不像npm網站一樣是被公開可以用。所以,這邊我們需要增加一些設定才可以抓取VSTS上的npm,不然直接下npm install xxxx是沒有用的,主要是要把VSTS Auth驗證資訊會透過.npmrc內資訊被設定在專案中 .npmrc : npm gets its config settings from the command line, environment variables, and npmrc files. 預設你可能沒有vsts-npm-auth套件,所以,需透過npm安裝這個套件1npm install -g vsts-npm-auth --registry https://registry.npmjs.com --always-auth false 然後,在專案手動加入空白的.npmrc檔案,目前還不知道怎樣自動加入此檔案,有了這個檔案後,根據本文上面第二張圖,有一段Add this feed to your project .npmrc,把裡面的資訊registry=XXX放入.npmrc檔案中。到了這一步完成後,就可以執行下面語法1vsts-npm-auth -config .npmrc 成功後會得到下面訊息 Getting new credentials for source:https://XXXXXXregistry/, scope:vso.packaging_write vso.drop_write 如果在Visual Studio中想要安裝VSTS上面的npm的套件,可以用package manager console工具或是安裝*Flatten Packages`工具,協助我們安裝npm套件,如果使用Visual Studio Code就更簡單了","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"Application Insights自訂過濾收集的訊息內容","slug":"Azure/ApplicationInsightsFilter","date":"2017-08-06T16:00:00.000Z","updated":"2017-08-07T12:23:13.642Z","comments":true,"path":"paper/2017/08/07/Azure/ApplicationInsightsFilter/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/08/07/Azure/ApplicationInsightsFilter/","excerpt":"","text":"Application Insights越做越強大,基本上程式內部怎樣運作,Application Insights都可以蒐集到相關資訊,不過,有時候這樣會帶來一種困惱就是在某些情境下的資訊,並不想被蒐集到Application Insights內進行分析,因為有可能造成分析錯誤或是統計資訊的誤差,舉例來說,目前發現如果在IIS中針對Web Site設定Preload功能,在Application Insights就會多一筆Request,帶出來的資訊是localhost/XXX,這樣資訊對目前數據分析並不重要,但是,又會被多記一筆Request的Count。 因此,像這種資訊就會希望不要被記錄到Application Insights中,目前,在Application Insights的Portal中似乎不能設定過濾訊息,所以,就必須從程式面著手 自訂Filter 從程式面就是需要自己訂定Filter功能,首先自己建立一個叫做TelemetryFilter的Class,並繼承ITelemetryProcessor,從官方解釋ITelemetryProcessor為 讓您更直接地控制包含在遙測串流中或排除於遙測串流外的內容 所以,透過它可以獲取要送到Application Insights的檢測資訊,進而做一些篩檢或是變更等動作,繼承ITelemetryProcessor會變成如下1234public void Process(ITelemetry item){ ....} 在這個Process中,針對遙測資訊進行處理,以剛剛案例來說,希望排除到http://localhost/XXX資訊。就可以在這處理器這樣寫12345678910111213public void Process(ITelemetry item){ var request = item as RequestTelemetry; if (request != null && request.Url != null && request.Url.Host.IndexOf(\"localhost\", StringComparison.InvariantCultureIgnoreCase) >= 0) { return; } else { this._next.Process(item); }} 把Item轉型為Request Type,並抓取資料中的Url進行過濾。如果,有符合過濾條件的,就拋棄掉這個訊息不做上報的動作,如果不是,則透過Process處理收集的資訊項目。完整的寫法如下123456789101112131415161718192021222324public class TelemetryFilter : ITelemetryProcessor{ private readonly ITelemetryProcessor _next; public TelemetryFilter(ITelemetryProcessor next) { this._next = next; } public void Process(ITelemetry item) { var request = item as RequestTelemetry; if (request != null && request.Url != null && request.Url.Host.IndexOf(\"localhost\", StringComparison.InvariantCultureIgnoreCase) >= 0) { return; } else { this._next.Process(item); } }} 有這樣方式,想要過濾甚麼就可自己去定義了 註冊過濾器 開發完畢後,還必須把過濾器註冊,這樣才有辦法當Application Insights啟動後,自動掛載這個過濾器。要註冊過濾器,只要在ApplicationInsights.config中設定就可以123<TelemetryProcessors> <Add Type=\"WebApplication1.ApplicationInsights.TelemetryFilter, WebApplication1\"/></TelemetryProcessors> 這樣就可以一個簡單的Application Insights資訊過濾器就可以運作,簡單說,這個就是AP & Application Insights訊息的中繼站,所有資訊都會先到這邊再往Azure送,換句話說要在這邊做置換資訊動作也是可以的","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"2017 第12屆 五金杯 中國五金產品工業設計大賽徵集","slug":"LifeStyle/Chinadesign","date":"2017-08-05T16:00:00.000Z","updated":"2017-08-06T15:16:39.031Z","comments":true,"path":"paper/2017/08/06/LifeStyle/Chinadesign/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/08/06/LifeStyle/Chinadesign/","excerpt":"","text":"2015年有幸到中國參加此大會評審,發現雖然名為五金產品比賽,當時不乏有些不錯的IoT產品出線,不過那時候只限於中國內作品參賽,這次也可以有台灣作品參賽,工業設計高手可以去挑戰看看 何謂五金杯大賽 “五金杯”中國五金產品工業設計大賽自2006年創辦以來已成功舉辦11屆,大賽在各主辦單位和協作單位的支持下,歷屆參賽作品的數量和質量都在不斷的進步。大賽以創新和務實的特點和國內外知名的專家評委陣容,吸引了全國幾十所高校、幾十家設計公司以及眾多獨立設計師的參與和支持。為了繼續提高五金產品創新設計能力,展現產品創新的新思路、新概念、新主張 詳細內容網址 :http://www.ykwjdesign.com/notice/3387.html","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"Mobile Center讓App有自動更新功能","slug":"Devops/MCin-apps","date":"2017-07-24T16:00:00.000Z","updated":"2017-07-25T11:35:58.355Z","comments":true,"path":"paper/2017/07/25/Devops/MCin-apps/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/07/25/Devops/MCin-apps/","excerpt":"","text":"微軟在Mobile的解決方案,原先是建構Hockey App上面,不過,從今年五月開始就慢慢轉移到Mobile Center上面,無論是Build還是Test,甚至到發布,都可以透過Mobile Center幫忙完成,先前的一篇文章[VSTS 整合Visual Studio Mobile Center ]中有介紹把VSTS的Repositories與Mobile Center結合,現在Mobile Center的SDK除了原本的收集Crash Report和Analytics外,還可以讓你的APP自動檢查Mobile Center上面是否有新的版本,如果有新版本則是跳出下載提示,讓使用者可以直接更新App 在先前的Mobile Center有新版本發布時候,只能透過Mail通知用戶,還必須讓用戶點擊Mail中的連結後,再登入Portal去下載新版的App,整個體驗就很不好,也不夠直覺 使用In-app update前提 在自己App加入In-app update功能前,有幾個前提必須先知道,不然,就算把Code加入,也不會有動作 第一次下載APP,須用通知Mail內的連結下載,不能直接用Group的Public URL下載APP Build的Configuration必須是Release,不然不會有做用 每次更新必須手動把CFBundleShortVersionString和CFBundleVersion版本號更新 一定要透過Mobile Center的Distribute安裝APP 加入In-app update SDK 加入Mobile Center的Distribution SDK到程式中,以下使用的範例為Xamarin.Form,找到Microsoft.Azure.Mobile.Distribute並安裝 安裝好之後,可以在Mobile Center要發布App的Get Started或是Setting地方找到App Secret 準備好以上條件後,先到App.Xml.cs的OnStart()加入啟動In-app update,在這邊可以發現,同時有加入typeof(Analytics) & typeof(Crashes)和typeof(Distribute),表示同時啟用收集Crash & 資料分析和In-app update功能,因為這三個功能都是共用同一個App Secret 12345678protected override void OnStart(){#if AppRelease Distribute.ReleaseAvailable = OnReleaseAvailable; MobileCenter.Start($\"ios={ConfigurationManager.AppSettings[\"MobileCenterAppSecret\"]};\", typeof(Analytics), typeof(Crashes), typeof(Distribute));#endif} 裡面有一行是Distribute.ReleaseAvailable,這是自訂當有APP版本更新時候,會跳出的提示訊息,基本上,如果不做,預設因該還是會有提示方塊,不過,測試一陣子似乎還是不會出現提示訊息,導致沒有辦法更新APP,因此,如果是自訂一個提示訊息就可以進行App更新。 12345678910111213141516171819202122232425262728293031private bool OnReleaseAvailable(ReleaseDetails releaseDetails){ string versionName = releaseDetails.ShortVersion; string versionCodeOrBuildNumber = releaseDetails.Version; string releaseNotes = releaseDetails.ReleaseNotes; Uri releaseNotesUrl = releaseDetails.ReleaseNotesUrl; var title = \"Version \" + versionName + \" available!\"; Task answer; if (releaseDetails.MandatoryUpdate) { answer = Current.MainPage.DisplayAlert(title, releaseNotes, \"Update Version\"); } else { answer = Current.MainPage.DisplayAlert(title, releaseNotes, \"Update Version\", \"Next Time\"); } answer.ContinueWith((task) => { if (releaseDetails.MandatoryUpdate || (task as Task<bool>).Result) { Distribute.NotifyUpdateAction(UpdateAction.Update); } else { Distribute.NotifyUpdateAction(UpdateAction.Postpone); } }); return true;} 改好這邊後,還必須到Xamarin.app.ios的AppDelegate.cs加入app啟動時候就檢查版本功能,不管程式怎樣寫檢查更新的程式一定不能在LoadApplication(new App())之前,不過呢,又經過一番測試後,發現把這一行放在Xamarin.Forms.Forms.Init()之後是最穩的 123456789public override bool FinishedLaunching(UIApplication app, NSDictionary options){ global::Xamarin.Forms.Forms.Init();#if AppRelease //檢查有無更新版本 Distribute.DontCheckForUpdatesInDebug();#endif LoadApplication(new App());} 另外,還必須到info.plist加入一個屬性,不過,因為在iOS中,測試App和Release的App是無法共用同一個Bundle Identifier,就如之前所說,Mobile Center中的Build Task是Mobile Center做好的,我們並無法在裡面做其他更改設定,這也導致無法在自動化時候去更新Bundle Identifier Name,所以,必須額外做一個Release用的plist檔案,讓在Release Build時候,置換原本的info.plist。因此,加入一個叫做InfoRelease.plist的檔案,並在這檔案中加入CFBundleURLTypes,這邊須至換掉裡面的{App secret},其值是跟ConfigurationManager.AppSettings["MobileCenterAppSecret"]}相同的123456789101112<key>CFBundleVersion</key><string>1.1.4</string>//加入下面內容<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>mobilecenter-{App Secret}</string> </array> </dict> </array> 到這一步,基本上就已經讓App有了In-app update功能,剩下就是要把InfoRelease.plist置換成info.plist。 置換info.plist 做到這一點,就只能在專案檔中加入以下設定,先在Xamarin.App.ios的專案檔找到Info.plist關鍵字,基本上未修改前是這樣1<None Include=\"Info.plist\" /> 修改後為這樣1234567<None Include=\"Info.plist\" Condition=\"'$(Configuration)' != 'Release'\"> <SubType>Designer</SubType></None><None Include=\"InfoRelease.plist\" Condition=\"'$(Configuration)' == 'Release'\"> <LogicalName>Info.plist</LogicalName> <SubType>Designer</SubType></None> 這樣就可以在Release時候,將Release階段需要的資訊轉換成Info.plist給iOS App用了 確定功能沒問題話,在第一次安裝App後,會跳出一個網頁畫面,內容會有一段是Enable in-app Update,有這一段話,基本這個App就具有自動更新的機制了","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[]},{"title":"Windows Server 2016 Containers初體驗","slug":"Docker/DockerCon","date":"2017-07-21T14:59:31.000Z","updated":"2017-08-21T03:31:03.296Z","comments":true,"path":"paper/2017/07/21/Docker/DockerCon/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/07/21/Docker/DockerCon/","excerpt":"","text":"當Windows Server 2016開始有支援Containers後,認為只要把Windows Server 2016內的Container服務啟動後,就可以立馬來使用Docker這項技術,殊不知這是錯誤的,因為,這樣做法只是讓Windows Server 2016有了Container功能,但是,要讓它可以用Docker,還必須額外安裝Docker模組才可以有辦法開始使用Docker的技術,而在Windows Server 2016支援的Containers有分成Windows Server Containers和Hyper-V Containers,下面採用的是Windows Server Containers。 安裝Docker 建議在安裝Docker之前,要把Windows Server 2016所有更新檔都必須要更新,才不會有問題,然後,用Admin權限啟動PowerShell,而第一個必須先安裝Docker-Microsoft PackageManagement套件,有了這個套件,才能去安裝Docker的Package 安裝Docker-Microsoft PackageManagement1Install-Module -Name DockerMsftProvider -Repository PSGallery -Force 安裝Docker Package1Install-Package -Name docker -ProviderName DockerMsftProvidere 都安裝完畢後,必須重新啟動電腦,讓Docker服務啟動,若是後續想要更新Docker,只要輸入更新指令就可以1Install-Package -Name Docker -ProviderName DockerMsftProvider -Update -Force 以上三步驟就可以在Windows Server 2016用Docker功能,若不確定是否可以用,只要輸入docker info能查看Docker相關訊息就沒問題了 安裝Docker-Compose Docker-Compose是讓你可以快速佈署或是啟動Container的設定檔,如果是透過VS.Code去編輯Docker-Compose的yml檔案,必須先在VS.Code內安裝相關Docker-Compose套件,才可以開始編輯,但按照先前作法,已經可以在Windows Server 2016使用Docker,不過,卻沒有Docker-Compose指令,因為,必須額外安裝Docker-Compose套件,才有辦法使用Docker-Compose指令,安裝套件位置[https://github.com/docker/compose/releases],下載的檔案名稱是會是這樣docker-compose-Windows-x86_64.exe,也可以直接用PowserShell的指令安裝套件1Invoke-WebRequest \"https://github.com/docker/compose/releases/download/1.14.0/docker-compose-Windows-x86_64.exe\" -UseBasicParsing -OutFile $Env:ProgramFiles\\docker\\docker-compose.exe 不過,若公司防火牆關係無法安裝化,就是必須先把檔案下載下來,並且,透過上面指令取代掉原本URL位置改成docker-compose-Windows-x86_64.exe檔案的路徑,就可以安裝了,或是更改檔名為docker-compose後放自訂一個目錄中,只是必須設定系統的Path指定到這個目錄中 製作自己的Docekr Image 我們會從Docker Store下載自己所需要的image建立Container,不過,從Store下載來的image只是原始的Source,有時候並不能符合我們實際需求,所以,還會額外把設定加入進去,但是,若是每次從Image建立Container,都還要重複設定一次,也很費工。如果這時候想要每次都直接用自己加工過的image,而不是原始的Source,必須花一點小方法來製作屬於自己的image,在原本Docker指令中,是有支援Export功能,但是,在Windows Server 2016 Containers目前沒有辦法用這個指令。所以,我們必須利用Commit方式進行。 以SQL Server Container為例,我們可以先把Containers建立起來後,並放入自己系統的DB1docker run -it --name SQLTest -d -p 14331:1433 -e sa_password=XXXXX -e ACCEPT_EULA=Y -v c:\\DB\\:C:\\DB\\ microsoft/mssql-server-windows-express:2016-sp1 這時候建立的DB Container就不會是原始的Source,且每次啟動DB Container也不想要再還原一次DB到新的Container,這時候要把這個Container變成自己的image,以後只要啟動自己的image就可以 第一就是要先停掉Container,這個Container已經加入自己的DB1docker stop SQLTest 停掉Container後,用Commit方式建立新的image,這步驟通常會一點點時間1docker commit Container_ID microsoft/mssql-server-windows-express:SQLTest 如下圖,這樣在image List中,就多出剛剛建立的客製化image source了 如果想要把這image搬到其他地方使用呢?一種就是放入registry中,若現實不允許,就只能自己把image匯出檔案囉1docker save -o \"c:\\image\\SQLTest.tar\" microsoft/mssql-server-windows-express:SQLTest 通常這一步又要花費更久時間,反之要把檔案匯入,則使用docker load,就可以建立一個自己情境的docker image 讓Remote Container執行Docker-Compose 上面執行Docker方式,都是在Windows Server中下達Docker指令,但是,如果要透過另一台VM或是機器去呼叫遠端的VM的Container,必須先做幾個設定,首先,要更改遠端機器的daemon.json檔案,加入下面參數,並重啟Docker(Restart-Service docker)1\"hosts\": [\"tcp://0.0.0.0:2375\", \"npipe://\"] 須注意就是遠端機器的防火牆必須要開啟2375 Port,然後執行docker -H Remote IP:2375 info,就可以確認是否有通了,到了這部表示遠端機器已經開放Port讓你可以遠距執行Docker指令,接下來就是執行.yml檔案去建立Container,這次案例是建立好一個要啟動SQL Container,在yaml的描述檔的內容如下:1234567891011121314151617version: '2.1'services: SQLDB: container_name: SQLTest2016 environment: ACCEPT_EULA: \"Y\" SA_PASSWORD: \"XXXX\" image: microsoft/mssql-server-windows-express:SQLTest ports: - 14331:1433 volumes: - C:\\DB\\:C:\\DB\\networks: default: external: name: nat 通常要執行這個yaml檔案會是放在要執行Container機器上,而這次是要透過自己電腦去啟動遠端的Container,所以,必須把yaml檔案放在自己電腦端,然後透過下面指令執行它1docker-compose -H Remote_IP -f docker-compose.yml up 就可以讓啟動遠端的Container了 參考來源 https://blog.yowko.com/2017/05/docker-command-in-windows.htmlhttps://philipzheng.gitbooks.io/docker_practice/content/introduction/what.html","categories":[],"tags":[{"name":"Docker","slug":"Docker","permalink":"http://edwardkuo.imas.tw/tags/Docker/"}],"keywords":[]},{"title":"用Azure Conditional Access限制公司以外地區不可以連入VSTS","slug":"Devops/VSTSSE","date":"2017-07-13T16:00:00.000Z","updated":"2017-07-14T07:04:16.950Z","comments":true,"path":"paper/2017/07/14/Devops/VSTSSE/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/07/14/Devops/VSTSSE/","excerpt":"","text":"就目前微軟以雲端服務為優先情況,VSTS的功能是越來越強大,再加上本身VSTS也可以與地端整合,所以,使用VSTS來做為版控工具是一個不錯選擇,不過,很多人知道好處,但畢竟是雲端服務又會很擔心,如果在公司外部讓公司有心人進入後,把所有程式碼都拿走就慘了,安全性的管理一直想用VSTS的一個。 其實只要透過Azure Conditional Access就可以解決這問題。畢竟,在整個微軟雲端服務中,無論是Office 365或是VSTS都是在Azure上面的一個SaaS服務,換句話說其帳號是在Azure AD中被管理,透過下圖可以知道就可以知道 因此,就來看看Conditional Access機制可以幫忙做到那些事情 進入Azure Conditional Access 使用VSTS時候,記得要讓Azure與VSTS綁定,可以到Team Services accounts看是否有被綁定進來,此外,還必須注意就是Azure AD的Subscription與VSTS被指定的Subscription是否有相同,如果是沒有多個Subscription基本就不會有問題,不然會發生怎樣設定都無法成功,因為被設定在不同的Subscription上面,如果是從Team Services accounts建立的VSTS問題是最少的 前置作業都確定差不多,就可以去Azure AD的Conditional Access功能 一進去就可以看到Conditional Access說明 開始新增規則 這裡可以設定多個規則,我們來設定一組規則試試看,按下新增規則,可以看到有下面幾點可以設定 分成工作指派和存取控制,前者是設定相對應的條件,後者是規範在前者條件下是否可以有存取權限,看似似乎不太難設定 使用者和群組有哪些人員要被規範,原則上都是全部人員,可以設定要包括人員或是排除那些人員不被限制 雲端應用程式這裡則是設定有被Azure AD管理的服務,就這組測試用的案例來說,只有VSTS有被Azure AD管理,只會出現VSTS,當然如果想要所有雲端應用程式都套用,就直接選定全部吧 像是正式環境,又有使用O365,所以,這邊列表的APP又多了Office 365,且基本上有用到微軟雲端服務的產品,都會被歸納進來,如Hockeyapp 條件設定在條件設定可以設定分別有 登入風險 裝置平台 : 可以套用那些平台上面 位置 : 主要設定白名單,有列在名單中才可以存取,這是最重要設定選項之一 用戶端應用程式 其中位置設定,若是公司網路,可以把公司網路範圍區域設定為白名單,這邊必須採用CIDR標示法,如果不知道要怎樣標示,也可以透過工具www.ipaddressguide.com/cidr幫忙 這邊情境我們設定如下 存取控制上面條件設定完成後,就是設定若是符合這些條件,需要進行那些動作,可以設定鎖定或是有條件的進入,先來設定全部封鎖存取 設定完成後,就可以多一個條件原則,這時候我們再去VSTS測試看看 用網頁登入後,就會出現這提示,表示你現在可能不在公司或是已經你現在網路位置是不被允許登入的,當然用Visual Studio也沒辦法連入了 如果這時候想要某些IP可以連入情況,就去排除選項把信任IP放入就可以,除了IP還可以設定被授予裝置,只是這部分需要與Intune整合就是 透過這樣條件組合,就可以在增強VSTS使用上的安全性,也可以符合每家企業對於安全性的不同定義。 參考資料https://docs.microsoft.com/en-us/azure/active-directory/active-directory-conditional-access","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"自動化建置取得不同VSTS平台內的Packages Manager套件","slug":"Devops/VSTSPackage","date":"2017-07-06T16:00:00.000Z","updated":"2017-07-07T00:23:53.726Z","comments":true,"path":"paper/2017/07/07/Devops/VSTSPackage/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/07/07/Devops/VSTSPackage/","excerpt":"","text":"自從VSTS有了Packages的功能,可以讓我們自建團隊私有的Nuget後,就習慣把大量可以Re-Use套件放上去,可以讓整個團隊共同使用這些套件。不過,如果給自己團隊是沒有甚麼問題,今天要跨團隊使用呢?就是給在不同專案成員也用你開發的Package,在同一個VSTS URL下,只要去設定Feed權限也就可以,如下圖,在BestFeed下設定給予要讀取此Package的人員那些權限 但是,如果今天是不同VSTS呢,例如 BBB.visualstud.com 要去讀取 AAA.visualstud.com Packages內的套件,又或是其他版控平台要來讀取AAA.visualstud.com Packages內的套件。當然第一前提依舊必須本身你有在AAA.visualstud.com內有帳號,如果沒有帳號一切就別談囉 以為有帳號就可以嗎?如果在Visual Studio內是沒問題,是可以正常把套件裝起來,不過,這時候你會發現必須先輸入AAA.visualstud.com帳號密碼,一旦做了自動化建置,並不會跳出這樣需求視窗,這時候就會發生找不到這個在AAA.visualstud.com內套件問題,想當然而就會build失敗了。要解決這問題採用一個最簡單方式,就是把驗證資訊設定在Nuget.config中 假設原本的Nuget.config是這樣設定12345678910111213<?xml version=\"1.0\" encoding=\"utf-8\"?><configuration> <apikeys> </apikeys> <packageSources> <clear /> <add key=\"AAA\" value=\"https://AAA.pkgs.visualstudio.com/_packaging/BestFeed/nuget/v3/index.json\" /> <add key=\"nuget.org\" value=\"https://www.nuget.org/api/v2/\" /> </packageSources> <activePackageSource> <add key=\"All\" value=\"(Aggregate source)\" /> </activePackageSource></configuration> 這時候需要加入<packageSourceCredentials>屬性,剛剛提到需要可以驗證通過除了帳號還需要密碼,但密碼不是使用這組帳號的密碼,而是必須產生一組PAT密碼,要建立PAT密碼可以參考這篇文章[打通自動化雲端部署到地端-安裝VSTS Agent ] 有了PAT密碼就把帳號與密碼資訊放入Nuget.config中,在<packageSourceCredentials>內要加一組跟PackageSources的Key Name一樣名稱的tag123456<packageSourceCredentials> <AAA> <add key=\"Username\" value=\"XXX\" /> <add key=\"ClearTextPassword\" value=\"123123123123123\" /> </AAA></packageSourceCredentials> 並添加Username和ClearTextPassword,前者就是登入到AAA.visualstud.com,後者就是PAT密碼。完成後,在自動化建置中就可以去抓去對方的Package了","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"Microsoft Teams整合VSTS Story Board","slug":"Devops/TEAMSVSTS","date":"2017-06-22T16:00:00.000Z","updated":"2017-06-23T05:32:13.698Z","comments":true,"path":"paper/2017/06/23/Devops/TEAMSVSTS/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/06/23/Devops/TEAMSVSTS/","excerpt":"","text":"先前在VSTS使用Story Board時候,又用Teams,想說是否可以不要兩邊切換看和討論Story,早期作法就只是把VSTS Story的Link address抓下來,利用Teams的Tab內的Web Site功能建立,不過,這個月更新,整合度就更好了,只需要透過幾個步驟,就可以把兩邊給串起來,且比我之前用link來做好多了 選VSTS Tab 到Teams的Tab功能列表中,找到VSTS的Function,並點選啟動它 開始設定連接參數 點選Function後,就可以開始設定,目前Teams帳號與VSTS帳號並沒有統一,所以,這邊會要你輸入VSTS的登入帳號 登入之後,就可以選訂要連結的VSTS位置,如果你有多個,就只能選擇一個來做綁定 就Teams是以團隊為主,所以,套用到VSTS時候,也必須選定團隊專案和團隊名稱,如果今日有一個團隊是跨多個專案,就必須設定多次了,沒有辦法在一次就可以全部看到的 在Backlog level中,只能選定Features,Stories 和Epics三種,設定好之後就按確定,就可以囉 開始使用 設定完成後,就可以在Teams的Tab上面就會出VSTS Story,也可以透過Teams聊天功能去討論Story了","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"還原DB發生Cannot execute as the database principal because the principal \"dbo\" does not exist...","slug":"SQL/SQLAA","date":"2017-06-02T16:00:00.000Z","updated":"2017-06-03T09:53:26.569Z","comments":true,"path":"paper/2017/06/03/SQL/SQLAA/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/06/03/SQL/SQLAA/","excerpt":"","text":"今天把某台的DB Server中的資料庫還原到另一台DB Server時候,發生這樣的訊息 Cannot execute as the database principal because the principal “dbo” does not exist, this type of principal cannot be impersonated, or you do not have permission 想說平常做備份還原都沒有遇到這問題,怎這次會遇到這樣問題,查了一下還原DB Log,並未發現甚麼錯誤,那樣到底是哪邊出問題 原來是DB Owner不見了,會發生這問題我猜想因該是因為不同台的DB Server內的帳號是不一致,導致還原DB到這台主機時候,找不到原先DB Owner,這時候只要重新給一個DB Owner帳號就可以囉","categories":[],"tags":[{"name":"T-SQL","slug":"T-SQL","permalink":"http://edwardkuo.imas.tw/tags/T-SQL/"}],"keywords":[]},{"title":"用Excel產生Json格式的資料","slug":"Other/EXCELJson","date":"2017-05-24T16:00:00.000Z","updated":"2017-06-03T01:56:35.270Z","comments":true,"path":"paper/2017/05/25/Other/EXCELJson/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/05/25/Other/EXCELJson/","excerpt":"","text":"Json做為資料傳遞格式傳遞是越來越普遍,就連把SQL也支援JSON資料傳入做Insert資料用。不過,雖然JSON資料普遍使用,但是,有一個比較大缺點,就是要產生JSON格式的資料並不容易,尤其要多筆資料時候,往往不是缺了[就是少了甚麼,造成格式錯誤。 尤其最近是把Json資料當作參數傳入SQL中,每每要組合這些資料,就快被搞死,因此,找到一個套件叫做Office with Excel to JSON,可以讓你把資料透過EXCEL設計好,然後轉成JSON字串,這樣就方便多。 使用這個套件必須是EXCEL 2016或是O365上的EXCEL版本才可以,Office with Excel to JSON下載點:https://store.office.com/addinstemplateinstallpage.aspx?rs=en-ZA&assetid=WA104380263 會彈出這個視窗,但是點下去就對 在Excel上要啟用編輯,就可以啟用這個增益集 啟用後的畫面如下 在這邊可以透過上傳EXCEL檔案產生Json,也可以直接在EXCEL表格上設計好數據,然後去產生Json資料,例如我們設計下面這樣數據格式 然後,在剛剛增益集上直接選擇Row,然後,按下Go,下面就會把資料Convert為Json囉12345[ {\"Name\":\"AAAA\",\"TEL\":\"0933932\",\"Status\":\"A\",\"Value\":1}, {\"Name\":\"BBBB\",\"TEL\":\"9012312\",\"Status\":\"B\",\"Value\":2}, {\"Name\":\"CCCC\",\"TEL\":\"123123\",\"Status\":\"V\",\"Value\":3}] 這樣是不是很方便呢?不然,每次要搞定這些資料就讓人頭痛了","categories":[],"tags":[{"name":"Other","slug":"Other","permalink":"http://edwardkuo.imas.tw/tags/Other/"}],"keywords":[]},{"title":"VSTS 整合Visual Studio Mobile Center","slug":"Devops/MobileCenter","date":"2017-05-23T16:00:00.000Z","updated":"2017-07-20T16:17:30.516Z","comments":true,"path":"paper/2017/05/24/Devops/MobileCenter/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/05/24/Devops/MobileCenter/","excerpt":"","text":"要在VSTS建置一個Xamarin開發出來的App,只要在Build Process將相關要建置的Task設定好基本上就可以產生出一個APP,若是要建置出iOS用的APP,就必須要在建置的Agent下一番功夫,例如使用Local agent或是第三方的Agent像是MacinCloud幫忙建置Xamarin專案,用Local agent則還是必須準備一台MAC在上面安裝Build Agent,似乎也不是很方便,第三方服務在付費方式上會有些”麻煩”。 去年就在關注Visual Studio Mobile Center發展(雖然現在依舊是Preview),當時它只能綁定Github或是其他開源的版控平台上面的程式,對於愛用VSTS的人來會是一個遺憾,不過,在2017 Build大會前一個月,Mobile Center宣布可以綁定VSTS上Repositories,讓建置直接透過Mobile Center做建置APP,讓整個CI又更方便了,因此,來把VSTS + Mobile Center串起來吧 準備事項 使用Mobile Center前,須注意下面幾點事項,這樣才會會讓整個Build流程順暢一點 安裝Mobile Center Analytics 和 Mobile Center Crashes 更新Xamarin套件到最新版本 移除Hockeyapp套件 Nuget.config要放在專案的Root位置,就是跟.sln同一層另外一個重要事情,就是記住要自己先在Local端可以Build成功阿,不然放上去也不會成功的 Visual Studio Mobile Center Build 話說在前頭,因為在VSTS中習慣自己在Build時候,去組合自己想要的Task流程和設定,但是,若是使用Mobile Center時候,這一部分是完全被省掉,講好聽一點就是省掉設定的麻煩,不好聽就是沒有控制權,若是中間有甚麼意外或是非標準化流程,我們自己也無法做更改。所以,目前建議還是依照自己情境來決定,是否要透過Mobile Center座建置這件事情 建立一個平台的APP專案進入Mobile Center時候,選擇Add New app,建立一個新的App,這部分感覺有點類似VSTS的Repositories,一開始會要你設定要產生哪一個平台的App,和你開發App用的語言,這裡就選擇iOS和Xamarin,所以說,如果你要產生不同平台的App,就要建立多個APP,這部分還算合理,畢竟不是所有人都是用Xamarin開發,可以跨平台的 建立完成之後,就會進入下面的管理介面 一進入後,會請你在Xamarin Project安裝相關套件,官網說是找到Mobile Center Analytics和Mobile Center Crashes這兩個套件,不過,實際上卻是找到是這兩名稱的套件 找到後安裝起來,說明文件上面有分Xamarin和Xamarin.Form兩種設定SDK用法,不過,雖然本身是使用Xamarin.Form開發,但是,還是可以使用Xamarin方式在Xamarin.ios中加入SDK,而這樣做法只是針對單一平台加入SDK,相關程式碼加入之後,就是開始設定Mobile Center的Build,因為要讓Mobile Center和VSTS的Repositories結合,所以,這裡當然只能選VSTS囉 一般來說會希望你Mobile Center的帳號與登入VSTS帳號的登入帳號是相同,這樣會比較單純,如果是這樣情境,會看到下面資訊,Mobile Center會要VSTS授權給它讀取VSTS的Repositories 綁定之後,就可以看到VSTS所有的Repositories,此時,只要選定你要的Build的Repositorie進行綁定就可以,而且一旦綁定後,就可以看到Repositorie內所有的Branch,在Mobile Center設定Definition方式是選定你要Build的Branch,然後,再做下一步的設定 來Build一個Branch這邊設定我只能說,真是走極簡風格阿,跟VSTS比較起來,Mobile Center所需要的設定基本都是可辨識的 如果要設定Device Build就必須上傳該App的Provisioning Profile和.P12 File,當然這是要建置iOS APP的憑證,若是沒有上傳這些憑證,只能使用Simulator build建置APP,而使用此模式,就不能發布到手機上使用 設定好之後或是每次修改設定後,只要一儲存,它就會開始Build了,除非這邊選擇手動觸發,另外,若是選定自動Build,當Code被Check in到VSTS後,也會開始自動建置。這介面上則是列出每次Build的狀況,以及要手動觸發建置的按鈕 每個狀態內,會顯示詳細的build資訊,還有每次Build的時間,不過,這邊有一點就是關於Build時間,Mobile Center背後其實是會啟動一個VM去做建置,所以,如果今天碰到是資源比較缺乏的,就會向下圖一樣,發生非常長的建置時間 當建置完成時候,會出現Download按鈕,若是建置失敗,只能建置過程的Log 如果建置失敗是不會有Distribute功能的 建置成功則在下載地方,還可以下載三種類型分別是build、symbols和logs的檔案,其中,Build裡面就是編譯好的ipa檔案 另外,從下載的Log還可以看得出來,Mobile Center在簡單的背後它設定了那些Task流程,如果想要知道Mobile Center背後怎樣建置你的APP,可以直接看log就可以清楚了解 Distribute APP 當你Build好之後,到Distribute就看到你剛剛Build的APP,還有建置版本號,也可以在這邊下載APP使用 結論 Mobile Center把Build程序簡單化,也讓微軟開發人員不一定要有MAC才可以建置iOS APP,不過,不知道是不是還在Preview,所以,很多機制都尚未完善,要真正導入到企業上用可能還有一段路要走,就拿現在還在運行的HockeyApp來說(未來可能就消失),個人覺得不足地方有幾點: 沒有類似HockeyApp一樣的Store,列出可以下載的APP,這樣可以減省企業自行建置Store的時間 因為是自動設定好Task,如果要切換Bundle Identifier Name,沒有辦法透過Merage Branch方式進行","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"修復RansomWin32WannaCrypt勒索病毒方式","slug":"LifeStyle/SaveRansomWin32WannaCrypt","date":"2017-05-14T16:00:00.000Z","updated":"2017-05-28T15:40:28.174Z","comments":true,"path":"paper/2017/05/15/LifeStyle/SaveRansomWin32WannaCrypt/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/05/15/LifeStyle/SaveRansomWin32WannaCrypt/","excerpt":"","text":"這一波病毒我想最累因該是企業內部MIS人員,有些朋友公司又有遇到遭情,整個節日就泡湯,這次大部分都是微軟作業系統(聽說MAC也會有)遭殃,但不可避免就是,已經不只是從原本被動模式中毒,就算放著連上網也會中毒,雖然,微軟早在之前就有發布更新,我相信很多人也是沒更新的 XD 根據微軟的安全報告指出,這個勒索軟體是屬於WannaCryptor病毒的其中一隻變種。為了協助Windows用戶共同面對這個大規模的惡意勒索病毒的威脅,MSRC已公布相關的建議措施,請參閱連結,MSRC blog - Customer Guidance for WannaCrypt Attacks 關於修復RansomWin32WannaCrypt勒索病毒,可以透過微軟提供方式來進行 安裝微軟於三月釋出的安全性更新中的MS17-010 但這次罕見的微軟會替Phase Out產品也做修補 Windows Server 2003 SP2 x64 Windows Server 2003 SP2 x86 Windows XP SP2 x64 Windows XP SP3 x86 Windows XP Embedded SP3 x86,Windows 8 x86 Windows 8 x64 沒中毒也別太高興,還是快點修補吧,畢竟,變種的已經又來了","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"在Application Insights標註VSTS Release的版本戳記","slug":"Devops/VSTSAI","date":"2017-05-14T16:00:00.000Z","updated":"2017-05-15T15:37:27.280Z","comments":true,"path":"paper/2017/05/15/Devops/VSTSAI/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/05/15/Devops/VSTSAI/","excerpt":"","text":"常用Application Insighs的人,可以了解Application Insighs能監控的資訊有多強大,不過,在這些資訊中往往會Miss掉一個訊息,就是現在運行的系統版本所得到資訊,跟之前的資訊是否是同一個版本呢?雖然,我們可以在Application Insights內用客製化屬性標記系統版本,但是,不過在統計圖表中卻無法得知這份資訊。在資料的判讀上就會出現問題 因此,為了解決這問題,其實Application Insights是可以主動紀錄每次發布的時間點,並標記在圖表上,尤其對於DevOps的團隊來說是很重要(責怪人亂發錯誤版本 =.=),可以確認問題點發生原因 取得Application Insights ID 和 Key 要能做到這點,必須使用Application Insights Enterprice版本,主要是必須使用到Application Insights API的功能,如果定價策略設定好之後,就到API 存取地方,先找到Application Insights API 的ID 有了ID之後,就是建立API Key,選擇建立API 金鑰 有了這兩組資訊,就可以到VSTS去做設定 設定VSTS的Release Application Insights 預設在VSTS並沒有Application Insights for Release的Task,必須到Marketplace下載安裝,從安裝說明看來,因該是TFS也可以使用,不過,這邊還是採用VSTS作範例 下載安裝後,就可以在VSTS的Deploy看到這個Task 把這個Task加入在整個流程最後一個,並填入剛剛取得Application ID & Application Key 完畢後,跑一次Release,再去Application Insights看發生怎樣變化,圖表上方多了戳記的圖案 點開戳記的內容,就可以看到這次Release相關版本資訊 藉由這樣方式,讓整個資訊就會更完整,對於監控Application來說又更方便了","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"},{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"(Docker Swarm)Azure Container Service中建立MS SQL Server for linux","slug":"Azure/AzurelinuxSQL","date":"2017-05-12T16:00:00.000Z","updated":"2017-05-28T08:13:36.446Z","comments":true,"path":"paper/2017/05/13/Azure/AzurelinuxSQL/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/05/13/Azure/AzurelinuxSQL/","excerpt":"","text":"繼上一篇的Azure Container Service初體驗之後,就在想要如何去應用ACS(Azure Container Service的簡稱)的功能,有什麼場景是在對於系統開發或是企業應用方面有幫助的方案,突然,想到其中一個方式,就是建立開發測試的資料庫,在開發時期拿來使用,所以,用ACS建立一個臨時要用的資料庫來做測試用,或許也是一個不錯的選擇,其實,也是可以做為微服務中的資料庫區塊 不過,說這樣多,還是先在ACS中建立一個可外部連線的資料庫吧 ACS的Docker Swarm 如果要使用Docker Swarm模式,就必須先了解這張圖架構圖,這張圖是說明了ACS中的Docker Swarm架構,這是非常重要的,在這之中包含了Master & Agent,與網路結構 不過,有一點不解的是這張圖的Master對應到的NAT,但是實際上建置起來後,是對應到Load Balance,也就是說是跟Agent相同,在Agent的Load Balance是80,443 & 8080的Port有被設定對外開放,如果今日你需要的服務對應的Port沒有被開啟,必須要在Loader Balance控制器做開起設定,就如等下做的SQL Server,必須要去開起1433,不然,外部系統是無法連線的到內部Container,如果是在Master,所有Port預設都是沒有被開放,必須自己去做設定輸入docker info得到的資訊,如下 如果是想要知道Master的Docker Host資訊,輸入docker -H 172.16.0.5 info就可以得知此Host的資訊,以及此Host對應的Agent IP 如前面所講的,因為是要安裝SQL Server,所以,需要再ACS的Loading Balance控制器設定對外與對內Mapping的Port 在狀態探查地方加入SQL的1433 Port,通訊協定選擇TCP 再到負戴平衡的地方,加入SQL的規則 設定內的內容會是下面這樣 以上設定完後,後續等安裝完SQL,就可以透過SSMS連線進去 安裝SQL Server for Linux 在Swarm中,所具備的VM是屬於Linux作業系統,所以,用一般的SQL Server是無法安裝的,必須使用SQL Server for Linux,因此,必須先去Docker Store下載,因為主要是在於開發使用,在SQL Server for Linux內的一些管理功能可能無法與一般的SQL Server一樣齊全,不過,這倒是影響不大 下載SQL Server for Linux1docker pull microsoft/mssql-server-linux 開始安裝SQL Server for Linux,預設登入帳號是SA1docker -H 172.16.0.5:2375 run --name linuxSQL -d -p 1433:1433 -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=XXXXXX' -d microsoft/mssql-server-linux 當安裝完畢後,輸入docker -H 172.16.0.5:2375 ps -a就可以下面資訊,表示服務有起來了,其中,會看到Port的對應關係是10.0.0.5,表示是位在Agent VM段12CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES2b37e7cdf38d microsoft/mssql-server-linux "/bin/sh -c /opt/m..." 24 hours ago Up 23 hours 10.0.0.5:1433->1433/tcp swarm-agent-615DB80F000001/linuxSQL docker -H-H, –host=[unix:///var/run/docker.sock]: tcp://[host:port]來綁定或者 unix://[/path/to/socket] 來使用。在 daemon 模式下綁定的 socket,透過一個或多個 tcp://host:port, unix:///path/to/socket, fd://* 這樣就安裝完畢,看是很簡單,當時要搞定這個,還花了不少時間,最常看到就是Port的資訊是空的,這表示SQL Server並未真正啟動,只是安裝好Container而已,還必須要透過docker run啟動 SSMS連線 設定好Container後,就必須要能進行連線,這邊是透過外部方式連入到ACS內的Container,因為是使用SQL Server,那就用SSMS工具來進行測試吧,要測試前首先要知道ACS對外的FQDN或是IP位置,我們可以去公用IP位址的服務找到Agent對外IP和Host Name 在資料庫伺服器位置,需輸入tcp:IP or tcp:hostname,同時,輸入你剛剛安裝SQL Server的Password,如果Container正常啟動,這樣就可以連入進去了,這裡看到名稱剛好會是Container ID","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"},{"name":"Docker","slug":"Docker","permalink":"http://edwardkuo.imas.tw/tags/Docker/"}],"keywords":[]},{"title":"Azure Container Service初體驗","slug":"Azure/AzureDocker","date":"2017-05-06T16:00:00.000Z","updated":"2017-05-28T15:49:44.442Z","comments":true,"path":"paper/2017/05/07/Azure/AzureDocker/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/05/07/Azure/AzureDocker/","excerpt":"","text":"研究Docker時候,總是在想為了來使用Docker技術,我必須架設具有Container機制的Server,或是在自己PC上使用Docker for Windows建立Container,然後才可以使用Docker Image,雖然不複雜,但有時候也覺得不方便,尤其在寫程式時候,會需要做到測試部分,會用到Docker建置相關環境,如果這環境會被地域限制住,感覺又那樣不方便,在Azure上看到一個叫做Azure Container Service的東西,感覺這東西就像把Container變成PaaS,可以方便來使用 Azure Container Service Azure Container Service是採用標準的Docker容器規範,所以,目前市面上的Docker技術,都是可以被放入這裡面,而在Azure Container Service內有三種模式可以選擇,分別為DC/OS、Docker Swarm和Kubernetes Docker Swarm 使用Docker CLI DC/OS使用DCOS CLI Kubernetes使用kubectl 可以依照個人習慣或是喜好來選擇自己想要的模式,後面範例會採用Docker Swarm模式來做操作,預設Azure中沒有Azure Container Service,必須自己到Marketplace安裝Azure Container Service服務,到Marketplace搜尋Azure Container Service,就可以找到此服務 找到之後,就能進行安裝Azure Container Service,這時候可以自己選擇自己想要的Docker模式 設定Azure Container Service 進入設定模式,大致上會有四個步驟要進行,首先,要設定你服務的基本配置,如前面所提,這裡選定Swarm作為我的Docker模式 基本設定完後,就設定服務的位置和連線進入的憑證 DNS︰用來為主要節點網域名稱的前置詞。 使用者名稱︰在叢集中每個 Linux 虛擬機器上帳戶的使用者名稱。 SSH RSA 公開金鑰:新增要用於對 Linux 虛擬機器進行驗證的公開金鑰。 主要主機計數:叢集中主要主機的數目。 後續就是要建立Agent,雖然,感覺是在用Container的PaaS,但實際上背後還是透過VM方式建立Container,所以,這邊必須選定啟用多少agent以及要使用的VM大小 完成後,會產生這樣的資訊 只要確認無誤後,按下OK,就開始建立了,不過,這樣建立需要一點點時間,建立完畢後,在你剛剛設定的資源群組中會發現被添加了許多的Azure服務 與Azure Container Service連線 如果要跟Azure Container Service連線,因為先前我們在建立此服務時候,是使用SSH Key,所以,連線時候必須要有可以透過SSH連線的Client軟體,這裡我使用是PuTTY的軟體進行,因此,這邊開啟Putty,進行連線設定,在Host Name部分,在containerservice-XXX內的Master FQDN可以找到,而Port部分就輸入2200 連線資訊設定完成後,就是設定Auth登入資訊,這邊提供剛剛在Azure Container Service的SSH私鑰,它會是.PPK的檔案 最後,就是設定對應的Port資訊,因為,這邊是採用Swarm,所以,對應的Port都使用2375 都設定完成後就可以開始連線,進去之後輸入docker info就可以看到關於docker的資訊了 以上方式就可以建置屬於Linux的Container,如果今日你要安裝的Docker Image是屬於Windows Container,就不能使用Swarm模式,必須使用Kubernetes模式,透過這樣方式,後續要在VSTS進行DevOps中的測試時候,也可以透過這樣方式進行,就不需要額外自行架設VM進行管理,至於,對於企業來說怎樣比較方便,後續還是要有實際案例再來進行比較,使用哪一種方式會是比較簡潔好用 文中有提到關於SSH相關設定,要知道怎樣設定SSH,可以參考這篇- 建立Azure管理中的SSH金鑰","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"},{"name":"Docker","slug":"Docker","permalink":"http://edwardkuo.imas.tw/tags/Docker/"}],"keywords":[]},{"title":"建立Azure管理所需要的SSH金鑰","slug":"Azure/AzureSSH","date":"2017-05-05T16:00:00.000Z","updated":"2017-05-29T13:02:15.135Z","comments":true,"path":"paper/2017/05/06/Azure/AzureSSH/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/05/06/Azure/AzureSSH/","excerpt":"","text":"進入Azure之後,我們可以透過很多工具或是方式去管理我們在Azure上面的資源或是VM,不過,可以發現很多管理上,已經不只是使用帳號密碼做登入驗證,部分身分驗證資訊已經改用SSH的金鑰來進行驗證,因此,就必須製作屬於SSH的公鑰與私鑰,當我們在建構服務時候,就需要我們自己產生SSH公鑰資訊填入,做為日後登入資訊的驗證,雖然,這樣方式是相對複雜,但對於安全性又是多一分保障。 準備事項 製作SSH Key前,必須先確認有這些工具,這樣會幫你比較簡單製作 Git Bash : 需安裝Git for windows,就會有這指令 PuTTY Tool : 作為Client端SSH連線工具,同時,也可以產生SSH Public key格式,下載點 建立SSH私鑰 如果上面工具都安裝好,就可以開始建立SSH金鑰,金鑰有公鑰與私鑰部分,因此,透過Git Bash來產生私鑰,其指令如下1openssl req -x509 -nodes -days 720 -newkey rsa:2048 -keyout azure.key -out myazure.pem 指令輸入後,就會產生一些資訊需要你填入,當資訊填完也就產生金鑰完畢了,這時候,可以到Windwos的自己帳戶下,看到azure.key & myazure.pem這兩個檔案 私鑰檔案內會有-----BEGIN PRIVATE KEY-----字樣開頭,有了私鑰後,如果也想產生對應的公鑰,可以透過指令產生該檔案的公鑰1openssl.exe rsa -pubout -in azure.key -out azurePublicKey.key 公鑰檔案內會有-----BEGIN PUBLIC KEY-----字樣開頭 轉換openSSH的公私鑰 透過OpenSSH的公鑰,格式還不是讓Client端連入驗證的SSH格式,這部分我們需要做轉換,一般Azure SSH公鑰內資訊格式會是如下 PuTTY除了本身是SSH連線工具外,也可以透過他產生這方面格式的SSH公鑰。要讓Putty可以把剛剛透過openSSH建立的私鑰做轉換,首先必須讓PuTTY可以讀到這個檔案,所以,必須把.Key轉換成_rsa,這部分還是需要透過OpenSSH工具指令1openssl rsa -in azure.key -out azure_rsa 這樣就可以產生_rsa的私鑰 打開PuTTY工具,將剛剛_ras檔案讀入,成功後就會有下面資訊 在畫面中的Public Key for pasting into OpenSSH....,可以看到這樣資訊12ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0hUrtwvnZOgKnQoFjkoSFyUvZR5nbBe4oZnLCAnNbru1kuyhDyl6zlgipCjMTLUbMxUAaBzlOSrymtQ3p5asC0cCh9otJszCI7L63BiP7nDY8pQsn+sDEOeSxEY6Lw5XezhnTzg9Mt00DXsZTeWX8Bj2c7cw4uB9US2aKR5j2x1iAOcn+RnBI8Dvt6i3QOy2KSS+4fmaSCwgfwZtAdhJrpTiNQIj3o6MHkEJeVZlFKSTt/M/tdRvG324Lw6uT/otQGk..... 把這些資訊Copy到Azure有SSH Public Key的地方放入就可以,如果,未來需要透過PuTTY連線,也要在此視窗中,選擇Save private Key,儲存後的附檔名為.ppk,後續必須使用私鑰的Key來跟Azure公鑰Key進行連線認證 透過以上方法就可以產生SSH Key for Azure來使用","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"Application Insights 結合OMS擴充監控分析","slug":"Azure/ApplicationInsightsOMS","date":"2017-04-24T16:00:00.000Z","updated":"2017-05-29T13:01:20.948Z","comments":true,"path":"paper/2017/04/25/Azure/ApplicationInsightsOMS/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/04/25/Azure/ApplicationInsightsOMS/","excerpt":"","text":"Application Insights好處在前面幾篇文章就有提到,尤其對於企業內部眾多的Application來說,Application Insights確實有助於我們從資料面去查詢一些蛛絲馬跡,不過,就整體管理而言,Azure Applcation Insights還是相對薄弱,畢竟,在上面要看一些指標或是報表並不是那樣友善,如果,把Application Insights結合OMS效果就不一樣,可以透過OMS的Dashboard強化,把監控數據視覺化或是進行分析,因此,就必須透過一些設定將Application Insights和OMS結合起來 確認Application Insights定價 想要啟用這功能,首先必須確定你的Application Insights定價,必須啟用Enterprise,才可以讓Application Insights資料整合到OMS內 開始啟用OMS 要啟用OMS,除了在Azure內設定外,也可以到Microsoft Operations Management Suite網站設定OMS的Workplace,只是從這邊進去啟用OMS,必須填寫一些資訊,然後,後續OMS要結合Azure資料,還是會透過Azure的Log Analytics去整合,因此,這邊就是透過Azure來啟動以及建置OMS。 首先,必須找到Log Analytics 設定相關資訊,在這裡其實就等於在建置OMS的工作區,如果是從Microsoft Operations Management Suite建置的,只需要填入OMS URL進來,如果不是,就取一個新OMS名稱,後續動作Azure都會幫你建置好 當建置完畢後,找到Log Analytics資源,進入後如下圖,可以看到OMS入口網站,從這裡就可以進入剛剛Azure幫你建置好的OMS網站 到這一步就做好嗎?不,這邊只是讓Azure幫你建置好OMS工作區而已,還沒把Application Insights資料與OMS串接 串接OMS與Application Insights 進入到OMS介面後,可以選擇自己想要的語系,然後,可以看到方案庫的選項 進入到方案庫後,可以找到Application Insights Connector,這目前還是屬於preview版本,然後,將此方案加入到OMS內,此時,可以看到下圖,表示方案已經加入OMS中,但是,還沒有設定連接器要與哪一個Application Insights整合 可以進入Data設定功能,找到Application Insights後,把你想要的Application Insights資源給加入進來,等都設定好之後,必須要等一段時間。讓OMS跟Application Insighs要資料進來 有資料後,就可以看到Dashboard的Application Insights方塊變了 這邊前提是,OMS只會抓取與Application Insights連接時間後的資料,如果之前的資料,並不會顯示被匯入到OMS中","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"讀取客製化Web.config / app.config的element","slug":"Net/Customelement","date":"2017-04-24T16:00:00.000Z","updated":"2017-05-29T10:46:46.847Z","comments":true,"path":"paper/2017/04/25/Net/Customelement/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/04/25/Net/Customelement/","excerpt":"","text":"通常在app.config都是用原本預設的element,不過,今天為了自己的元件的設定,必須透過客製化的element作為元件的config,好久沒有研究這部分,所以,研究一下,終於被我弄出來,因此,在這紀錄一下,讓有後續想用的人可以參考 自訂.config標籤 這裡自訂標籤如下,主要標籤分為三層,第一層Token為最外面標籤,等同於元件要開始讀取此設定的root位置,第二層TokenTarget,定義為設定值得Group集合,在root下,可以設定多個不同的Group,第三層target就是我們要讀得設定參數123456<Token> <TokenTarget> <target type=\"File\" IgnorePath=\"\" TokenPath=\"\" TokenDuration=\"10\"/> <target type=\"DB\" IgnorePath=\"\" TokenDuration=\"10\" connectionString=\"\"></target> </TokenTarget></Token> 而target每個屬性都代表要給予的參數值,設定好自訂標籤的config,接下來就是要讀取標籤內的資料,Config內只設定這樣還不夠,還必須設定<configSections>中註冊要讀取這客製化標籤的元件名稱,例如1<section name=\"Token\" type=\"CustomeXMLConfig.Token,CustomeXMLConfig\" /> 在這標籤中的name設定的是自訂標籤的第一層名字也就是Token,在type的設定格式,前者為namespace+第一層的Class名稱,後者為namespace,以這例子,namespace=CustomeXMLConfig,第一層的Class名稱是Token 讀取客製化Config標籤資料 在C#則是把XML的結構進行拆解,每一層其實都是一個物件,所以,先從最裡面的target開始,可以訂定如下的Class,使用之前必須先參考System.Configuration進來1234567891011121314151617public class Target : ConfigurationElement{ [ConfigurationProperty(\"type\", IsRequired = true)] public string Type => (string)this[\"type\"]; [ConfigurationProperty(\"IgnorePath\", IsRequired = false)] public string IgnorePath => (string)this[\"IgnorePath\"]; [ConfigurationProperty(\"TokenPath\", IsRequired = false)] public string TokenPath => this[\"TokenPath\"] == null ? \"\" : (string)this[\"TokenPath\"]; [ConfigurationProperty(\"TokenDuration\", IsRequired = false)] public int TokenDuration => (int)this[\"TokenDuration\"]; [ConfigurationProperty(\"connectionString\", IsRequired = false)] public string ConnectionString => this[\"connectionString\"] == null ? \"\" : (string)this[\"connectionString\"];} IsRequired是代表這屬性是為必要,如果是必要,在XML設定中就必須放入值進去,在ConfigurationProperty內定義要抓取在target內的屬性標籤名字,所以,這部分可以稱做是Element 再來,就是第二層的TokenTarget,這裡則稱為Collection,在這裡必須告知在Collection裡面要抓的element名稱,必須給定是target12345678910111213141516171819[ConfigurationCollection(typeof(Target))]public class TokenTarget : ConfigurationElementCollection{ private const string PropertyName = \"target\"; public override ConfigurationElementCollectionType CollectionType => ConfigurationElementCollectionType.BasicMapAlternate; protected override string ElementName => PropertyName; protected override ConfigurationElement CreateNewElement() { return new Target(); } protected override object GetElementKey(ConfigurationElement element) { return ((Target) element).Type; } public Target this[int idx] => (Target)BaseGet(idx);} 其中,Target this[int idx] => (Target)BaseGet(idx)這一段可以讓你在後續要使用時候,可以列出target所具有的屬性 最後就是第一層的位置,如果在Collection只有一個TokenTarget時候,這邊就可以直接設定要讀取Property為TokenTarget物件,再由TokenTarget物件帶出target物件123456789public class Token : ConfigurationSection{ [ConfigurationProperty(\"TokenTarget\")] public TokenTarget TokenTarget { get => ((TokenTarget) (this[\"TokenTarget\"])); set => this[\"TokenTarget\"] = value; }} 以上標籤對應的類別定義好之後,就可以去讀取它了,透過GetSection取得root名稱下的標籤,這邊root名稱為Token1var config = System.Configuration.ConfigurationManager.GetSection(\"Token\"); 抓出第二層的資訊1var token = (config as Token).TokenTarget; 然後,再從第二層物件取得最後一層element的屬性12345for (int i = 0; i < token.Count; i++){ Console.WriteLine(token[i].Type); Console.WriteLine(token[i].TokenDuration.ToString());} 就這樣就可以把我們想要客製化element中的設定檔讀出來了","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"開始建立SQL Server for Windows Containers","slug":"Docker/DockerSQL","date":"2017-04-08T14:59:31.000Z","updated":"2017-05-28T15:41:36.204Z","comments":true,"path":"paper/2017/04/08/Docker/DockerSQL/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/04/08/Docker/DockerSQL/","excerpt":"","text":"有了Docker這項技術後,想要把SQL Server也放入到Docker中,自從SSMS 2016開始,管理工具與DB可以分開安裝後,就沒有在自己電腦安裝DB,但是,有時候在開發專案,並不可能隨時與DB連線,如果手邊沒有SQL Server也很不方便,所以,可以用Docker建立SQL Server,如果中間被搞壞了,也不用太害怕。此外,或許可以透過這樣方式解決一些實務上遇到SQL測試的另一種問題 此外,這篇實作環境在Windows10搭配docker for windows,並啟用Windows Container 安裝SQL Server Containers 要安裝SQL Server,可以到Docker Store找到安裝指令,不過,如果在Docker Store開始找,可能只會找到mssql-server-windows-express這個Image,此時,不需要太緊張,因為,在這個image的文件中,有包含到SQL Server for Windows Containers的資訊,只要點擊它就可以找到mssql-server-windows,如果不想要找,也可以執行下面指令就可以開始安裝了1docker run -d -p 1433:1433 -e sa_password=<SA_PASSWORD> -e ACCEPT_EULA=Y microsoft/mssql-server-windows 如果是第一次,會需要一段時間下載相關性的image,這段時間會比較久一點,之後就不會了,如果下載完畢,就會開始解壓縮,並啟動Containers,之後每次要建立SQL Server Containers,只要重複執行這段指令就可以,另位,預設是透過SQL帳號進行登入,且帳號是用sa,所以,會透過sa_password設定sa密碼 SSMS連線SQL Server Containers 使用docker run指令後,可以透過docker ps確認這個Container是否有啟動,若是有啟動成功,就會出現如下圖的資訊 但是,這樣不代表就可以讓SSMS連入,我們還必須要知道這台在Containers內的SQL Server的IP位置才行,所以,必須使用下面指令查詢SQL Server IP1docker inspect --format \"{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}\" ff04d07c4b51 其中,ff04d07c4b51是代表你啟動這個Container的ID,用先前的docker ps就可以找到資訊,有了IP之後,就可以開心用SSMS連入了 如果,今天你忘記sa密碼,還可以用docker exec指令加入新的sa密碼1docker exec -it <DOCKER_CONTAINER_ID> sqlcmd -S. -Usa 網路問題? 如果在SSMS中紀錄這次建立的Container的IP,若是移除這個Container後,重新建立時候,就有可能下次就無法登入,要做這測試很簡單,只要你把剛剛建立的Container移除,移除指令如下12docker stop ff04d07c4b51docker rm ff04d07c4b51 然後,再建立一個新的Container,會發現SQL Server網路位置變了,這主要是因為在Windows Container內的網路是透過NAT方式進行對外公開,所以,會導致每次重建後,IP位置會有所變更,想要指定IP給SQL Server,就必須給予這個Container固定IP1docker run --ip 172.20.1.10 -d -p 1433:1433 -e sa_password=<SA_PASSWORD> -e ACCEPT_EULA=Y microsoft/mssql-server-windows 這時候會很好奇,為什麼要給172.20.1.10,主要是Container內是透過NAT方式轉換IP,預設都會啟動NAT,又或是可以透過docker network ls查詢目前網路配置,就可以看到有啟動NAT了,不過,這樣依舊無法知道NAT配置IP範圍,所以, 要知道IP的分配範圍1docker network inspect nat 這樣就可以知道了IP範圍,就可以啟動Container時候去指定IP,指定的IP必須在NAT範圍內,不然會發生錯誤 匯入資料 到這一步,還不能高興太早,因為,我們還沒有把資料匯入進去,因此,就必須讓Container能讀取外部資料夾或是檔案,才可以把DB還原到Container的SQL Server裡面。把資料匯入SQL Server有兩種方式,一種就是用掛載mdf檔案,另一種就是直接匯入備份檔,我比較習慣用匯入備份檔方式進行,所以,必須把正式區DB備份下來,這裡假設是放到E:\\DB下面,然後,我們需要透過資料夾mapping方式,將Container內的資料夾與外部資料夾連結起來,如果有用過VM人大概可以了解這意思。1docker run -it --ip 172.20.1.10 -d -p 1433:1433 -e sa_password=<SA_PASSWORD> -e ACCEPT_EULA=Y -v e:/DB/:c:/DB/ microsoft/mssql-server-windows 我們把Container內的c:\\DB對應到E:\\DB,就可以在SQL Server還原DB時候找到這個備份的DB檔案以上就可以把SQL Server Container建立起來,並匯入我們想要的DB,如果想要一氣呵成的話,也是可以,不用每次要建立Container都花這樣多工,整個指令如下,其中有一點不同的是,在這邊我們指定了Container Name,讓後續操作可以直接使用Container Name而不是用Container ID123docker run -it --name SQLTest --ip XXX.XXX.XXX.XXX -d -p 1433:1433 -e sa_password=<SA_PASSWORD> -e ACCEPT_EULA=Y -v e:/DB/:c:/DB/ microsoft/mssql-server-windowsdocker exec SQLTest SqlCmd -E -S XXX.XXX.XXX.XXX -Q \"RESTORE DATABASE [DEV_EAS] FROM DISK = N'C:\\db\\XXX.bak' WITH FILE = 1, MOVE N'XXX' TO N'C:\\Program Files\\Microsoft SQL Server\\MSSQL14.MSSQLSERVER\\MSSQL\\DATA\\XXX.mdf', MOVE N'XXX_log' TO N'C:\\Program Files\\Microsoft SQL Server\\MSSQL14.MSSQLSERVER\\MSSQL\\DATA\\XXX_log.ldf', MOVE N'XXX_mod1' TO N'C:\\Program Files\\Microsoft SQL Server\\MSSQL14.MSSQLSERVER\\MSSQL\\DATA\\XXX_mod1', NOUNLOAD, STATS = 5\" 第二個步驟主要是透過SqlCmd做還原DB的動作,從"Restore XXXXX"這一段就是SQL中還原DB指令,這樣我們就可以很快啟動一個具有資料的SQL Server Container了","categories":[],"tags":[{"name":"Docker","slug":"Docker","permalink":"http://edwardkuo.imas.tw/tags/Docker/"}],"keywords":[]},{"title":"用Azure Web App內的Continuous Delivery快速建置VSTS的CI / CD流程","slug":"Azure/VSTSWebAPP","date":"2017-04-01T16:00:00.000Z","updated":"2017-05-29T06:08:27.889Z","comments":true,"path":"paper/2017/04/02/Azure/VSTSWebAPP/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/04/02/Azure/VSTSWebAPP/","excerpt":"","text":"如果版控是用VSTS,我們可以在VSTS裡面設定Continuous Build&Continuous Release,讓我們的Web專案可以自動化建置到自動化佈署,且佈署到Azure Web App又有Task可用,基本上只需要把相關屬性設定完成,就可以運作,整體來說並會太困難 但是,對於VSTS不熟的人,可能要花一點時間去了解如何設定這些Task,才能讓Continuous Build&Continuous Release很順利進行,這樣下來也是需要一點時間,尤其是在Release部分,還要需要額外設定Service Endpoint跟Azure做連接。這一點就需要花一點工了。 現在,想要省掉這些步驟,是可以直接在Azure的Web App屬性中,直接使用Continuous Delivery幫忙去完成VSTS上的CI / CD。在這實作有一個前提要注意的,要用Azure Web App的Continuous Delivery,必須確認你登入Azure的Account,和登入VSTS的Account是否相同,如果,今天你登入Azure和登入VSTS的Account是不相同,就不能用這樣的功能。如果,兩者是相同,就順便在Azure中與VSTS做link吧。做法可以參考這篇從Azure管理Visual Studio Team Services服務 開始設定Continuous Delivery 到Web App的Deployment就可以看到Continuous Delivery,一開始還沒有設定前,會如上圖所示,由於,這目前還在Preview階段,所以,部分功能可能有點陽春,不過,我實作後發現,其實基本的設置已經滿足一個.NET的Web了,看到畫面中的Config,我們按下Config,就開始設定相關Build & Release了 整個設定流程中,不外乎是Source,Build,Test和Release循環,這跟在VSTS上的流程是相同的,如果有在VSTS自行設定過的,對這就不會太陌生,如果從未自己設定過這部分流程,這邊也會一步一步指導設定完成,且會比在VSTS上設定簡單許多,很多部分都自動化幫你做完了 設定Souce 前面提到,如果在Azure裡面,你的Visual Studio Team Services account已經與Azure綁定,這邊資訊就會自動帶出來,在VSTS放程式碼的地方叫做Code,這裡是用Source,但是意思是相同,裡面有幾個屬性分別如下 Project : VSTS內的專案 Repository : VSTS內Code的位置 Branch : 選擇要部署的Branch 設定Build 設定要Build專案的Framework,目前只有提供ASP.NET & ASP.NET Core,其他Web,我想這邊因該沒有辦法直接Build,如果,設定完成後,會自動在VSTS的Build中,長出這樣的建置流程,而這個流程。基本上就包含所有建置該有的Task了 很多人在build Solution的MS Build Arguments可能不會進行設定,而這邊會在build Solution的MS Build Arguments內設定參數,參數內容主要是把專案發行成Package,Release則可以透過Web Deploy方式佈署到Azure1/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\\\\" 雖然,透過這樣方式會幫你在VSTS自動化建置好Build的Task流程,但是,不代表我們不能自行修改,我們也可以在依照自己的特性,去修改Build裡面每個Task屬性或是增加Task,讓整個Build是可以符合本身專案需求。不過,有一點我沒有特別嘗試,就是如果是非.NET專案,例如PHP專案,我在Azure Web App設定Continuous Delivery,這樣的結果會是如何? 我猜想它依舊會建立相同流程的Task,只是這些流程可能不符合PHP特性,造成Build Fail,自己必須手動在修改這裡面所有Task,但是,這樣似乎降低在Web App內使用Continuous Delivery的方便性,畢竟,如果客製化或是手動程度高,這樣想要省工的地方也沒多了,跟自己在VSTS內設定並沒有差太多,而剩下唯一好處就是在Web App內,可以看到VSTS佈署到Web App的相關資訊,不需要再到VSTS內看 設定Test & Deploy 設定Test,這邊主要是設定Loading Test,如果本身沒有做這部分,就可以忽略不需要設定,如果有,這邊只需要開起就可以,另外,在Deploy部分,也只要打開就可以,會自動幫你在VSTS的Release設定好Deploy Task 其中,連要在Azure App Service Deploy中的Service Endpoint都幫你設定好,也會自動幫你跟之前建立的Build綁定,就可以做到CI & CD 如果要在VSTS做到更細緻化,這樣方式只是幫我們把骨幹建立出來,其餘部分,還是建議到VSTS內去做調整,在管理上也會比較方便點","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"},{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[]},{"title":"透過參考數值設定In Memory Table的Index","slug":"SQL/Memorytableindex","date":"2017-03-22T16:00:00.000Z","updated":"2017-05-29T15:44:44.908Z","comments":true,"path":"paper/2017/03/23/SQL/Memorytableindex/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/03/23/SQL/Memorytableindex/","excerpt":"","text":"自從SQL 2014開始,有了In Memory Table感覺在效能上又多了一道曙光,而到了SQL 2016這部分又更強化了,可用的SQL語句又增加,雖然In Memory Table是可以增加效能,但是,如果沒有設定好index反而會造成效益不彰的狀況,這幾天針對這部分進行一些調教,原本以為跟傳統資料表設定index一樣,最後發其實沒有這樣簡單,反而相對複雜,主要是因為在In Memory Table中的Index多了一個BUCKET_COUNT需要考量,設定太大,則消耗記憶體,設定太小速度反而更慢。在In Memory Table中除了叢集索引外,還可以設定非叢集索引,非叢集索引分為兩類 非叢集索索引 : Index…..NONCLUSTERED 雜湊型非叢集索引 : Index…..NONCLUSTERED HASH…..WITH (BUCKET_COUNT = 20) 這兩種索引要去設定,還真的會讓人搞昏,所以,藉由一些參考值讓我們至少有一些些依據可以設定,而非盲目的亂設定,尤其是BUCKET_COUNT的大小 BUCKET_COUNT 值參考 如果你設定的索引值,在資料表內的資料重複性相當高的時候,建議採用非叢集索引,反之,該索引所造成的資料重複性小的時候,建議採用雜湊型非叢集索,造成這兩差異主要在於BUCKET_COUNT的設計,而就官方說法,如果這個索引中你無法很明確設定BUCKET_COUNT值,就要改用非叢集索引。若是,確定要設定NONCLUSTERED HASH index時,不知道怎樣設定BUCKET_COUNT大小時候,可以透過下面語法的值去設定12345SELECT POWER(2, CEILING(LOG(COUNT(0)) / LOG(2))) AS 'BUCKET_COUNT'FROM ( SELECT DISTINCT A,B FROM Table ) [T]; 其中A&B就是要設定索引的欄位,由這樣方式可以計算出BUCKET_COUNT值,再由這個值去設定或是比這個值大兩倍去設定都是可以 調整非叢集索引類型 索引不是一開始建立後就可以不管它,畢竟,當資料流穩定之後,還是必須回頭看看設定的index是否是有確實被用到或是有遺漏的,而在In Memory Table中,也必須確定倒底是要設定雜湊型還是非雜湊型。所以,要在Review一下123456789101112SELECT OBJECT_NAME([hs].[object_id]) AS 'object name' ,[i].[name] AS 'index name' ,[hs].[total_bucket_count] ,[hs].[empty_bucket_count] ,FLOOR(( CAST([empty_bucket_count] AS FLOAT) / [total_bucket_count] ) * 100) AS 'empty_bucket_percent' ,[hs].[avg_chain_length] ,[hs].[max_chain_length]FROM [sys].[dm_db_xtp_hash_index_stats] AS [hs] JOIN [sys].[indexes] AS [i] ON [hs].[object_id] = [i].[object_id] AND [hs].[index_id] = [i].[index_id]; 透過上面語法,透過一些指標去判定設定Index是否合宜。 empty_bucket_percent : 小於 10%,表示這個值區計數可能太低,理想的應該是33%或更高 avg_chain_length : 表示是否有重複值,理想的平均鏈結長度為 1 因此,在這兩個值中,如果 avg_chain_length 大於 10,且 empty_bucket_percent 大於 10%,則可能有許多重複的索引鍵值,那麼非叢集索引會較為理想,而不是設定雜湊的非叢集索。當發現empty_bucket_percent過小或是趨近於0,就必須看是否要把BUCKET_COUNT值調大了 參考資料 https://msdn.microsoft.com/zh-tw/library/dn494956(v=sql.120).aspx.aspx)","categories":[],"tags":[{"name":"T-SQL","slug":"T-SQL","permalink":"http://edwardkuo.imas.tw/tags/T-SQL/"}],"keywords":[]},{"title":"VSTS佈署Xamarin.iOS到Hockeyapp,自動更新版號和切換BundleIdentifier","slug":"Devops/VSTSHockyApp","date":"2017-03-14T16:00:00.000Z","updated":"2017-05-28T15:46:30.780Z","comments":true,"path":"paper/2017/03/15/Devops/VSTSHockyApp/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/03/15/Devops/VSTSHockyApp/","excerpt":"","text":"在VSTS上面,可以建置Xamarin並將App發佈到HockeyApp上面進行,就可以讓用戶透過HockeyApp下載App,且HockeyApp本身可以讓APP有更新上架後,讓用戶開啟App之後,自動跳出更新App的訊息,這樣好處就可以減少開發人員再去做版本更新的通知功能。HockeyApp其背後的通知更新的機制在於Build版號要更新,才會通知有下載用戶說有新版本上架,換句話說如果只是單純上架新版的ipa是沒有用的 要做到版本更新,手動方式就是在Hockapp介面去調整build number,不過,這樣似乎有一點麻煩,期望可以這部分自動化,讓ipa檔上傳後就自動更新版號。因此,必須在VSTS做一些設定即可 自動更新版號 要做到自動更新版號,主要需了解HockeyApp版號的控制,由下圖可以知道,版號的取得是來自於plist檔案中的CFBundleVersion數值 只要知道它取得資訊地方,基本上在VSTS內要做到修改版號這件事情就簡單多。只要我們在Build的時候,去修改CFBundleVersion數值,不就可以了嗎?基於此想法,所以,後續動作就是修改plist檔案。 預設在VSTS裡面並沒有像MAC有方便更新plist的工具,所以,需安裝一個套件來幫我們簡化這個步驟,套件名稱為Colin's ALM Corner Build & Release Tools 這工具可以修改東西有這些: Version Assemblies Replace Tokens DacPac Change Report Task Tokenizer Coverage Gate 主要是透過Version Assemblies方式去修改plist檔案,原本Build Xamarin流程 我們加上一個Version Assemblies Task,輔助我們修改plist檔案 在這Task幾個項目要設定 Source Path : 要取得plist檔案目錄 File Pattern : 這邊當然是指定plist檔案囉,/Info.plist Version Source : 設定版本號的來源,可以使用Build Number或自訂變數,如果你要有自己的版本號設定,就選用自訂變數,不過,這邊的自訂變數,必須切記要符合Apple版本的編碼格式:1.0.0 Variable to use : 要使用的自訂變數,這邊一般可以使用Build.BuildNumber,原本因該是$Build.BuildNumber,但是這邊不可以加上$ Version Extract Pattern : 原本版本的型態格式,這邊使用Custom Regex,由我們來定義,符合plist內的CFBundleVersion格式 Custom Regex Find Pattern : Regex的表達式:(?:\\d+\\.\\d+\\.)(\\d+),就直接抄這個,不需要變更 這運作機制,其實就是幫忙找到plist檔案,有設定CFBundleVersion版本的地方,用$Build.BuildNumber去Replace原本設定值,另外,在Advanced的Replace Pattern設定為1.0.0,且一個重點就是Build Regex Group Index必須視為0 因此,當每次build完後,就可以增量增加版號,這時候再把build好的ipa檔,傳到HockeyApp就可以 切換bundle identifier 我們都知道在iOS中BundleIdentifier名稱是唯一的,且每個名稱都會帶入一個憑證。一般我們在開發階段可以使用apple develop的憑證,做開發與發佈。不過,如果要正式發布給用戶安裝,就不能使用開發的憑證,必須到正式發布的憑證,憑證的改變還算簡單,這要在Build Xamarin.iOS的Task中,去更換P12 Certificate File,P12 Password & Provisioning Profile File對應的資訊就可以 但是,困難的是修改bundle identifier,畢竟在開發階段是不會設定bundle identifier為正式發布的名稱,而是當我們要Release時候,才會進行變更。要做這方面原本以為很困難,不過,發現這資訊也是被綁在plist檔案內,這時候發現一道曙光。就是如上面更新版號一樣作法去修改plist檔案 不過,這邊操作起來就簡單許多,因為我們只要Replace開發用的BundleIdentifier名稱,換成正式發布的名稱就可以,這樣上面會動到的地方有: Variable to use : 用變數指定正式發布名稱 Version Extract Pattern : 一樣用Custom Regex Custom Regex Find Pattern : 設定測試的BundleIdentifier的名字,後面可以直接Replace這個名字另外,在Advanced設定 Custom Regex Replace Pattern : 設定測試的BundleIdentifier的名字 Replace Pattern : 設定Custom Regex Build Regex Group Index : 設定為0 這樣就可以變更名稱了,以上這些步驟都要在build之前,這樣才會把資訊跟ipa檔一起打包 所以,後續只要透過Branch去拆分開發與正式版本就可以,也就可以達到自動化佈署與切換的功能","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"無法刪除Docker資料夾中的windowsfilter目錄","slug":"Docker/Deletewindowsfilter","date":"2017-03-09T16:00:00.000Z","updated":"2017-05-28T15:42:13.874Z","comments":true,"path":"paper/2017/03/10/Docker/Deletewindowsfilter/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/03/10/Docker/Deletewindowsfilter/","excerpt":"","text":"因為安裝了Docker for Windows,並透過Docker指令去抓取Docker Store中的image後發現,在Docker預設是把image放在C:\\ProgramData\\Dock路徑下,這樣我C槽如果要放很多種image,有可能就不夠大了,於是想要把Image放到其他地方。這時候可以透過Docker for Windows中的Setting去修改預設路徑 這邊只要加入"graph": "d:\\\\Docker"就可以 不過,當我可以把後續相關image檔案下載到新的路徑,但是原生舊的檔案,還是必須要移除掉,不然怎釋放空間呢?這時候,不管我用甚麼指令去移除C:\\ProgramData\\Dock內的windowsfilter目錄,始終顯示我沒有存取權限,因此,就無法移除這個資料夾,剛好這資料夾又放特別多大的檔案,其他檔案大小其實不大,對於釋放空間幫助有限。 我猜這是Docker指令中的一個bug,要能移除這個資料夾,必須使用docker-ci-zap.exe指令去刪除此資料,此檔案下載位置 https://github.com/jhowardmsft/docker-ci-zap 下載後,只要去執行這個執行檔,指令很簡單123docker-ci-zap.exe -folder 資料夾路徑範例docker-ci-zap.exe -folder "C:\\ProgramData\\Docker" 這樣就可以徹底把windowsfilter目錄給刪除掉了,另外,再刪除前,記得要關掉dock for windows,如果還是無法刪除,就重新開機後,再次執行就可以了。如果刪除完畢後會顯示INFO: Zapped successfully,這樣就完成囉","categories":[],"tags":[{"name":"Docker","slug":"Docker","permalink":"http://edwardkuo.imas.tw/tags/Docker/"}],"keywords":[]},{"title":"Powershell刪除檔案和更改檔名","slug":"PowerShell/PowershellFile","date":"2017-02-28T16:00:00.000Z","updated":"2017-05-29T10:48:18.038Z","comments":true,"path":"paper/2017/03/01/PowerShell/PowershellFile/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/03/01/PowerShell/PowershellFile/","excerpt":"","text":"之前在研討會曾提過,要把自動化程序搞好,善用PowerShell是不可少的,尤其在企業內部的管理面上,不使用PowerShell感覺還是卡卡的。在這邊分享如何用PowerShell去更改檔案名稱以及把過期檔案給刪除 更改檔案名稱 抓取某個資料夾中指定的副檔名,並修改成自己想要的副檔名。透過Get-ChildItem把該資料夾內的檔案列表抓出來。其中,為了讓整個.ps更靈活,所以,這邊採用$args[0]讓外部可以輸入參數進來 1$file=Get-ChildItem -Path $args[0] -File 這邊主要抓取該資料夾中副檔名為.dll的檔案,如果是.dll就把副檔名變更成.XXX,其中,使用BaseName抓取檔名,用Extension取得副檔名 12345678ForEach ($item in $file){ if ($item.Extension -eq '.dll') { $newFileName= $item.BaseName+'.XXX' Rename-Item $item.FullName $newFileName }} 使用Rename-Item修改檔案名稱,其語法如下,FullName是取得檔名+副檔名 1Rename-Item 原始檔名 新黨案名稱 這樣就可以修改檔案名稱 刪除備份檔案 刪除備份檔案,主要動作就是透過PowerShell刪除檔案,其做法跟前面修改檔名方式相同,也是必須透過Get-ChildItem取得該資料夾檔案列表,因為,要判對檔案的最後修改日期是否有過期,所以,必須抓取今日時間,語法如下1$Currentlytime=Get-Date 有了現在時間後,就是判斷檔案最後修改時間,藉由LastWriteTime抓取檔案最後修改時間,利用AddDays可以對$Currentlytime做時間的運算123if($item.LastWriteTime -ile $Currentlytime.AddDays($args[1])) { Remove-Item $item.FullName | out-null} 若是要刪除30天前的檔案,外部輸入就設定-30,這樣就可以把-30值帶入時間運算。然後,再用Remove-Item把檔案給刪除,這裡需要使用fullName才可以,完整範例12345ForEach ($item in $file) { if( $item.LastWriteTime -ile $Currentlytime.AddDays($args[1])) { Remove-Item $item.FullName | out-null } }","categories":[],"tags":[{"name":"PowerShell","slug":"PowerShell","permalink":"http://edwardkuo.imas.tw/tags/PowerShell/"}],"keywords":[]},{"title":"善用VSTS的Library功能管理參數","slug":"Devops/VSTSLibrary","date":"2017-02-13T16:00:00.000Z","updated":"2017-05-28T15:45:51.425Z","comments":true,"path":"paper/2017/02/14/Devops/VSTSLibrary/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/02/14/Devops/VSTSLibrary/","excerpt":"","text":"大部專案都透過VSTS來進行佈署,雖然專案多,但是其實很多時候要設定的參數往往都相同,或是要佈署的路徑可能有80%是一樣,就必須每次都設定一次,或是說要用到一些Command的指令,在不同專案可能要寫一樣,若是,當中有需要變換指令寫法,就必須記住那些專案有用到,然後去改他,這樣非常不方便。再者,有些設定參數可能是具有安全性,不適合寫在Task中。 基於上面一些理由,就可以透過VSTS的Library來做管理,目前可以在Release的Definitions引入Library設定的變數群組,Build的Deginition目前還無法使用變數群組功能 另外,變數群組是依附Project,無法跨Project共用 設定Library 進入Library後,就可以替每個參數設定想要的群組,另外,在安全性部分,可以設定甚麼人可以進來編輯群組資訊 在主要Library上的安全性,是控管可以進入使用Libray的成員。 然後,使用新增群組,就可以增加變數群組,可以把相關屬性的變數歸納一起,設定變數方式很簡單,就只是Key & Value方式 這時候,我們可以看見,設定安全性的地方,在這邊可以針對這個群組去設定使用人員的角色,做進一步群組安全性的管控 Reader : 只能看到Item,但不能使用裡面的參數 User : 可以使用參數,但是不能管理Item Administrator : 可以管理Item 使用Libray變數群組 設定完變數群組後,再來就是到Release Definitions中去引用它。 選擇Variable Group,就可以搜尋在Libray類設定群組。只要把想要納入的變數組加入,就可以看到群組相關設定變數的值 在變數的value中,是以字串形式呈現,可以讓你設定任何資訊。只要把Variable Group引入到這個Definitions中,在任何的Task就可以使用它。使用變數語法是$(變數名稱) 藉由這方式進行管理,就會非常方便,當之後有變數要變動時候,就可以集中修改,不忘記有那些沒有變更到","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"快速刪除VSTS Package某一個元件所有的版本","slug":"Devops/DeletePackageVSTS","date":"2017-02-08T16:00:00.000Z","updated":"2017-05-28T15:44:22.278Z","comments":true,"path":"paper/2017/02/09/Devops/DeletePackageVSTS/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/02/09/Devops/DeletePackageVSTS/","excerpt":"","text":"VSTS Packages可以讓我們自訂團隊的Nuget Service,我們可以把自訂元件放到VSTS內,並分享給團隊人使用,一般來說這樣應用問題不太大,不過,用一段時間發現一個問題,就是當要把這個元件從Package Feed移掉時候,並沒有想像中簡單。雖然,介面上有提供Unlist & Delete Package,前者是讓這個版本不顯示在Feed上面,後者則是把這版本元件給刪除,當然同時也不會顯示在Feed上面。 又或者不想透過介面去刪除,也可以透過Nuget指令刪掉。不過,這樣都只能一個一個手動處理,似乎不太方便,介面也不能多選後刪除,在管理上,想讓這個元件完全消失在團隊的Feed列表,就必須刪除這個元件所有版本才可以,這樣可能會按到手痠,因此,這一段就必須自己寫一點點小程式讓它自動刪除所有版本。 第一步,下載Nuget.exe 下載VSTS上面的Download NuGet + VSTS Credential Provider工具,這壓縮檔裡面會有Nuget.exe執行檔,曾經試過用nuget.org下載的Nuget.exe,即使輸入VSTS帳號密碼,依舊會再跟你要一次帳號密碼,呈現無窮迴圈狀態,所以,還是建議使用從這邊下載的Nuget.exe來用 在執行有發生彈跳一個輸入VSTS彈跳視窗,這邊只要輸入登入VSTS帳號密碼後,就可以了,後面就不需要再輸入 第二步,撰寫小程式 這邊使用PowerShell指令來撰寫,一般來說要控制VSTS Package上面可使用nuget和PowerShell指令,只是後者必須在Visual Studio中的套件管理去下指令。但是,針對刪除套件這件事來說,目前就只能透過Nuget.exe執行了,而Nuget的刪除指令如下:1nuget delete <packageID> <packageVersion> [options] 首先必須取得該套件所有版本列表,這邊加入-prerelease,主要是找出beta的版本,因為預設只會找Release版本, 1.\\NuGet.exe list {元件名稱} -Source {VSTS Feed URL} -allversions -prerelease 再來就是執行Nuget的刪除指令 1.\\NuGet.exe delete {元件名稱} {版本號} -Source {VSTS Feed URL} -ApiKey {apikey} 因此,把這兩個指令組合起來,用Foreach讀取所有版本號,放入刪除功能中123456789$AllVersion= .\\NuGet.exe list XXXXX -Source \"https://AAAAA.pkgs.visualstudio.com/_packaging/Feed/nuget/v3/index.json\" -prerelease -allversionsForeach ($data in $AllVersion){ $version=$data.Split(' ')[1] \"Delete \"+$version echo 是|.\\NuGet.exe delete XXXXX $version -Source \"https://AAAAA.pkgs.visualstudio.com/_packaging/Feed/nuget/v3/index.json\" -ApiKey XXX \"Delete OK\"} 在這邊有加入一個echo 是,這主要是當你刪除時候,會跳出詢問框,問你是否真的要刪除,為了達到自動化目的,所以加入這個指令,如果今天你的OS是英文版,要把是改成Yes,後續再加工一下,把XXXXX這個元件名稱當作外部參數輸入,就可以讓ps檔能自動化執行了。就可以省下很多人工要去刪除套件版本的時間","categories":[],"tags":[{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"},{"name":"PowerShell","slug":"PowerShell","permalink":"http://edwardkuo.imas.tw/tags/PowerShell/"}],"keywords":[]},{"title":"用Powershell執行遠端VM內的Powershell Script","slug":"PowerShell/RemotePowershell","date":"2017-02-06T16:00:00.000Z","updated":"2017-10-02T00:56:40.115Z","comments":true,"path":"paper/2017/02/07/PowerShell/RemotePowershell/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/02/07/PowerShell/RemotePowershell/","excerpt":"","text":"遇到VSTS佈署到遠端VM後,必須執行一些遠端VM中的Powershell的情境,執行佈署的Server和遠端VM並不在同一個網域內,所以,無法透過網域的方式去執行遠端VM中的PowerShell指令。因此,為了要達到這個目的,就必須在遠端VM中安裝WinRM( Windows remote management),這樣才有辦法在Clinet端呼叫遠端VM中的Powersehll 設定WINRM 首先,必須在遠端VM安裝Winrm元件,我們才可以透過WinRM和遠端的PowerShell溝通。安裝完畢後,執行啟動PSRemote功能1Enable-PSRemoting 為了確保WINRM有啟動,可以再執行下面指令確認1winrm quickconfig 若有出現詢問視窗,基本上都選擇Y,完畢後會出現下面資訊 WinRM service is already running on this machine.WinRM is already set up for remote management on this computer. 遠端VM設定好之後,還要設定呼叫端的TrustedHosts,不然,會出現連線驗證的問題,所以,可以在呼叫端先查詢TrustedHosts設定,一般來說預設並沒有設定任何Trusted的Hosts 1get-item wsman:\\localhost\\Client\\TrustedHosts 要設定TrustedHosts其指令如下,其中*,代表任何位置都可以,如果要特定的位置,就把星號改成IP或是HostName1set-item wsman:\\localhost\\Client\\TrustedHosts -value * 這樣基本雙方環境就設定的差不多,接下來就可以開始撰寫Powershell的Script,這邊把要呼叫遠端VM的Powershell的指令,也寫成一個Script 執行Remote PowerShell 在呼叫遠端的Powershell指令前,我們需要幾個參數 $machineaddress : 遠端VM的IP $machineName : 登入VM的帳號 $machinePwd : 登入VM的密碼 因為,後續要把這個Powershell Script放到VSTS做自動化佈署用,所以,必須讓密碼能直接被使用,而不是彈跳出輸入密碼的對話框1$pw = convertto-securestring -AsPlainText -Force -String $machinePwd 建立登入VM的憑證1$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $machineName,$pw 設定Clinet連線到遠端VM的Session,並且要Keep這個Session,讓後續指令可以使用1$s = New-PSSession -ComputerName $machineaddress -Credential $cred 取得遠端VM要被執行的Powershell檔案的路徑1$filepath='C:\\test\\test.ps1' 使用Invoke-Command來執行呼叫test.ps1的動作,基本寫法可以這樣1Invoke-Command -Session $s -scriptblock {& 'C:\\test\\test.ps1'} 另一種寫法就是把-scriptblock {}中的值作為一個Local變數來處理,後面再用帶參數的方式填入$filepath,所以,寫法可以改成下面這樣,這樣寫法的彈性個人覺得會比較好1Invoke-Command -Session $s -scriptblock {& $args[0]} -ArgumentList $filepath 今日,如果要被執行的Powershell Script,本身有需要外部帶入參數時候,就可以擴充如下,等同執行C:\\test\\test.ps1 Hello world意思是相同的1Invoke-Command -Session $s -scriptblock {& $args[0] $args[1] $args[2]} -ArgumentList $filepath,'Hello','world' 所以,完整的程式碼如下123456789$machineaddress=$args[0]$machineName=$args[1]$machinePwd=$args[2]$pw = convertto-securestring -AsPlainText -Force -String $machinePwd$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $machineName,$pw$s = New-PSSession -ComputerName $machineaddress -Credential $cred$filepath='C:\\test\\test.ps1'Invoke-Command -Session $s -scriptblock {& $args[0] $args[1] $args[2]} -ArgumentList $filepath,'Hello','world'","categories":[],"tags":[{"name":"PowerShell","slug":"PowerShell","permalink":"http://edwardkuo.imas.tw/tags/PowerShell/"}],"keywords":[]},{"title":"Microsoft Teams 結合Azure Application Insights Alert","slug":"Devops/MicrosoftTeamsAI","date":"2017-01-31T16:00:00.000Z","updated":"2017-05-28T15:43:54.074Z","comments":true,"path":"paper/2017/02/01/Devops/MicrosoftTeamsAI/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/02/01/Devops/MicrosoftTeamsAI/","excerpt":"","text":"之前還很高興的把Application Insights與Slack串接起來,可參考Azure Application Insights發Alert訊息到Slack ,但沒多久Microsoft又出了一個Microsoft Teams的協同工具,再加上部分工作已經轉移到Teams,為了整合各項資訊到同一平台上,所以,打算把原本發送到Slack的轉移到到Teams上面,再加上Slack免費版只有10000則訊息上限,Teams這方面則沒有上限,當然就二話不說轉過來囉。 基本上是沒有辦法直接在Application Insights的webhooks直接與Teams連結,這之間依舊必須透過logic app和Teams的連接器做橋接 建立Teams 連接器 首先在Teams內建立連接器,把連接器產生的URL放到logic App內 選擇連接器 2.選擇傳入Webhook 3.給這webhook取個名字,按下確定後,就會產生URL,把這URL保留下來,等下開發logic app會需要用到 這樣在Teams上面設定就算完成了 開發Logic App 關於開發Logic App部分,方法跟之前與Slack方式類似,只是這次不需要在Azure上建立連接器,可以先參考這兩篇 Azure Application Insights發Alert訊息到Slack Visual Studio開發Azure Logic App 這邊會用到Logic App原因主要是要把Application Insights送出來的Alert格式轉換成O365 Connect可接受的格式,Application Insights送出的格式如下:12345678910111213141516171819{ \"status\": \"Activated\", \"context\": { \"id\": \"XXXXX\", \"name\": Server exception\", \"description\": \"\", \"conditionType\": \"Metric\", \"condition\": { \"metricName\": \"basicExceptionServer.count\", \"metricUnit\": \"\", \"metricValue\": \"1\", \"threshold\": \"1\", \"timeAggregation\": \"Average\", \"operator\": \"GreaterThanOrEqual\", \"windowSize\": \"5\" }, \"subscriptionId\": \"XXXXXX\", \"resourceGroupName\": \"XXXXXX\", \"timestamp\": \"11/24/2016 15:35:03\", \"resourceName\": \"XXXXXX\", \"resourceType\": \"components\", \"resourceId\": \"XXXXX\", \"resourceRegion\": \"East US\", \"portalLink\": \"https://XXXXXX\" }, \"properties\": {}} 而Microsoft Teams是透過Office 365 API Connectors做串聯,所以,必須將上面資訊對應到Office 365 API Connectors訊息格式內,關於這格式說明,可以參考下面這篇 如何使用Office 365 API Connectors 所以,在Logic App部分只需要用到HTTP就可以,這樣就簡單多 在這Task內的設定如下,其中的URI就放入連接器的URL,而在body部分,就串出符合O365訊息格式資訊就可以123456789101112131415161718192021222324252627282930\"HTTP\": { \"type\": \"Http\", \"inputs\": { \"method\": \"POST\", \"uri\": \"XXXXX\", \"headers\": { \"Content-Type\": \"application/json\" }, \"body\": { \"sections\": [ { \"activityText\": \"[Look Problem](@{triggerBody()['context']['portalLink']})\", \"activityTitle\": \"Type : @{triggerBody()['context']['resourceName']}\" }, { \"facts\": [ { \"name\": \"Detail Information\", \"value\": \"@{triggerBody()}\" } ], \"title\": \"Details\" } ], \"summary\": \"Application Insights Alert\", \"title\": \"@{triggerBody()['context']['name']}\" } }, \"runAfter\": {} } 開發完成後,只要把Logic App的URL放入Application Insights Alert的webhooks裡面就可以,這樣只要有發生錯誤或是相關警示訊息,就會拋到Teams裡面了,個人覺得這部分開發相對比Slack簡單一點","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"Microsoft Teams結合VSTS","slug":"Devops/MSTeamsandVSTS","date":"2017-01-21T16:00:00.000Z","updated":"2017-05-28T15:43:16.547Z","comments":true,"path":"paper/2017/01/22/Devops/MSTeamsandVSTS/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/01/22/Devops/MSTeamsandVSTS/","excerpt":"","text":"Teams除了一般協同工具之用外,針對開發人員來說又多一個好玩的東西,就是可以整合VSTS了,在整合部分目前可以整合就是VSTS發送通知,讓團隊在不管是在Build或是Release時候,都可以即時獲得訊息,尤其是當Release需要被Approve時候,也可以透過通知方式,通知要Approve人來處理 整合VSTS訊息 在還沒有Teams以前,我是用Slack去整合VSTS資訊,在Slack應用面上,主要是在Slack的Channel取得Webhook URL放入到VSTS的Service Hooks現在,在Teams則是透過連接器方式與VSTS的Service Hooks整合,其方式如下: 選擇連接器,找到Visual Studio Team Services 選擇『新增』 不知道是否還為Release緣故,需要等待一下子才會跳出設定視窗,如果你的VSTS與Office 365帳號是綁定的,就會自動帶出Visual Studio Team Services帳戶,不然你就要自行用Office 365建立建立VSTS,這邊可以設定的Event Type如下 說真的,可以設定還針對,如果全都要設定也滿累人,而不同的Even Type下面可以調整的選項也會有所不同 設定完成後,儲存起來就可以,然後,再到VSTS的Service Hooks查看 都會自動幫你建立好相關Link,不需要再手動過來進行設定 整合VSTS看版 為了達到統一資訊平台目的,在Teams目前也可以把VSTS的Story Board整併進來,不過,這部分感覺非常地弱,其實,就像把Board網頁嵌入到Teams,而做法其實就在是Teams增加一個Tab概念 選擇『新增分頁』 在裡面就會看到有VSTS,選擇它就對 選擇VSTS Account,而這邊感覺上又不需要VSTS與Office 365帳號綁定,只要你輸入VSTS上面所有帳號就可以 設定相關屬性,選擇你想要整併進來的專案還有團隊,以及Backlog Level Backlog Level,這邊有三種可以選擇 設定完成後,就可以把Backlog變成Teams其中一個頁籤了,如果要針對這些資訊做討論,可以直接選擇上方的交談按鈕就可以邊看邊交談 個人覺得這一個地方整合互動性並不是很高,純粹就像看黑板資訊討論感覺,雖然,你還是可以直接在上面拖拉Story,但是交談時又不能tag該Story,是有點可惜","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"VSTS 能夾帶附檔的Send Mail套件","slug":"Devops/VSTSSendMail","date":"2017-01-19T16:00:00.000Z","updated":"2017-05-28T15:42:52.165Z","comments":true,"path":"paper/2017/01/20/Devops/VSTSSendMail/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/01/20/Devops/VSTSSendMail/","excerpt":"","text":"在前面的[自動化建立Database版本差異化Script]提到,我們可以透過SQL Compare方式去產生這次要佈署的SQL檔案,不過,在實務上來說,會習慣把產出檔案直接寄送給相關人員去佈署。又或是如果今天是撰寫元件的團隊,要把改版或是修正版的dll傳送給人員做更新。現在可以當你自動Buil & Release後直接寄送檔案給指定人員 安裝Send Mail套件 首先到VSTS的Marketplace找到SendMail這個套件安裝 這個套件可以支援多個收件者,同時,也可以夾帶附檔寄出 套件基本上操作非常簡單,只需簡單幾個設定步驟就可以 設定SendMail 目前情境會在當build後在release階段將檔案寄出,所以,我們在release部分加入了SendMail的Task 這畫面設定中,主要就是設定收件者、寄件者、信件標題和信件內容,如果要有多個收件者,用;隔開就可以,不過,這邊有一點就是收件者和寄件者的信箱,不會與VSTS內的人員綁定,必須手動去建立相關人員的Email 在信件內容中,也可以用html語法撰寫成具有html格式的文件內容,不過,若是這樣,就必須開啟Is HTML Body的功能 這時候,如果想要Mail能夾帶附檔,就必須勾選Add Attachment,並在下方填入要抓取檔案的位置,假設我希望將地端要佈署的SQL File寄出,路徑我可以這樣填寫1D:\\DataBase_dacpac\\XXX_DB\\Release\\XXXXX.sql 透過這樣方式,就可以自動化將所需要的檔案寄給有需要的人了","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"Microsoft Teams + Office 365 ,輕鬆讓檔案雲和地的同步","slug":"Devops/MicrosoftTeamsFile","date":"2017-01-14T16:00:00.000Z","updated":"2017-05-28T15:43:34.766Z","comments":true,"path":"paper/2017/01/15/Devops/MicrosoftTeamsFile/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/01/15/Devops/MicrosoftTeamsFile/","excerpt":"","text":"Microsoft Teams其實是跟Office 365人員的功能榜的相當緊密,所以,當你在Teams建立一個小組時候,同時,會在Office 365的人員建立起群組 Teams是直接和O365同步的唷 如果在群組中下建立自己Channel則就不會再Office 365中的群組有甚麼變化,不過,有一個地方卻是不同,就是在檔案中會區分各個Channel的資料夾出來 這樣代表甚麼涵義呢?,也就是說當你在交談的Channel中有帶有上傳檔案的訊息,檔案自動都會被儲存到這些資料夾中, 看Teams的檔案裡面就有剛剛交談視窗中上傳的檔案 Office 365上也同步了 換句話說就不需要擔心聊天過程中,因為訊息太多找不到之前同事傳給你的檔案在哪邊了,只要到這與Channel名稱相同的資料夾就可以找到所有歷史上傳的檔案,至於空間大小,就取決自己O365上面的給予的空間大小了 如果有這樣功能,我們就可以做到讓檔案上傳,不僅可以直接儲存在雲端,也可以同步到地端自己的電腦,當然,也是可以在自己電腦放入檔案,自然也會同步到Office 365且Microsoft Teams的Files裡面也可以看到唷,這樣就能做到隨處都可以辦公的狀態(不知道這樣是好是壞Orz) 另外,如果在檔案資料夾不僅可以有原先的Channel資料夾外,還可以自行建立資料夾,就可以輕易地做分類 設定群組檔案與本機同步 如上面提到Microsoft Teams的檔案可以和O365群組檔案同步,所以,透過這樣模式再把群組檔案與本地端同步,就可以讓檔案的協同合作更方便 1.選擇檔案到O365的該群組中選擇檔案 2.選擇同步處裡這邊會出現比較奇異現象,會要求你安裝Ondrive for Bussiness,但是,實際又是用Sharepoint方式進行同步,之後只要選擇你打算把檔案同步到本機哪一個位置就可以 等你同步後,會在本機資料夾看到Sharepoint的標誌 利用這簡單方式,就可以做到跨平台的檔案分享,你只要在本地端有標示Sharepoint的資料夾存入檔案,就會自動同步到Office 365且Microsoft Teams裡面也可以看到 這樣檔案安全性呢? 這時候,想必就會考慮到檔案安全性問題,畢竟,企業很多檔案是具有機密性,雖然這樣檔案分享很方便,但是,方便和安全往往是一體兩面,要解決這問題可以透過兩種方式處理1.透過Azure RMS在檔案上傳前進行版權控管2.如果覺得這樣麻煩,就開啟IRM功能 因為Teams的檔案既然是存在O365上面,且群組的檔案管理,它的背後其實也是Office 365的Sharepoint,所以,可以到Office 365將檔案開啟IRM功能 一樣先進入檔案後,選擇上面設定中的文件庫 -開啟資訊版權管理 -啟動IRM 這樣就可以做到檔案的安全性控管了","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"使用Memory Table前須先建立資料庫的Memory最佳化檔案群組群組","slug":"SQL/MemoryFileGroup","date":"2017-01-06T16:00:00.000Z","updated":"2017-05-29T15:44:28.626Z","comments":true,"path":"paper/2017/01/07/SQL/MemoryFileGroup/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2017/01/07/SQL/MemoryFileGroup/","excerpt":"","text":"在SQL 2014之後,有了Memory Table這功能後,在處理大量資料上的效能相對於以往加快不少,不過,在使用這項功能前必須先建立好該資料庫的Memory Optimize檔案群組,這個在預設是不會產生的,每次都會忘記要先做這一個步驟,導致建立Memory Table都會發生錯誤 記憶體最佳化檔案群組被建立後,會有幾點限制,須事前要先注意 無法進行刪除動作,除非是卸載該資料庫,才能讓它被刪除 不能指定大小群組檔案大小為Maxsize 若該檔案群組非空的,也不能被卸載 建立Memory 最佳化檔案群組 每個資料庫只能有一個Memory最佳化檔案群組,而該群組必須是被設定為Memory Optimiz,其中XXXX表示為該資料庫名稱1ALTER DATABASE XXXX ADD FILEGROUP XXXX_mod CONTAINS MEMORY_OPTIMIZED_DATA 建立好群組後,就是加入檔案到這個群組中1ALTER DATABASE XXXX ADD FILE (name='XXXX_mod1', filename='d:\\database\\XXXX_mod1') TO FILEGROUP XXXX_mod 透過以上兩行指令就可以完成建立了。這樣才可以開始使用Memory Table的功能","categories":[],"tags":[{"name":"T-SQL","slug":"T-SQL","permalink":"http://edwardkuo.imas.tw/tags/T-SQL/"}],"keywords":[]},{"title":"VSTS也可以在Process Template Layout加入客製化欄位","slug":"Devops/VSTSCustomer","date":"2016-12-24T16:00:00.000Z","updated":"2017-05-28T15:47:03.063Z","comments":true,"path":"paper/2016/12/25/Devops/VSTSCustomer/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/12/25/Devops/VSTSCustomer/","excerpt":"","text":"在VSTS提供三種預設樣板,分別為Agile、CMMI和Scrum,這三種比較屬於標準型的流程,但是,在許多實務上並非這三種內所包含的欄位或是要觀看的指標是符合現狀,如果,覺得這預設值表可以符合現狀,其實也滿怪的,以Scrum為例,雖然,Scrum有提到一些所謂的”標準”流程或是方式,但是,如果只是一昧認為開發流程要去符合上面Scrum所定義的才算是Scrum,感覺就是倒果為因,反倒是因該讓兩者相輔相成,這時候就可能必須額外增加一些客製化欄位以及在管理者層面所有需要的一些指標。因此,就必須變動原本Process上面的Layout了 增加客製化的Process 在TFS中,如果要針對現有的Process去變動Layout,則必須透過Visual Studio建立好相關Layout後,再佈署到TFS上面進行變更Template,不過,在VSTS中則可以不需要這樣麻煩,直接到到VSTS的管理介面中,可以看到基本的三種類型 這三種類型是無法直接進行修改的,我們想要自訂客製化的Layout,必須先建立自己得Template,而建立時候,也必須決定你要繼承哪一個Process,以下圖來說,我要建立一個以Scrum為基礎的Process 輸入我想要的template Name 建立好後,會呈現如下圖 一旦建立好之後,就可以在自訂的Template中的每個流程內如backlog、Task…等的Layout內加入自己想要的欄位 增加額外欄位 在每個流程內點擊開來,會有Overview,Layout,Fields,Stauts和Backlogs,這五種Stage提供我們去做修改或是設定, 其中,在Status部分,原本預設不會有測試這個流程,如果基於團隊流程,需要額外訂定一個測試流程,在Stauts這邊也可以加入額外的狀態來符合企業需求 多了test的流程 專案的狀態中也有test的狀態了 另外,如果在原本的Layout中有資訊不足,則到你想要的修改的那個項目中的Layout去修改就可以,不過,有一點就是原本繼承下來的欄位資訊是不可以被刪掉的,但是,如果是自己額外增加,則是可以做刪除 以Task為例,我們可以在Detail的Group中加入,我們想要的資訊,而要加入的欄位可以是原本系統預設或是額外產生的 如果是採用預設有的欄位,是無法變動其欄位的格式,只有新增欄位才可以選取該欄位的格式,在新增欄位中有三個屬性可以被設定 Definition : 主要是增加一個欄位 Options : 設定此欄位是否為必填選項 Layout : 新欄位的配置,配置部分主要是要讓欄位放在哪一個Group資訊內 這邊所謂的Group是這樣呈現的,紅色框就表示是一個Group,而Details就是這個Group Name 因此,我們就可以自己新增一個欄位並設定該欄位為必填 然後再到實際的Task觀看,就會發現多一個剛剛加入的欄位名稱,同時,會提示你說該欄位還沒有被加入值,必須填值後才可以儲存 雖然,客製化原本的Process是複雜,但是,操作上其實並不困難,直接在UI就可以達到我們想要的樣板,甚至,連Visual Studio都不需要開啟,而透過能客製化修改,就可以讓開發流程更貼近團隊或是企業現狀,而不會讓工具與管理是無法整合,這樣就失去用工具去節省時間的美意。一個好的工具就是該讓工作行為是能貼近流程與團隊或是組織的實際運作,而不是讓團隊或是組織去為配合所謂”合理正確”的流程或是工具做一些不符合現狀的改變,這樣不僅無法讓原本開發更敏捷,反而會帶來更多災難。","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"前端也可以享受Application Insights功能","slug":"Azure/jsApplicationInsights","date":"2016-12-19T16:00:00.000Z","updated":"2017-05-29T13:02:32.519Z","comments":true,"path":"paper/2016/12/20/Azure/jsApplicationInsights/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/12/20/Azure/jsApplicationInsights/","excerpt":"","text":"在先前談到使用Application Insights時候,大都是講Backend如何去加入Application Insights功能,不過,現在很多架構上,Backend被用於Web API,操作介面則大部分是以FrontEnd技術為主,這樣就無法使用到Application Insights功能?其實不然,使用前端技術時,同時也可以享用Applciation Insights,且使用起來還相當簡單 取得Javascript files 前端主要的Application Insights主要是透過javascript去監控我們網頁,利用這方式可以追蹤每個網頁被點擊時間,同時,也可以追蹤網頁的Loading時間,當然,若有發生相關Javascript錯誤,基本上都可以被抓出來,要取得這段程式碼片段,可以進入Azure你的Application Insights裡面12345678910<script type=\"text/javascript\"> var appInsights=window.appInsights||function(config){ function i(config){t[config]=function(){var i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},u=document,e=window,o=\"script\",s=\"AuthenticatedUserContext\",h=\"start\",c=\"stop\",l=\"Track\",a=l+\"Event\",v=l+\"Page\",y=u.createElement(o),r,f;y.src=config.url||\"https://az416426.vo.msecnd.net/scripts/a/ai.0.js\";u.getElementsByTagName(o)[0].parentNode.appendChild(y);try{t.cookie=u.cookie}catch(p){}for(t.queue=[],t.version=\"1.0\",r=[\"Event\",\"Exception\",\"Metric\",\"PageView\",\"Trace\",\"Dependency\"];r.length;)i(\"track\"+r.pop());return i(\"set\"+s),i(\"clear\"+s),i(h+a),i(c+a),i(h+v),i(c+v),i(\"flush\"),config.disableExceptionTracking||(r=\"onerror\",i(\"_\"+r),f=e[r],e[r]=function(config,i,u,e,o){var s=f&&f(config,i,u,e,o);return s!==!0&&t[\"_\"+r](config,i,u,e,o),s}),t }({ instrumentationKey:\"xxxxxxx\" }); window.appInsights=appInsights; appInsights.trackPageView();</script> 把這個程式碼片段放入</head>之前,並在instrumentationKey填入屬於你自己的Application Insights的Key就可以,基本上這樣就可以開始監控你的前端程式了,像是在C#中,我們可以去增加Application Insights的客製化屬性,或是初始化telemetry,在前端是否可以呢?這當然是沒問題,我們可以透過addTelemetryInitializer,增加properties123456appInsights.queue.push(function () { appInsights.context.addTelemetryInitializer(function (envelope) { var telemetryItem = envelope.data.baseData; telemetryItem.properties = telemetryItem.properties || {}; telemetryItem.properties[\"ApplicationName\"] = \"TEST\";});}); 完整寫法123456789101112131415161718<script type=\"text/javascript\"> var appInsights=window.appInsights||function(config){ function i(config){t[config]=function(){var i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},u=document,e=window,o=\"script\",s=\"AuthenticatedUserContext\",h=\"start\",c=\"stop\",l=\"Track\",a=l+\"Event\",v=l+\"Page\",y=u.createElement(o),r,f;y.src=config.url||\"https://az416426.vo.msecnd.net/scripts/a/ai.0.js\";u.getElementsByTagName(o)[0].parentNode.appendChild(y);try{t.cookie=u.cookie}catch(p){}for(t.queue=[],t.version=\"1.0\",r=[\"Event\",\"Exception\",\"Metric\",\"PageView\",\"Trace\",\"Dependency\"];r.length;)i(\"track\"+r.pop());return i(\"set\"+s),i(\"clear\"+s),i(h+a),i(c+a),i(h+v),i(c+v),i(\"flush\"),config.disableExceptionTracking||(r=\"onerror\",i(\"_\"+r),f=e[r],e[r]=function(config,i,u,e,o){var s=f&&f(config,i,u,e,o);return s!==!0&&t[\"_\"+r](config,i,u,e,o),s}),t }({ instrumentationKey:\"KEY\" }); window.appInsights = appInsights; appInsights.queue.push(function () { appInsights.context.addTelemetryInitializer(function (envelope) { var telemetryItem = envelope.data.baseData; telemetryItem.properties = telemetryItem.properties || {}; telemetryItem.properties[\"ApplicationName\"] = \"TEST\";}); }); appInsights.trackPageView();</script> 效果 不敢保證所有前端問題Application Insights都一定可以抓到,但是,目前所有網頁行為與錯誤是都可以抓到,這時候就要擔心使用量是否足夠我們使用 如果想要找出網頁的相關性,也是可以用這方式去做,就可以幫忙蒐集到資料了,這算是非常簡單且又不會影響到程式的方式之一呢","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"在vmware內的Macos也可以連上實體IPhone","slug":"Other/VMware","date":"2016-12-12T16:00:00.000Z","updated":"2017-05-28T15:39:52.503Z","comments":true,"path":"paper/2016/12/13/Other/VMware/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/12/13/Other/VMware/","excerpt":"","text":"因開發Xamarin關係,每次在Build iOS App時,必須透過MAC OS才有辦法達成,如果,平常在辦公室或許還可以透過Remote到MAC電腦,但是,就行動開發者來說,怎可能隨身再攜帶一台電腦?所以,就想辦法在Windows環境中安裝MAC OS,這樣就可以不需要Remote到MAC電腦中,雖然,這樣解決了Build App的困境以及產iOS模擬器的問題,但是,衍伸另一個問題就是,今天要做Notification功能時候,在模擬器上無法呈現這樣功能,必須把App佈署到實體手機才可以,所以,就必須讓VM中的MAC OS能連上手機 作業環境 VMWare : VMware Workstation 12 Player Windows : Windows 10 MAC OS : 10.12.1 NoteBook : Surface book Mobile Phone : iPhone 6 設定VMware 在沒有特別設定下,當你把手機與電腦連接起來後,VM中的OS基本上是抓不到你手機的,首先,你必須在VMware的USB設定部分做更改 如果你電腦的USB是支援3.0,預設會是設定3.0,這邊必須調降為2.0,另外,如果沒有安裝VMWare Tool也必須安裝 當你插上手機時候,在VMWare會出現如下圖,多出手機圖示 啟動連接 然後,去iTunes就會看到手機圖示。這樣就表示連接成功囉,當然,啟動xCode也可以連接到手機,用Visual Studio也可以直接將Xamarin App直接佈署到手機上 這樣就方便多囉","categories":[],"tags":[{"name":"Other","slug":"Other","permalink":"http://edwardkuo.imas.tw/tags/Other/"}],"keywords":[]},{"title":"Microsoft Teams使用整理","slug":"Devops/ThinkMicrosoftTeams","date":"2016-12-08T16:00:00.000Z","updated":"2017-05-28T15:44:52.281Z","comments":true,"path":"paper/2016/12/09/Devops/ThinkMicrosoftTeams/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/12/09/Devops/ThinkMicrosoftTeams/","excerpt":"","text":"用了一陣子Microsoft Teams後,把手邊之前跟Slakc整合的服務,陸續轉移到Teams,因為,Teams目前還在Preview版本,所以,建議使用的人務必將Teams的語系改成英文版,不然會出現一些莫名的問題,例如:建立Meeting時間會永遠出現前後時間錯誤或是無法設定問題 目前比較完整的功能只有在PC版,手機版本雖然可以跨三個平台使用,不過,功能跟PC版本就差異很大,手機版本現有功能只有在交談和檔案分享,也不能做視訊聊天,只能有語音聊天,不過,我認為這些問題之後都可以被解決,畢竟在Skype for business都能做到,這技術上因該問題就不大,後面針對PC版Teams來做分享 設定部分 說真的設定真的是簡單到不行,基本也沒甚麼可以設定的 Themes : 設定整個Teams顏色風格,目前只有Default , Dark & Hight Contract三種 Notifications : 設定收到通知要如何顯示 Keyboard shortcuts : 設定鍵盤快速鍵 其餘就是宣告資訊,及更新Teams功能 檔案功能 檔案功能,主要是列出你在Office 365的OneDrive跟Teams中所儲存的檔案 會議功能 小組成員可以發起會議通知,一旦發起該小組會議通知,就會自動發訊息到該小組的Channel,等到時間到時候,也會再發一次訊息通知,看到該訊息通知,被邀請人只需要點擊訊息中的加入即可參加會議,當然會議中可以用語音或是視訊 通知功能 通知功能分為 Notifications : 只要是聊天或是在群組中被tag的訊息都會顯示在這 Recent : 這邊顯示你收在聊天或是群組中收到訊息的列表 聊天功能 聊天功能和小組功能的差異,我認為一個只是非工作上的需求,一個是工作上的需求差別。由圖中可以看到在聊天功能中,不僅僅只是雙方對話,你還可以加入其他人做群聊,當然也可以用視訊和語音進行溝通,另外,tab上分別是: Conversation : 就是雙方聊天訊息 File : 雙方檔案共享 Note : 線上OneNote筆記本 到這邊,跟小組功能是差不多的,當然你也可以自己增加Tab,不過,在聊天中的Tab是只能增加微軟提供的功能,並不能自己客製化。而目前只有提供Power BI的功能,另外,現在有一個缺點就是聊天群是不能被刪除,也就是凡事走過必留下痕跡的概念 Organization : 顯示該成員在組織中的部門或是相關資訊,若是沒設定這部分,則不會顯示資訊 Activity : 這個功能很神奇,只要該人員小組中發訊息,且你有在該訊息下有做回覆,在這地方就會把所有你和他的互動資訊全部都列出來 在聊天中,如果是多人聊天,需要用@去Tag某位人員,這樣對方才會出現提醒,包含手機也才會收到Push Message,如果沒有加入@,這樣對方就不會有任何提示訊息 小組功能 小組就是Teams最主要的核心功能,這邊小組協同合作方式跟slack有一點不同,在slack中,Host Name就是代表小組的意思,每個Channel類似要合作專案項目,所以,在小組裡成員可以看到Channel列表,但是你沒有被受邀到該Channel,你是無法知道該Channel裡面討論的訊息。 Teams則是先用小組做區分,只要你有被邀請到這小組裡面,該小組的所有Channel你都可以參與討論,但是,你沒有被受邀的小組,你是無法看到該小組的存在,在小組的tab中可以與Office 365多項服務給綁定,如果不夠,還可以自行客製化Tab 另外,在小組內聊天中有傳遞過任何檔案,都會自動被儲存在Office 365內,可以到File內找到,如果是不同Channel則會分成不同資料夾,這樣好處在於當後續要回過頭找檔案時候,不會找不到 在聊天時候,有提到要使用@去提醒對方,在小組聊天也是這樣,不過,如果有重大訊息要一次提請全部人,每個人都要逐一加上@是很笨的,所以,這邊簡單作法就是@小組名稱,例如:@MS Teams Test,就可以一次提醒整個小組了 多種Connectors 本身每個Channel有提供多種連接器可以與其他雲端服務做串接,當然也可以與VSTS整合唷,就看自己需要哪些服務,目前這種作法不管在office 365,Flow…等微軟出的產品中,用法都大同小異了 開發人員 對於開發人員來說,就是希望整合相關開發流程或是將相關資訊也放入Teams,做法可以參考下面幾個 Microsoft Teams結合VSTS Microsoft Teams 結合Azure Application Insights Alert 本身也提供不少客製化開發模式,很適合讓開發人員惡搞,且又可以把bot framework整合進來,就可以做出Service Desk的服務 多種好玩的表情圖示 用Teams另一個好玩的地方,就是聊天用的表情圖示,發現內建的圖示還滿多,不過,目前只有支援PC版本才有,手機版本目前沒有唷 如果只是發發表情圖案有甚麼稀奇,稀奇是竟然可以改動表情內的對話文字,這樣就很特別了 後記 目前Teams還是有很多問題需要被修復,尤其在行動裝置的APP功能明顯不足,Teams往往會被跟Slack比,基本上我認為這兩者產品區隔還是有所不同,一個重點在整合,一個是種輕巧,企業內使用Teams會比Slack適合多,畢竟,在整合企業環境是微軟強項,但是,如果是一般團隊或是新創公司用Slack就已經在協同合作上就足夠,不過,從另一個角度考量,那還需要用SharePoint嗎?早期SharePoint也是在協同合作有其效益,不過,現在都講求小團隊,用SharePoint似乎就有點殺雞用刀。個人覺得如果能在Teams無論在操作或是功能擴充能再加強,未嘗不是一套可以成為企業級的協同工具","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"如何使用Office 365 API Connectors","slug":"Azure/O365API","date":"2016-11-27T16:00:00.000Z","updated":"2017-05-29T15:42:44.853Z","comments":true,"path":"paper/2016/11/28/Azure/O365API/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/11/28/Azure/O365API/","excerpt":"","text":"在Office 365提供了webhooks的功能,讓外部系統可以與Office 365進行溝通,因此,只要能開發相容或是本身有相容webhooks定義,就可以讓外部系統把訊息傳遞到Office 365,因此,了解Office 365 webhook可接受的傳遞的格式就很重要。由於本身webhooks是透過Http協定,所以,在哪一種平台上去開發,就部會是障礙,而格式內容是使用json方式,這樣操作起來就更容易,在訊息Header要加上1\"Content-Type\" : \"application/json\" 我們發送一個簡單文字格式,例如:123{ \"text\":\"Hello world\" } 這樣就可以把訊息傳到O365中,不過,只是單純這樣的訊息似乎也太寒酸,所以,在整個O365的json訊息中,又可以分為幾大塊模組,讓我們組出想要的訊息內容,只是每個欄位名稱必須符合O365定義,大概可以分成下面主要的幾大塊 title Actions Sections 利用這些區塊就可以組出我們想要的資訊內容 title & text title算是整個訊息的標題,不過,在不同服務內呈現樣貌會有一點不同,如果只有輸入下面這樣指令是不會Work的,若只想單純文字,只要用text就可以123{ \"title\":\"我是Title\"} 還必須加上內容才可以,內容用text加入,不然是發送不出去1234{ \"title\":\"我是Title\", \"text\":\"第一個訊息\"} 若是要在文字中加入超連結,這是可以,其寫法就跟寫Markdown的超連結語法相同,用[]()組合,像是1234{ \"title\":\"我是Title\", \"text\":\"第一個訊息[Link](http://www.google.com)\"} 就可以做到具有超連結的文字 Actions Actions的概念就像是在訊息中間帶入一個button,可以讓人去點擊,不過,實作上在某些開發編輯器或是服務上會認為這樣語法是有錯誤,主要是因為有用到@context和@type這兩個屬性會被視為錯誤的json格式,導致無法發送,這裡@type中可以用的選項,可以參考http://schema.org/ViewAction了解有那些可以用1234567891011{ \"text\":\"第一個訊息[Link](http://www.google.com)\", \"potentialAction\": [ { \"@context\": \"http://schema.org\", \"@type\": \"ViewAction\", \"name\": \"拜訪Google\", \"target\": [\"https://www.google.com\"] } ]} Sections 前面使用text用來描述相關資訊,感覺似乎有一點點少,畢竟,某些時候這樣的資訊是不夠我們使用,因此,便會想要我擴充資訊內容,這時候就可以用Sections加上Fact的搭配,Sections內則使用activityTitle ,activitySubtitle,和activityText做摘要性的描述,詳細描述則透過Fact方式的Key & Value概念去放入必要的資訊,另外,在使用Sections時候,必須要先有title和text,只有單純sections是會發生錯誤12345678910{ \"title\":\"我是Title\", \"text\":\"第一個訊息[Link](http://www.google.com)\", \"sections\": [ { \"activityTitle\": \"Office 365 API\", \"activitySubtitle\": \"如何使用\", \"activityText\": \"透過API傳遞資訊\" }]} 這時候,再配上Fact則可以填入更多的訊息,而Fact內是搭配name和value方式把資訊填入,且可以有多組的Fact,如果資訊過長,還會自動幫你摺疊訊息12345678910111213141516171819202122232425262728293031323334353637{ \"title\":\"我是Title\", \"text\":\"第一個訊息[Link](http://www.google.com)\", \"sections\": [ { \"activityTitle\": \"Office 365 API\", \"activitySubtitle\": \"如何使用\", \"activityText\": \"透過API傳遞資訊\" } ,{ \"title\": \"人員1\", \"facts\": [ { \"name\": \"姓名\", \"value\": \"王大明\" }, { \"name\": \"電話\", \"value\": \"1000000\" } ] }, { \"title\": \"人員2\", \"facts\": [ { \"name\": \"姓名\", \"value\": \"王大明\" }, { \"name\": \"電話\", \"value\": \"1000000\" } ] } ]} 利用webhook方式再搭配json資訊格式,看來要與Office 365做整合也就不是那樣困難了 參考資訊 1.https://dev.outlook.com/connectors/reference2.http://schema.org/ViewAction","categories":[],"tags":[{"name":"Office 365","slug":"Office-365","permalink":"http://edwardkuo.imas.tw/tags/Office-365/"}],"keywords":[]},{"title":"解決SQL Project中Script遇到跨DB參照問題","slug":"Devops/2016-11-16","date":"2016-11-15T16:00:00.000Z","updated":"2017-05-28T08:11:19.088Z","comments":true,"path":"paper/2016/11/16/Devops/2016-11-16/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/11/16/Devops/2016-11-16/","excerpt":"","text":"做單一系統資料庫專案,透過SQL Project方式開發,基本上並無太大問題,但是,如果在企業內部時候,會遇到一個實務上問題是,當要把某一個系統的資料庫轉換變成SQL Project時候,裡面如果Script有參照到其他資料庫,或是你在A資料庫下寫View或是Store Procedure時必須參照到同一台Server不同DB抓資料(如果是Link Server可以參考這解決[點我],這時候在A資料庫專案終究會有問題出現,會發現你的Script出現紅色警告,甚至無法編譯成功。範例是當你在A DB的View用到B DB的Table123SELECT *FROM A.dbo.XXX AS a LEFT OUTER JOINB.dbo.MMM AS b ON a.ID = b.ID 最簡單解決方式,當然也是把另一個DB也變成SQL Project,然後做Database Reference,但是,實務上要執行會是有相當難度 第一:你可能只用到一個資料表,卻要把整個DB變成你的專案 第二:DB Owner並不是你 所以,必須要有變相的做法來解決這問題,不然,在A資料庫的SQL Project將會無法編譯成功,又或是需要大費周章把有參照到資料庫都變成SQL Project 建立一個被參照DB的殼 在自己專案內,建立一個要參照B資料庫的專案檔,在專案檔下面建立要對應的Table 然後,在Table的欄位中,只要放入你所有需要的欄位就可以 設定SQL Project參照 建立好要被參照SQL Project後,就在原來SQL Project去參照它 然後就會跳出相關設定的屬性 紅色框,就選擇剛剛要被參照的SQL Project名稱 藍色框,則是透過變數方式去設定在A SQL Project要替代的變數,其中,Database Name如果SQL Project專案名稱與實際DB Name不同,這邊要換成實際DB Name,這樣在後續部署上才不會出問題,至於變數名稱就看自己喜好訂定 設定完成後,會多出一個Reference,這跟寫C#一樣,是參照不同Assemably的概念 透過變數方式,只要在後面有用到這個DB時候,都可以透過變數取代 所以,就可以把剛剛上面語法變成下面這樣,用[$(RefHR)]去代替B,就可以解決無法參照問題123SELECT *FROM A.dbo.XXX AS a LEFT OUTER JOIN[$(RefHR)].dbo.MMM AS b ON a.ID = b.ID 但是,這種做法透過New Schema Comparison去部署,也是可以的唷 因為,Visual Studio在幫你部署SQL Statement時候,自動把[$(RefHR)]變數至換成實際的值,所以,透過這樣做法也還是可以能用SQL Project做版控的,只是切記別真的把被參照的DB也部署到Server就好","categories":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}]},{"title":"找DataBase資料表的Miss Index並建立","slug":"SQL/2016-11-15","date":"2016-11-14T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/11/15/SQL/2016-11-15/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/11/15/SQL/2016-11-15/","excerpt":"","text":"一般開發系統人員常常遇到當自己系統跑一段時間後,就會被使用者抱怨說系統怎越跑越慢,當然,系統越跑越慢的因素很多,其中一項就是Table該要有的Index卻沒有建立,在系統初期設計上,不是很容易訂定有效的,不過,當系統越來越大時候,透過SQL Server的統計資訊分析後,去找出較為精準的Index反而會簡單一點,且Index不是建立越多越好,不好的Index反而會讓系統效能變低。 因此,在有一次聽過百敬老師的DB效能調教課程後,原來,可以透過T-SQL去找出目前DB中有哪些資料表是缺乏Index的然後,先針對這些Miss Index資訊建立Index,可算是一個比較安全建立Index方式,其語法如下: 12345678910111213141516171819202122232425262728SELECT DB_NAME(database_id) AS DB_NAME , OBJECT_NAME(object_id, database_id) AS Table_Name , MisDetail.equality_columns [相等欄位] , MisDetail.inequality_columns [不等欄位] , MisDetail.included_columns [覆蓋欄位] , ( user_seeks + user_scans ) * avg_total_user_cost * ( avg_user_impact * 0.01 ) [建索引可降低的成本] , MisStatus.unique_compiles [可用此索引的已編譯執行計畫之數量] , MisStatus.user_seeks [使用者搜尋次數] , MisStatus.user_scans [使用者掃描次數] , MisStatus.avg_total_user_cost [平均使用者可以降低的成本] , MisStatus.avg_user_impact [使用後成本佔原成本的百分率] , 'use ' + DB_NAME(database_id) + ' create index idx' + OBJECT_NAME(object_id, database_id) + '_missing_' + CONVERT(VARCHAR(10), MisDetail.index_handle) + ' on [' + OBJECT_NAME(object_id, database_id) + '](' + ISNULL(MisDetail.equality_columns, '') + CASE WHEN MisDetail.equality_columns IS NOT NULL AND MisDetail.inequality_columns IS NOT NULL THEN ',' ELSE '' END + ISNULL(MisDetail.inequality_columns, '') + ')' + ISNULL('include (' + included_columns + ')', '') AS SQL_StatmentFROM sys.dm_db_missing_index_group_stats MisStatus WITH ( NOLOCK ) JOIN sys.dm_db_missing_index_groups MisGroup WITH ( NOLOCK ) ON MisStatus.group_handle = MisGroup.index_group_handle JOIN sys.dm_db_missing_index_details MisDetail WITH ( NOLOCK ) ON MisGroup.index_handle = MisDetail.index_handleORDER BY 1 , 2 ASC 在SQL_Statment欄位中,是顯示要建立Index語法,只要把內容Copy出來就可以建立Index了,省去還要去撰寫建立Index的SQL語法。123USE msdbCREATE INDEX idxsysjobhistory_missing_97620 ON [sysjobhistory]([job_id])INCLUDE ([instance_id], [step_id], [step_name], [message], [run_status], [run_date], [run_time], [run_duration], [operator_id_emailed], [operator_id_netsent], [operator_id_paged]) 個人認為因該先從使用者搜尋次數高的優先找尋要建立Index的資訊,畢竟使用者次數少的,可能只是IT人員自行下條件搜尋,並非是系統再使用的,因此,建立Index後可能效益也不大。然後再找建索引可降低的成本最高和平均使用者可以降低的成本最高的為優先考量,透過這樣簡單分析,去建立比較可靠的Index,比胡亂建立Index有效益多了","categories":[],"tags":[{"name":"T-SQL","slug":"T-SQL","permalink":"http://edwardkuo.imas.tw/tags/T-SQL/"}],"keywords":[]},{"title":"西雅圖的Fremont Troll小鎮","slug":"LifeStyle/2016-11-11","date":"2016-11-11T16:00:00.000Z","updated":"2017-05-28T15:45:08.510Z","comments":true,"path":"paper/2016/11/12/LifeStyle/2016-11-11/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/11/12/LifeStyle/2016-11-11/","excerpt":"","text":"西雅圖幾個知名的景點,想必大家都一定去過或是聽過像是星巴克創始店,ww,太空塔…等,這都是在西雅圖Downtown內的知名觀光景點,不在Downtown內的景點也有不少,不過,這次介紹是一般比較少人去的一個小鎮Fremont Troll,這小鎮是位於Downtown的北邊。趁著出差時候,想說西雅圖著名景點大致上都有去過,所以,來去一個一般觀光客比較少會去的景點。 到Fremont Troll交通方式,是必須搭BUS前往,如果不在Downtown人,必需到Down Town的Bus Station,然後再轉其他BUS前往(用Google Map可以幫你規劃Bus轉乘路線唷)比較方便,不然,就必須了解每個轉乘點,轉換不同BUS前往 Fremont Troll中的Troll可被翻譯成魔物或是巨魔之類,主要是在Fremont中的一座橋下有一個公眾藝術品取名而來的,而這個藝術品聽說是屬於世界十大最偉大的雕塑之一據說週末很多人會聚集在這邊,因為,是平日早上來感覺這邊並無其他遊客,不過,這邊似乎感覺沒有打掃很乾淨這邊並無特別大的商店,取而代之反而是這些一個一個小商店,每個商店都賣自己一些商品,如果漫步細看,很多還是一些文創商品呢,風味跟Downtown不太一樣,很適合慢步在其中Fremont Troll據說也是一個藝術小鎮,不管走到哪邊都可以看到裝置藝術,像是這個火箭裝置又或是這個土星環的裝置路上還可以看到這骷顱頭如果只認為這小鎮只有這些小東西外,那可就錯,因為,我們走到湖畔邊,竟然發現很多大公司都在這邊設立據點,其中最有名的google, adobe…等,在這邊可以看到他們的身影走近Google Office看一下,裡面真風格就是不同,其中一個Building裡面都是充滿吃的和玩的,果然可以讓工程師好好放鬆 在Google旁就是Adobe`,不過在這裡好像不是開發中心,倒像是出貨用的,實際是做什麼並不是很清楚數據分析大廠Tableau這是?沒錯就是巨大的列寧雕像,上面還有被人潑灑紅色油漆 在我們剛下車附近的一個候車亭,有這個藝術品,他們被命名為Waiting for the interureban,意思在說這幾位一直在等公車到來,據說居民或是藝術家會常來幫他們做變裝秀在Waiting for the interureban旁邊,可以看到小丑的裝置藝術,似乎在取笑世人的忙碌 這個小鎮除了上述景觀藝術之外,聽說在假日會有熱鬧市集可以逛逛,此外,另一個特點就是酒吧特別多,幾乎每走幾步路都可以看到小酒吧,因為,這次是白天前往,所以,所有的酒吧都是關門的,想必晚上因該會非常熱鬧,此外,到這邊有一種讓你感覺步調變緩慢的感覺。","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"Visual Studio開發Azure Logic App","slug":"Azure/2016-11-04","date":"2016-11-04T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/11/05/Azure/2016-11-04/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/11/05/Azure/2016-11-04/","excerpt":"","text":"在這篇[Azure Application Insights發Alert訊息到Slack]中,建立了一個Azure Logic App發送訊息,當時是在Azure Portal上進行開發與設計,雖然操作上有點不順,但也給我建立完成。不過,當發現我這個Flow要越長越大時候,在Azure Portal進行設計還真不是一個好點子,一來網頁設計上延遲感還蠻嚴重,二來有時候沒有辦法一次開發完畢,也不能(敢)儲存,最後,還是透過Visual Studio開發好了 準備項目 要開始設計Logic App前,必須先確認下面幾個東西,你已經有安裝了 Visual Studio 2015 Latest Azure SDK (2.9.1 or greater) Azure PowerShell 預設上,在Visual Studio並不會讓你有視覺化設計的介面,如果,想要跟Azure Portal一樣,具有視覺化設計功能,還必須安裝Azure Logic Apps Tools for Visual Studio,這可以在Nuget上找到 開始開發Logic App 安裝完以上必備的套件後,就在新增專案中選取Cloud範本中的Azure 資源群組 然後,找到Logic App並開啟它 開啟後,會出現跟Azure Portal一樣,讓你選取預設的範本 而在專案部分,則是出現Logicapp.json , Logicapp.parameters.json和一個ps1檔案,主要編寫都是在Logicapp.json中,如果你直接點擊這個檔案,則是會出現Code的視窗,想要有視覺化編輯,則是針對Logicapp.json按右鍵選取使用邏輯應用程式設計工具開啟 這樣就可以開始編輯了,雖然,你是在Visual Studio中編輯,但是,其實他還是會與你Azure中設定的做連動,舉例來說,如果你要加入一個Slack的流程,你在Azure上有設定Slack連線,在Visual Studio中則可以選到已經設定好的Slack連線,不然,你就會在Visual Studio做Slack連線設定動作 當然,在視覺化設計外,你也可以切換到在Json檔案中設定,有時候用視覺化不一定好,用Code去改反而比較快呢。編輯完畢後,只要針對專案,按下部署,並選擇你要部署到Azure哪一個資源群組就可以 目前搞定的流程架構,還會再持續長大呢","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"開始使用Microsoft Teams","slug":"Devops/2016-11-04","date":"2016-11-03T16:00:00.000Z","updated":"2016-12-02T00:27:20.000Z","comments":true,"path":"paper/2016/11/04/Devops/2016-11-04/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/11/04/Devops/2016-11-04/","excerpt":"","text":"微軟剛發表一個類似Slack的團隊協同溝通工具叫做Microsoft Teams,這工具直覺上就是Slack翻版,不過,在整合性上與自家產品的整合性就非常高,幾乎只要是微軟的產品都可以在這裡面使用。一開始以為是在網站上可以登入,沒想到卻是一個APP,所以,要開始使用前必須先下載此APP 安裝Microsoft Teams App 下載Microsoft Teams網址如下:https://teams.microsoft.com/downloads 進入網址後,可以看到各種平台的APP 到這一步就可能會讓很多人退卻,因為它不像Slack一樣,任何人都可以申請使用,你如果要使用它,必須本身有Office 365帳號,它的登入帳號就是你在Office 365上面帳號,這方面一整個感覺就是主打商業或是企業用戶。 安裝完畢後,就可以輸入帳號密碼進去,一進入後會要你建立小組群組,如果還不知道怎樣建立,可以先跳過這步驟,如果有建立,它同時會Office 365上多出群組 在Chat結構上,是先建立群組然後預設會有一個common的頻道,你可以在這群組下新增自己想要的頻道。當然,你也可以同時身在多個群組裡面,好處是不像Slack要切換群組這樣麻煩 此外,若是在手機上,你也可以當作是IM軟體,可以獨自跟其他成員聊天,如果,今日有檔案放在Office 365,也可以直接在Microsoft Teams取出來使用,目前可以用Microsoft Teams的Office 365訂閱層級如下: Business Essentials Business Premium Enterprise E1, E3, and E5 Developer 啟動Office Microsoft Team 在使用之前,須先到Office 365啟動要使用Microsoft Teams功能,在Office 365管理員那邊的設定中找到APP 再到旁邊找到Microsoft Teams就可以啟動它 另外,如果想要有bot功能,記得也要啟動bot唷 整合VSTS Alert 早期還記得要隨時收到Alert是套用Slack,現在也可以開始改用Miscrosoft Teams囉 現在也可以把訊息傳入Miscrosoft Teams了,只要在你的頻道中設定連接器就可以 不過,目前可以收到Alert只有下面幾項 Work items Pull requests Code commits Builds Releases (available 11/9) 參考資料 1.https://msdn.microsoft.com/en-us/microsoft-teams/2.https://products.office.com/en-us/microsoft-teams/group-chat-software","categories":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"Microsoft Teams","slug":"Microsoft-Teams","permalink":"http://edwardkuo.imas.tw/categories/Microsoft-Teams/"}]},{"title":"Visual Studio整合Azure Application Insights","slug":"Azure/2016-11-02","date":"2016-11-01T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/11/02/Azure/2016-11-02/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/11/02/Azure/2016-11-02/","excerpt":"","text":"我們可以透過Application Insights SDK與自己系統進行整合,然後將資料送上雲端,不過,要看資料時候,還要登入Azure Portal查看話,似乎又有一點點麻煩,不過,現在可以直接在Visual Studio去查看你在Azure Application Insights內的資料記錄,且不只是看資料列表,還可以針對資料點進行互動性的分析 Application Insights 搜尋與趨勢 在Visual Studio的其他視窗中可以找到Application Insights 搜尋和Application Insights 趨勢兩種功能 雖然,看似是兩種功能,不過在資料互動上這兩個是互通的,簡單說,如果想要直接看詳細資料的內容,就直接點選Application Insights 搜尋,如果想要做簡單的資料分析,去了解問題點或是資料與資料相互關係的就點選Application Insights 趨勢,此時也可以從Application Insights 趨勢再往下鑽到Application Insights 搜尋看資料的詳細資訊 因此,無論從哪一個方向進去,都必須先做一件事情,就是在Visual Studio和Azure Application Insights的資料源結合起來 一旦取得資料後,就可以看到如下圖一樣的趨勢分析圖表,用圓圈大小表示該時間的事件記錄多寡 如果不喜愛預設的分析,可以透過篩選器,去選擇想要的資料區間,或是要觀察的遙測類型 在趨勢圖中,想要知道該節點內包含的資料內容,只要去點這個節點 就會帶出該節點是抓取那些資料點,這時候就會跳到Application Insights 搜尋頁面,在這個地方,你依舊還可以針對想要資訊再進行過濾 另外,不要以為只能對上面圖表進行互動,下面所呈現的分類資訊,也可以去進行點擊,來改變圖表的XY軸資訊,你可以透過點擊不同類別來做想要的資訊分析 如果,覺得每次都要上Azure Portal查看Application Insights查看資料麻煩話,也是可以透過Visual Studio作查詢之用 結合CodeLens 覺得結合CodeLen這一段實在太驚人,竟然可以把Application Insights的資訊與自己專案的Code給對照出來,立馬想到的好處就是企業中系統在看Code時候,可以快速發現這個function是否真的現在還有再被使用,還是已經是陳年老酒的Code 要做到這功能,必須確認自己的Application Insights資料源是否有設定,可以在專案按右鍵開啟Application Insights,選擇設定Application Insights 一旦設定完成後,在原本專案下的ApplicationInsights.config下面,可以看到多出這些資訊 如果在你的專案地下沒有ApplicationInsights.config這個檔案,這時候去設定會出現Error,這裡是需要有這個Config,你發現你專案沒有這檔案,有可能是你遺失或是你的Application Insights的SDK沒有裝到最新,用javascript的Application Insights的人,就會沒有這個Config,必須用SDK加回來 設定完成後,在你的codelens就會多出這些資訊 若是屬於API類或是Web controller類型的,會多出Request Count資訊,這樣可以了解這個Action被呼叫幾次,如果不是這類型,目前會顯示這Function發生Exception次數,透過這樣資訊就可以快速把Code和實際運作情況相結合起來 這樣讓開發跟維運整合又邁進一大步","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"Azure Application Insights結合NLog擴大企業運用","slug":"Azure/2016-10-27","date":"2016-10-26T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/10/27/Azure/2016-10-27/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/10/27/Azure/2016-10-27/","excerpt":"","text":"Application Insights功能多好用,之前已經有提過,不過,在Application Insights前,大部分開發者都會用NLog來做Log蒐集器,如果,要大家改用Application Insights話,難不成之前有寫Log的地方,都要改用TelemetryClient.TrackEvent方式改寫嗎?這樣似乎會讓系統改到天荒地暗,企業內部的系統又多的跟山一樣,要一一改進似乎不太可能 還好我們可以透過Application Insights NLog Target的套件 讓我們原本用NLog儲存的資訊,直接透過此套件傳送到Application Insights中,例如原本是1234567private readonly ILogger _logger;Publid void Test(){ _logger = LogManager.GetCurrentClassLogger(); _logger.Error(\"Error: Parameter is empty2.\"); _logger.Warn(\"TEST1\"); } 安裝好套件好,會出現一個警告訊息 如果你有用到NLog.Config時候,必須移除Targets,extensions和rules這幾個Tag,主要是因為這些Tag會放到web.config中或App.config123<configSections> <section name=\"nlog\" type=\"NLog.Config.ConfigSectionHandler, NLog\" /> </configSections>.........<nlog> <extensions> <add assembly=\"Microsoft.ApplicationInsights.NLogTarget\" /> </extensions> <targets> <target type=\"ApplicationInsightsTarget\" name=\"aiTarget\" /> </targets> <rules> <logger name=\"*\" minlevel=\"Trace\" writeTo=\"aiTarget\" /> </rules> </nlog> 這樣原本的程式一行都不用改唷,就可以搬到NLog中,如果想要混搭原本TelemetryClient語法也是可以的,並不會受限制,不過,若是你依舊想要原本在Local端也可以繼續記錄Log話,只要把原本在NLog.Config中你的設定值,例如下面1<target type=\"File\" name=\"f\" fileName=\"${basedir}/logs/${shortdate}.log\" layout=\"${longdate} ${uppercase:${level}} ${message}\" maxArchiveFiles=\"30\" concurrentWrites=\"true\" /> <target type=\"Debugger\" name=\"debugger\" layout=\"${longdate} ${uppercase:${level}} ${message}\"/> 搬到App.config或是Web.config的NLog Tag下面就可以囉,同時地端與雲端都存放Log,這樣方式就可以增加運用彈性了","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"Visual Studio Code寫SCSS,並自動編譯為CSS","slug":"VisualStudio/2016-10-20","date":"2016-10-19T16:00:00.000Z","updated":"2017-05-29T15:45:26.987Z","comments":true,"path":"paper/2016/10/20/VisualStudio/2016-10-20/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/10/20/VisualStudio/2016-10-20/","excerpt":"","text":"早期都用Sublime來寫Compass或是SCSS,畢竟透過這類工具寫這種CSS有很多套件且又可以自動幫我編譯成CSS,用起來還滿順手,不過,隨著Visual Studio Code越來越強大,且套件可安裝也越來多,重點還可以是中文的 要開始寫SCSS前,記得必須安裝SCSS相關套件,基本上在Visual Studio Code的Marketplace上可以找到很多,再來就必須在你電腦上安裝好Node.js和npm工具,要把SCSS編譯成CSS,必須靠這兩個工具幫忙 開始設定Visual Studio Code 可以在VS Code中安裝npm套件,這樣可以在VS.Code內執行npm指令 用Ctrl+Shift+P開啟命令列,並執行下面指令,開始安裝Sass相關套件,記得網路要通,因為會到Github上抓取套件1npm install -g node-sass less 這時候寫一個簡單的SCSS程式123456789.A1 { .A2 { width: (100/2)px; height: 100px; } .A2 { color: red; }} 在偵錯地方開啟task選擇Configure Task Runner後 再選擇設定Other Task.json檔案中設定如下123456789{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format \"version\": \"0.1.0\", \"command\": \"node-sass\", \"isShellCommand\": true, \"args\": [\"test.scss\", \"test.css\"], \"showOutput\": \"always\"} 設定完成後,會在跟SCSS檔案同目錄下多出一個.VSCode的目錄裡面會有一個Task.Json檔案,然後用Ctrl+Shift+B開始編譯,最明顯地方在於(100/2),這邊在CSS會等於是50,所以,看編譯完成後得CSS檔案,這樣就完成編譯成CSS123456.A1 .A2 { width: 50 px; height: 100px; }.A1 .A2 { color: red; } 自動編譯CSS 上面方式可以讓SCSS編譯為CSS,但這還不好,因為每次都要用Ctrl+Shift+B編譯它,似乎又很麻煩,如果可以自動編譯就更好了,所以,要再安裝兩個套件,一樣可以直接在VS.Code去執行指令12npm install -g gulpnpm install gulp gulp-sass gulp-less 安裝完畢後,在和SCSS同一個目錄下又會多出node_module目錄,裡面會有gulp相關指令,這時候還沒有完畢,必須在主目錄下產生一個gulpfile.js檔案,並在檔案中設定下面指令123456789101112131415// Sass configurationvar gulp = require('gulp');var sass = require('gulp-sass');gulp.task('sass', function() { gulp.src('*.scss') .pipe(sass()) .pipe(gulp.dest(function(f) { return f.base; }))});gulp.task('default', ['sass'], function() { gulp.watch('*.scss', ['sass']);}) 如果想要監控主目錄下所有的資料夾,可以修改成/**/*.scss1234567891011gulp.task('sass', function() { gulp.src('./scss/**/*.scss') .pipe(sass()) .pipe(gulp.dest(function(f) { return f.base; }))});gulp.task('default', ['sass'], function() { gulp.watch('./scss/**/*.scss', ['sass']);}) 若是想要把輸出的.CSS檔案換成自己想要的目錄,把原本這一段123gulp.dest(function(f) {return f.base;} 換成1.pipe(gulp.dest('./CSS/')) 之後再回去修改原本的Task.json,讓它去監控同目錄下的SCSS檔案,當檔案有變更時候,能自動進行編譯12345678910111213{ \"version\": \"0.1.0\", \"command\": \"gulp\", \"isShellCommand\": true, \"tasks\": [ { \"taskName\": \"default\", \"isBuildCommand\": true, \"showOutput\": \"always\", \"isWatching\": true } ]} 都設定完成後依舊還是必須執行Ctrl+Shift+B,這時候可以發現Output視窗,每當你有修改SCSS並儲存後,就會開始編譯,因為這時候已經啟動Watch File機制了,另外,Watch資料機制必須在啟動Watch前把資料夾建立好,如果在啟動Watch後建立資料夾,這樣該資料內的SCSS就不會更新,必須重新啟動Watch指令了","categories":[],"tags":[{"name":"Visual Studio","slug":"Visual-Studio","permalink":"http://edwardkuo.imas.tw/tags/Visual-Studio/"}],"keywords":[]},{"title":"使用Azure Application Insights效益","slug":"Azure/2016-10-16","date":"2016-10-15T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/10/16/Azure/2016-10-16/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/10/16/Azure/2016-10-16/","excerpt":"","text":"Azure Application Insights是對於要監控系統效能或是追蹤Application跟行動App使用率的一個非常有效的服務,追蹤使用率是企業內部IT部門很常做的一件事情,主要還是希望在有限資源下去開發有迫切需求的系統,而不是做隔靴搔癢的動作虛,畢竟,內部IT開發也還是有成本的,透過使用Application Insights則無論系統是在企業內部還是在雲端都可以快速監控。 早期也用過AVI Code來作為監控.NET Application,後來因為整合到System Center內,又要安裝龐大的產品,如果只是為了監控程式沒有其他應用而裝System Center,感覺又像殺雞用牛刀般。 雖然,感覺好像Application Insights很威,但是,它可以做到事情大概有下面幾點: 追蹤系統可用性,監視系統效能和即時發送自定義的警告訊息 可以採集一些資訊,例如:頁面資訊,系統事件或是自定義事件和相對應指標(metrics) 有強大搜尋功能,可以搜尋追蹤的訊息和一些Exception資訊 可以在各種平台上使用,甚至透過javascript也可以追蹤Html網頁 不過只能在visual studio 2013 update 3版本後加入Application Insights SDK Application Insights如何收集資訊呢?主要是透過HTTPs傳遞監控訊息,因為目前還在preview階段,所以,只能接收端還在北美資料中心內。當Application Insights收到資訊後,會依照資訊類型分別被派送到內部不同Channel中。 在使用Application Insights時,基本上只需要EnableSDK就可以,如果覺得官方監控的資訊不夠,也可以自己定義要收集的資訊進去 新版的SDK,統一採用TelemetryClient作為各個不同平台相同的API,透過這個類別可以搜集相關所需要的資訊,而這個類別可以分成六種Tag(在Portal是六種不同分類)分別如下: TrackPageView : 顧名思義就是監控網頁,表單或是瀏覽器相關資訊 TrackEvent : 可以了解用戶操作行為跟Application事件,一般都是在觀察用戶怎樣操作系統,以及衍生的效能問題 TrackMetric : 主要是針對效能指標相關數據搜集,這個目前個人是還沒有用過,都是採用預設值 TrackException : 追蹤系統發生的Application Exception,這部分如果不自己追加,本身也會自動幫忙記錄,紀錄的Exception可以完整Trace出來,目前認為最好用之一 TrackRequest : 記錄Application收到的Request量和時間,作為監控效能之用 TrackTrace : 可以幫你追蹤到第三方元件,甚至你呼叫Store procedure也可以告訴這個花費多少時間完成 如果,純粹把Application Insights作為可以快速搜集Log或是即時監視系統效能或是問題的一個蒐集器,對於企業來說其實並不夠吸引人,很多企業內部系統,說不定都已經有相對應的解決方案,搞不好反而更可以符合企業內的系統應用(畢竟比較接地氣) 所以,Application Insights在資料分析,則提供不少資訊分析模組讓我們使用,而Analytics功能更可以針對搜集資料做客製化分析,畢竟,資料做有效分析才是有意義,進而做到提前預防系統問題或是進行策略應用,而不是純搜集資料而已,也因此應用在企業內不僅有了Log記錄功能也可以省掉對資料分析應用的開發,專注在其他有意義事物上","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"開始使用Azure Application Insights REST API","slug":"Azure/2016-10-12","date":"2016-10-11T16:00:00.000Z","updated":"2017-04-03T15:13:39.807Z","comments":true,"path":"paper/2016/10/12/Azure/2016-10-12/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/10/12/Azure/2016-10-12/","excerpt":"","text":"Application Insights是Azure監控我們開發的系統一個很好的服務之一,主要可以讓我們省去很多工,就可以抓取到系統運作資訊和問題點。通常,我們能到Azure Portal查看Application Insights紀錄的資訊,不過,Azure上面資訊統計或是分析方式,畢竟還是微軟官方提供的,如果想要客製化來分析資料,就必須把資料抓回來,自己針對資料做相關性分析,現在可以透過Azure Application Insights REST API讓我們把資料給傳遞回來 Azure Application Insights REST API現在是屬於Beta版,所以,使用上難免有一些不方便,且功能性還不是那麼完全,但是,一些常用性的資訊已經給被傳遞出來,在開始使用Azure Application Insights REST API前,必須先到Azure Portal進行一些準備事項 事前準備 Application Insights付費機制最少必須是Standard 為什麼有這限制,我猜因該是在於是否有Data Export功能所致吧 建立Application Insights API金鑰 記得建立完成後,要把金鑰記錄下來,不然事後回來是查不到的 開始使用API吧 目前在API的資料可以提供的資料種類Metric,Events和Query三種方式,個人最常用到的是查詢Events類型的資料,而Application Insights API查詢資料方式是使用OData的語法做資料搜尋 Application Insights API的Address如下1https://api.applicationinsights.io/beta/apps/{APPID}/{queryType}/{queryPath}?{parameterString} 網址中的參數分別為: APPID : 就是Application Insights中的金鑰 queryType : 就是要查詢資料種類類型 queryPath : 就是要查詢的資料位置,若是用Event Type來說,目前提供requests和$all可以使用,不同類型使用的位置也不同 parameterString : 這就是使用OData的指令進行查詢了,例如使用$top,$filter…等,這邊針對有哪些欄位部分,可能還是必須進入Portal查看會比較清楚 在每個類型可用的queryPath,也可以查看下面這個表 在Event類型下的資訊,共有這六種分類 所以,當呼叫API回傳的Json格式也是包含這六種分類的資料內容,這邊先把回傳的Json資料結構轉換成強型別使用123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132public class ApplicationInsightsMessage { public string odatacontext { get; set; } public AiMessages[] aimessages { get; set; } public Value[] value { get; set; } } public class AiMessages { public string code { get; set; } public string message { get; set; } } public class Value { public DateTime timestamp { get; set; } public string id { get; set; } public string type { get; set; } public int count { get; set; } public Exception exception { get; set; } public Customdimensions customDimensions { get; set; } public object customMeasurements { get; set; } public Operation operation { get; set; } public Session session { get; set; } public User user { get; set; } public Application application { get; set; } public Client client { get; set; } public Cloud cloud { get; set; } public Ai ai { get; set; } public Pageview pageView { get; set; } public Customevent customEvent { get; set; } } public class Exception { public string problemId { get; set; } public string handledAt { get; set; } public string type { get; set; } public object message { get; set; } public string assembly { get; set; } public string method { get; set; } public string outerType { get; set; } public string outerMessage { get; set; } public object outerAssembly { get; set; } public object outerMethod { get; set; } public string innermostType { get; set; } public string innermostMessage { get; set; } public object innermostAssembly { get; set; } public object innermostMethod { get; set; } public object severityLevel { get; set; } public Detail[] details { get; set; } } public class Detail { public string outerId { get; set; } public string message { get; set; } public string type { get; set; } public string id { get; set; } } public class Customdimensions { public string CPUCore { get; set; } public string ApplicationVersion { get; set; } public string Time { get; set; } public string PhysicalMemory { get; set; } } public class Operation { public object name { get; set; } public object id { get; set; } public object parentId { get; set; } public object syntheticSource { get; set; } } public class Session { public string id { get; set; } } public class User { public string id { get; set; } public object authenticatedId { get; set; } public object accountId { get; set; } } public class Application { public object version { get; set; } } public class Client { public string type { get; set; } public object model { get; set; } public string os { get; set; } public string ip { get; set; } public string city { get; set; } public object stateOrProvince { get; set; } public string countryOrRegion { get; set; } public object browser { get; set; } } public class Cloud { public object roleName { get; set; } public object roleInstance { get; set; } } public class Ai { public string appId { get; set; } public string appName { get; set; } public string iKey { get; set; } public string sdkVersion { get; set; } } public class Pageview { public string name { get; set; } public object url { get; set; } public object duration { get; set; } public object performanceBucket { get; set; } } public class Customevent { public string name { get; set; } } 然後,就可以透過API把資料取回來,其中在x-api-key填入你剛剛在Portal建立Application Insights API時所產生的金鑰 123456789101112131415161718192021222324string APPID = \"XXX\";string queryType = \"events\";string queryPath = \"$all\";string parameterString = \"$top=1\";string Result = string.Empty;HttpClient client = new HttpClient();client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue(\"application/json\"));client.DefaultRequestHeaders.Add(\"x-api-key\", \"XXXX\");var req = string.Format(\"https://api.applicationinsights.io/beta/apps/{0}/{1}/{2}?{3}\", APPID, queryType, queryPath, parameterString);HttpResponseMessage response = client.GetAsync(req).Result;if (response.IsSuccessStatusCode){ ApplicationInsightsMessage applicationInsightsMessage = JsonConvert.DeserializeObject<ApplicationInsightsMessage>( response.Content.ReadAsStringAsync().Result); return applicationInsightsMessage;}else{ return null;} 這樣就可以呼叫API取資料了,這寫一個小小的Unit Test驗證是否正確,因為,目前實測結果,當資料送出後,Application Insights收到大約要經過三分鐘,所以,這邊必須先Sleep,不然會發生測試錯誤1234_telemetryClient.TrackPageView(\"TrackPageViewTest2\");System.Threading.Thread.Sleep(210000);ApplicationInsightsMessage AIM = ApplicationInsightsAPI.ReadEvent();Assert.AreEqual(\"TrackPageViewTest2\", AIM.value[0].pageView.name); 目前上面資料點保存時間只有七天,如果資料是屬於統計分析或是針對資料做相依性分析,建議把資料傳回自己的DB保存起來 參考資料 OData : http://www.odata.org Application Insights API : https://dev.applicationinsights.io/documentation/overview","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"踏入職場前該具備什麼樣能力之我見","slug":"LifeStyle/2016-10-04","date":"2016-10-03T16:00:00.000Z","updated":"2017-05-30T15:44:36.799Z","comments":true,"path":"paper/2016/10/04/LifeStyle/2016-10-04/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/10/04/LifeStyle/2016-10-04/","excerpt":"","text":"有幸讓雲科大的PIE立坊電子報專訪,提出我對於在校生學習上有什麼該注意地方的看法,雖然,自己也不是什麼人資大師,但就,自己多年工作的經驗,提出一些我認為在校生可以再多注意的地方,而這些地方也是當時自己在學時期所不足,下面為完整內文: 在校生應該培養什麼樣的能力在進入職場後才有優勢 學校傳授給我們的知識與技能,僅是讓我們進入職場的入門磚,要在職場上更具有優勢,我覺得必須先培養自己有這五種能力,『自學』,『抄』,『溝通』,『T型』和『社群』 『自學能力』:職場不是學校,公司或是前輩其實並沒有義務需要指導或是教導你所不會的事情,自己必須要能有自學能力去學習課堂沒有教過的知識。另外,現今社會與科技變化速度越來越快,商業模式也推陳出新,如Big Data,Internet,IoT,A.I,Fintech…等這些新的應用,將會影響到各個領域,唯有不斷靠自主性去學習成長,才能因應整個職場的變化 『抄的能力』:抄,常跟『偷竊』這一類不用好的用語歸納在一起,世界其實很多成功或是有創意的作品最初都是由『抄』去醞釀而生。對一個職場新鮮人來說,用『抄』去學習比自己優秀之人的成功經驗或是特點,不僅可以加速自己在職場上的成長,也能激盪自己的思維與增長智慧。切記,千萬不可以只是囫圇吞棗地『抄』 『溝通能力』: 溝通能力是在團隊合作上是非常重要的能力,『能聊天』和『能溝通』兩者並非相同,在職場上很多時候必須透過『溝通』才有辦法完成事情,尤其,在大企業中這項能力就更顯得重要,畢竟,現在已經不是可以單打獨鬥的年代,要有團結力才能讓事情成功。 『T型能力』: 無論在企業或是在職場上要解決問題方式不再只靠單一模式或專長就可以,必須有多元性的思考和跨技能的整合能力。所以,除了自我本身專業外,也建議要多多學習其他技能,在學習過程中也要能整合自身專業,這樣在解決問題的思考上,就可以更廣泛更多元。而非永遠只有單一答案,另外,透過多項能力結合,進而也可以培養自己的創新能力,不僅是在企業內部是有效益,對自己未來職涯規劃也是好事 『社群能力』: 現在求職不再只有透過傳統的人力銀行,很多公司的人才探訪或是工作機會的合作越來越多會從社群開始尋找,有時候社群反而更能顯現求職者能力的真實性,所以,現今如何透過『Facebook』或『LinkedIN』打造自己的個人品牌也是很重要的,利用社群力量證明自己的能力或是人才,不過,社群是兩面刃,它可以證明你的個人能力,也容易你不良事蹟曝光 除了以上五點,提培養英文能力,依舊是在職場上具有的優勢之一,此外,職場上的『工作態度』是表現出你對這一份工作的責任心,也讓主管或是合作之人對你有所信任感,即使你有非常強的專業技能,但是,不好的工作態度,不僅讓你在團隊合作中屢屢受創,也會容易造成主管對你的不信任感,對於自己職涯是不利的。 工業工程所學與工作上面的應用 工業工程學習過程中,從『統計學』,『製造程序規劃 』,『人因工程』…等各項學科,對不同的職場環境,都是有所幫助,往往新鮮人會擔心剛入社會時,好像學校教的都用不上,如果把職涯規劃拉長來看,其實,每個科目所傳授的知識或是本質,多多少少在職場都是會用到,只是我們並不知道我們正在用它們。雲科求學過程中除了知識技能外,其中最有幫助的就是增加自己的『抗壓性』和『自我組織』能力,在職場的工作壓力是遠大於學校時期的壓力,再加上遇到問題如何自己思考找到方式解決也是職場上必備能力。畢竟,企業招募人員,是希望人員可以協助企業成長與前進。 職場上的經驗提醒在校生學習上有什麼該注意的地方 建議嘗試跨科系學習,讓自己能擁有不同角度去看事情,在求職過程中盡量選擇自己想要挑戰或是喜愛的工作項目,讓自己樂在工作中,才會有動力且自主性的成長與學習。如果,遇到自己並沒有具備該項職務的能力時,可以藉由線上的Mooc公開課程加以學習,學習著不恥下問的精神,遇到自己不懂或是不了解的地方,盡量多多發問,即時它可能是一件平常不過的問題,也會有意想不到的答案。勇於嘗試各種事物,培養自己的經驗,縱使遭遇失敗也是一種成長。 最後,建議在校時期,除了本科的課業知識外,也要多了解目前社會是全球產業流行趨勢,在校時期能多多涉獵它們,並且能培養自己的見解,另外,也提升自己對問題的解決能力與個人整合能力 以上純屬個人看法,不過,每當回想這些歷程,也會因世代變遷可能思維也會不同,看來勇於擁抱『改變』才是王道","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"2016 Azure bootcamp-China Azure 使用經驗分享","slug":"Azure/2016-10-03","date":"2016-10-02T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/10/03/Azure/2016-10-03/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/10/03/Azure/2016-10-03/","excerpt":"","text":"以下是在2016 Azure bootcamp所講的投影片,歡迎大家互相交流唷 2016 Azurebootcamp 中國Azure 使用經驗 from Edward Kuo","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"打通自動化雲端部署到地端-VSTS用MSBuild產生部署Web Site所需要的Files","slug":"Devops/2016-09-27","date":"2016-09-26T16:00:00.000Z","updated":"2017-03-08T03:18:54.319Z","comments":true,"path":"paper/2016/09/27/Devops/2016-09-27/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/09/27/Devops/2016-09-27/","excerpt":"","text":"用VSTS去部署Web Site有什麼難的?尤其部署到Azure Web Site更是沒有難度,基本上只要用Azure web app deployment這個Task就可以。但是,部署到地端的IIS裡面,就沒有這樣簡單,尤其是要從雲到地的部署,沒有這樣簡單的原因,不外乎幾點: IIS沒有辦法裝Web deploy套件 地端Agent可能沒有用Web deploy的權限 VSTS並沒有類似Azure web app deployment簡單操作的Task可用 如果真的要做到第三點,可以用這兩種做法去做,不過,前提都是必須要克服第一和第二點問題 用Visual Studio Build Task內的MSBuild Arguments,透過MSBuild參數做Web deploy,直接部署到IIS,不過,這樣流程就不容易拆分Build和Release 用Visual Studio Build Task內的MSBuild Arguments,透過MSBuild參數做Web deploy Package,再用IIS Web App Deployment的Task,取得Web deploy package的Zip檔作部署動作 所以,除了Web Deploy外,另一個作法就是產生要Publish檔案,透過File Copy方式放到IIS中Application資料夾內,這樣也可以同時把Build和Release流程分開 Build 的流程 設定Build流程其實不難,如下圖這樣做法就可以 其中,有一個需注意的就是Copy Publish Artifact或是Publish Artifact這兩個Task,它們並不會自動把你Build完的專案,產出只需要Publish的檔案,它只會把Build完畢的專案資料夾內檔案原封不動放到$(Build.ArtifactStagingDirectory)資料夾內,所以,還是會把像是.cs檔案一併取出來。如果,要在$(Build.ArtifactStagingDirectory)存放真正要部署的檔案,必須在Visual Studio Build的Task去下MSBuild Arguments的Command,其指令為1/p:OutDir=$(Build.StagingDirectory) /P:TransformConfigFiles=true 然後,把Build完畢檔案放到$(Build.StagingDirectory)內,在Copy Publish Artifact的Task設定如下: 不過,這樣產生部署的檔案,還會有一點點問題,這問題會在你的專案中如果有加入這兩個Package Microsoft.Net.Compilers 1.1.1 Microsoft.CodeDom.Providers.DotNetCompilerPlatform 1.0.1 它會產生一個Roslyn的資料夾在Bin資料夾內,這樣Build後會發現要Publish的資料夾中,在Roslyn中內的dll或是其他程式會放在跟Bin同一層目錄下 當你執行這個Web site就會發生這種錯誤, 找不到\\bin\\roslyn\\csc.exe的錯誤資訊 如果沒有用到這兩個Package就把它移除吧,但是,如果真的有在使用的話,就必須在.csproj裡面加入下面指令1234567<Target Name=\"CopyRoslynFiles\" AfterTargets=\"AfterBuild\" Condition=\"!$(Disable_CopyWebApplication) And '$(OutDir)' != '$(OutputPath)'\"> <ItemGroup> <RoslynFiles Include=\"$(CscToolPath)\\*\" /> </ItemGroup> <MakeDir Directories=\"$(WebProjectOutputDir)\\bin\\roslyn\" /> <Copy SourceFiles=\"@(RoslynFiles)\" DestinationFolder=\"$(WebProjectOutputDir)\\bin\\roslyn\" SkipUnchangedFiles=\"true\" Retries=\"$(CopyRetryCount)\" RetryDelayMilliseconds=\"$(CopyRetryDelayMilliseconds)\" /></Target> 或是1234567891011<Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> <PostBuildEvent> if not exist \"$(WebProjectOutputDir)\\bin\\Roslyn\" md \"$(WebProjectOutputDir)\\bin\\Roslyn\" start /MIN xcopy /s /y /R \"$(OutDir)roslyn\\*.*\" \"$(WebProjectOutputDir)\\bin\\Roslyn\"</PostBuildEvent> </PropertyGroup> <Error Condition=\"!Exists('..\\packages\\Microsoft.Net.Compilers.1.3.2\\build\\Microsoft.Net.Compilers.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Microsoft.Net.Compilers.1.3.2\\build\\Microsoft.Net.Compilers.props'))\" /> <Error Condition=\"!Exists('..\\packages\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.2\\build\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.2\\build\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))\" /></Target> 又或者是在Visual studio中加入也可以12if not exist "$(WebProjectOutputDir)\\bin\\Roslyn" md "$(WebProjectOutputDir)\\bin\\Roslyn" start /MIN xcopy /s /y /R "$(OutDir)roslyn\\*.*" "$(WebProjectOutputDir)\\bin\\Roslyn" 這樣就會在bin裡面多一個roslyn資料夾,且裡面也會有相關檔案,不過,這樣做法,其實是把原本Publish資料夾外的roslyn資料夾,拷貝一份到bin裡面 原始在bin資料夾內的roslyn資料夾中的檔案還是存在bin資料夾內 Release流程 在Release部分就相當簡單,就是把產生的Publish資料夾內的檔案複製到你IIS 所以,使用Copy Files toTask完成,在Source Path中,選_PublishedWebsites內的檔案就可以,如果還有多一層目錄,就選到那個目錄內的檔案即可,而Target Folder就是IIS Web Site資料夾路徑位置,這樣就可以透過Copy File方式部署檔案了","categories":[{"name":"雲端到地端的持續整合與交付","slug":"雲端到地端的持續整合與交付","permalink":"http://edwardkuo.imas.tw/categories/雲端到地端的持續整合與交付/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[{"name":"雲端到地端的持續整合與交付","slug":"雲端到地端的持續整合與交付","permalink":"http://edwardkuo.imas.tw/categories/雲端到地端的持續整合與交付/"}]},{"title":"Azure Application Insights發Alert訊息到Slack","slug":"Azure/2016-09-26","date":"2016-09-25T16:00:00.000Z","updated":"2017-10-16T08:12:57.045Z","comments":true,"path":"paper/2016/09/26/Azure/2016-09-26/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/09/26/Azure/2016-09-26/","excerpt":"","text":"使用Azure的Application Insights可以輕鬆監控自己系統的狀況和資訊外,另一個重要的部分,在於當發現問題時候,要能即時通知團隊,才能做即時的處理。雖然,Application Insights可以建立Alert Mail的機制,通知團隊問題發,但是,感覺還是味道還是差一點,況且有些問題可以需要透過討論後才有辦法解決 所以,來使用目前比較流行的『Slack』,作為團隊溝通協調的一個平台,且透過『Slack』也可以減少要開發手機Push Message機制的App,因為,Slack本身也具有Push Message了。 本身Application Insights並無直接跟Slack整合,而是透過Application Insights內的Webhook機制與其他平台進行整合,所以,我們必須先透過Logic App產生能符合Webhook規範的URL,因此,我們必須在Azure上建立一個Logic App 建立Azure Logic App 首先建立一個Logic App的服務 當它服務建立好後,一開始就是準備建立資訊流程,在Logic App動作行為是依賴流程去撰寫。在預設的官方Template並沒有符合我們需求,所以,這邊我們手動建立一個屬於自己的流程。在這個案例中,input來源是Application Insights,Output位置是Slack,再加上要把Application Insights提供資訊網址,用Google的短網址服務,將很長的網址縮短,所以,我們這邊會用到三個方塊組合流程,分別是 Request Http Slack 後續就分別去設定這三個流程的內容就可以 設定Request 這方塊意義在於當Application Insights監測到異常時候,會透過Webhook通知,一旦Logic app的Request收到訊息,就會開始跑後續流程,在這裡的HTTP POST TO THIS URL,等流程設定完儲存後才會出現,在REQUEST BODY JSON SCHEMA內填入下面json資訊1234567891011121314151617181920212223242526272829303132{ \"$schema\": \"http://json-schema.org/draft-04/schema#\", \"properties\": { \"context\": { \"properties\": { \"name\": { \"type\": \"string\" }, \"portalLink\": { \"type\": \"string\" }, \"resourceName\": { \"type\": \"string\" } }, \"required\": [ \"name\", \"portalLink\", \"resourceName\" ], \"type\": \"object\" }, \"status\": { \"type\": \"string\" } }, \"required\": [ \"status\", \"context\" ], \"type\": \"object\"} 設定Http 收到Request時,會把Application Insights的網址,透過Google服務將網址縮短,所以,是透過post方式把資訊傳送給Google Service,然後,我們再把接收到的短網址放到後續發送到Slack的資訊之一 1.HTTP Method設定Post2.URI 設定填入Google短網址服務的URL1https://www.googleapis.com/urlshortener/v1/url?key=AIzaSyBkT1BRbA-uULHz8HMUAi0ywJtpNLXHShI 3.Headers 設定要傳送訊息的型態,這邊設定為json123{ \"Content-Type\": \"application/json\" } 4.Body 則是設定原本Application Insights事件的長網址,傳送給Google服務,這邊可以透過紅色匡點選portalink,就會自動把portalink資訊帶入 這一段在Logic App code view為1234567891011121314\"HTTP\": { \"inputs\": { \"body\": { \"longUrl\": \"@{triggerBody()['context']['portalLink']}\" }, \"headers\": { \"Content-Type\": \"application/json\" }, \"method\": \"POST\", \"uri\": \"https://www.googleapis.com/urlshortener/v1/url?key=AIzaSyBkT1BRbA-uULHz8HMUAi0ywJtpNLXHShI\" }, \"runAfter\": {}, \"type\": \"Http\"} 設定Slack 一開始必須先建立Slack連線資訊,點選Sign In會跳出登入畫面,這時候輸入團隊在Slack的名稱和帳號密碼,團隊Slack是XXX.slack.com,名稱就是XXX 輸入完後會跳出Microsoft Azure Logic Apps would like access to XXX訊息,這是讓Azure和Slack建立授權關係,基本上就是要按同意囉 然後,就要建立對應在Slack的相關設定 Channel_Name 就是設定你要發送到Slack Channel的名稱,格式因該是#XXX Messaage Text 就是設定想要在Slack Channel上顯示的資訊,設定後的資訊如下 以上設定完成後,可以發現在Azure不僅僅多了一個Logic App外,也會多一個API COnnection 此外,在Request區塊中HTTP POST TO THIS URL也會自動有了URL,要把這組URL放到Application Insights Alert設定的Webhook,當要發送Alert時候,也會Application Insights也會透過Webhook把資訊傳給Logic App 在Logic App也可以看是否資訊有正常發送出去 如果發現有發生錯誤的地方,只要點選Faild的Event就可以看出是哪一段流程出問題 整個Logic App Code View1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192{ \"$schema\": \"https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#\", \"actions\": { \"HTTP\": { \"inputs\": { \"body\": { \"longUrl\": \"@{triggerBody()['context']['portalLink']}\" }, \"headers\": { \"Content-Type\": \"application/json\" }, \"method\": \"POST\", \"uri\": \"https://www.googleapis.com/urlshortener/v1/url?key=AIzaSyBkT1BRbA-uULHz8HMUAi0ywJtpNLXHShI\" }, \"runAfter\": {}, \"type\": \"Http\" }, \"Post_Message\": { \"inputs\": { \"host\": { \"api\": { \"runtimeUrl\": \"XXXX\" }, \"connection\": { \"name\": \"@parameters('$connections')['slack']['connectionId']\" } }, \"method\": \"post\", \"path\": \"/chat.postMessage\", \"queries\": { \"channel\": \"#alert\\n\", \"text\": \"@{triggerBody()['context']['resourceName']} Alert\\nAlert Name : @{triggerBody()['context']['name']}\\nDescription:@{triggerBody()['context']['description']}\\nInfo Link: @{body('Http')['id']} \\n----------------------------------------\\n@{triggerBody()}\", \"username\": \"Service\" } }, \"runAfter\": { \"HTTP\": [ \"Succeeded\" ] }, \"type\": \"ApiConnection\" } }, \"contentVersion\": \"1.0.0.0\", \"outputs\": {}, \"parameters\": { \"$connections\": { \"defaultValue\": {}, \"type\": \"Object\" } }, \"triggers\": { \"manual\": { \"inputs\": { \"schema\": { \"$schema\": \"http://json-schema.org/draft-04/schema#\", \"properties\": { \"context\": { \"properties\": { \"name\": { \"type\": \"string\" }, \"portalLink\": { \"type\": \"string\" }, \"resourceName\": { \"type\": \"string\" } }, \"required\": [ \"name\", \"portalLink\", \"resourceName\" ], \"type\": \"object\" }, \"status\": { \"type\": \"string\" } }, \"required\": [ \"status\", \"context\" ], \"type\": \"object\" } }, \"kind\": \"Http\", \"type\": \"Request\" } }}","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"用Application Insights監控IIS的Application","slug":"Azure/2016-09-20","date":"2016-09-19T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/09/20/Azure/2016-09-20/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/09/20/Azure/2016-09-20/","excerpt":"","text":"Application Insights用來監控Application是非常好用的工具,不過,如果今天你已經有存在的系統,或是可能比較老舊的系統,可能無法透過Application Insights SDK做監控,但是,不做監控又怪怪,這時候可以用比較偷懶方式,就是下載Application Insights的ApplicationInsightsStatusMonitor,安裝到你想要監控的IIS上面。基本上不需要改任何程式碼就可以自動幫你做監控Application的動作 安裝ApplicationInsightsStatusMonitor 首先,到http://go.microsoft.com/fwlink/?LinkId=506648下載套件進行安裝 安套件相當簡單,只需要不斷的下一步就可以,目前這個套件還在Preview版本,所以,設定介面相當陽春,這邊需要等待額外下載Agent。 都上面畫面跑完,就會自動安裝了,因為,啟動Monitor時候,它會自動去掃你這台Server的IIS,所以必須要等一下時間 設定ApplicationInsightsStatusMonitor 安裝完畢套件後,再來就是設定相關要監控的Application,這時候必須先登入你的Azure,就會自動抓取Azure上面已經存在的Application Insights服務或是要即時開啟服務,當你要開始監控IIS時,建議網站最好一定要設定監控,下面其他次網站是否要監控就看需求決定 當你設定站啟動Application Insights後,在網站下面會看到自動被新增ApplicationInsights.config檔案 此外,當設定完Application Insights Monitor後,必須重新啟動IIS 這時候就可以開始做遙測了 開始遙測的狀態 當你開始進行遙測,就可以透過Azure看到Server的一些狀態,下面是Live Stream的狀態圖,可以即時遙測Server和Application現狀 不過,當你的IIS的Application沒有任何活動,也是沒有人訪問時候,這時候Live Stream就會停止不會有數據產生和收集 下面則是Server端環境數據分析 另外,也推薦可以看Application Map可以分析系統關係圖,如果早期有用過AVI Code的人,也因該會想要用這樣方式瞭解系統串接性 可能無資料 有可能裝好沒有產生資料,可以檢查防火牆是否有開啟,要開啟防火牆的位置,可以參考下面的列表 https://azure.microsoft.com/zh-tw/documentation/articles/app-insights-ip-addresses/ 基本上只要開啟目的是遙測和LiveStream就可以,如果要想要在Server上看Azure Portal的Application Insights資料就還必須開啟資料存取 API。 如果,不能開防火牆,要透過Proxy這條路時候,目前測試上需要做兩個動作,才有辦法把資料拋出去 如果網站有Web.Config,要設定Proxy 12345<system.net> <defaultProxy> <proxy proxyaddress=\"http://XXXX:80\" bypassonlocal=\"True\" usesystemdefault=\"True\"/> </defaultProxy></system.net> 在Applicationinsights.config加入EndpointAddress 123<TelemetryChannel Type=\"Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel\" > <EndpointAddress>http://XXXX</EndpointAddress></TelemetryChannel> 一般來說因該只需要設定Web.config就可以","categories":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[{"name":"Azure Application Insights","slug":"Azure-Application-Insights","permalink":"http://edwardkuo.imas.tw/categories/Azure-Application-Insights/"}]},{"title":"Visual Studio也是可以執行SQL Statment看結果","slug":"VisualStudio/2016-09-09","date":"2016-09-11T16:00:00.000Z","updated":"2016-11-29T12:15:58.000Z","comments":true,"path":"paper/2016/09/12/VisualStudio/2016-09-09/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/09/12/VisualStudio/2016-09-09/","excerpt":"","text":"寫在前頭,本篇並非要說明要捨棄SSMS,SSMS還是在管理DB或是SQL效能調教有大的幫助,不過,就SQL程式開發層面的控管上,還是建議需要把程式納入版本管控無論是SQL或是C#,先前提到開始用SQL Project做資料庫程式的版控和佈署的做法,很多朋友最大的一個要克服點,就是當從SSMS轉移到Visual Studio時,要怎樣在Visual Studio內去看我執行想要的SQL Statment結果,畢竟,並非每個人都是SQL 大神,可以等寫完部署後才去驗證SQL的。因為,一般人還是習慣編寫SQL Statment,邊看跑出來的資料,並且同時把每一段SQL Statment放入要開發的Store Procedure中,這時候如果要在Visual Studio和SSMS間切換,似乎又很惱人 其實,這部分在Visual Studio內也可以做到,不需在Visual Studio和SSMS間切換,首先必須到Visual Studio的View開啟SQL Server Object Explorer 這時候,增加一個SQL Server,這邊的SQL Server可以是內部Server或是Azure的 在Explorer就會列出所有你管理的SQL Server,這部分跟SSMS呈現是相同的,不同地方在於有一些是屬於DBA管裡面的功能,在這邊可能會看不到,但是絕大部分的SQL物件類型都是有的 想要下SQL Statment查資料,只需要到選取那個DB,並且按下右鍵,選擇New Query就可以 介面跟SSMS也很像,也可以查看執行計畫,且還有SQL的Intellisense唷 執行後的結果呈現也跟SSMS是相同的,該有的資訊幾乎都沒有少,如果要執行Store Procedure呢?這也是可以的,直接在你想要執行的Store Procedure按下右鍵選Execute Procedure就可以,跳出的GUI介面可能跟SSMS不太一樣,但是運作原理是相同的。因此,如果在Visual Studio內可以做到跟操作SSMS行為模式,似乎用SQL Project來做版控也相對容易許多。 不過,就專職DBA來講用Visual Studio做資料庫管理確實是很不實際,就開發人員來說已經是足夠使用的","categories":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}],"tags":[{"name":"Visual Studio","slug":"Visual-Studio","permalink":"http://edwardkuo.imas.tw/tags/Visual-Studio/"}],"keywords":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}]},{"title":"解決VSTS內Azure File Copy的Content Type問題","slug":"Devops/2016-09-01","date":"2016-08-31T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/09/01/Devops/2016-09-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/09/01/Devops/2016-09-01/","excerpt":"","text":"透過Azure File Copy的Task,可以把檔案部署到VM或是Blob中,在後者部署上如果只是一般的檔案,基本上並無太大問題,不過今日要是你部署的是js,image,css或是fonts檔案可能就會出現問題 最容易發生的問題就是Web的連結這些Link檔案,雖然不會出現404問題,但是檔案內容也不會有做作用。主要是因為使用這Task部署後,檔案在Blob的Content Type會被設定octet-stream 這樣就會導致CSS即使被下載後還是依舊不能顯示 所以,必須在Azure File Copy Task的Additional Arguments設定 因為,Azure File Copy Task背後是透過Azcopy命令程式進行動作,而Additional Arguments內擺放的參數就是Azcopy參數,關於Azcopy可以參考下面網址:https://azure.microsoft.com/zh-tw/documentation/articles/storage-use-azcopy/ 以部署CSS檔案為例,如果都不設定,在Blob的Content Type會是application/octet-stream,這樣會讓網頁無法讀取檔案內容,所以,必須在Additional Arguments內加入下面指令1/SetContentType:text/css 若是遇到不同檔案要有不同的Content Type,需要建立多個Task,分別過濾出檔案的Content Type去設定,然後部署,所以,語法就會變成下面這樣1/SetContentType:image/svg+xml /Pattern:*.svg 這就可以在部署到Blob後,也改變其檔案的Content Type了","categories":[],"tags":[{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"「晨晨跨海上學去」紀錄片DVD出版了","slug":"LifeStyle/2016-08-31","date":"2016-08-30T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/08/31/LifeStyle/2016-08-31/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/31/LifeStyle/2016-08-31/","excerpt":"","text":"故事內容 一個11歲,來自中國河南鄭州的身心障礙特殊孩子晨晨,他在中國大陸的教育體制適應不良,脾氣不好、不懂規矩、很容易和老師起衝突,甚至與同學打架,也無法參與課外活動。一直到媽媽某次來台自由行,晨晨參加了台灣的夏令營,回大陸後發現他的態度有很大轉變,於是媽媽向國台辦申請到台灣交流,讓晨晨到新竹的融合校區就學。班上老師對學生的包容,友善環境跟同學的接納,讓晨晨自然學到了尊重與禮貌、行為明顯改變。而這場跨海學習之旅,也觸動了周圍人的心靈…..全片跳脫了批判式的紀錄片觀點,以流暢的節奏跟拍晨晨來台的一舉一動,並以田野研究般的精神,到河南拍攝晨晨與家鄉同學的互動,並捕捉、對照晨晨來台灣之後的變化。教師耐心的指導,跟母親滿懷愛心的照顧,讓影片不時流露一種溫暖正向的力量。 晨晨母親說:「如果之前能(懂得如何)包容接納晨晨,晨晨就不會變成霸道、不守規矩的孩子。」正是這部影片闡釋出的最大善意。晨晨不但在紀錄片當中呈現出他的前後改變,鏡頭下看出他懂得尊重女同學,以及學習到「尊重」人的這種態度。 教育改變人生,首先要結合人性。本片直讓人想起伊朗導演阿巴斯《何處是我朋友家》的樸實誠懇,更讓我們對於兩岸教育、對於下一代,如何包容歧見尊重他人,提供了一個良善的示範。 購買方式 電洽財團法人福榮融合教育推廣基金會(Tel:03-5753133)購買家庭版,每片500元內有導讀手冊,可開捐款收據 匯款帳號:彰化銀行 北新竹分行 96275120699-200劃撥帳號 : 19614091,戶名:財團法人福榮融合教育推廣基金會 如要公開放映請洽輝洪開發股份有限公司購買公播版,電洽Tel:02-2702-3594 預告片 導演 吳淑美教授被譽為臺灣融合教育推手,用鏡頭記錄孩子們在融合教育的成長過程,用影像寬拓社會對教育創新的想像,在獲獎紀錄片《同班同學》及《天使在唱歌》後,本片為第三部作品,由大師級電影人廖慶松指導剪接,影片完成前曾獲中國央視關注並採訪,她也曾到中國河南省拍攝晨晨與家鄉同學的互動,並詳細紀錄他在台灣接受融合教育的改變。","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"Entity Framework發生『Validation failed for one or more entities. See 'EntityValidationErrors' property for more details』","slug":"Net/2016-08-27","date":"2016-08-26T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/08/27/Net/2016-08-27/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/27/Net/2016-08-27/","excerpt":"","text":"使用Entity Framework在處理資料存入資料庫是非常方便,但是缺點就是因為太自動幫我們都做好很多處理,導致有時候發生問題,就不知道問題在哪邊增加Debug的困難性,例如下圖,當我使用SaveChanges,就出現這個Exception,但是,這錯誤實在不知道在那邊,從這exception也無法明確地確定問題所在 不過,大概心裡有數因該是資料跟欄位上有問題,可是,以這個案例來說,資料表欄位超多,不可能一個欄位一個欄位去做確認,甚至是去比對資料。若是可以再多一些資訊,就更好了。從錯誤訊息是要我們去看EntityValidationErrors屬性去看更多資訊。千萬不要從原本的Exception去找EntityValidationErrors屬性,這樣根本還是找不到錯誤。因此,若之後有遇到這樣錯誤訊息,建議可以使用DbEntityValidationException類別幫忙我們找出問題 DbEntityValidationException 類別: Represents an exception thrown from SaveChanges() when the validation of entities fails. 從這個類別中就有EntityValidationErrors屬性可以使用了,就可以輕易找出問題所在 使用一個簡單範例,找出當錯誤發生時候,秀出Entity到底是哪邊出問題12345678catch (DbEntityValidationException ex){ var entityError = ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage); var getFullMessage = string.Join(\"; \", entityError); var exceptionMessage = string.Concat(ex.Message, \"errors are: \", getFullMessage); //NLog LogException(new Exception(string.Format(\"File : {0} {1}.\", logFile.FullName, exceptionMessage), ex));}","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"企業內開發人員該如何選用技術或框架?","slug":"LifeStyle/2016-08-25","date":"2016-08-24T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/08/25/LifeStyle/2016-08-25/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/25/LifeStyle/2016-08-25/","excerpt":"","text":"常常被人問到你團隊有用甚麼新技術或是框架去開發?或是,我們因該要用什麼新技術和選哪一個框架去開發,這系統比較好?用AngualrJS好像不錯。現在很熱門,採用SPA開發網頁好像可以節省頻寬,使得整體反應相當快速…等。突然覺得在這技術爆炸年代,讓開發變得很不單純,又當微軟宣布.NET走向開源之後,不管在前端(前端Framework更是雨後春筍般出現)或後端的技術開發,或是新的框架的誕生,真是多到不知道該怎樣去選擇才好? 有些時候,感覺不去”使用”這些新的語言或是新的開發方式去開發系統,就好像是落伍或是跟不上時代,又或是外界媒體不段在洗腦或是傳達某些技術,感覺使用這個才是王道。(注意,這邊我是用”使用”一詞。因為,學習跟使用 這兩者是不同),確實,當時代不斷改變,人是必須不斷去學習各種程式和新技術所帶來的衝擊,至少當你是走在資訊這個產業時,必須要有的領悟。 回到該用那種技術或框架開發系統這一個問題,我個人覺得如果你本身不是公司老闆或是在公司的政策強迫下,在使用新技術去開發可以從下面三個層面去思考, 解決問題 這一層面主要是從商業或是業務需求面去看。 我認為不管那一種的新技術或是新框架的誕生,都是為了解決當時的一些需求或是某開發上的問題所衍生出來的。因此,當我們去開發一套系統時候,不該一昧認為最新的技術就是最好用的,而是,必須先做事前的分析,了解目前的業務需求舉例來說,如果你的系統,未來只會去服務十個使用者,而它的目的只是讓使用者加速他日常工作或是簡化一些流程(別笑,很多in House系統就是這樣),單純用自己拿手的WebForm開發就可以解決使用者問題?是否有必要採用SPA方式去開發? 又或是,當大家都在談論開發要搭配AngularJS,但,整體需求面看不到,導入AngularJS會解決業務或是架構問題時,是否單純搭配Javascrip或Jquery就可以呢?不過,如果今天你的系統必須要高效能高可擴充性且需要降低網頁傳輸量,那請使用SPA,甚至ReactJS去開發,或是,一些可以解決這方面的技術,即使困難度很高,還是有其導入必要性。一切都必須從需求和解決問題去思考該用哪一種技術。 ROI 這一層面主要是從系統開發過程的投資報酬率去看開發系統的ROI評估,這一點很重要,一套不熟悉的框架或是技術的導入,對一般人來說都是一個高成本的投入,像是在新創團隊中,能快速將自己的發想或是解決問題的方法變成產品,並趕緊丟到市場驗證,驗證回來後再持續快速修正,這才是最有效益的,投入一個你都不熟悉的技術或是框架,等你摸完再開發出來,此時,你的投資回報率已經不見了,因為,你的可能主意已經被別人捷足先登了。而在一般企業中,MIS往往都被時程壓著打,甚至,從分析到開發測試,往往只有一兩個月就要完成,且通常還會被用系統產出率決定MIS的績效,與其導入一個比完成需求還複雜的技術或是框架時,還不如採用合宜的目前需求的框架去開發,那樣怎樣才知道要用那些技術或是框架才合宜呢?這就是開發人員還是要持續的原因,有時候學習的廣會比學習的深還有幫助 維護成本 這一層面則是從團隊文化去看 對於開發In House系統來說這是很重要的考量,且往往又是很不好拿捏,就拿內部系統開發來說好了,內部系統大都是像是肝一樣,辛苦但往往會被忽視。而且,內部系統不是說時間到就可以升級版本,或是,舊版本就不去維護。也因此,久而久之,可以發現MIS要了解的語言從 VB6到.NET 5都有,還不包括一些林林種種的分支技術。再者,加上公司人員來來去去,系統的Owner不斷改變,需求不斷增加(新需求往往會被建築在多年前的系統上)維護成本就越來越高了。 從維護成本思考下,就必須了解整個團隊對於該技術與框架的熟悉度。若只是,團隊中只有一兩個人對此框架熟悉,大部分都不熟悉時候,就要強行導入,後續可能就會墊加系統的維護成本了,畢竟,當系統上線有異常時候,團隊有辦法去維護嗎?可被允許的down time是多少?又或是當商業需求改變,要立即增加或是修改系統功能時,所要付出的成本是多少。從以上角度思考,是否要此刻運用此技術或是框架到團隊中就是需要評估的,又或是該逐步提升團隊技能或是熟悉度再做考量呢? 技術 這東西有如兩面刃,它可以帶來很大效益,同時,也會伴隨許多風險,唯有不斷學習和改善才可以去降低使用風險,而無論是架構設計或是技術框架的導入,還是必須依附在商業與業務需求,過多或是不及架構或是一昧聽從潮流而去使用的技術,對於產品和系統的幫助都不大。 從團隊角度來看,若是成員技術差異很大時候,與其採用一些新技術,還不如先提升成員的技術力,讓大家彼此的能力差距縮小,縱使使用一些舊有技術又何妨呢?現在已經是不缺選擇使用框架與技術的世代,而是要怎樣選擇的才是有助於整體開發的思維了。","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"如何替VSTS增加User Account , Agents和Build時數","slug":"Devops/2016-08-22","date":"2016-08-21T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/08/22/Devops/2016-08-22/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/22/Devops/2016-08-22/","excerpt":"","text":"一般來說使用VSTS好處是在五人以下的團隊可以免費使用VSTS的功能,且VSTS額外提供幾項免費項目 每個月免費build 240分鐘 每個月免費20000名的虛擬使用者分鐘數 (VUM) 一個免費的build agent 一個免費私人的部署agent相關計價方式可以參考下面詳細價格資訊https://www.visualstudio.com/pricing/visual-studio-team-services-pricing-vs 不過,雖然說可以免費使用,但是當使用到一定規模時候,這些優惠可能就不夠用,就必須透過購買相關需求面的項目來使用 購買方式 目前VSTS本身並沒有辦法讓你能在線上做付款購買或是擴充服務,說穿了它也是Azure上的一個SaaS服務,所以,你本身必須透過Azure的付款機制去付這一筆費用,且此付款不可以使用MSDN的優惠金額付款唷,一定要真正從自己口袋拿出錢的才可以,所以,首先必須用你VSTS帳號去登入Azure,並在Azure找到Team Service Accounts 可以看到你所屬的VSTS,建議做到這一步時候,最好使用的VSTS Owner Account來登入Azure並操作其步驟,如果非VSTS Owner可能在設定會出問題 透過Unlink的按鈕綁定你所訂閱的Azure 這樣就可以增加相對應的服務 就Build and Deployment service這功能來說,就可以從Free變成Paid 如果沒有這樣子,你安裝超過一個Agent,它會提示你說你的Slot不夠,無法安裝 注意!注意! 實作上有遇到幾個雷,提供給大家注意 VSTS上的Current owner必須在VSTS的Azure Active Directory內 且必須用這AD的所在的Azure訂閱中去綁訂VSTS,不能用其他AD的訂閱來綁訂這個VSTS,換句話說當你是用其他Azure AD訂閱時,就必須在那個訂閱下面去建立VSTS才能對VSTS進行付款動作。不然,這VSTS就會變成孤兒想付款也沒辦法 當你從Free變成Paid把相關Agent設定好後,再去解除VSTS和訂閱的關係,然後在Link起來時,記得所有Agent需要移除再重新安裝,不然,會發現你的Agent一直不work,會一直處於Idle狀態,且又不會有任何錯誤告訴你。你在解除VSTS和訂閱也不會有任何錯誤或是提警告告訴你","categories":[],"tags":[{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"打通自動化雲端部署到地端-自動化建立Database版本差異化Script","slug":"Devops/2016-08-17","date":"2016-08-16T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/08/17/Devops/2016-08-17/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/17/Devops/2016-08-17/","excerpt":"","text":"基於雲到地部署,除了我們在Application能做到CI&DI的流程,現在連Database也是可以做到這個流程,不過,在實務上不太可能讓開發人員自動化去更新資料庫,尤其在正式環境下更是不可能,畢竟異動資料庫的風險是很大的,所以,一般保險作法可以產生要部署的SQL Script提供給DBA確認後,再做部署的動作 要產生部署的SQL Script不是很容易嗎?是的,不過當你從開發到真正要上線的時間可能並非很短暫,且每次更新原本的Script又怎能保證在部署階段時候,不會遺漏掉有哪些Store Procedure或是View之類的忘記更新呢!所以,透過自動化方式與正式環境DB比較這是最保險的,可避免遺漏部分 準備事項 如果要做到這一步份,並非隨便就可以把產生差異化的DB Script給自動化,必須要有幾個前提須先完成 DB設計與開發都必須做版控並納入VSTS內 使用SQL Project進行開發 能產生.dacpac檔案 地端的Agent那台Server必須安裝好SQL Server Data Tools (SSDT),這樣才有sqlpackage.exe程式這是前期必須要準備好的,如果已經準備好這樣的環境,後面的CI就可以開始做了Build SQL Project 首先要必須要SQL Project編譯成.dacpac檔案,所以,必須先把專案給編譯過一次才行,跟編譯.NET程式的流程是類似的。 建置SQL Solution其實只有三個步驟就可以,而這邊只需要使用MS Buid,而裡面設定基本上只要用到基礎值就可以 第一步驟使用Ms Build,把專案編譯成.dacpac Source地方請務必選擇專案的.sln檔案的位置,如果有用到Nuget記得要Restore一下 第二步驟也只是把編譯好的.dacpac搬到要發佈的目錄 第三步驟發佈.dacpac 基本上這三步驟就完成建置,不過,今天如果你一個.sln檔案裡面不只一個SQL Project,且可能會使用到Nuget Package,就必須多一個步驟Nuget Restore,不能在Visual Studio Build內去還原Nuget Package,因為在Visual Studio Build內只能選擇某一個SQL Project的.sqlproj檔,在.sqlproj檔案並沒有讓你取得Nuget Package資訊,所以,執行nuget restore就會發生錯誤。 且如果要使用地端Agent部署,請改用地端的Agent 產生差異化SQL 建置部分是比較簡單的,再來就是在Release地方去執行產生差異化指令的程序。在這邊,必須有幾樣事情需要先定義 定義Source資料夾,這是要存放Build出來的.dacpac 定義Target資料夾,這是存放與正式資料庫的.dacpac 定義Diff資料夾,這是存放差異化Script的.sql然後,定義Release流程 Copy build .dacpac到Source資料夾 與Target比較,如果第一次做比較則需要先把一份正式資料庫的.dacpac放在此資料夾,再做比較 產生差異化的script放到Diff資料夾 如果執行差異化的script在正式資料庫後,DBA審核後無誤再去同意把Source內的.dacpac檔案覆蓋到Target資料夾 第一步驟就是從Source Folder把$(System.DefaultWorkingDirectory)內的.dacpac檔案複製一份到Source資料夾,就是設定中的Target Folder 執行地端的sqlpackage進行差異化比較,選用Command Line Task 這邊最麻煩就是如何去執行SQLpackage指令,要參考其指令可以看下面網址https://msdn.microsoft.com/zh-tw/library/hh550080(v=vs.103).aspx.aspx) Tool部分是去找到sqlpackage.exe.目錄位置,位置可以參考1"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\Extensions\\Microsoft\\SQLDB\\DAC\\130\\sqlpackage.exe" Arguments則是擺放sqlpackage指令,目前我採用指令如下1/action:Script /q:true /sourcefile:"D:\\DataBase_dacpac\\xxx\\Source\\Source.dacpac" /targetfile:"D:\\DataBase_dacpac\\xxx\\Target\\Target.dacpac" /targetdatabasename:XXX /outputpath:"D:\\DataBase_dacpac\\xxx\\Diff\\xxxDiff.sql" /p:ScriptDatabaseCompatibility=false /p:ExcludeObjectTypes=DatabaseRoles,RoleMembership,Rules,Audits,Credentials,DatabaseAuditSpecifications,ServerRoleMembership 裡面有用到比較重要的指令分別是 /p:ScriptDatabaseCompatibility : 指定當您發行至資料庫時,應該忽略或更新資料庫相容性的差異 /Quiet:{True | False} : 指定是否隱藏詳細的意見反應。預設為 False。 /p:ExcludeObjectTypes : 為了避免產生過多不必要的Script,這邊可以設定要忽略的DB物件,讓他們不要去跟正式資料庫比較,因為有些物件可能是屬於DBA專用,開發人員不太會去碰觸到 另外,在environment設定部份,兩個Task有一點不同,不同點在於事件的Trigger部分 Different SQL Task TargetDB Task 因為產生的差異檔是本身是可以透過SQLcmd去執行,所以,如果這個Script檔案在SSMS內執行,必須啟動SQLcmd模式才可以 透過這種方式就可以讓SQL Project也可以自動產生差異化檔案給DBA做部署","categories":[{"name":"雲端到地端的持續整合與交付","slug":"雲端到地端的持續整合與交付","permalink":"http://edwardkuo.imas.tw/categories/雲端到地端的持續整合與交付/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[{"name":"雲端到地端的持續整合與交付","slug":"雲端到地端的持續整合與交付","permalink":"http://edwardkuo.imas.tw/categories/雲端到地端的持續整合與交付/"}]},{"title":"使用PowerShell設定Azure Blob檔案內的max-age值","slug":"Azure/2016-08-16","date":"2016-08-15T16:00:00.000Z","updated":"2016-11-29T08:48:36.000Z","comments":true,"path":"paper/2016/08/16/Azure/2016-08-16/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/16/Azure/2016-08-16/","excerpt":"","text":"為什麼要替blob內的檔案設定max-age,如果你網站相關的靜態檔案是放在blob,那樣設定max-age的值是比較好的,什麼是max-age?主要是在網頁中一些靜態檔案的Cache,是透過Http header中的cache control作為控制,通常我們可以設定是屬性有private、no-cache、max-age、must-revalidate這幾種可以設定,一般你設定private、no-cache、must-revalidate這屬性,進入網站時候都會在讀取一下靜態檔案,若是設定max-age,則是在一個範圍時間內都不會去讀取這個靜態檔案,但是,你若是按下重新整理,不管設定哪一種屬性都會去讀取檔案,也因此設定max-age就有其必要性 通常你靜態檔案跟網站放在一起,可以透過web.config方式去設定http header或是透過程式去控制,不過,若是靜態檔案是放在Azure Blob中,就沒有這樣方便,如果你要透過azure exploer去設定也是可以,但是檔案一多,或是你是透過其他方式將檔案放入時候,就有可能會沒設定到,因此,可以透過Powershell一次都幫你設定完成,甚至你也可以作到自動化方式去設定 首先必須取得blob讀寫權限 12345$targetSubscription=\"XXX\"$storageAccountsName=\"AAA\"$storageContainers=\"ABC\"#存取帳戶金鑰$storagekey=\"plVh13GipfmA4k7YaPFf0fUXbRLfrHs1ojjEkB3i5dCgV+oRpDey+hasY/5atBt8P2KozbC6MNCImURwUHu3gg==\" 取得blob內所有檔案,並設定max-age值 12345$sourceFile = @()$sourceFile = Get-AzureStorageBlob -Container $storageContainers -Blob \"*\"$totalCount = $sourceFile.Count$cacheControlValue =\"max-age=43200\"$ctx = New-AzureStorageContext -StorageAccountName $storageAccountsName -StorageAccountKey $storagekey 用迴圈方式每一筆去設定就可以 12345678foreach($file in $sourceFile){ $Blob = Get-AzureStorageBlob -Context $ctx -Container $storageContainers -Blob $file.Name $CloudBlockBlob = [Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob] $Blob.ICloudBlob $CloudBlockBlob.Properties.CacheControl=$cacheControlValue $CloudBlockBlob.SetProperties() Write-Host $CloudBlockBlob.Properties.CacheControl} 這樣檔案中的Cache control就會被設定max-age了,後續也可以把這powershell去做排程或是其他自動化的設定,就可以達到cache效果","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"打通自動化雲端部署到地端-安裝VSTS Agent","slug":"Devops/2016-08-11","date":"2016-08-10T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/08/11/Devops/2016-08-11/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/11/Devops/2016-08-11/","excerpt":"","text":"當開始使用Visual Studio Online做版控後,雖然很多新功能都可以優先使用以及運用一些雲端的優勢,但是,頭痛地方在於用VSTS做版控的系統,並非都會部署到雲端環境,尤其企業內部的系統往往必須部署在自己的Server內。所以,如何運用VSTS的優勢再結合實務上的需求,這就很重要。 要讓雲端Source可以與地端接觸,必須要安裝Agent,讓Agent與VSTS做溝通,Agent可以在Visual Studio Online裡面取得 Agent也是跨平台的,所以,可以選擇你要的自己下載,其中在Windows平台中,目前有分成兩種 2016/08之後建議選擇Windows不要選擇Windows(legacy),這兩者差異分別在於Windows Service內的服務名稱和資料夾的結構。舊版在Windows Service內叫做VSO Agent,新版則是VSTS Agent 而其中最重要的是資料夾結構,在舊版的資料結構,在_Work資料夾內就是一個資料夾包含一個Application資料夾 而在新版的_Work資料夾結構則是跟VSTS線上Build的資料夾結構是相同的,這樣好處在於我們可以隨時切換雲與地的Build和Release,也不太需要變更資料夾路徑的設定 預備Agent Server 為什麼要用Agent Server呢?其實,VSTS Agent跟TFS Agent一樣,可以安裝在很多台機器,但是不同的地方,安裝多個VSTS Agent是要錢錢的,TFS Agent則是免費,所以,架構的取捨也必須不同。因此,在地端要準備好一個安裝Agent的環境,建議使用Windows Server 2012 R2以上,最好這台機器能有安裝Visual Studio跟SSDT,這樣可以避免在地端編譯時候會缺東缺西的,如果還有需要用NPM,也必須再把Node.js一起安裝。 另外,因為會透過Agent去做Build & Release到其他Server,所以,啟動這個Agent服務的AD Account,也必須要在其他Server內,最好能是Admin權限,如果不能有到Admin權限,也必須讓它可以從Agent Server端部署到目的端的權限 安裝Agent 安裝Agent指令很簡單,把下載的Agent安裝套件解開後,用powershell到該目錄執行1.\\config.cmd 就可以開始安裝,這個安裝指令會把Agent設定成Windows Service,如果只是單純想跑起這Agent其指令是1.\\run.cmd 因為要把它變成Windows Service,所以,選擇使用第一個指令。整個操作畫面如下: Enter Server URL : 填入VSTS的URL位置,像是https://XXX.visualstudio.com Enter authentication : 預設使用PAT (Personal access tokens),這個資訊建議使用VSTS Own的PAT,PAT資訊在VSTS點選帳號後,選擇Security 這邊就可以建立PAT Key,這把Key建立完畢當下換顯示出來,把這串Key填入就可以 因為這組Key之後會查不到,建議先額外儲存,不然,就要重新建立PAT了 Enter Agent Pool : 填入在VSTS上面的Agent Pool Name Enter Agent Name : 替這個Agent取個名字,會顯在VSTS上面 Enter Work Folder : 這邊使用預設名字就可以 Enter run agent as service : 是否要把它變成Windows Service,預設是不要 Enter User Account to Use … : 上面設定如果是Y,這邊就必須設定啟動服務的Account,當你Release的目的地與Agent Server在同一台,用預設就可以,如果不同台,就必須如上述所說,設定一個AD Account Enter Password for Account : 輸入這個AD Account 密碼 以上這樣就可以安裝好Agent Server了,然後到VSTS的Agent Pool查看這個Agent Status是綠燈就表示有連線成功了 設定Build & Release流程中,主要是在Agent Pool Name,並非地端Agent Name,所以,後續Agent Name有換名稱,但是,Pool Name沒換,這樣流程也不需要改變 移除Agent 移除Agent很簡單 關掉Windows Service中的VSTS服務 執行.\\config.cmd remove就可以了","categories":[{"name":"雲端到地端的持續整合與交付","slug":"雲端到地端的持續整合與交付","permalink":"http://edwardkuo.imas.tw/categories/雲端到地端的持續整合與交付/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[{"name":"雲端到地端的持續整合與交付","slug":"雲端到地端的持續整合與交付","permalink":"http://edwardkuo.imas.tw/categories/雲端到地端的持續整合與交付/"}]},{"title":"讓iOS app能在企業內部上架","slug":"Apple/2016-08-09","date":"2016-08-08T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/08/09/Apple/2016-08-09/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/09/Apple/2016-08-09/","excerpt":"","text":"iOS企業內部APP上架與一般App上架最大不同在於可以省掉Apple官方的審核機制,但是不代表企業App就可以隨意開發,這只是意味著把App審核權交到企業人員身上。而企業內APP另一個好處就是可以自己建置自己的企業Store,然後把內部開發APP都放到企業Store的網站提供給企業員工下載。不過要達到這目地錢,你必須先完成下面幾個步驟,才有辦法實現 申請Apple企業帳號和憑證 自己公司必須跟Apple購買企業帳號,一年大約299美金,每年必須續約。有了帳號之後,還必須建立企業In House憑證,建立方式可以參考 製作iOS in House + Azure Notification Hub 憑證 說明 設定iOS Info 在Xcode中打開App專案,選到Info的標籤中的URL Type 然後,設定其中的屬性資料 identifier : 這邊設定跟Bundle identifier名稱一樣 URL Schemes : 替App取一個獨一無二的名稱,主要是為了讓後續外部程式可以喚醒你的App 我這邊使用的是Cordova專案,所以,其他就可以先暫時不設定 設定Archive屬性 以上設定完成後,再來就是進行app Archive的設定,在Archive之前它會先編譯專案,如果編譯成功才會走下一步 因為我們要做企業上架,所以,不需要選擇Upload to App Store,直接選Explot就可以 選擇Explot後,這邊當然是選擇Save for Enterprise Deployment 之後會跳出account,這邊記得要選擇有做過企業憑證的Account,不然無法簽入憑證的,然後,你可以選擇你要Support的Device 然後到了設定manifest屬性,這部分很重要,不然到時候會出現問題 設定Name的名稱,必須跟App URL最後的.ipa檔名要一樣,換句話說,如果你的Name設定為ASDF,你的.ipa檔名也要設定成ASDF.ipa,不然manifest會抓不到這個檔案下載。剩下的Display Image URL & Full Size URL部分,有規定圖片的大小要分別是57x57 & 512x512,其檔案格式務必與提示一樣,所以,只需要把這些相關圖檔放到可被網路聯結的位置就可以 操作完畢後就會Archive兩個檔案,分別是.ipa & .plist,在自己建立的App Store的Web Site中的Hypelink則是指向.plist檔案,在.plist檔中的格式如下:12345678910111213141516171819202122232425262728293031323334353637383940414243<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><dict> <key>items</key> <array> <dict> <key>assets</key> <array> <dict> <key>kind</key> <string>software-package</string> <key>url</key> <string>https://qqq.qq/AAAA.ipa</string> </dict> <dict> <key>kind</key> <string>display-image</string> <key>url</key> <string>https://www/qq.jpg</string> </dict> <dict> <key>kind</key> <string>full-size-image</string> <key>url</key> <string>https://www/qq2.jpg</string> </dict> </array> <key>metadata</key> <dict> <key>bundle-identifier</key> <string>ios.cordova.XXX</string> <key>bundle-version</key> <string>1.0.0</string> <key>kind</key> <string>software</string> <key>title</key> <string>XXX</string> </dict> </dict> </array></dict></plist> 其中,software-package會指向設定的.ipa檔案位置","categories":[],"tags":[{"name":"Apple","slug":"Apple","permalink":"http://edwardkuo.imas.tw/tags/Apple/"}],"keywords":[]},{"title":"控制IIS Application Pool","slug":"Net/2016-08-01","date":"2016-08-01T14:59:31.000Z","updated":"2016-11-29T12:17:24.590Z","comments":true,"path":"paper/2016/08/01/Net/2016-08-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/08/01/Net/2016-08-01/","excerpt":"","text":"在使用系統方式去針對Application Pool進行控制,可以遠端開起停止等動作。這樣就可以方便管理一堆伺服器中的每個網站這裡依舊使用DirectoryEntry類別來進行此動作。並搭配Invoke方法。 首先須取得要控制的Application Pool Name1string appPoolPath = @\"IIS://HostName/W3SVC/AppPools/\" + Application Name; 前置的處理可參考這兩篇去進行 顯示IIS站台列表的實體位置路徑 顯示IIS所有站台列表 啟動Application Pool12DirectoryEntry w3svc = new DirectoryEntry(appPoolPath);w3svc.Invoke(\"Start\", null); 停止Application Pool12DirectoryEntry w3svc = new DirectoryEntry(appPoolPath);w3svc.Invoke(\"Stop\", null); 回收Application Pool12DirectoryEntry w3svc = new DirectoryEntry(appPoolPath);w3svc.Invoke(\"recycle\", null); 以上方式就可以遠端控制IIS中的Application Pool的狀態。此外,若是在Domain內話,必須用有遠端控制IIS權限的NT帳號進行使用,否則會出現權限不足的狀況發生。若是Web Site話,該Web Site的Application Pool的識別也要設定遠端控制IIS權限的NT帳號","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"顯示IIS站台列表的實體位置路徑","slug":"Net/2016-07-31","date":"2016-07-31T14:59:31.000Z","updated":"2016-11-29T12:17:18.093Z","comments":true,"path":"paper/2016/07/31/Net/2016-07-31/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/31/Net/2016-07-31/","excerpt":"","text":"當我們需要管理很多台Server中的每個Web Site時日子久了難免會忘記該Web Site對應虛擬目錄路徑,因該這次透過顯示IIS所有站台列表方式,我們可以找到每個網站所對應的虛擬目錄位址 首先還是需要找出IIS中的每個網站及下面的虛擬目錄。前端程式碼可以參考顯示IIS所有站台列表作法 使用DirectoryEntry的Properties屬性就可以找到其對應虛擬目錄位址。Properties:是取得DirectoryEntry的 Active Directory 屬性。 程式碼如下12345678static string GetVirtualDirPath(string siteName, string vdName){ string stringPath = string.Format(@\"IIS://HostName/W3SVC/{0}/root/{1}\", siteName,vdName); DirectoryEntry entry = new DirectoryEntry(stringPath); return entry.Properties[\"Path\"].Value.ToString(); }","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"製作iOS in House + Azure Notification Hub 憑證","slug":"Azure/2016-07-31","date":"2016-07-30T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/07/31/Azure/2016-07-31/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/31/Azure/2016-07-31/","excerpt":"","text":"要製作iOS企業發布憑證,步驟還真是煩瑣,且其中還必須匯出p12檔給Azure Notification Hub,這樣才能讓In House的App也可以順利使用Azure Notification Hub發送Push Message。 這憑證不是屬於Developer用,所以,建議重新申請一組全新的憑證給In House App用 建立CA憑證 先從MAC的鑰匙圈建立一組新的CA憑證,這憑證建立後,記得存放在硬碟中,因為,後續會被廣泛使用 輸入相對應的資訊,記住一定要存放到硬碟,之後.certSigningRequest檔案會一直被用到Apple Developer Center中 產生AAA.certSigningRequest檔案建立iOS Certificates (Production) 到Apple Developer Center建立一個in house app production憑證,這邊不選Apple Push Notification service SSL (Sandbox & Production)原因是因為我們還需要建置一個可以發布in house app憑證,Push Notification service是可以被綁訂在這憑證中 按下一步之後,會要求上傳CSR檔案,這時候可以上傳剛剛做的AAA.certSigningRequest檔案 上傳完畢後,就會產生一個ios_distribution.cer,這時候要把這檔案下載儲存起來 產生ios_distribution.cer檔案建立APP Identifiers 當憑證建立好,就必須建立憑證和APP Identifiers關係,所謂的Identifiers,可以透過XCode中找到 建立新的iOS App IDS,Description是可以自行定義 下面會需要填入Bundle ID,這邊的Bundle ID,必須跟XCode中Bundle Identifiers值是相同的,當然,可以先定義好這邊Bundle ID再放入XCode的Bundle Identifiers也是可以,而Bundle ID命名規則是com.domainname.appname 最後的App Services記得要開啟Push Notifications,如果這時候沒有開啟也沒關係,後續還是可以再修改的,按下一步後,就可以把這APP ID註冊 開通Apple App Push Notifications 雖然上述我們建立好CA和APP Identifiers,但是,這樣不代表有開通Apple的Push Notifications,點入剛剛建立好的APP Identifiers,會看到Push Notifications還是顯示Configurable,這裡可以設定APP在Development和Distribution不同的憑證,這一點對於後續產生憑證檔案是要上傳到Azure Push Notifications是很重要,可以依照不同憑證決定Push是屬於正式使用還只是測試用 這邊也要上傳一個Certificate,就上傳剛剛的AAA.certSigningRequest檔 上傳完畢後就會產生一個Apple Push Services的憑證,這個aps.cer憑證必須下載下來 然後在你的Apple Developer平台中的Certificates類型,除了最早建立的iOS Distribution外,又會多一個Apple Push Services 產生aps.cer檔案建立Azure Notifications Hub APNS憑證 要建立Azure Notifications與APNS溝通憑證,必須透過剛剛的aps.cer來製作。aps.cer點擊兩下在鑰匙圈建立一組Apple Push Service憑證,並把Apple Push Service憑證輸出一個.p12的檔案 把製作好的.p12檔上傳到Azure Notifications Hub的Notifications Service裡面,因為是要正式發佈使用,所以,Mode要選擇Production 到這一步Azure Notifications Hub與APNS溝通間的憑證已經好了,如果今天沒有Push的需求,開通Apple App Push Notifications和建立Azure Notifications Hub APNS憑證這兩個步驟是可以不需要做的 建立iOS Provisioning Profiles 到這一步,就是要先前的憑證和APP Identifiers兩者作連結,一樣地因為是要做企業APP,所以,要選In House 選擇剛剛的APP Identifiers ID 選擇要配發的憑證,這邊要選用使用相同AAA.certSigningRequest建立的憑證 選定好後,下一步就是給定Provisioning Profiles名字,完畢後下載此profile,下載完畢後,記得點擊它安裝 最後,只要在Xcode中找到該專案的Code Signing的Provisioning Profiles選擇剛剛的Provisioning Profiles名字就可以 產生BBB.mobileprovision檔案 Cordova在Xcode放入Provisioning Profiles 如果是Cordova專案,發佈到MAC用Xcode時候,如果是在Target的Build Settings去選擇Provisioning Profiles,可能會發生UIDD的錯誤 這時候改用Project的Build Settings指定Provisioning Profiles,就可以 另一種就是都不指定Provisioning Profiles,讓XCode自行選擇,不過,通常發現這樣結果就是APP依舊可以當作In House發佈,但是,Azure Notifications功能會失效,所以,建議手動去指定","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"},{"name":"Apple","slug":"Apple","permalink":"http://edwardkuo.imas.tw/tags/Apple/"}],"keywords":[]},{"title":"使用Azure DocumentDB儲存資料","slug":"Azure/2016-07-26","date":"2016-07-25T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/07/26/Azure/2016-07-26/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/26/Azure/2016-07-26/","excerpt":"","text":"做Azure Notification Hub時候,雖然,查詢Notification Hub本身中PNS和註冊ID的對應表,但是,有時候會因為不明原因導致這份Mapping表消失,為了避免這現象,需要額外把這些資訊給額外儲存起來。在Azure除了能使用RMS DB存放資料外,也來試試看使用NoSQL來除儲存資料,選用DocumentDB作為這次的方案。 DocumentDB是屬於JSON資料庫且提供結構描述彈性,以及能依需求擴大和縮小資料庫,使用DocumentDB最重要是下面這樣的結構圖: 此外,DocumentDB本身也提供相對應各類型程式語言的API,所以,操作上就相對就方便許多 建立DocumentDB 要在Azure建立DocumentDB相當簡單,只需要到Azure Portal選用DocumentDB 並且填入相關設定值,就可以建立一個DocumentDB Account了 記住這時候只是建立DocumentDB Account,還沒有建立可以儲存的DB,換成RMS DB來說就只是建立好SQL Server還沒有建立SQL Server內的DB是一樣的,因此,還必須到DocumentDB Account中加入一個Database 這時候就會出現Database可以用了 DocumentDB的CRUD 一旦建立好Database後,後面就可以開始針對DocumentDB進行操作了,DocumentDB雖然是儲存資料,但是,其實把每一個Json資訊作為文件給儲存起來。例如你的Json格式如下:1{ \"platform\":\"apns\", \"Handle\":\"cd\", \"Tags\":['222','aaaa'] } 被放在DocumentDB中就是一筆資料,也可以說是一份文件,所以,你有多少份Json檔,就會有多少筆資料,而在DocumentDB為了存放這些『文件』,必須透過建立一個容器做儲存,因此,從DocumentDB Account到DocumentDB到Collection到Document,可以看出來其DocumentDB階層,如下圖 前面已經建立好了DocumentDB Database,還必須在DocumentDB Database中建立一個Collection儲存文件資料 其中,在DocumentDB的定價部分,則取決於Collection建置的規模大小了 在DocumentDB中除了你自行定義的資料欄位外,有一個預設會自動幫你加上的就是ID這個標籤,這個ID標籤可以讓系統幫你自動設定一組GUID碼,或是你自行設定自己想要的資訊,若是自行設定,前提必須確保ID是所有Document中的唯一值,若是你的Json檔中沒有ID欄位,系統也會自動幫你產生ID欄位 當Azure上面都設定好之後,現在就是可以下載.NET的DocumentDB SDK,到Nuget搜尋Microsoft.Azure.DocumentDB並安裝,就可以開始進行開發了,在開始前必須先到DocumentDB找到連線字串和金鑰 1private string DocumentDBConnection = \"Connection string\"; private string DocumentDBKey = \"Key\"; Create建立一份文件,首先必須先定義好此文件中的Json格式,換句話說也是欄位資訊1public class DeviceRegisterationInfo { [JsonProperty(PropertyName = \"id\")] public string Id { get; set; } public string PNS { get; set; } public string Platform { get; set; } public string Tags { get; set; } } 如上述所有說,如果沒有id欄位,系統會自動幫你設定,不過,如果對業務流程清晰的話,我還是建議自己設定會比較好,至少在搜尋時候可以依照ID進行搜尋會比較快。開始建立與DocumentDB的連線123private DocumentClient client;private void DBconnection() { this.client = new DocumentClient(new Uri(DocumentDBConnection), DocumentDBKey); } 當Collection內有該份ID文件時,你並不能再建立一個相同ID文件去覆蓋掉它,如果你要強行建立就會發生DocumentClientException Message: {“Errors”:[“Resource with specified id or name already exists”]}ActivityId: 1b1a3770-e220-4bd5-b8dc-5bf48a8042bb, Request URI: /apps/cd04a067-b8de-46a2-8825-a25652296b7f/services/7af737f3-15ed-4ae9-98bb-08865fe0fbb5/partitions/dec123e2-d08a-4f2e-88d8-311e6a8e2e0e/replicas/131139654072259410p 不過,當你要去查這筆文件時候,如果也查不到文件時候,也會發生DocumentClientException錯誤,這時候就可以去建立一筆新的文件資料12private async Task Insertdata(string databaseName, string collectionName, DeviceRegisterationInfo inDocument) { try { await this.client.ReadDocumentAsync(UriFactory.CreateDocumentUri(databaseName, collectionName, inDocument.Id)); } catch (DocumentClientException ex) { if (ex.StatusCode == HttpStatusCode.NotFound) { await this.client.CreateDocumentAsync( UriFactory.CreateDocumentCollectionUri(databaseName, collectionName), inDocument); } } } 就可以執行寫入資料的程式了 1Program p = new Program(); p.DBconnection(); DeviceRegisterationInfo dr = new DeviceRegisterationInfo(); dr.PNS = \"test1\"; dr.Platform = \"APNS\"; dr.Tags = \"Azure\"; dr.Id = \"edwardkuo3@gmail.com\"; p.Insertdata(\"test\", \"demo1\",dr); 結果如下,資料中的ID,會等同Azure管理介面上的『識別碼』 Read要讀取資料很簡單,就是透過Linq語法和DocumentDB溝通就可以1IQueryable<DeviceRegisterationInfo> result = this.client.CreateDocumentQuery<DeviceRegisterationInfo>( UriFactory.CreateDocumentCollectionUri(databaseName, collectionName)) ; foreach (DeviceRegisterationInfo family in result) { Console.WriteLine(\"ID {0}\", family.Id); Console.WriteLine(\"Tag {0}\", family.Tags); } 就可以取出來了 Update要更新資料,基本上你必須知道你要更新文件的ID,才有辦法直接更新資料,所以,一開始是使用系統幫你設定的ID編碼,就必須先查出文件ID才有辦法進行更新資料12private void Updatedata(string databaseName, string collectionName, DeviceRegisterationInfo inDocument) { this.client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(databaseName, collectionName, inDocument.Id), inDocument); } 目前資料如下,要把edwardkuo3@gmail.com中的PNS值改為WPS和Tag值改成Azure 修改DeviceRegisterationInfo內容1DeviceRegisterationInfo dr = new DeviceRegisterationInfo(); dr.PNS = \"test1\"; dr.Platform = \"WPS\"; dr.Tags = \"Azure\"; dr.Id = \"edwardkuo3@gmail.com\"; 結果如下 Delete刪掉資料,就只需要把ID放入就可以輕鬆刪除資料1this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseName, collectionName, inDocumentD.Id)) 在操作DocumentDB中的Database Name和Collection名稱記得要注意大小寫,在Function中的大小寫與Azure上的設定不同,會不Work的","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"修改MAC畫面截圖的檔案存放路徑和檔名","slug":"Apple/2016-07-26","date":"2016-07-24T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/07/25/Apple/2016-07-26/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/25/Apple/2016-07-26/","excerpt":"","text":"每次用Command+shift+4進行畫面截圖,都會把圖存放到桌面上,有時候因為截圖並不是要馬上用,就會導致畫面很凌亂,且在MAC中的畫面擷取程式中又不能有屬性可以修改,造成相當困擾,因此,要改善這問題,就必須透過指令去修改了 修改檔案存放路徑 在終端機下,先輸入下面指令1killall SystemUIServer 如果沒有先輸入這指令,有時候會造成修改路徑的指令失效,書入完畢上面指令後,在輸入修改路徑,可以把~/Desktop/畫面截圖這一段修改自己想要存放圖片的路徑就可以1defaults write com.apple.screencapture location ~/Desktop/畫面截圖 修改檔案儲存名稱 主要是每次檔案儲存後,在中文版的OSX中,檔案名稱會出現「螢幕快照」,感覺很不舒服,因此,想要把「螢幕快照」換成自己想要的,這部分也是必須透過指令才有辦法1defaults write com.apple.screencapture name EK 其中的EK就是可以自己設定想要的名稱 透過簡單指令就可以完成改變這些設定","categories":[],"tags":[{"name":"Apple","slug":"Apple","permalink":"http://edwardkuo.imas.tw/tags/Apple/"}],"keywords":[]},{"title":"修改MAC畫面截圖的檔案存放路徑和檔名","slug":"Apple/2016-07-25","date":"2016-07-24T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/07/25/Apple/2016-07-25/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/25/Apple/2016-07-25/","excerpt":"","text":"每次用Command+shift+4進行畫面截圖,都會把圖存放到桌面上,有時候因為截圖並不是要馬上用,就會導致畫面很凌亂,且在MAC中的畫面擷取程式中又不能有屬性可以修改,造成相當困擾,因此,要改善這問題,就必須透過指令去修改了 修改檔案存放路徑 在終端機下,先輸入下面指令1killall SystemUIServer 如果沒有先輸入這指令,有時候會造成修改路徑的指令失效,書入完畢上面指令後,在輸入修改路徑,可以把~/Desktop/畫面截圖這一段修改自己想要存放圖片的路徑就可以1defaults write com.apple.screencapture location ~/Desktop/畫面截圖 修改檔案儲存名稱 主要是每次檔案儲存後,在中文版的OSX中,檔案名稱會出現「螢幕快照」,感覺很不舒服,因此,想要把「螢幕快照」換成自己想要的,這部分也是必須透過指令才有辦法1defaults write com.apple.screencapture name EK 其中的EK就是可以自己設定想要的名稱 透過簡單指令就可以完成改變這些設定","categories":[],"tags":[{"name":"Apple","slug":"Apple","permalink":"http://edwardkuo.imas.tw/tags/Apple/"}],"keywords":[]},{"title":"用Office 365 Exchange Online作為發送Mail Server","slug":"Azure/2016-07-21","date":"2016-07-20T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/07/21/Azure/2016-07-21/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/21/Azure/2016-07-21/","excerpt":"","text":"觀看這篇文章前,必須確定自己有O365帳號,若是自己不是O365帳號,也必須先確定自己是否有O365上面Exchange Online的權限。如果以上條件都具備,就可以開始下面的設定 這主要目的在於當我們需要使用DB MAIL時候,不見得自己有在管理地端的Exchange Server或是SMTP Server,但是,如果有使用O365的功能時候,就可以把這部分透過雲端化去解決要透過O365來發送郵件,可以先看一下下面的規範與限制 一般如果是個人或是中小企業需要使用,可以看用戶端SMTP提交就可以,且這方案算是比較簡單的因此,要提供DB Mail發送,建議在Office 365建一個虛擬帳號,提供給DB Mail使用,這樣管理上會相對簡單一些 Office 365的SMTP Server : smtp.office365.com Port可以使用25或是587,官方文件中是建議大家使用587這個,之後就可以照一般DB Mail方式去設定了這邊記得需要把SSL給打勾,不然會無法寄送出去 上述是透過DB Mail發送,若是在程式端要發送呢?這也是可以的12345SmtpClient client = new SmtpClient(\"smtp.office365.com\", 587);client.Credentials = new NetworkCredential(\"mailadmin@XXX.onmicrosoft.com\", 填入Password);client.EnableSsl = true;MailMessage pp = new MailMessage(\"mailadmin@XXXX.onmicrosoft.com\", \"XXXX@gmail.com\", \"ss\", \"gg\");client.Send(pp); 以上簡單幾個方式就可以透過雲端的SMTP幫我們發送信件,且也不需要自己管理SMTP SERVER,這邊有注意一點就是電子郵件地址必須在O365上有存在帳號才可以使用","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"IBM Notes日曆同步到Google日曆","slug":"Other/2016-07-18","date":"2016-07-17T16:00:00.000Z","updated":"2017-05-28T15:39:26.890Z","comments":true,"path":"paper/2016/07/18/Other/2016-07-18/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/18/Other/2016-07-18/","excerpt":"","text":"行事曆的手機APP可以幫我們整合各種常用的行事曆到手機端,不過,IBM Notes行事曆似乎就沒有辦法,但是,工作常常要用的開會行事曆都在Notes,因此,為了不遺漏大大小小會議,既然無法直接同步到手機端,只好先把它同步到Google日曆 在IBM Notes Client 9.0本身可以設定跟Google日曆同步 不過,這倒是不符合我需求,因如果要非公開月曆的設定,就會把Google中有建立的日曆都匯入,如果不要這樣,就必須把Google日曆設定成公開,因此,還是使用原本的Notes日曆比較保險 要做到這件事情,首先必須在有安裝IBM Notes Client去安裝LotusNotes-Google Calendar Synchronizer套件,這套可以在這地方下載http://sourceforge.net/projects/lngooglecalsync下載之後,就開始進行設定了 Google Calendar API 設定 必須設定Google OAuth權限,讓軟體可以抓取認證權限,所以,必須先到Google API平台設定Calendar API存取權限Google API平台:https://console.developers.google.com/ 建立一個Google專案 建立專案完畢後,選擇Calendar API,並且啟用它 建立憑證,請建立屬於OAuth ID的憑證 這個憑證的應用程式類型,務必要選其他唷,不然會發生錯誤 建立好之後,請把這憑證的Json檔案下載儲存,不過這邊儲存的檔案名稱,請務必改成client_secret.json 到這一步,基本上Google Calendar API都設定好了 LotusNotes-Google Calendar Synchronizer設定 下載完LotusNotes-Google Calendar Synchronizer,並執行它,會出現下面這樣畫面 直接到Connection Setting設定對Notes和Google的連線設定 如果不知道這邊要怎樣填寫Notes相關設定,可以直接點擊Detect Lotus Setting,會幫你自動填入相關Notes的設定,你只要輸入你的Notes信箱密碼就好 其他就是把Google帳號設定好以及如果企業內部有Proxy的卡控,也務必要把相關權限給填入,都設定完成後,再回到Perform Sync就可以開始同步你的Notes行事曆囉,此外,也可以在Sync Setting那邊設定要多久同步一次,還有要同步的內容屬性","categories":[],"tags":[{"name":"Other","slug":"Other","permalink":"http://edwardkuo.imas.tw/tags/Other/"}],"keywords":[]},{"title":"Cordova用Web API註冊Azure Notification Hub","slug":"Azure/2016-07-15","date":"2016-07-14T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/07/15/Azure/2016-07-15/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/15/Azure/2016-07-15/","excerpt":"","text":"早些時候Cordova想要透過Azure Notification Hub做推播功能,可以透過azure-mobile-apps-js-client和phonegap-plugin-push套件,並搭配Azure Mobile app就可以輕鬆做到Push Message功能,不過,今日這樣組合已經無法幫Cordova在不寫程式情況下透過Azure Mobile App向Notification Hub註冊Device,主要是Azure Mobile App跟Notification Hub整合後的註冊device API似乎不見了,所以,使用上會出現下面錯誤 “Failed to load resource: the server responded with a status of 404 - Cannot GET /push/installations/xxxxx(it’s a guid string)” 因此,就必須在Mobile App上自己開發這一段API 安裝套件 要讓我們開發的API跟Azure Notification Hub做溝通,須安裝Microsoft.Azure.Notification套件,並建立一個Notification class來設定API與Notification Hub連線資訊1234567891011public class NotificationHub{ public static NotificationHub Instance = new NotificationHub(); public NotificationHubClient Hub { get; set; } private NotificationHub() { Hub = NotificationHubClient.CreateClientFromConnectionString(\"DefaultFullSharedAccessSignature\",\"Notification Name\"); }} DefaultFullSharedAccessSignature:在Notification Hub的Access Policies可以找到 Notification Name:就是你的Azure Notification Hub的名稱 向Notification Hub註冊Device 幫你的Device註冊到Azure Notification Hub的資訊如下: PNS識別碼:主要是要跟推播平台註冊的ID,每一個平台的編碼方式不同 註冊ID:主要是跟zure Notification Hub註冊的識別碼 標記:在這邊我們主要是定義pns識別碼的使用者識別,好讓我們後續能做個別推播的發送 其中,PNS和註冊ID在當你APP被移除重新安裝時候,在Notification Hub上的這兩個資訊就會被更新 取得註冊ID這邊先把Notification Hub通道建立起來12345private NotificationHubClient hub;public PushController(){ hub = NotificationHub.Instance.Hub;} 當Device註冊到Azure Notification Hub時,Notification Hub本身就會自動幫你建立一個Mapping表,透過下面程式可以列出所有註冊在Notification Hub上資訊,不過,有一點要注意,就是當你的Notification Hub在註冊推播平台的憑證換掉後,這些資訊似乎會消失123456789var allRegistrations = await hub.GetAllRegistrationsAsync(0);var continuationToken = allRegistrations.ContinuationToken;var registrationDescriptionsList = new List<RegistrationDescription>(allRegistrations);while (!string.IsNullOrWhiteSpace(continuationToken)){ var otherRegistrations = await hub.GetAllRegistrationsAsync(continuationToken, 0); registrationDescriptionsList.AddRange(otherRegistrations); continuationToken = otherRegistrations.ContinuationToken;} 因此,為了避免同一個PNS會出現不同註冊ID,當需要取得註冊ID時候,可以把PNS碼帶入,如果有相同的PNS碼就會沿用當下的註冊ID,如果還是擔心,也可以加入Tag資訊做判斷12345678910111213141516171819202122232425262728[HttpPost]public async Task<string> GetNhRegistrationid(string PNS = null){ string newNhRegistid = null; if (PNS != null) { var registrations = await hub.GetRegistrationsByChannelAsync(PNS, 100); foreach (RegistrationDescription registration in registrations) { if (newNhRegistid == null) { newNhRegistid = registration.RegistrationId; } else { await hub.DeleteRegistrationAsync(registration); } } } if (newNhRegistid == null) { newNhRegistid = await hub.CreateRegistrationIdAsync(); } return newNhRegistid;} 當有了註冊ID之後,接下來就是要註冊Device,所以,要建立註冊Device資訊的Class,這邊的Tag如果不是只有一組,可以使用陣列123456public class DeviceRegist{ public string Platform { get; set; } public string PNS { get; set; } public string Tags { get; set; }} 其中,Platform簡稱是不能亂定義,資訊可以參考Notification Hub對於各個推播平台的簡稱 在deviceupdate.Platform中,會針對不同推播平台使用不同的方法去註冊PNS,而各大推播平台基本上也只認得PNS識別碼,所以,不僅要把註冊資訊註冊到Hub中,也必須把PNS註冊註冊到推播平台上123456789101112131415161718192021222324252627282930313233[HttpPut]public async Task<HttpResponseMessage> RegisteredDevice(string inRegistrationId, DeviceRegist deviceupdate){ RegistrationDescription registration = null; switch (deviceupdate.Platform) { case \"apns\": registration = new AppleRegistrationDescription(deviceupdate.PNS); break; case \"gcm\": registration = new GcmRegistrationDescription(deviceupdate.PNS); break; default: throw new HttpResponseException(HttpStatusCode.BadRequest); } registration.RegistrationId = inRegistrationId; registration.Tags = new HashSet<string>(); registration.Tags.Add(deviceupdate.Tags); try { await hub.CreateOrUpdateRegistrationAsync(registration); } catch (MessagingException ex) { ReturnGoneIfHubResponseIsGone(ex); } catch (Exception ex1) { throw ex1; } return Request.CreateResponse(HttpStatusCode.OK);} 以上方式基本上就可以自行做到透過API將資訊註冊到Hub中,如果要想自己去刪掉推播平台上的PNS碼,可以自行加入下面這一段123456[HttpDelete]public async Task<HttpResponseMessage> Delete(string PNS){ await hub.DeleteRegistrationAsync(PNS); return Request.CreateResponse(HttpStatusCode.OK);} 此外,因為註冊資訊可能因為憑證被換掉或是更新導致Mapping被清掉,所以,這邊其實可以把這資訊存放到資料庫中,這樣就可以避免資訊消失,另外,因為PNS和註冊ID這資訊格式基本上是固定,為了讓推播更有效率或是能分門別類的推播,就必須依賴Tag管理,利用Tag資訊去分門別類推播 這樣做完之後,Cordova要怎樣呼叫呢?我們依舊還是可以azure-mobile-apps-js-client和phonegap-plugin-push套件處理,只是不能採用原本文件上的寫法1234push.on('registration', function (data) { console.log('PNS data'+data.registrationId); azureClient.push.register('gcm', data.registrationId);}); 這部分可以參考 Cordova 無法使用mobile service plugin結合azure PushNotification 的替代方案 這篇的解法","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"讓Visual Studio 也可以寫Markdown","slug":"VisualStudio/2016-07-13","date":"2016-07-12T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/07/13/VisualStudio/2016-07-13/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/13/VisualStudio/2016-07-13/","excerpt":"","text":"一般我們寫Markdown時候,往往會使用一些第三方軟體來撰寫Markdown語法,例如使用markdownpad , MWeb…等,現在也可以在Visual Studio內直接撰寫Markdown了,不過,需要額外安裝一個Markdown Editor套件 Markdown Editor 你可以點擊連結下載https://visualstudiogallery.msdn.microsoft.com/eaab33c3-437b-4918-8354-872dfe5d1bfe或是直接在Visual Studio內安裝 Markdown Editor 使用 安裝完套件後,可以在新增檔案那邊找到.md的範本編輯Markdown時候,除了編寫文件外,也可以有預覽結果,如果要開啟即時預覽,可以到選項中的文字編輯器找到Markdown的設置,開啟即時預覽就可以 對於一般使用上並無太大問題,標準的Markdown語法都可以被使用,對於圖形部分支援還需要加強,此外,它本身提供一些Convert的功能 Covert to Link Cover to Image Cover to Blockquote Cover to Code就已Cover to Code功能來說,當你把程式碼貼入.md檔中 你只要把整行Code選取起來,就會出現燈泡符號 選擇Cover to Code就會幫你把Code highlight,排版上就簡單許多 雖然,功能與市面上的編輯器來說整合性功能可能並不多,但是,整合到Visual Studio內,對於重度使用Visual Studio的開發者來說,這已經是非常好了","categories":[],"tags":[{"name":"Visual Studio","slug":"Visual-Studio","permalink":"http://edwardkuo.imas.tw/tags/Visual-Studio/"}],"keywords":[]},{"title":"Community Open Camp 活動","slug":"LifeStyle/2016-07-11","date":"2016-07-10T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/07/11/LifeStyle/2016-07-11/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/11/LifeStyle/2016-07-11/","excerpt":"","text":"活動詳情Community open camp 由微軟 MVP 以及 Docker 、Laravel 台灣、R 、Python等社群高手,即將於2016年8月27日星期六於中央研究院學術活動中心及人文社會科學館,帶給您一整天的實戰經驗分享。這次將由 22 位身經百戰的專家主講最熱門的技術議題與實戰的案例分享,包括從 Ansible 到Docker、Docker Swarm on Azure、給 PHP 開發者的 Visual Studio Code 指南、用Python + Azure 做出你的聊天機器人、DevOps In OpenSource、利用微軟IoT打造專屬的環控機器人、Xamarin 跨平台原生 APP 開發介紹,等等精彩的課程內容不但提升自己的技術競爭力,同時掌握最新的科技趨勢,歡迎您來參加 Community open camp。 推薦理由一次讓你可以同時學會不同種類技術,從雲端到IoT的實作與經驗分享都有,且每個講師都經驗豐富,怎可以不參加呢 活動時間2016/08/27(六) 09:00 ~ 18:00 活動地點中央研究院人文社會科學館 / 台北市南港區研究院路2段128號 報名資訊點我報名","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"Visual Studio 2015的Web Essentials 2015已經取消Bundle功能","slug":"Web/2016-07-04","date":"2016-07-03T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/07/04/Web/2016-07-04/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/04/Web/2016-07-04/","excerpt":"","text":"在VS2013中的Web Essentials具有可以將多個CSS或是JS檔案合併的功能,甚至還可以進行壓縮檔案,讓整體網頁效能提升,但是,新版的VS2015的Web Essentials已經沒有這功能了 必須去下載新的擴充功能,主要是因為這項功能被獨立出來了,你可以透過搜尋 Bundler就可以找到,或是到VisualStudio gallert下載 下載安裝完畢就可以開始使用,舊版是透過XML方式進行設定,新版則是透過json格式設定,主要是VS2015一個重大變革,就是很多的設定都改用JSON形式去設定了,所以,這個也不例外 紅色框部分則是可以設定檔案輸出後要擺放的目錄,同時也可以設定是否要進行壓縮,若是你要把Script也加入,也是在同一個bundleconfig.json檔案中進行設定就可以了,當你儲存或是重新編譯就又會產生新的檔案了。如果,就專案已經有存在的呢?基本上如果沒有變動,放著還是可以跑得只是你無法進行裡面設定去修改","categories":[],"tags":[{"name":"Front-End","slug":"Front-End","permalink":"http://edwardkuo.imas.tw/tags/Front-End/"}],"keywords":[]},{"title":"如何找出iOS Device UDID","slug":"Apple/2016-07-04","date":"2016-07-03T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/07/04/Apple/2016-07-04/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/04/Apple/2016-07-04/","excerpt":"","text":"如果你公司內有Apple的企業帳號,就可以讓公司的iOS開發人員去開發iOS App,不需要再額外申請開發者帳號,但是還是必須在Apple Enterprise Portal將該位開發者的Certificates加入,此外,有了開發者的Certificates,還必須讓此開發者的Device被註冊到Apple Enterprise Portal內,才能讓他使用自己的手機測試App 所以,要註冊開發人員的Device,需要填入資訊有兩項 開發人員姓名姓名部分這很簡單,就取一個可以識別的名稱就可以 Device UDID要找UDID就沒有那樣直覺,網路上有其他工具可以找到,不過,最簡單方式就是透過iTunes,只要把iOS Device與iTunes連線,在iTunes的Device資訊,可用滑鼠去點擊,就會不斷切換資訊。這樣就可以找到UDID了 然後,要把這串資訊註冊UDID就可以了","categories":[],"tags":[{"name":"Apple","slug":"Apple","permalink":"http://edwardkuo.imas.tw/tags/Apple/"}],"keywords":[]},{"title":"西元日期轉換成民國日期或是農曆日期","slug":"Net/2016-07-03","date":"2016-07-02T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/07/03/Net/2016-07-03/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/03/Net/2016-07-03/","excerpt":"","text":"一般取得日期大都是採用西元年方式,但是,在某些運用方面還是必須顯示成為民國日期甚至是農曆的日期來表示12DateTime dt = DateTime.Now;Console.WriteLine(string.Format(\"{0}\", dt.Year)); 取得民國年可以先算出西元年再去扣掉1911得到,不過,在C#內有另一種方式取得相對應的民國年,就是用System.Globalization.TaiwanCalendar類別來幫忙進行轉換,從類別名稱顧名思義就是以台灣曆法為主的一種表示法。而主要是在System.Globalization命名空間含有定義相關文化特性資訊的類別,包括語言、國家 (地區)、使用中的日曆、格式化日期模式…等,因此在這命名空間還包含了中華人民共和國跟其他的表示法。 做法只需要用到System.Globalization.TaiwanCalendar的GetYear就可以達到轉換的目的,做法只有兩個步驟 Datetime取得西元日期 System.Globalization.TaiwanCalendar轉換成民國日期12345DateTime dt = DateTime.Now;System.Globalization.TaiwanCalendar TC = new System.Globalization.TaiwanCalendar();Response.Write(\"西元年:\" + dt.Year.ToString());Response.Write(\"民國年:\" + TC.GetYear(dt)); 轉換成農曆日期呢?在C#也提供TaiwanLunisolarCalendar類別來顯示農曆的日期。做法也和前一個相同,都是先取得西元日期再進行轉換12345System.Globalization.TaiwanCalendar TC = new System.Globalization.TaiwanCalendar();System.Globalization.TaiwanLunisolarCalendar TA = new System.Globalization.TaiwanLunisolarCalendar();Response.Write(string.Format(\"西元:{0}/{1}/{2} <br>\", dt.Year, dt.Month, dt.Day));Response.Write(string.Format(\"明國:{0}/{1}/{2} <br>\", TC.GetYear(dt), TC.GetMonth(dt), TC.GetDayOfMonth(dt)));Response.Write(string.Format(\"農歷:{0}/{1}/{2} <br>\", TA.GetYear(dt), TA.GetMonth(dt), TA.GetDayOfMonth(dt))); 這樣就可以很簡單達到我們的需求了","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"用WRK做Azure Web Site的HTTP壓力測試","slug":"Azure/2016-07-01","date":"2016-06-30T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/07/01/Azure/2016-07-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/07/01/Azure/2016-07-01/","excerpt":"","text":"最近,因為網站效能Issue,所以除了針對系統進行調整外,也想試試看系統在Web Site & CDN節點對於HTTP的負荷量,除了透過原本Visual Studio工具外,我們也可以用WRK來進行HTTP的測試。個人覺得這是一個簡單的工具而已,整體的資訊跟介面(基本上也沒介面)都是比較簡單的。要使用WRK前必須到WRK的Github下載,這個工具不能在Windows環境執行必須透過MAC執行,這有一點可惜。直接從Github下載下來,然後直接到WRK目錄,用make去編譯檔案就可以開始用,不過,在編譯前,必須先確認你的環境是否有安裝openssl和Lua兩個套件,不然會發生找不到openssl的狀況 其Wrk目錄檔案如下: 直接下這樣的指令啟動1wrk -t10 -c10 -d20 http://dice.xxxxxxxxx 就可以得到測試結果,這指令的參數分別為:▪ -t:代表用幾個Thread去測試▪ -c:模擬多少個Request去連線▪ -d:表示在多少時間範圍內,這邊顯示d20s,測試時間為20sec▪ -T:表示認定當回應超過多久表示Timeout,預設是一秒,所以,從上面數據發現有一個Request發生Timeout了 統計出來資訊,會有平均值,標準差,最大值,和正負標準差,另外,還有我們可以知道能承受多少Request,我們在測試另一個網站試試看 測試msdn.microsoft.com/cloud-app-development-msdn1wrk -t20 -c100 -d20s -T5 https://msdn.microsoft.com/cloud-app-development-msdn 得到的結果123456789Running 20s test @ https://msdn.microsoft.com/cloud-app-development-msdn 20 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.95s 1.09s 4.92s 78.36% Req/Sec 3.12 3.74 20.00 83.73% 605 requests in 20.09s, 29.00MB read Socket errors: connect 0, read 0, write 0, timeout 55Requests/sec: 30.11Transfer/sec: 1.44MB 從上面可以知道我們在20.9sec中發出了605個Request,因為設定為超過5秒就Timeout,所以,共有55個Timeout,每秒處理30.11個Request和傳輸1.44 MB。其中,Latency表示每個Request的Reponse的時間。 下面這數據,表示每個執行緒在一秒內可以完成Http的需求個數1Req/Sec 3.12 3.74 20.00 83.73% 如果我們加上--latency,就可以看出回應時間的分佈,就可以了解更詳細一點的資訊1234567891011121314Running 20s test @ https://msdn.microsoft.com/cloud-app-development-msdn 20 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.84s 1.13s 5.00s 79.78% Req/Sec 3.07 3.74 20.00 82.64% Latency Distribution 50% 1.42s 75% 2.39s 90% 3.80s 99% 4.83s 608 requests in 20.10s, 29.02MB read Socket errors: connect 0, read 0, write 0, timeout 69Requests/sec: 30.25Transfer/sec: 1.44MB 這只是一個簡單的測試工具,可以拿來使用看看,如果還想要更精進部分,也可以透過lua腳本去撰寫相對應的程式,可以測試的準確度根細緻化會更高,要執行lua script可以這樣下指令1wrk -t12 -c100 -d30s -T30s --script=AA.lua --latency http://XXXXX 個人覺得這是一個簡易型的工具,雖然整體完整性可能不是那樣高,但是基本該有的東西都包含了,所以,要做一些HTTP壓測還是拿來用看看","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"Hexo+VSTS+Azure Web app 的持續整合與交付","slug":"Devops/2016-06-18","date":"2016-06-17T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/06/18/Devops/2016-06-18/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/18/Devops/2016-06-18/","excerpt":"","text":"Markdown撰寫文件的方式,大多被常用在blog撰寫,不過,其實在很多地方應用上,也可以透過這種簡易方式去架設企業KM或是一般產品或是商店的簡易型網站。撇開個人blog的應用外,其他應用上難免都會有需要多人一起協同開發或是撰寫的場境,因此,基於協同合作的模式,還是必須要對這些文件做版本控管。 Markdown只是撰寫內容的模式,還是要給它套上有質感的殼,才能出去見人,所以,選用Hexo框架來包裝Markdown內容,利用Hexo框架不僅可以省去很多在開發上的困難,另外,還有很多的Themes和外掛使用,可以避免很多麻煩。Hexo網址:https://hexo.io Hexo Hexo是一個快速、簡單且強大的網誌框架。Hexo使用Markdown解析的文章,並在幾秒鐘內,透過漂亮的主題產生靜態檔案。在自己電腦環境必須先具備下列幾點,才有辦法使用Heox * Node.js * Git * 安裝hexo-cli *npm install -g hexo-cli* 其餘關於Hexo相關操作指令與設定,可以參考Hexo網站:https://hexo.io/zh-tw/docs/index.html Version Control 這邊不採用Visual Studio的整合性功能,而是透過SourceTree工具來操作VSTS的GIT流程,所以,把VSTS的Git Reposity同步到本機端資料夾 如果是新專案,就初始化一個Hexo專案出來,或是把原有的Hexo專案內的檔案搬過來,初始化後的預設專案資料夾如下圖,這些資料夾都是Hexo框架的原始檔案,要發行成網站還必須編譯Hexo產生Public資料夾,在這資料夾中的內容才是可以被發佈 不過,在這邊不需要先編譯好Hexo去產生Public資料夾出來,因為這個動作會在VSTS內透過自動化方式產生Public資料夾 VSTS + Azure Web App 一旦將Hexo的Source Code或是Markdown內容跟VSTS整合後,後面要將Hexo自動化的持續部署就簡單了 建立VSTS Build流程 在VSTS的Hexo專案建立一個空白的Build流程 共使用五個Task來完成Build & Deploy工作,因為,使用是非Visual Studio專案,所以,不使用MS Build或是Visual Studio Build 第一個NPM Task中,必須安裝hexo-cli,後面才可以執行Hexo的指令 第二個NPM Task中,是你如果有用到Hexo Themes內需要安裝hexo-renderer-sass,記得須要安裝此套件,如果發現Install hexo-renderer-sass會出現錯誤,則採用Rebuild node-sass,就會成功了,當然如果你不需要這個套件,這一個Task就可以不需要執行了 因為預設在VSTS的Build環境中就會安裝好Node.js,如果沒有安裝Node.js,就必須自己安裝Node.Js套件,這樣才可以直接透過Command Line去生成Hexo網站和Markdown內容 *. 第一個Command Line Task的`Hexo clean`指令是清除舊的網站資料 *. 第二個Command Line Task是透過`Hexo generate`指令把Markdown內容轉換成網頁 開始部署 Copy Publish Artifact Task是把generate出來網站檔案,拷貝一份到部署資料夾,可以用$(Build.SourcesDirectory)找到搬過去的檔案路徑的位置 A. Copy Root : 表示要拷貝資料夾的位置,這邊是拷貝主目錄下的public資料夾 B. Contents : 要拷貝的檔案,這邊可以指定檔案名稱或是附檔名稱,如果你要全部 檔案以及子資料夾就設定**\\* C. Artifact Name:目的地的目錄名 D. Artifact Type:在VSTS內基本上都是選擇**Server**,若是,你的build是在Local也可以選擇Share folder 最後,我們透過FTP上傳方式把檔案傳到Azure Web App中,就大功告成了,預設會找不到Uploading Using FTP Task,必須到Marketplace安裝 A. Source Path:設定檔案存放位置,$(Build.ArtifactStagingDirectory)/Markdown/為路徑位置 B. Remote Path : 這邊必須設定/Site/wwwroot/,這樣才會放入Azure Web的資料夾內 C. 帳號密碼 : 帳號密碼和FTP位置設定,可以在Azure Web App Portal找到相關資訊 若是想要每次更新檔案都刪除舊有檔案,Delete Old Files就必須打勾 CI & DI 要做到當SourceTree一旦Commit後,就自動跑完這些流程,只要到triggers功能這邊將CI勾選起來就可以 就可以作到自動化編譯和部署了,不過,目前這樣狀況還不是很滿意,畢竟每次部署都需要重來一次,還是要想辦法做到可以差異化部署才可以,這樣才可以加快部署的腳步","categories":[],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"},{"name":"VSTS","slug":"VSTS","permalink":"http://edwardkuo.imas.tw/tags/VSTS/"}],"keywords":[]},{"title":"免繳$99美金開發者帳號,讓Cordova直接部署到iPhone測試","slug":"App/2016-06-16","date":"2016-06-15T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/06/16/App/2016-06-16/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/16/App/2016-06-16/","excerpt":"","text":"在開發Cordova時候,要做iOS的測試是相對麻煩的,首先你必須要能讓Visual Studio Remote到一台Mac機器上,才有辦法進行iOS的測試,且必須先在MAC上面安裝remotebuild的套件才可以,在MAC安裝Remotebuild的指令如下:1sudo npm install -g remotebuild 記得先更新npm到最新版,安裝完畢後,指要執行下面指令,就可以在MAC啟動Remotebuild的功能1remotebuild --secure false 再去Visual Studio的Cordova設定iOS configuration的Remote agent configuration中的Server address就可以進行編譯,並且,同時啟動MacOS中的iPhone模擬器了 講到這邊,相信大家有碰Cordova的人對這一段不陌生,不過,畢竟模擬歸模擬還是與實際的Device感覺還是不同,如果,你只是短時間想測試看看Cordova製作的iOS APP效果怎樣,又不想去註冊付費一個$99美金的開發帳號時候,就可以透過下面簡單方式,免去付錢又可以將測試的APP部署到iPhone。 首先我們必須先改一下Remotebuild產生出來app build的路徑原本路徑太複雜,如果你都不改,原本路徑\\Users\\使用者\\.taco_home,如果要修改build後的路徑,指令如下:1remotebuild saveconfig 就會產生一個RemoteBuild.config在\\Users\\使用者\\.taco_home目錄下,打開編輯器修改路徑到你想要的位置 開始去Build你的Cordova程式,當你正在Visual Studio建置方案時候,可以觀察Remotebuild server的變化,Visual Studio會把要Build的檔案丟到Remotebuild Server,同時,Remotebuild Server也會幫你下載Cordova需要安裝的套件,所以,這時候網路不可以斷線 編譯好之後,到Remotebuild的路徑裡面找到taco-remote資料夾,然後進去找到builds資料夾,找到剛剛build出來的版號資料夾,依照下圖的方向,就可以找到XCode的專案檔.xcodeproject 用Xcode去開啟它 基本上你是不需要去編輯這檔案內容,只要選擇Product中的Destination內的Device這時候iPhone必須連上該台MAC 選好之後按下Build,記得必須在iPhone中的描述檔與裝置管理,將開發人員APP的選項勾選信任唷,之後就可以在手機上看到自己開發的APP了,如果途中有跳出需要信任的對話框,直接選確定就可以了","categories":[],"tags":[{"name":"Cordova","slug":"Cordova","permalink":"http://edwardkuo.imas.tw/tags/Cordova/"}],"keywords":[]},{"title":"舊有MS Database匯入成SQL Project,並解決產生Link Server問題","slug":"Devops/2016-06-16","date":"2016-06-15T14:59:31.000Z","updated":"2016-11-29T12:15:32.000Z","comments":true,"path":"paper/2016/06/15/Devops/2016-06-16/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/15/Devops/2016-06-16/","excerpt":"","text":"之前有提到我們可以利用SQL Project對DB程式進行的版控,但是,今日要針對已存在DB Server內的資料庫,要怎樣也一併納入版控呢? 其實,要將既有的DB納入SQL Project做程式的版控,其實很簡單,只要幾個步驟就可以 先建立一個空白的SQL Project專案 在專案按下右鍵做DB的匯入,因為是要對已經存在的資料庫來做版控,所以,選擇匯入資料庫 設定資料庫的連線資訊 如果你要完全複製資料庫,就在資料夾結構中,選擇結構描述和物件類型,選完就等它匯入囉 匯入的時間要看你的資料庫本身的複雜程度,而這裡發生一個問題,就是專案上會出現紅色的~~~,這表示專案中的程式碼有問題,如果不管它,是會編譯不過 解決Link Server匯入問題 錯誤就是在View內有遇到物件無法進行參考,在檢查View的程式碼,發現在View內有使用OpenQuery語法,造成物件無法參考12SELECT * FROM OPENQUERY(XXX,'SELECT * FROM table') 因為,資料庫匯入時候,並不會把Link Server的設定資訊匯入,而造成專案錯誤,要解決這方法,可以在專案中建立一個叫做LinkServer資料夾 使用SSMS找到你資料庫所需要用到的Link Server設定 以上面那一段敘述為例,Link Server的Server是XXX,找到那一台XXX的物件,查看它的建立XXX的SQL語法 1EXEC sp_addlinkedserver @server = N'XXX', @srvproduct=N'cc', @provider=N'MSDASQL', @datasrc=N'cc' @srvproduct: 這是要當做連結伺服器加入的 OLE DB 資料來源產品名稱。 如果是 SQL Server,則不必指定 provider_name、data_source、location、provider_string 和 catalog。 @provider: 這是對應於這個資料來源之 OLE DB 提供者的唯一程式化識別碼 (PROGID)。 provider_name 對於安裝在目前電腦上的指定 OLE DB 提供者來說,必須是唯一的。 但是,如果省略 provider_name,就使用 SQLNCLI。 (使用 SQLNCLI 和 SQL Server 將會重新導向最新版的 SQL Server Native Client OLE DB 提供者)。OLE DB 提供者必須向登錄中指定的 PROGID 註冊。 @datasrc: 這是資料來源的名稱,如 OLE DB 提供者所解譯。 data_source 是 nvarchar(4000)。 data_source 會當做 DBPROP_INIT_DATASOURCE 屬性來傳遞,以初始化 OLE DB 提供者。 在LinkServer資料夾內,新增一個.SQL檔案 選擇組建 把上面建立Link Server SQL語法貼上,就會發現原本是紅色蚯蚓的線,就這樣消失了 這樣就大功告成,可以開始撰寫後續程式,要編譯也不會出現問題了","categories":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}]},{"title":"從Azure管理Visual Studio Team Services服務","slug":"Azure/2016-06-15","date":"2016-06-14T16:00:00.000Z","updated":"2017-04-03T15:07:37.496Z","comments":true,"path":"paper/2016/06/15/Azure/2016-06-15/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/15/Azure/2016-06-15/","excerpt":"","text":"使用Visual Studio Team Services做團隊專案管理,早期一定到visualstudio.com去申請一組來用,畢竟五人以下的團隊就能免費使用,怎能不去試試呢。現在,如果你有Azure帳號,就可以讓你直接從Azure建立團隊的Visual Studio Team Services。所建立的功能和在visualstudio.com建立是一樣的,只是現在不需要再到visualstudio.com了,且還可以在Azure內進行管理唷,而透過Azure建立的VSTS,其收費方式是跟從visualstudio.com建立是相同。不過,在Azure建立完成後,還是必須到團隊VSTS內才可以喲 開始建立VSTS 在Azure裡面,可以看到一個叫做Team Project服務,目前還在預覽階段,就直接點下去就可以 看到這畫面是否很熟悉呢?就跟在VSTS內建立一個專案是相同的,如果你本身還沒有建立一個團隊的VSTS,這邊也會要求你建立一個新的Account 新的Account就等於未來VSTS的登入網址,若是,你在這團隊的VSTS要建立另一個專案,則只需要選擇已經存在的Account就可以 選擇要版本控管的方式,要用Git或是TFVC 軟體開發流程要用哪一個Template,這也是跟在VSTS上面開專案要選的範本是相同的 目前這服務的資料中心,只有在美國和歐洲有,其他地區尚未開放 當你建立完成後必須等一下,讓Azure建立相關環境,目前從Azure還沒有辦法直接進入你剛剛建立好的VSTS,所以,還是必須從visualstudio.com進入到團隊的VSTS,或是也可以直接輸入VSTS團隊的網址也是可以。利用這樣建立的方式,就可以讓Azure和VSTS關聯起來了,部分操作也可以在Azure執行,不一定要到VSTS執行。 但是,如果今天你是先在visualstudio.com建立VSTS,才購買Azure帳號時候,要怎把兩者關聯起來,目前還不知道要怎樣做,或許之後可以讓這兩者建立起關係,畢竟,現在越來越多VSTS上面的其他服務,必須綁定在Azure帳戶或是在Azure帳戶才有辦法進行購買 從下圖可以在Azure看到你VSTS內有哪些專案必須Azure和VSTS有關聯,無論你是從VSTS內去建立還是從Azure去建立,這兩邊都會同時Sync 這時候會問,那樣從Azure建立VSTS有什麼好處?我認為好處在於後續資訊整合以及如果要針對資料進行分析,可以用到Azure上的其他資源 Azure & VSTS 資訊整合 從下圖就可以從Azure知道目前專案Commit的狀況,以及了解專案的一些資訊 了解團隊和你自己Check in的統計資訊,同時也能從Azure Portal看到VSTS內的專案Code的Commit次數,甚至也可以直接Review Code,只是感覺目前的設計還不是很好用,看Code的樣式有一點醜 目前這服務還在預覽階段,所以很多功能算是陽春,不過,我認為雙方資訊一旦關聯起來,後續要做怎樣的管理或是分析,就不是難事,畢竟,VSTS後台也是架設在Azure上,一旦整合起來將可以做更多的事情了。 不過,這有一個小問題就是當你從Azure上移除Team Project或是該所屬的資源庫移除,並不會真正的把你透過Azure建立的VSTS移除,你還是必須到VSTS內去移除這個Team的URL,才算真正的移除團隊專案","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"動態呼叫不同種類的Web Service","slug":"Net/2016-06-15","date":"2016-06-14T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/06/15/Net/2016-06-15/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/15/Net/2016-06-15/","excerpt":"","text":"呼叫Web Service最簡單方式就是在專案中把Web Service參考進來就可以使用。不過,今天要設計一個是可以把Web Service資訊放入資料庫中,系統可以針對不同需求呼叫所需要的Web Serivce的Method並傳入參數,取得對應的值,大致架構如下: 這樣好處在於當Web Service是其他單位設計時候,其他同仁可以專注在Web Service開發,開發完畢後將相關資訊註冊到,資料庫中這樣系統就可以動態取得Web Service並呼叫。註冊該Web Service時,只需要幾個Info就可以 Web Service Address Web Service Name Web Server Method及該Method對應的參數值 實作此方式需要先實踐幾個動作 取得該Web Service的WSDL描述 讀取該Web Service WSDL內的XML描述 產生對應Web Service Proxy並動態編譯為Assembly呼叫會使用到的Namespace 會使用的Namespace 需要語言編譯Assembly的語言,設定為C# 1using Microsoft.CSharp; 動態原始程式碼的產生和編譯 12using System.CodeDom;using System.CodeDom.Compiler; 取得Web 服務描述語言WSDL,透過機制可以讓我們動態取用Web Service及其Method跟輸入參數 1using System.Web.Services.Description; 產生Client Proxy 類別 要了解整個Web Service內的Method及操作相關資訊,最重要的部分就是要先了解其服務描述,因此透過服務描述就可以開始操作相關Service動作服務描述範例會示範服務如何在執行階段擷取其服務描述資訊。此範例是以使用者入門範例為基礎,同時包含已定義可傳回有關服務之描述資訊的其他服務作業。傳回的資訊會列出服務的基底位址與端點。服務會使用OperationContext、ServiceHost和ServiceDescription類別提供這項資訊。 取得Web Service的WSDL描述的XML字串,其中_UriAddress為Web Service的Address 1XmlTextReader XTR = new XmlTextReader(_UriAddress.ToString() + \"?WSDL\") 讀取到Web Service的WSDL內容轉成用戶端的Proxy類別,這樣才有辦法供自己進行呼叫。要將WSDL轉成Proxy,Assembly則用ServiceDescriptionImporter類別 1ServiceDescriptionImporter drimport = GetWSDLProxy(XTR); 將XmlTextReader讀到的xml字串轉換為具有適當命名空間、項目和屬性的有效Web服務描述語言WSDL文件,ServiceDescription類別使用new關鍵字或靜態Read方法加以建立,該方法會剖析WSDL,並將它的值指派至適當的類別成員 123456if(!ServiceDescription.CanRead(_XTR)){ throw new Exception(\"WSDL的Description錯誤\");}//取得WSDL內容ServiceDescription Description = ServiceDescription.Read(_XTR); 透過CanRead先判斷XML格式是否可以有效解析 Read 方法加以建立物件 產生用戶端的Web Service Proxy 1ServiceDescriptionImporter oProxy = new ServiceDescriptionImporter(); 設定ProtocoName屬性 1oProxy.ProtocolName = \"SOAP\"; 設定其他屬性 123oProxy.AddServiceDescription(Description, null, null);//Style選擇ClientoProxy.Style = ServiceDescriptionImportStyle.Client; 定義XML基礎型別 1oProxy.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties; 這樣就可以取得該Web Service的WSDL並且產生Web Service Proxy的類別,後續再將將此類別編譯成Assembly供系統使用 完整程式碼1234567891011121314151617private ServiceDescriptionImporter GetWSDLProxy(XmlTextReader _XTR){ if(!ServiceDescription.CanRead(_XTR)) { throw new Exception(\"WSDL的Description錯誤\"); } //取得WSDL內容 ServiceDescription Description = ServiceDescription.Read(_XTR); //產生Web Service Proxy ServiceDescriptionImporter oProxy = new ServiceDescriptionImporter(); oProxy.ProtocolName = \"SOAP\"; oProxy.AddServiceDescription(Description, null, null); //Style選擇Client oProxy.Style = ServiceDescriptionImportStyle.Client; oProxy.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties; return oProxy;} 即時編譯Proxy Class 需要再將類別透過C#編譯為Assembly,供內部程式作為使用。欲做到這樣動作,需要用CodeNamespace & CodeCompileUnit兩個類別。以上兩個類別都是屬於System.CodeDom NameSpace CodeCompileUnit & CodeNamespace 類別 12CodeNamespace oCodeNamespace = new CodeNamespace();CodeCompileUnit oCodeCompileUnit = new CodeCompileUnit(); 新增一個命名空間 1oCodeCompileUnit.Namespaces.Add(oCodeNamespace); 匯入指定的 ServiceDescriptions 值並產生警告型別的物件 1ServiceDescriptionImportWarnings Warning = _sim.Import(oCodeNamespace, oCodeCompileUnit); 因為是要編譯是Web Service及XML的Assembly的物件,所以,需要相關性的dll協助我們做這些事情,因此,在後面的編譯器,需要參考到System.Web.Services.dll和System.Xml.dll 1string[] references = new string[2] { \"System.Web.Services.dll\", \"System.Xml.dll\" }; 給定編譯器所需要的參數 1CompilerParameters parameters = new CompilerParameters(references); 回傳編譯的結果,因為是要編譯成C#,所以,需要再額外參考Microsoft.CSharp Namespace,這樣才可以提供CSharpCodeProvider作為編譯器,這樣可以把CodeCompileUnit物件之指定陣列所包含的System.CodeDom樹狀結構,編譯一個組件 1CompilerResults results = new CSharpCodeProvider().CompileAssemblyFromDom(parameters, oCodeCompileUnit); 若是使用CompileAssemblyFromFile,將可以指定檔案所包含的原始程式碼中編譯組件 最後回傳Assembly12345foreach (CompilerError oops in results.Errors){ throw new Exception(\"Compilation Error Creating Assembly\");}return results.CompiledAssembly; 完整程式碼12345678910111213141516171819202122CodeNamespace oCodeNamespace = new CodeNamespace();CodeCompileUnit oCodeCompileUnit = new CodeCompileUnit();oCodeCompileUnit.Namespaces.Add(oCodeNamespace);ServiceDescriptionImportWarnings Warning = _sim.Import(oCodeNamespace, oCodeCompileUnit);if (Warning == 0){ string[] references = new string[2] { \"System.Web.Services.dll\", \"System.Xml.dll\" }; CompilerParameters parameters = new CompilerParameters(references); CompilerResults results = new CSharpCodeProvider().CompileAssemblyFromDom(parameters, oCodeCompileUnit); foreach (CompilerError oops in results.Errors) { throw new Exception(\"Compilation Error Creating Assembly\"); } return results.CompiledAssembly;}else{ throw new Exception(\"錯誤的 WSDL\");}","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"開始使用Microsoft Flow","slug":"Azure/2016-06-13","date":"2016-06-12T16:00:00.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/06/13/Azure/2016-06-13/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/13/Azure/2016-06-13/","excerpt":"","text":"Microsoft提供一套雲端版的個人流程工具服務,如果有用過ifttt服務的人,因該能體會這功能的好用之處,Microsoft Flow是源自Microsoft PowerApps和Azure Logic AppsFlow的整合,主要是想要讓非開發人員也可以很快運用工具,做出符合工作場境的自動化流程,提升工作的生產力 而Flow整合了眾多SaaS的服務,讓你能把這些SaaS服務組合起來,串出一個你所需要的場景,不過,Flow還在預覽階段,所以,部分功能操作還不是很順暢,且還缺少IM相關服務的整合,不過,倒是跟Azure中的服務整合還滿不錯的,現在拿來做一些基礎場景的運用,已經非常足夠了 因為Flow和Azure Logic在某方面的功能是類似的,所以,要怎樣去區分要使用哪一種服務呢?我認為最簡單的分法就是需求是否是需要靠寫程式來完成的,Microsoft也提供幾點區分建議: 主要使用Excel、Access和SharePoint作為工具時 業務需求和開發複雜程度較低時 生產環境上無法立即透過開發流程來滿足的時候 準備開始使用Flow 從flow.microsoft.com網站登入,就可以開始使用囉,在使用前有一個限制必須知道,就是你註冊的Email Address,不能是個人Email Address,像是@outlook.com或@gmail.com…等免費信箱,在Flow服務中,已經有提供下面已經設定好的template可以直接拿來使用 蒐集Twitter關於HoloLens訊息到Mail 用這個案例,主要是因為最近要關於Hololens在Twitter的相關資訊和動態,但是,Twitter的流動訊息很多,又不一定自己會有關注,且就算關注也常常會Miss掉,所以,藉由MS Flow幫我蒐集資訊並寄信給我,當然,如果覺得Mail管理不方便,在Flow中也可以設定將這些資訊寫入到Azure SQL Database。 由於,這個情境並沒有在Flow的Templete內找到,因此,必須自己手動去建立新的Flow 建立一個空白的Flow,開始建立自己的Task項目 設定在Twitter訊息中有出現符合自己訂定的字串,一旦符合就做抓取資訊的動作 在Query text輸入我想要找的資訊,只要以關於#Hololens的訊息都要Send Mail給我,記得要在紅色框中把自己的Twitter帳號連線資訊設定好,不然會有問題的 設定第二個Task,選定Office 365 Send Mail,因為,要透過Office 365作為發送Mail的Mail Server,如果沒有Office 365帳號,也可以選其他能發送Mail的主機或是SMTP Sever作為Task 以Office 365為例,這邊要求你設定要收信人的Mail,收信者可以不只一位,如果你想要給其他人也收到,就可以設定多位收信人,然後,再設定Mail標題,關於信件內容,你可以自己輸入,或是選擇用抓取Twitter內容作為信件內容也,不過,這邊提供原生的Twitter可選用資訊還不算多,Facebook能用的訊息就更少 流程都設定完成後,就為這個流程命個名吧,然後儲存起來就可以 剛建立好的流程引擎,需要等一下子才會開始自動Run,可以先到管理介面等待它執行 在管理介面中,有編輯 刪除 查看歷史紀錄功能 歷史紀錄內,可以看到每次跑完一個流程,在每一個Task需要多少時間來完成 回去自己的信箱,就會發現信箱內不斷會收到關於Hololens在Twitter上的資訊,就可以自動化的蒐集你想要的資訊 其他的運用,待後續有用到再分享,另外,Flow也有提供API可以被呼叫,似乎如果再搭配自己程式開發,說不定也可以透過Flow做到ifttt功能或是其他好玩的應用","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"用C#改變文字檔的編碼方式","slug":"Net/2016-06-06","date":"2016-06-05T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/06/06/Net/2016-06-06/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/06/Net/2016-06-06/","excerpt":"","text":"一般來說在讀寫文字檔時候很少會注意文字檔案的編碼方式,畢竟都在windows環境,怎樣都可以把文字檔內容讀出來不過,當今日文字檔是做為資料傳遞工具時候,編碼方式就會很重要。剛好與到一個案例,其實在程式中可以快速進行編碼轉換。例如原本編碼如下圖: 來源檔案編碼都不相同,但是想要把output檔案轉成統一格式,以這個案例為例,想要把檔案統一轉為UTF-8格式。可以這樣寫一個簡單的轉換程式1234567891011121314string SourcePath = Properties.Settings.Default[\"SourcePath\"].ToString(); string TargetPath = Properties.Settings.Default[\"TargetPath\"].ToString(); DirectoryInfo info = new DirectoryInfo(SourcePath); Console.Write(\"Start Change Format!!\"); foreach (var s in info.GetFiles(\"*.txt\")) { Console.WriteLine(s.FullName); File.WriteAllText(string.Format(\"{0}\\\\{1}\", TargetPath, s.Name), File.ReadAllText(s.FullName, Encoding.Default), Encoding.UTF8); File.Delete(s.FullName); } Console.Write(\"End Change!!\"); Console.Read(); 作法就是將檔案抓出來,然後再寫入另一個檔案,再寫入檔案同時進行Encoding動作就可以。在C#常用的編碼方式都可以列舉出來 若是遇到無列舉的編碼,也可以用Encoding.GetEncoding("UTF-8")去進行編碼動作。要是今天透過Stream物件呢?把資料讀進來處理後再作寫檔案的動作,這樣也是可以做編碼的指定1234using(StreamWriter sw=new StreamWriter(string,false,Encoding.UTF8)){ ......}","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"IEnumerable轉成DataTable","slug":"Net/2016-06-07","date":"2016-06-05T16:00:00.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/06/06/Net/2016-06-07/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/06/Net/2016-06-07/","excerpt":"","text":"IEnumerable<T>這個型別在Framework3.5之後開始常用,且Linq語法對於某些程式撰寫與處理變成方便許多,甚至在處理像是Linq to SQL等模式也很方便,但是不可諱言的,在企業中很多系統往往還是需透過Datatable或是Dataset物件進行物件傳遞,尤其在用完IEnumerable(ex:var)之後要在系統進行資料傳遞或是後續處理時,要用for或是foreach組成Datatable是一件很麻煩的事情,且在企業這種想要讓大家快速開發思維下,這是很浪費時間,因此,想說有沒有一個可以快速的做法,讓我們可以快速進行資料轉換。於是,參考到網路一種做法 將此方法可以寫成一個component或是method,下次用到就簡單多了 12345678910111213141516171819202122232425262728293031public static DataTable LinqQueryToDataTable<T>(IEnumerable<T> query) { DataTable tbl = new DataTable(); PropertyInfo[] props = null; foreach (T item in query) { if (props == null) //尚未初始化 { Type t = item.GetType(); props = t.GetProperties(); foreach (PropertyInfo pi in props) { Type colType = pi.PropertyType; //針對Nullable<>特別處理 if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>)) { colType = colType.GetGenericArguments()[0]; } //建立欄位 tbl.Columns.Add(pi.Name, colType); } } DataRow row = tbl.NewRow(); foreach (PropertyInfo pi in props) { row[pi.Name] = pi.GetValue(item, null) ?? DBNull.Value; } tbl.Rows.Add(row); } return tbl; } 使用方法 1234 var a =from s in dd select new {s.name,s.tel};Datatable dt=LinqQueryToDataTable(a);","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"在MAC中的Visual Studio Code編譯ionic的Cordova專案","slug":"App/2016-06-03","date":"2016-06-03T15:59:31.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/06/03/App/2016-06-03/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/03/App/2016-06-03/","excerpt":"","text":"MAC中用Visual Studio Code做開發已經越來越稀鬆平常,但是,實際上有些時候還是會踩到雷和一些步驟需要克服,不過,其中最大好處就是可以快速使用iOS模擬器,不需要再去做Remote MAC編譯的一些設定 要在MAC啟動Visual Studio Code去編譯Codova大概需要一些基礎設定才可以讓你的Cordova專案在MAC的Visual Studio啟動。 記得要安裝好npm和Nod.js套件,前者基本上因該都有內建在OSX裡面 在Visual Studio Code中安裝Cordova編譯器 安裝完畢就會出現手機模擬程式了 接下來步驟 Mac中安裝Cordova套件 1sudo npm install -g cordova MAC安裝ionic 套件 1sudo npm install -g ionic 有時候套件版本會影響使用ionic開發上的一些問題,所以我們可以透過指令看目前安裝的版本是多少,以及自己現在的Cordova版本也可以知道 1ionic info 這時候看似美好,因該可以編譯Cordova和啟動模擬器,若是你的模擬器是採用Serve to the browser,這時候會出現下面錯錯誤訊:[cordova-debug-adapter] Error: Serving to the browser is currently only supported ionic 1 project 要解決這問題,就必須升級你在MAC中的ionic套件,通常這會發生你在Visual Studio開發Cordova專案後,把這專案又拿到MAC的Visual Studio Code內使用造成,升級ionic套件必須先到此Cordova專案中的www目錄下,使用ionic update的指令:1ionic lib update 就可以解決這問題 當你成功後,就會在原本Cordova專案的www目錄會多出一個lib的目錄,以上都安裝好之後,預設會有ios模擬器,如果需要android device,請務必另外在安裝android device模擬器,才有辦法啟動了","categories":[],"tags":[{"name":"Cordova","slug":"Cordova","permalink":"http://edwardkuo.imas.tw/tags/Cordova/"}],"keywords":[]},{"title":"管理Azure Storage的好工具","slug":"Azure/2016-06-02","date":"2016-06-02T14:59:31.000Z","updated":"2016-11-22T15:55:08.000Z","comments":true,"path":"paper/2016/06/02/Azure/2016-06-02/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/02/Azure/2016-06-02/","excerpt":"","text":"管理Azure的Storage之前都是用Azure Storage Explorer 6 Preview,不過,用久了還是有一點不順手,畢竟,除了介面比較陽春外,功能也很陽春,若是你有好幾個Storage要管理,管理起來也不是很方便,因此,微軟出了一個新版的Azure Storage Explore 不僅在Windwos上面可以安裝,連在MAC上面也可以安裝,越來越符合微軟的跨平台的策略了,基本上這套無論在Windows或是MAC上用起來都是一樣的,並無太大區別 一開始會要你輸入你的Azure登入帳號,只要輸入完畢後,就可以馬上管理Azure的Storage,如果你同時擁有很多個Azure訂閱帳戶,也會一併幫你匯入進來管理唷 介面上,你可以透過搜尋方式去找到你想要管理的Blob或是Table等資源 檔案呈現列表簡直比之前好太多,不僅介面漂亮外,也可以搜尋想要的檔案名稱,另外,如果想要知道這個檔案的URL,以前都必須點進去檔案才有辦法拷貝,現在直接點選上面工具,就可以知道檔案的URL了,方便許多 另外,在不同Storage複製檔案也簡單多了,不需要像以前要用手打目的地,直接拷貝然後到要得放入的位置直接貼上就可以,然後在安全性控管上,多了排程的概念,不只檔案可以設定要甚麼時間開放或是關閉,連Container也可以了 管理Container,除了剛剛提到開放權限時間設定外,還可以做直接拷貝Container或是刪除的動作 管理Storage檔案,不需做下載再上傳的動作了,直接在一套軟體內就可以完成,剛剛提到一開始就設定Azure帳號就可以管理自己的Azure儲存體,透過Storage connection方式去連結外,也可以透過Attach External方式去加載設定方式就跟舊版一樣 若是你有用中國Azure或是SAS,這套都可以支援唷","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"C# 無條件進位,無條件捨去及四捨五入寫法","slug":"Net/2016-06-01-9","date":"2016-06-01T14:59:31.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/06/01/Net/2016-06-01-9/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/01/Net/2016-06-01-9/","excerpt":"","text":"雖然程式很簡單,但是,一時要用還真的不知道要怎樣寫,畢竟現在一個程式開發者要記憶的東西太多,所以,不時時刻刻記憶一些東西還真的不行呢 無條件進位 123double s = 100;int result = 0;result = Convert.ToInt16(Math.Ceiling(s / 3)); 無條件捨去 123double s = 100;int result = 0;result =Convert.ToInt16( Math.Floor(s / 3)); 四捨五入 使用Math.Round, Math.Round(計算值,小數點第幾位)123double s = 110;double result = 0;result = Math.Round((s / 3), 2); 若是要呈現一般認知的四捨五入需加入第三個參數,MidpointRounding.AwayFromZer1System.Math.Round(1.235 , 2, MidpointRounding.AwayFromZero) 參考來源:http://msdn.microsoft.com/zh-tw/library/ef48waz8(v=VS.100).aspx","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"使用Visual Studio佈署DB,自動化填入資料","slug":"Devops/2016-06-01-6","date":"2016-06-01T14:59:31.000Z","updated":"2016-11-29T12:15:06.000Z","comments":true,"path":"paper/2016/06/01/Devops/2016-06-01-6/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/06/01/Devops/2016-06-01-6/","excerpt":"","text":"在一些實際案例上,往往佈署資料庫後,無論是要進行資料庫測試,或是要在資料表放入一些初始設定值或是初始化資料,就是先準備初始化資料的Script,等資料庫建立完畢後,再去執行這些Script放入資料,不過,若是透過透過Visual Studio資料庫專案,則可以將這部分一併做到自動化,也就是說當資料庫建立完成後,資料也一併填入資料表,這樣不僅可以在開發階段去定義要填入的資料,也可以避免資料表有異動時候,要填入資料的script沒有做變更,造成資料無法填入。 一開始做法跟開始進行資料庫程式的版控和佈署這篇教學是相同的,後面,我們只要在做放入要自動化SQL Script就可以 首先我們要加入指令碼,通常這指令碼就是SQL Script 選擇佈署後指令碼,其目的在於是當資料庫佈署完畢後才會執行,若是有些東西需要在佈署前先做,就選擇預先佈署指令碼就可以 新增完畢後的檔案內容如下,這邊只要去填入自己要塞入DB資料的Script就可以。 以上幾個簡單步驟就可以做到自動化填入資料囉。不過,運用上還需要一些小技巧,以目前手邊案例來說,因為資料有時候,有先後順序且在團隊分工上,要做到分工去完成一些填資料動作,若是都在一個檔案中去實作,要管理起來是非常麻煩的。所以,運用上我會把這檔案當作運作塞資料的主流程,然後在這檔案中用SQLCMD去執行每個要Insert Data的 Script檔案 其他的.sql檔案,就可以用一般的SQL Script去產生出來 然後再去定義我們要塞入資料的順序,甚至在測試時候,我們也可以放入一些測試資料的SQL Script,等正式上線再移除這些測試的Script,這樣在管理上就方便多了完成之後,進行發布就可以了。若是你的資料有相依或是唯一性,在重複佈署時候可能會有發生資料問題,只要在佈署時候選擇重新建立資料庫就可以。不過,這部分要仔細確認後再作業避免後悔","categories":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}]},{"title":"管理Azure Resources內的Resources Group","slug":"Azure/2016-05-23","date":"2016-05-23T14:59:31.000Z","updated":"2016-11-27T02:33:52.459Z","comments":true,"path":"paper/2016/05/23/Azure/2016-05-23/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/05/23/Azure/2016-05-23/","excerpt":"","text":"之前在Azure開一些服務時候,它會自動配置一個Resources Group給你,又或是一開始在規劃架構時候,我們都會自行會設定一些Resources Group,但是久了之後,可能因為業務需求變動下,導致在Azure的服務被分得很零散,要管理起來就不是很方便或是很直覺。 在Azure的Resources Group設計中,是讓我們很容易去管理Azure服務。因此,對於初期架構設計的一些『錯誤』或是業務的變更,後面還是必須想辦法去彌補或是去更新,才不會等到最後架構變大,服務變多了,要管理起來也就更不方便 例如:業務A的Web App和SQL Database分散在不同Resources Group,我們定義一個名叫A Resources Group,把分散在各地屬於A服務的資源放在一起,要怎樣做呢? Move SQL Database 首先,把SQL Database搬到新的Resources Group,這部分可以在新的Azure Portal 去做搬遷,記住搬遷SQL Database,一定要連同SQL Database Server一起搬遷,不能只有把Database進行轉移,所以,在SQL Server選擇『Move』就可以開始進行轉移 選擇要遷入的Resource Group名稱,按下確定之後,就可以進行搬遷囉,在搬遷時候,服務會停止一下,不過,時間不確定要多長,以目前這個SQL Database Size比較小,在30秒內就可以完成搬遷 Storage Move 搬遷Storage,搬遷Storage步驟就多一點點,選擇storage的屬性 往下滑動,就可以找到Resource Group,在這邊就可以變換Resource Group 選擇要搬遷的Storage,就可以開始進行搬遷了 Web App Move 移動App Servie方式也跟移動Storage一樣,到屬性的地方去修改要移動到的Resource Group,就可以把資源給轉移了,不過,這邊有一個陷阱,就是你在轉移Web App,記得所屬的App Service Plan也要一併轉移,不然到時候會無法把原本的Web App去轉移到其他的App Service Plan。這樣會出現Service Plan橫跨不同Resource Group的錯誤。 此外,在Web App轉移上,目前有一個限制,就是如果在一個Resource Group裡面有多個App Service Plan,就無法做移轉的動作,換句話說想要做移轉,必須確保Resource Group內只有一個App Service Plan才行,如下圖,這樣是無法進行移轉的 如果還是強行移轉,在Portal是看不到錯誤資訊,只是不會有動作,如果用PowerShell去跑,就會出現下面錯誤,這一點要注意的 如果不想透過Portal去做轉移,也可以使用PowerShell去控制123$webapp = Get-AzureRmResource -ResourceGroupName OldResourceGroupName -ResourceName ResourceName$plan = Get-AzureRmResource -ResourceGroupName OldResourceGroupName -ResourceName ResourceNameMove-AzureRmResource -DestinationResourceGroupName NewResourceGroupName -ResourceId $webapp.ResourceId, $plan.ResourceId","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"使用Azure OSA Key啟用Azure帳號","slug":"Azure/2016-05-16","date":"2016-05-15T16:00:00.000Z","updated":"2016-11-29T08:48:28.000Z","comments":true,"path":"paper/2016/05/16/Azure/2016-05-16/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/05/16/Azure/2016-05-16/","excerpt":"","text":"啟用Azure帳號可以透過pay-as-you-go或是公司有簽EA方式啟動,另一種方式就跟微軟的Azure的經銷商買Azure點數,其概念就類似儲持卡的概念,這先點數換會轉換成金額,而這些金額就是讓你所使用的服務去扣。如果你今天採用這樣方式購買Azure,你會收到經銷商給你的Azure金鑰格式會是xxxxx-xxxxx-xxxxx-xxxxx-xxxxx,之後必須啟用這金鑰才可以 要啟用這金鑰前,你必須先去註冊一組Azure帳號,然後到去Azure官網的開始使用 Azure in Open 授權做啟用 https://azure.microsoft.com/zh-tw/offers/ms-azr-0111p/ 如果是第一次使用就選啟用,如果是要再儲值就選增加信用額度 之後就會要你輸入登入Azure的帳號,就會進入到這個畫面,輸入經銷商給你的金鑰,就可以啟用了 這時候進入你的Azure管理平臺,就會看到Azure In Open就表示啟用成功了","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"建立Azure上海與香港資料中心Site to Site VPN","slug":"Azure/2016-05-15","date":"2016-05-15T14:59:31.000Z","updated":"2016-11-27T02:34:12.048Z","comments":true,"path":"paper/2016/05/15/Azure/2016-05-15/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/05/15/Azure/2016-05-15/","excerpt":"","text":"如果有同時使用China Azure和Global Azure,遇到最麻煩的事情,就是怎樣把兩邊的資料做整合,一方面是兩邊的Azure功能性不一致,另一方面是因為中國長城關係,導致資料Sync不能透過一般HTTP解決,因此,為了解決這問題,只好建立一組Site to Site的VPN,解決雙方的Azure資料中心的溝通問題 先自行規劃上海資料中心和香港資料中心的網路IP分配12* 上海資料中心:10.1.0.0 /16,名稱:CN-NET* 香港資料中心:10.2.0.0 /16,名稱:HK-NET 建立上海資料中心虛擬網路 開始設定Azure的虛擬網路吧,先設定CN-NET這部分 虛擬網路名稱取名為CN-NET 選 設定網站間VPN 設定香港資料中心的虛擬網路資訊,名稱設定為HK-NET,名稱後續要跟設定香港資料中心的名稱一樣,位置空間的IP就設定IP:10.2.0.0 /16,VPN裝置的IP位址,可以先隨便設定一個,後面會改掉,但是,設定的IP不可以跟你後續香港或是上海資料中內的位址IP有重複,不然會發生錯誤 設定上海資料中心的虛擬網路的IP10.1.0.0 /16,然後再設定Subnet IP 10.1.1.0 /29,按下確定就可以 建立香港資料中心虛擬網路 上海資料中心設定完成後,再來設定香港資料中心,幾乎步驟都相同,只有在設定的地方不一樣 這邊依舊選設定網站間VPN 改設定上海資料中心的虛擬網路資訊,所以名稱設定為CN-NET,位址IP10.1.0.0 /16,這邊的VPN IP位址,也可以先隨便設定一個,同樣的不可以跟你後續香港或是上海資料中內的位址重複,不然會出現錯誤 設定香港資料中心的虛擬網路的IP10.2.0.0 /16,在設定Subnet IP 10.2.1.0 /29,按下確定就可以設定完成 兩邊資料中心都設定完成後,在兩邊設定畫面中,就會出現VNET組態檔,這時候我們要把這組態檔匯出來 下載出來的組態檔內容如下,我們後續會修改組態檔中的 VPNGatewayaddress 的值12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061<NetworkConfiguration xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration\"> <VirtualNetworkConfiguration> <Dns /> <LocalNetworkSites> <LocalNetworkSite name=\"HK-NET\"> <AddressSpace> <AddressPrefix>10.2.0.0/16</AddressPrefix> </AddressSpace> <VPNGatewayAddress>2.2.2.2</VPNGatewayAddress> </LocalNetworkSite> <LocalNetworkSite name=\"v-net-west\"> <AddressSpace> <AddressPrefix>10.200.0.0/16</AddressPrefix> </AddressSpace> <VPNGatewayAddress>23.99.112.76</VPNGatewayAddress> </LocalNetworkSite> </LocalNetworkSites> <VirtualNetworkSites> <VirtualNetworkSite name=\"CN-NET\" Location=\"China East\"> <AddressSpace> <AddressPrefix>10.1.0.0/16</AddressPrefix> </AddressSpace> <Subnets> <Subnet name=\"Subnet-1\"> <AddressPrefix>10.1.0.0/24</AddressPrefix> </Subnet> <Subnet name=\"GatewaySubnet\"> <AddressPrefix>10.1.1.0/29</AddressPrefix> </Subnet> </Subnets> <Gateway> <ConnectionsToLocalNetwork> <LocalNetworkSiteRef name=\"HK-NET\"> <Connection type=\"IPsec\" /> </LocalNetworkSiteRef> </ConnectionsToLocalNetwork> </Gateway> </VirtualNetworkSite> <VirtualNetworkSite name=\"v-net-china\" Location=\"China East\"> <AddressSpace> <AddressPrefix>10.100.0.0/16</AddressPrefix> </AddressSpace> <Subnets> <Subnet name=\"Subnet-1\"> <AddressPrefix>10.100.0.0/24</AddressPrefix> </Subnet> <Subnet name=\"GatewaySubnet\"> <AddressPrefix>10.100.1.0/29</AddressPrefix> </Subnet> </Subnets> <Gateway> <ConnectionsToLocalNetwork> <LocalNetworkSiteRef name=\"v-net-west\"> <Connection type=\"IPsec\" /> </LocalNetworkSiteRef> </ConnectionsToLocalNetwork> </Gateway> </VirtualNetworkSite> </VirtualNetworkSites> </VirtualNetworkConfiguration></NetworkConfiguration> 在兩處的Azure虛擬網路部分,建立閘道,選定 動態路由 建立閘道時間會比較長,可能要20多分鐘以上,路由建立好後,會出現下面樣子 回到剛剛的組態檔案,從CN-NET得到的閘道IP,修改從HK-NET下載的組態檔中的VPNgetwayaddress的值,然後再到香港資料中心取得其閘道IP,再將這閘道IP,取代從CN-NET下載的組態檔案中的VPNgetwayaddress的值 都設定好之後,分別上傳組態檔案,上海組態檔上傳到上海資料中心,香港組態檔上傳到香港資料中心 上面會顯示有被更新的資訊,直接確認就可以 完成到這一步,基本上在介面上的設定都完畢,剩下就必須透過Powershell去把這兩邊的資料中心連線串接起來 PowerShell 設定 首先先設定上海資料中心部分,使用Powershell去取得中國的Azure帳號,其指令是 1Add-AzureAccount -Environment AzureChinaCloud 登入後,使用 1Select-AzureSubscription -SubscriptionId "訂閱號碼“ 選定我們的訂閱戶,開始配置兩邊的共享金鑰,金鑰名稱可以自行輸入,但是,兩邊資料中心的金鑰要使用一樣,如果在上海資料中心,設定的VNetName就是CN-Net,LocalNetworkSiteName就是hk-Net 1Set-AzureVNetGatewaykey -VNetName CN-NET -LocalNetworkSiteName HK-NET –SharedKey 金鑰 設定香港的資料中心 1Set-AzureVNetGatewaykey -VNetName HK-NET -LocalNetworkSiteName CN-NET –SharedKey 金鑰 兩邊都設定成功後,請再等待幾分鐘,就可以看到這兩邊的VNET串接起來了 如果不確定,也可以透過Powershell指令去查看1Get-AzureVnetConnection –VnetName HK-NET 這樣中國與Global兩邊資料中心的虛擬網路就串起來了,最後提醒一下,是設定Site to Site,而不是Point to Site VPN唷","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"使用Visual Studio Code寫TypeScript","slug":"App/2016-05-14","date":"2016-05-13T16:00:00.000Z","updated":"2017-05-29T06:07:24.980Z","comments":true,"path":"paper/2016/05/14/App/2016-05-14/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/05/14/App/2016-05-14/","excerpt":"","text":"Visual Studio Code的功能越來越多元,果然是一套跨平台好用的編輯器,雖然,現階段功能還沒有Sublime多,但是,它不僅能編輯前端還可以撰寫後端程式碼,這部分就可以讓人期待它的後續發展,因此,嘗試用它在Macbook pro上來開發微軟多方宣傳的Typescript試試看 要在Mac上使用,首先必須先安裝好Typescript套件 安裝Typescript Package 1npm install -g typescript 如果發生下面這樣錯誤,表示你權限不夠,再下另一個指令就可以安裝完成了 1sudo npm install -g typescript 測試 安裝完畢,我們就可以打開Visual Studio Code,建立一個Typescript的config檔案,這檔案名稱請命名tsconfig.json,然後在裡面打入這樣內容1234567{ \"compilerOptions\": { \"target\": \"es5\", \"module\": \"amd\", \"sourceMap\": true }} 這時候,打這些名稱別擔心不會打,因為會有~~~提示唷,想不到在Visual Studio中的Intellisense功能,這邊也可以用 之後,就可以開始撰寫Typescript了。趕緊建立一個.Ts檔案來試試看,Typescript主要是透過你撰寫.ts檔案後,透過編譯方式將ts轉換成js檔案,所以,必須先寫.ts檔案123456789101112131415class Greeter { greeting :string; constructor(msg:string) { this.greeting=msg+\"eee\"; } greet(){ return \"Hello\"+this.greeting; } }var AA=new Greeter(\"你好嗎\"); 撰寫好之後讓它去編譯,在Visual Code裡面的編譯,必須使用Task Runner去做build的動作,因此,必須先取得Task runner config檔案,只要在Visual Studio Code的命令列打上 config就會出現安裝 安裝完畢後,你在左側或是你的資料夾中就會出現Task.json檔案 123456789101112131415161718192021// A task runner that calls the Typescript compiler (tsc) and// Compiles a HelloWorld.ts program{ \"version\": \"0.1.0\", // The command is tsc. Assumes that tsc has been installed using npm install -g typescript \"command\": \"tsc\", // The command is a shell script \"isShellCommand\": true, // Show the output window only if unrecognized errors occur. \"showOutput\": \"silent\", // args is the HelloWorld program to compile. \"args\": [], // use the standard tsc problem matcher to find compile problems // in the output. \"problemMatcher\": \"$tsc\"} 相關細節都可以在這邊進行設定,這樣就可以開始進行編譯的動作,不過,每次改完都要手動編譯,感覺也很擾人,我們可以透過指令進行自動編譯動作,首先,隨便針對檔案按右鍵打開『終端機』 打入下列指令1tsc *.ts --watch 這樣當你的ts檔案有做更新儲存後,就會自動編譯成js檔案了","categories":[],"tags":[{"name":"Cordova","slug":"Cordova","permalink":"http://edwardkuo.imas.tw/tags/Cordova/"}],"keywords":[]},{"title":"Azure Web App Inbound IP和Outbound IP的不同","slug":"Azure/2016-05-10","date":"2016-05-10T12:09:34.000Z","updated":"2016-11-27T02:34:38.920Z","comments":true,"path":"paper/2016/05/10/Azure/2016-05-10/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/05/10/Azure/2016-05-10/","excerpt":"","text":"Azure Web App有分為兩種類型的IP位址,一種是Inbound IP,一種是Outbound IP Inbound IP是所謂內部虛擬IP,一般你沒有綁定SSL憑證時,這個IP是與大家分享的 Outbound IP是對外的實體IP,這個IP取決於資料中心的配置,通常是四個IP輪詢 Inbound & Outbound最簡單識別方式就是 A Web Site Call B Web Site 時,在B Web Site看到呼叫端的A Web Site IP就是屬於A Web Site的Outbound IP,B Web Site則是用Inbound接收A Web Site的Request 通常我們是不需要去管Web Site Outbound IP,不過,在某些情境下為了去設定防火牆,讓我們的Azure Web App能呼叫企業內部的服務或是網站,就必須去知道Web Site Outbound IP,才有辦法設定防火牆通過 這裡有Outbound IP List列出所有Azure資料中心的Outbound IP,不過,為了以防萬一這些資訊有所變更不在這列表中,還可以用另一種方式去找到Outbound IP,就是到Azure Portal中的Web App內去找 先找到該Web App,然後到它的屬性內的Outbound IP 就可以查看這Web Site的Outbound IP,通常是都會配四組Outbound IP給這個Web Site 如果不想要透過這種方式去查詢Outbound IP,也可以使用Azure Resource Explorer這個工具去查詢,Azure Resource Explorer的網址https://resources.azure.com,它是一個可以發現Azure服務API的一個Web工具,雖然並非所有Azure服務都有支援,使用ARE好處如下: 取得Azure 服務的API 取得API相關資訊 可以直接使用上面API,更新你服務的設定 這個工具目前尚在Preview階段,所以,部分功能還不完整。以目前要查Outbound IP為例,只要去找到你所屬的Web Site名稱,就可以在旁邊的Json資訊中找到outboundIpAddresses Key,然後就可以發現此Web Site的Outbound IP List__如果,有用中國Azure的人,目前此工具還不支援,再加上又沒有新的Portal可以支援查詢,因此,列出北京與上海資料中心的Outbound IP給有需要的人 Scale Unit Name: BJB-001 (北京資料中心) Outbound IP Addresses 42.159.4.73 42.159.4.84 42.159.4.211 42.159.4.160 Scale Unit Name: SHA-001 (上海資料中心) Outbound IP Addresses 42.159.135.109 42.159.135.174 42.159.135.208 42.159.133.172","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"CommittableTransaction & TransactionScope 用法","slug":"Net/2016-05-01","date":"2016-05-01T14:59:31.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/05/01/Net/2016-05-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/05/01/Net/2016-05-01/","excerpt":"","text":"在程式撰寫中常常會遇到需要做資料Transaction的機制,當有異常時需要透過Rollback還原。在.NET中有兩種Transaction模式分別是明確交易與隱含交易。通常使用的方式分別為CommittableTransaction & TransactionScope TransactionScope:類別提供一個簡單的方式,讓您不用與交易互動,即可將一段程式碼標記為參與交易,此方式只需要在程序範圍內加入Complete()就可以 CommittableTransaction:類別為應用程式提供使用交易的明確方式,而非隱含地使用 TransactionScope 類別,這部分需要透過呼叫Commit()和Rollback()方法 這兩種方式撰寫方式比早期使用SqlTransaction方式簡單多了,且可用的東西也強化了。這兩種效能是否有明顯差異還需要再測試下面程式碼的處理情境是在填入資料前,我先將所有資料表內資料刪除再進行Insert,若是有錯誤則Rollback。使用此兩個類別都需要參考System.Transactions CommittableTransaction 123456789101112131415161718192021222324252627string strSQL = \"delete [dbo].[TestTB]\";using (SqlConnection SQL = new SqlConnection(\"data source=.;Initial Catalog=test;User ID=test;Password=1234\")) { CommittableTransaction ct = new CommittableTransaction(); SQL.Open(); SQL.EnlistTransaction(ct); using (SqlCommand sqlcom = new SqlCommand()) { try { sqlcom.Connection = SQL; sqlcom.CommandText = strSQL; sqlcom.ExecuteNonQuery(); for (int i = 0; i < 1000; i++) { sqlcom.CommandText = string.Format(\"insert into [dbo].[TestTB] (A,B,C,D,E,F,H) values ('A{0}','A{1}','A{2}','A{3}','A{4}','A{5}',{6})\", i, i + 1, i + 2, i + 3, i + 4, i + 9, i); sqlcom.ExecuteNonQuery(); } ct.Commit(); } catch (Exception ex) { ct.Rollback(); } } } 首先先宣告明確交易的CommittableTransaction物件1CommittableTransaction ct = new CommittableTransaction(); 再將明確交易註冊到Connection中1SQL.EnlistTransaction(ct); EnlistTransaction:ADO.NET 2.0中的新功能獲得支援,以使用EnlistTransaction方法,登記在分散式交易中。由於在Transaction執行個體中登記連接,EnlistTransaction會利用System.Transactions命名空間中提供的功能,管理分散式交易,之後在SQLCommand中進行我們所需要的交易行為與SQL處理模式,當行為完成後再執行Commit()就可以進行資料寫入動作,若是中途發生Exception,也可以透過Rollback()將資料還原。 TransactionScope 123456789101112131415161718192021222324252627string strSQL = \"delete [dbo].[TestTB]\";using (TransactionScope ts = new TransactionScope()){ using (SqlConnection SQL = new SqlConnection(\"data source=.;Initial Catalog=test;User ID=test;Password=1234\")) { SQL.Open(); using (SqlCommand sqlcom = new SqlCommand()) { try { sqlcom.Connection = SQL; sqlcom.CommandText = strSQL; sqlcom.ExecuteNonQuery(); for (int i = 0; i < 1000; i++) { sqlcom.CommandText = string.Format(\"insert into [dbo].[TestTB] (A,B,C,D,E,F,H) values ('A{0}','A{1}','A{2}','A{3}','A{4}','A{5}',{6})\", i, i + 1, i + 2, i + 3, i + 4, i + 9, i); sqlcom.ExecuteNonQuery(); } ts.Complete(); } catch (Exception ex) { } } }} 使用TransactionScope後,使用Using宣告式在整個Connection包起來,在這範圍內撰寫相關與SQL有關的處理程序即可。由new陳述式執行個體化TransactionScope時,交易管理員會決定要參與哪個交易,一旦決定後,範圍永遠會參與該交易。此決策是根據兩個因素而定:環境交易是否存在,以及建構函式中的TransactionScopeOption參數值如果沒有任何例外狀況在交易範圍中發生 (也就是,在 TransactionScope 物件的初始化與呼叫其 Dispose 方法之間),則會允許範圍所參與的交易繼續。如果有例外狀況在交易範圍內發生,則會復原範圍所參與的交易。在這處理程序完畢後,只要在最後面加上Complete(),就可以完成此交易。若是沒有加入Complete(),則此交易將不被完成。 透過以上兩個方式,讓撰寫交易相關程式簡化許多","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"動態產生Web.sitemap檔案","slug":"Web/2016-05-01","date":"2016-05-01T14:59:31.000Z","updated":"2016-11-22T15:55:12.000Z","comments":true,"path":"paper/2016/05/01/Web/2016-05-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/05/01/Web/2016-05-01/","excerpt":"","text":"一般要在網站上使用Web導覽列,使用SiteMapPath控制項並且搭配Web.sitemap便可以製作出網站導覽列。只要在Web.sitemap建立相對應好的XML檔就可以,但是,若是這些導覽列屬於變動型,每次有變動就要在對Web.sitemap檔案,進行更新也是很麻煩的。因此,把相對的功能與功能頁面連結放入資料庫中,然後動態產生此Web.sitemap檔案,便可以隨時變動Web.sitemap內容符合網站需求 建立XML Writer 123string strPathName = Server.Path(\"\\\\\") + \"Web.sitemap\";Encoding oENC = Encoding.UTF8;XmlTextWriter oXML = new XmlTextWriter(strPathName, oENC); 建立主節點1234XML.WriteStartDocument(); oXML.WriteStartElement(\"siteMap\"); oXML.WriteStartElement(\"siteMapNode\");oXML.WriteAttributeString(\"title\", \"目前位置\"); 建立第二節點123oXML.WriteStartElement(\"siteMapNode\");oXML.WriteAttributeString(\"title\",\"首頁\");//Title attribute set,Second LeveloXML.WriteAttributeString(\"url\", \"Default.aspx\"); 從資料庫讀取動態資料結點資料,若是多層架構就需要用多層迴圈做新增節點12345678910111213141516171819for (int i = 0; i < dt.Rows.Count; i++) { if (! int.Parse(dt.Rows[i][\"AID\"].ToString()).Equals(dFirst))//值不相等則表示子節點為不同主節點 { if (i > 0)//一開始進入不可結束子節點 { oXML.WriteEndElement();//Close the siteMapNoded } oXML.WriteStartElement(\"siteMapNode\"); oXML.WriteAttributeString(\"title\", dt.Rows[i][\"AIDName\"].ToString());//建立節點 dFirst = int.Parse(dt.Rows[i][\"AID\"].ToString()); } oXML.WriteStartElement(\"siteMapNode\");//建立第二節點 oXML.WriteAttributeString(\"title\", dt.Rows[i][\"BIDName\"].ToString()); oXML.WriteAttributeString(\"url\", dt.Rows[i][\"BIDUrl\"].ToString()); oXML.WriteEndElement();//結束子節點 Element } oXML.WriteEndElement(); 結束所有節點12345 oXML.WriteEndDocument(); oXML.Flush(); oXML.Close(); oXML = null;","categories":[],"tags":[{"name":"ASP.NET","slug":"ASP-NET","permalink":"http://edwardkuo.imas.tw/tags/ASP-NET/"}],"keywords":[]},{"title":"T-SQL 時間欄位的格式化(用Convert / Cast作法)","slug":"SQL/2016-04-23","date":"2016-04-23T14:59:31.000Z","updated":"2016-11-27T02:32:28.555Z","comments":true,"path":"paper/2016/04/23/SQL/2016-04-23/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/04/23/SQL/2016-04-23/","excerpt":"","text":"用T-SQL要把資料的時間輸出想要的格式是很常見的需求,例如:年月日時分秒或是年月日,在C#可以用tostring("yyyy-MM-dd")方式。在T-SQL中可以用Convert或是Cast,但是,每次用Convert時候,都還要去記住格式化的代碼有點難,這邊整理一些相關資訊,供大家參考也給自己記憶。 用Cast方式,可以轉換成下列幾種格式 分別執行結果如下: 用Convert方式,將時間欄位轉成varchar,並搭配style方式,轉換成自己要的時間格式 1select convert(varchar,getdate(),填入center style) 簡碼對照表 不過,在這簡碼中,若是要轉換成年月日時分,似乎沒有這樣的格式可以用,要達到此需求,可以定義varchar長度解決1select convert(varchar(16),getdate(),120)","categories":[],"tags":[{"name":"T-SQL","slug":"T-SQL","permalink":"http://edwardkuo.imas.tw/tags/T-SQL/"}],"keywords":[]},{"title":"將物件轉換成XML檔案","slug":"Net/2016-04-21","date":"2016-04-21T14:59:31.000Z","updated":"2016-11-27T02:25:17.000Z","comments":true,"path":"paper/2016/04/21/Net/2016-04-21/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/04/21/Net/2016-04-21/","excerpt":"","text":"一般講到檔案儲存,大都是可被識別之內容的檔案居多,主要是這些檔案還是可以被某些程式開啟,不過,這次遇到卻是需要把物件作為檔案格式儲存下來,後續有需要用到時候,再把這些物件取出。不過為啥要這樣做呢? 舉例:一個List<Dataset>物件來說,其內容在有限時間區間內是會被重複利用,若是,每次用到都要再重新取得資訊,是相當浪費資源,所以,會先將此物件以檔案型態存放,有用到就直接取得檔案就可以,避免再重複邏輯計算 所以,就必須把物件用檔案型態存放,我這邊採用XML檔案儲存。範例中先把Datatable放入list物件1234System.Collections.Generic.List<System.Data.DataTable> oo = new List<DataTable>();Data.clsData ss = new Data.clsData();oo.Add(ss.Getdate1());oo.Add(ss.Getdate1()); 序列化需要使用到System.Xml.Serialization.XmlSerializer類別來實作 Object寫入XML File 宣告XmlSerializer物件,Type就採用序列化的型別List<System.Data.DataTable> 1System.Xml.Serialization.XmlSerializer writer =new System.Xml.Serialization.XmlSerializer(typeof(List<System.Data.DataTable>)); 使用System.IO.StreamWriter類別指定要寫入檔案的路徑,透過XmlSerializer的Serialize將物件寫入到XML檔案 1234using (System.IO.StreamWriter WR = new System.IO.StreamWriter(Server.MapPath(\"eee.xml\"))){ writer.Serialize(WR, oo);} 要用Objec也是可以123456Object oA = new Object();oA = \"wwww\";using (System.IO.StreamWriter WR = new System.IO.StreamWriter(Server.MapPath(\"eee.xml\"))){ writer.Serialize(WR, oA);} 從XML File讀取Object 既然有寫入,當然就要讀出囉,這邊就比較簡單一點 前置作業跟寫入步驟是相同的 1System.Xml.Serialization.XmlSerializer writer =new System.Xml.Serialization.XmlSerializer(typeof(List<System.Data.DataTable>)); 把Serialize改為Deserialize且把原本是Writer改為Reader就可以,不過須注意一點,反序列化之後還必須透過轉型,才有辦法回復到原本的物件型別 1234using (System.IO.StreamReader RR = new System.IO.StreamReader(Server.MapPath(\"eee.xml\"))){ oo = (List<DataTable>)writer.Deserialize(RR);} 這就大功告成了","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"看懂Azure Storage的Blob監控指標","slug":"Azure/2016-04-15","date":"2016-04-14T16:00:00.000Z","updated":"2016-11-29T08:49:42.575Z","comments":true,"path":"paper/2016/04/15/Azure/2016-04-15/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/04/15/Azure/2016-04-15/","excerpt":"","text":"Azure Storage是Azure服務中,最被應用的一個服務,其中又以Blob是被大家常用,雖然,大家常常用卻不知道其實blob本身也是會有效能問題,並非只是把檔案放進去,讓它輸入和輸出這樣簡單,所以,我們透過Blob的監控,看你自己的Blob目前的效能狀況,進而改善檔案配置 分享幾個Blob指標給大家,也可以透過幾個簡單指標去判斷,你目前Blob效能狀況,這些指標都是會有相互影響,怎樣設計出一個好的Blob架構,還是需要看自己業務上的需求來決定,這樣會比較適當。 ▪ TotalRequests:向Blob服務發出的請求數 ▪ TotalEgress:一定時間內從blob傳輸出去的網路流量 ▪ TotalIngress:一定時間內傳輸進入Blob的網路流量 ▪ TotalBillableRequests:這是計費的請求數,畢竟,從Azure內部機制而言, 某些失敗的請求是不會算在計費範圍內的。 ▪ ThrottlingError:可以了解Request的塞車程度,儲存體本身也會有瓶頸, 如果遇到這樣狀況,可以適當的去將需求分配到多個儲存帳號,提高系統的整體效能。 ▪ PercentThrottlingError:請求失敗及錯誤的百分比。 ▪ PercentTimeoutError,請求失敗和出現超時錯誤的百分比,其數字包括客戶端和 伺服器超時的都算在這裡面 ▪ AuthorizationError:驗證失敗的請求百分比。主要是對於安全性方面的監控, 有助於防止惡意攻擊、侵入等安全隱患。 ▪ NetworkError:這個即是呼叫Blob API發生NetworkError的驗證失敗的請求數。 指標中有些具有相互影響的關係,所以,在監看的時候,建議看你關心是屬於那部分,就把同類型的指標,用多指標分析方式去看,會比較了解到各項因子的相互關係,上面是目前我常用的指標 另外,也搭配使用AverageE2ELatency和AverageServerLatency這兩個指標,去協助去判斷Blob效能的好壞,這兩個指標分別代表的意義如下: ▪ AverageE2ELatency:即向Blob服務發出的成功完成Reqeuse與Response的 平均時間,這期間包括讀取請求、傳送響應以及接收響應確認所需的處理時間(ms) ▪ 如果,發現AverageE2ELatency指標高,可能就是客戶端的網路問題,或是有其 他情況造成反應過慢,這時候就可以考慮是否要在客戶端放入快取機制 ▪ AverageServerLatency:這表示內部blob處理一個成功的Request所需要的 平均時間(ms) ▪ 如果,發現AverageServerLatency指標高,我們可以這樣判斷『當同一個Blob或 Blob集合不斷收到重複的要求』,而且 Blob 下載要求出現高 AverageServerLatency時, 您應該考慮使用Azure快取或是Azure內容傳遞網路(CDN)快取處理這些 Blob』 另外,如果一直發現高AverageServerLatency,有可能表示資料表或是查詢設計不良造成,可以再多參考一些指標去判斷,例如:PercentThrottlingError,透過這樣分析找出整體系統的效能瓶頸是在那邊而去改善 參考資料 https://azure.microsoft.com/zh-tw/documentation/articles/storage-monitoring-diagnosing-troubleshooting/#metrics-show-an-increase-in-PercentTimeoutError https://azure.microsoft.com/zh-tw/documentation/articles/storage-monitoring-diagnosing-troubleshooting/#metrics-show-high-AverageE2ELatency-and-low-AverageServerLatency","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"開始進行資料庫程式的版控和佈署","slug":"Devops/2016-04-12","date":"2016-04-12T14:59:31.000Z","updated":"2016-11-29T12:14:36.000Z","comments":true,"path":"paper/2016/04/12/Devops/2016-04-12/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/04/12/Devops/2016-04-12/","excerpt":"","text":"在程式開發上,大家都知道要對程式碼進行版控的動作,但是,對於DB的Table Schema或是資料庫物件就不會去做版控。針對這一部份,大都採用傳統方式,用複製的動作進行版控,久而久之就會開始遺失或是缺東缺西。早期要做資料庫物件版控其實也不容易,畢竟,DB是透過Script運作。自從VisualStudio有資料庫專案後,再加上資料庫更新與建制,可以透過.dacpac封裝方式進行部署與差異化更新,因此,要把資料庫納入版控就相對簡單許多。因此,可以開始嘗試使用DB資料庫專案進行開發 首先,在Visual Studio內找到SQL Server專案範本,透過這專案範本就可以建立資料庫專案了 開啟資料庫專案後,就跟開發程式一樣簡單了,可以透過新增項目去開發資料庫的物件。若是,針對舊有的資料庫進行版控,就必須將資料庫匯入資料庫專案中,這樣後續才有辦法產生.dacpac檔案,設計完畢後,就可以透過Visual Stduio進行發行資料庫或是透過SSMS進行佈署。 個人還是喜歡透過SSMS進行操作,畢竟,實務上這一段不一定是開發人員佈署或是一般人都有權限可以直接有權限接觸DB,透過,將封裝檔案透過SSMS佈署或是更新是比較適宜的。所以,當我們設計好的資料庫專案,就可以透過編譯方式產生封裝檔案,若是中間有語法錯誤或是物件不對,就會發生編譯失敗問題。使用SSMS只要選擇佈署精靈就可以很快的佈署完畢了。先選擇要佈署的檔案,和要產生資料庫的名稱 這邊可以看到要佈署的封裝檔案的版本。 若是第一次進行封裝佈署,基本上只要不斷按下一步就可以。而若是在開發專案中有遇到資料庫更新部分,也可以透過封裝檔案進行 把某一個資料表的ID設定為識別碼 並且把封裝版本號修改一下 然後,透過SSMS的更新資料應用程式,進行資料庫物件的更新 當然,還是需要選擇新版本的封裝檔案 基本上若是資料庫的資料表內有資料,都會跳出警告訊息,這部分主要是告知這些異動會動到資料表,有可能會有資料表內的資料遺失風險 下圖也是進行相同的提示,這邊若是不須勾選確認會資料遺失的按鈕,就無法繼續下一步了 按完之後就等他進行更新了更新完畢後,就可以看到ID已經被設定成識別碼了。 以上透過這樣方式就可以佈署資料庫,同時也可以將資料庫設計納入版控中。但是,個人覺得在第一次進行資料庫佈署時候,透過封裝檔案方式進行佈署,算是非常方便的,且相關機制都可以透過Visual Studio進行管控與紀錄。若是,當我們有針對資料庫內資料表或是相關程式更新時候,尤其是資料表部分,還是建議乖乖去資料表內透過手動或是寫好Script方式進行更新資料表以免真的有資料遺失。雖然,可以備份資料,但是,若是資料表內資料非常的多時候,有時候遺失那些資料還真的找不出來,又要做資料比對又很花時間與精神,而針對原本預存程序或是檢視表的更新,就可以透過封裝檔案進行","categories":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}],"tags":[{"name":"DevOps","slug":"DevOps","permalink":"http://edwardkuo.imas.tw/tags/DevOps/"}],"keywords":[{"name":"資料庫程式版控","slug":"資料庫程式版控","permalink":"http://edwardkuo.imas.tw/categories/資料庫程式版控/"}]},{"title":"建立Azure SQL Database 全文搜索功能","slug":"Azure/2016-04-09","date":"2016-04-08T16:00:00.000Z","updated":"2016-11-27T02:39:06.000Z","comments":true,"path":"paper/2016/04/09/Azure/2016-04-09/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/04/09/Azure/2016-04-09/","excerpt":"","text":"自從Azure SQL Database Release 全文檢索功能一直沒有機會去使用,今天剛好遇到需要進行多欄位資料模糊查詢的需求,為了避免使用Like 加 OR 有可能會導致查詢性能下,因此,來使用一下Azure SQL Database功能,以前在地端的SQL Server要做全文檢索,還需要自行去安裝這部分功能,雖然,沒有太難安裝,但似乎也沒有那樣便利,如果在Azure就可以省去這些麻煩,另外,在Azure上面使用全文檢索好處是還不需要花費呢 一開始預設是沒有設定全文搜索,所以,情況會是下面這樣(這當然是廢話囉,沒設定一定會出錯) 所以,開始建立全文檢索吧,這次要建立全文檢索是對應到檢視表,一開始還必須先把檢視表設定好index,要設定檢視表的index必須注意一件事情,就是必須先把檢視表加入WITH SCHEMABINDING,一開始不知道這問題,一直發生錯誤訊息123CREATE VIEW [dbo].[VW_XXXX] WITH SCHEMABINDINGAS select ..... 就可以幫檢視表建立索引了 12345 CREATE UNIQUE CLUSTERED INDEX [VW_XXX_idx] ON [dbo].[VW_XXX]( [UserID] ASC)GO 接下來就是建立全文索引目錄1CREATE FULLTEXT CATALOG UserCatalog AS DEFAULT; 建立完畢後,在SSMS看Azure SQL Database就可以看到如下圖這樣 建立檢視表的全文索引,這邊我們要進行全文索引共包含三個欄位,因為建立全文索引,必須要對應到資料表或是檢視表的索引,所以,前面我們必須在檢視表中加入索引,如果是對應到資料表這動作也是要做的123CREATE FULLTEXT INDEX ON VW_XXX ( NickName,company,jobtitle ) KEY INDEX [VW_XXX_idx] ON UserCatalog; 完畢後,開始啟用索引或是說擴張該資料表或是檢視表的索引12ALTER FULLTEXT INDEX ON VW_XXX ENABLE;ALTER FULLTEXT INDEX ON VW_XXX START FULL POPULATION; 建立完成後,可以用下面語法看你建立的全文索引12SELECT *FROM sys.dm_fts_index_population; 如果你要看你的資料被斷詞的狀況,可以使用下面這語法12SELECT *FROM sys.dm_fts_index_keywords ( DB_ID('DB Name'),OBJECT_ID('VW_XXX')) ; 這樣就可以輕輕鬆鬆擁有全文檢索功能了","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"將Datatable轉換成Vba可接受的RecordSet類別","slug":"Net/2016-04-02","date":"2016-04-01T16:00:00.000Z","updated":"2016-11-27T02:27:32.263Z","comments":true,"path":"paper/2016/04/02/Net/2016-04-02/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/04/02/Net/2016-04-02/","excerpt":"","text":"由於目前工作地方大部分程式還是建構在EXCEL中,使用VBA撈取資料庫資料並做資料運算。但是,將資料撈回到EXCEL再用VBA做運算效能比較差且又擔心USER在運算邏輯的程式亂做修改,造成資料有誤。想說改用Excel呼叫Web Service,把邏輯運算都靠Web service做好,再把整包資料丟回到EXCEL這樣就可以避免上述一些問題。 不過,由於在.NET環境中主要都是ADO.NET架構,其回傳類型並未有早期的ADO架構中的RecordSet,所以,除了在Server端將資料計算完成,還必須想辦法Output資料可以讓Excel使用,因次,將必須把Dataset 或Datatable轉換成RecordSet,讓EXCEL做處理 在專案內參考兩個物件,後面將必須使用這兩個物件做轉換 ADO與ADO.NET型別轉換 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071switch (dt.Columns[i].DataType.FullName) { case \"System.Boolean\": fieldType = ADODB.DataTypeEnum.adBoolean; break; case \"System.Byte\": fieldType = ADODB.DataTypeEnum.adUnsignedTinyInt; break; case \"System.Char\": fieldType = ADODB.DataTypeEnum.adWChar; dfieldLength = dt.Columns[i].MaxLength; if (dfieldLength == -1) { dfieldLength = 255; } break; case \"System.DateTime\": fieldType = ADODB.DataTypeEnum.adDate; break; case \"System.Decimal\": fieldType = ADODB.DataTypeEnum.adCurrency; break; case \"System.Double\": fieldType = ADODB.DataTypeEnum.adDouble; break; case \"System.Int16\": fieldType = ADODB.DataTypeEnum.adSmallInt; break; case \"System.Int32\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.Int64\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.SByte\": fieldType = ADODB.DataTypeEnum.adSmallInt; break; case \"System.Single\": fieldType = ADODB.DataTypeEnum.adSingle; break; case \"System.String\": // 因為 MDB 檔的文字欄位最大長度是 255 // 所以超過時,以 memo 欄位存放 if (dt.Columns[i].MaxLength > 255) { fieldType = ADODB.DataTypeEnum.adLongVarWChar; dfieldLength = 0; } else { fieldType = ADODB.DataTypeEnum.adVarWChar; dfieldLength = dt.Columns[i].MaxLength; if (dfieldLength == -1) { dfieldLength = 255; } } break; case \"System.UInt16\": fieldType = ADODB.DataTypeEnum.adSmallInt; break; case \"System.UInt32\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.UInt64\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.Byte[]\": fieldType = ADODB.DataTypeEnum.adLongVarBinary; break;} 完整程式碼123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131internal string oDatatableToRecordSet(DataTable _dt) { string strRecordSet = string.Empty; DataTable dt = new DataTable(); dt = _dt; MSXML2.DOMDocument dom = new MSXML2.DOMDocumentClass(); ADODB.RecordsetClass rs = new ADODB.RecordsetClass(); ADODB.DataTypeEnum fieldType = ADODB.DataTypeEnum.adWChar; int dfieldLength = 0; try { //定義RecordSet欄位屬性與名稱,從Datatable轉換過來。 for (int i = 0; i < dt.Columns.Count; i++) { #region 取得對應Dataset與RecordSet屬性 try { switch (dt.Columns[i].DataType.FullName) { case \"System.Boolean\": fieldType = ADODB.DataTypeEnum.adBoolean; break; case \"System.Byte\": fieldType = ADODB.DataTypeEnum.adUnsignedTinyInt; break; case \"System.Char\": fieldType = ADODB.DataTypeEnum.adWChar; dfieldLength = dt.Columns[i].MaxLength; if (dfieldLength == -1) { dfieldLength = 255; } break; case \"System.DateTime\": fieldType = ADODB.DataTypeEnum.adDate; break; case \"System.Decimal\": fieldType = ADODB.DataTypeEnum.adCurrency; break; case \"System.Double\": fieldType = ADODB.DataTypeEnum.adDouble; break; case \"System.Int16\": fieldType = ADODB.DataTypeEnum.adSmallInt; break; case \"System.Int32\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.Int64\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.SByte\": fieldType = ADODB.DataTypeEnum.adSmallInt; break; case \"System.Single\": fieldType = ADODB.DataTypeEnum.adSingle; break; case \"System.String\": // 因為 MDB 檔的文字欄位最大長度是 255 // 所以超過時,以 memo 欄位存放 if (dt.Columns[i].MaxLength > 255) { fieldType = ADODB.DataTypeEnum.adLongVarWChar; dfieldLength = 0; } else { fieldType = ADODB.DataTypeEnum.adVarWChar; dfieldLength = dt.Columns[i].MaxLength; if (dfieldLength == -1) { dfieldLength = 255; } } break; case \"System.UInt16\": fieldType = ADODB.DataTypeEnum.adSmallInt; break; case \"System.UInt32\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.UInt64\": fieldType = ADODB.DataTypeEnum.adInteger; break; case \"System.Byte[]\": fieldType = ADODB.DataTypeEnum.adLongVarBinary; break; } } catch { } #endregion //填入Reciordset rs.Fields.Append(dt.Columns[i].ColumnName, fieldType, dfieldLength, ADODB.FieldAttributeEnum.adFldUnspecified, Missing.Value); } rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient; rs.Open(Missing.Value, Missing.Value, ADODB.CursorTypeEnum.adOpenUnspecified, ADODB.LockTypeEnum.adLockUnspecified, -1); rs.AddNew(Missing.Value, Missing.Value); //加入新列到rs //填入數值 for (int j = 0; j < dt.Rows.Count; j++) { for (int m = 0; m < dt.Columns.Count; m++) { if (!string.IsNullOrEmpty(dt.Rows[j][m].ToString())) { rs.Fields[m].Value = dt.Rows[j][m];// == \"\" ? \"\" : dt.Rows[i][j]; } } rs.AddNew(Missing.Value, Missing.Value); } rs.Save(dom, ADODB.PersistFormatEnum.adPersistXML); strRecordSet = dom.xml.Replace(\"<z:row/>\", \"\"); } catch (Exception ex) { } finally { dom = null; rs.Close(); rs = null; dt.Dispose(); dt = null; } return strRecordSet; }","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"Cannot truncate table,because it is being referenced by a FOREIGN KEY constraint?","slug":"SQL/2016-04-01","date":"2016-04-01T14:59:31.000Z","updated":"2016-11-27T02:33:18.000Z","comments":true,"path":"paper/2016/04/01/SQL/2016-04-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/04/01/SQL/2016-04-01/","excerpt":"","text":"今天測試資料完畢,想要把所有測試表全部truncate table,竟然出現下面字樣 Cannot truncate table ‘XXXXX’ because it is being referenced by a FOREIGN KEY constraint.” 現在才知道若是這個資料表的主索引,是別的資料表的FK,則不能直接使用 truncate table,將所有相關性資料一次清掉,若是依舊想要Trucate table,則最簡單方法就是把FK的設定拿掉,但是,每次測試資料完畢後,都要做這樣動作實在太費時了,想說因該有其他方法可以更Smart一點方法,於是,查了一下,發現竟然可以用下面方法就可以做到自動化刪除所有資料,這樣就可以減省還需要重新設定FK時間12DELETE [資料表名稱]; DBCC CHECKIDENT('資料表名稱', RESEED, 0); 簡單的兩行,就解決","categories":[],"tags":[{"name":"T-SQL","slug":"T-SQL","permalink":"http://edwardkuo.imas.tw/tags/T-SQL/"}],"keywords":[]},{"title":"取得當前程式執行階段的Method Name","slug":"Net/2016-03-04","date":"2016-03-26T16:00:00.000Z","updated":"2016-11-22T15:55:10.000Z","comments":true,"path":"paper/2016/03/27/Net/2016-03-04/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/03/27/Net/2016-03-04/","excerpt":"","text":"當你在開發或維護大型程式系統時,其系統中的各項Method錯綜複雜(就是程式很亂),又有馬上需要 Trouble shooting壓力,這時候就很需要知道,程式是執行到哪一個Method,方便進行Trace。通常我會把這功用下列兩個地方: 系統發生Exception地方,需記錄知道哪一個Method發生問題 系統Kernel的地方,以方便了解資料進出是發生在哪一個Method 首先參照下面的Namespace1using System.Reflection System.Reflection命名空間包含的型別可透過檢查 Managed 程式碼中組件、模組、成員、參數和其他實體Entity的中繼資料Metadata,擷取這些項目的相關資訊 用MethodInfo類別或是MethodBase類別的GetCurrentMethod方法來取得Method名稱12345public static void Method2(){ Console.Write(string.Format(\"Method Name:{0}\",MethodBase.GetCurrentMethod().Name)); Console.Write(string.Format(\"Method Name:{0}\",MethodInfo.GetCurrentMethod().Name));} 當程式發生問題時候,在Trace bug就可以比較容易找出問題的環節了。不然,就會摸不著頭緒找Bug","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"全球供應鏈的思維","slug":"LifeStyle/2016-03-26","date":"2016-03-25T16:00:00.000Z","updated":"2016-11-27T02:42:48.000Z","comments":true,"path":"paper/2016/03/26/LifeStyle/2016-03-26/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/03/26/LifeStyle/2016-03-26/","excerpt":"","text":"雖然,SCM (Supply Chain Management)對於我來說並不陌生,再加上自己也曾經做過SCM系統一段時日,但是,日子久了畢竟人還是會健忘的,加上自己現在工作還是跟這方面有著間接關系,所以,還是趕緊把自己曾經講過SCM課程,做一下摘要性整理 何謂全球供應鏈管理 全球市場為範圍,將集團或是公司在涉及不同國家的運籌管理功能,進行協調與合理化。 滿足客戶需求的前提下,把物流與庫存成本降到最小。 增加物料管理與產品運配之可靠性。 全球供應鏈管理目標 提高交貨給客戶的可靠性和靈活性。 減少產品出貨與生產時間。 降低產品庫存,減少產品生產及分銷的費用。 錯誤生產成本去除,異常事件消弭。 以最小生產成本達到最大銷售利潤。 全球生產供應鏈組成單元 全球生產製造基地 集團子公司 材料供應商 外包廠 合資廠 外包廠 模組段的生產成本主要為組裝人員,故將部分組裝流程,委外給其他代工廠協助生產。 優點 可以避免人力不足或過剩問題。 降低包材之生產成本。 減少半成品或成品運送品質變異。 不良品之成本由外包廠負擔。 合資廠 兩個以上公司間所形成的合夥關係,以達成策略性商業目標 對企業本身優點 確保產品之出海口。 貼近市場需求。 了解市場趨勢。 綁定客戶。 對於合夥夥伴優點 確保來料供貨穩定。 減少設廠成本。 減少產品出貨時間。全球供應鏈管理結構 全球供應鏈管理追求之期望目標 產品力:專注追求高良率高品質的生產能力。 技術力:對新技術新應用整合開發,並持續累積專利。 管理能力:高績效的營運管理能力。供應鏈中的生產規劃主要KPI 成品與半成品之存貨週轉天數控制。 成品與半成品庫存控制。供應鏈中的生產排程常見指標數值 成品庫存量 Stock需隨時掌控全球各地製造廠區之庫存量 成品帳齡 Aging確認是否有庫存過久,尚未出貨之成品 成品在途資訊 In-transit 中繼站 Hub生產規劃對供應鏈重要性 目的在於降低生產時效,成本控管,主要作業項目如下: 根據訂單需求、材料供給、產能及良率限制,訂定MPS Schedule 監督生產計劃執行狀況 確保產品順利出貨 掌控全球產品庫存量 生產排程之異常處理 縮短產品生產時間","categories":[],"tags":[{"name":"LifeStyle","slug":"LifeStyle","permalink":"http://edwardkuo.imas.tw/tags/LifeStyle/"}],"keywords":[]},{"title":"使用Ajax.BeginForm在Controller做頁面跳轉","slug":"Web/2016-03-24","date":"2016-03-24T04:59:31.000Z","updated":"2016-11-27T02:43:56.000Z","comments":true,"path":"paper/2016/03/24/Web/2016-03-24/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/03/24/Web/2016-03-24/","excerpt":"","text":"MVC使用Ajax.BeginForm並且在Controller控制頁面轉跳是很常使用的,若是在Controller用return RedirectToAction(XXXX)跳轉,就會發生頁面卡著不動。 View 1234567@using (Ajax.BeginForm(\"Login\", \"XXX\", new AjaxOptions { UpdateTargetId = \"ErrorMessage\" })){ ....... <input type=\"submit\" class=\"button button-green contactSubmitButton\" value=\"Sign On\" />} Controller 原本使用RedirectToAction(XXXX)就會發生頁面卡住的現象,所以,Controller必須修改成這樣如下:1return Json(new { url = Url.Action(\"Main\", \"Main\") }); 而在View中也需增加下面這一段1234567<script> var onSuccess = function (result) { if (result.url) { window.location.href = result.url; } }</script> 再把Ajax.BeginForm增加一個OnSuccess的觸發事件就可以進行頁面跳轉了","categories":[],"tags":[{"name":"ASP.NET","slug":"ASP-NET","permalink":"http://edwardkuo.imas.tw/tags/ASP-NET/"}],"keywords":[]},{"title":"如何序列化Datatable / Dataset物件","slug":"Net/2016-03-22","date":"2016-03-22T14:59:31.000Z","updated":"2016-11-27T02:31:49.832Z","comments":true,"path":"paper/2016/03/22/Net/2016-03-22/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/03/22/Net/2016-03-22/","excerpt":"","text":"在做SOA機制上,有需要接受Datatable或DataSet傳送給SOA平台,但是,物件無法這樣直接傳遞,必須先做過序列化才有辦法將物件傳遞出去。 DataTable 序列化 123456789internal string DatatableSerialize(System.Data.DataTable _dt){ System.Xml.Serialization.XmlSerializer s = new System.Xml.Serialization.XmlSerializer(_dt.GetType()); StringBuilder sb = new StringBuilder(); StringWriter wr = new StringWriter(sb); s.Serialize(wr, _dt); return sb.ToString();} DataTable反序列化 12345678910internal DataTable DatatableDeserialize(string _strDATA){ DataTable dt = new DataTable(); System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument(); xdoc.LoadXml(_strDATA); System.Xml.XmlNodeReader r = new System.Xml.XmlNodeReader(xdoc.DocumentElement); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(dt.GetType()); object ob = ser.Deserialize(r); return ob as DataTable;} 若是要把DataTable改成Dataset呢?只要在序列化的傳遞物建部分改成Dataset就可以。而在反序列化部分,要修改這兩部分。ds為DataSet物件,並將回傳的ob轉型為Dataset就可以12System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(ds.GetType());return ob as DataSet; 本篇主要只是針對後續真的必需DataSet或是DataTable要做序列化的朋友提供一個語法方式,若是架構允許話,透過Web Service或WCF傳輸資料,最好還是不要使用DataSet或DataTable型別,這樣對於效能上是會有影響 參考資料 如何用 C# 撰寫序列化(Serialize)與反序列化(Deserialize)","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"將VBA的RecordSet轉換Datatable類別","slug":"Net/2016-03-17","date":"2016-03-16T16:00:00.000Z","updated":"2016-11-27T02:31:20.000Z","comments":true,"path":"paper/2016/03/17/Net/2016-03-17/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/03/17/Net/2016-03-17/","excerpt":"","text":"寫一篇關於將Datatable轉換成Vba可接受的RecordSet類別,如果把結果顛倒過來呢?這也是可以的。其主要目的是讓Excel內的資料上傳後,可以透RecordSet 轉換成 Datatable解析其中資料內容或是讓.Net可以快速針對內容作處理。 主要需要靠ADODB.Stream&ADODB.Recordset物件幫助。 12Type adoStreamType = Type.GetTypeFromProgID(\"ADODB.Stream\");Type adoRecordsetType = Type.GetTypeFromProgID(\"ADODB.Recordset\"); 透過System.Activator物件幫忙進行轉換 1234567891011121314151617181920212223242526272829303132string strXML = //<-接Recordset format字串用DataSet ds = new DataSet();OleDbDataAdapter odb = new OleDbDataAdapter();Type adoStreamType = Type.GetTypeFromProgID(\"ADODB.Stream\");Type adoRecordsetType = Type.GetTypeFromProgID(\"ADODB.Recordset\");object adoStream = Activator.CreateInstance(adoStreamType);object adoRecordset = Activator.CreateInstance(adoRecordsetType);try{ adoStreamType.InvokeMember(\"Open\", System.Reflection.BindingFlags.InvokeMethod, null, adoStream, new object[] { }); adoStreamType.InvokeMember(\"WriteText\", System.Reflection.BindingFlags.InvokeMethod, null, adoStream, new object[] { strXML }); adoStreamType.InvokeMember(\"Position\", System.Reflection.BindingFlags.SetProperty, null, adoStream, new object[] { 0 }); adoRecordsetType.InvokeMember(\"Open\", System.Reflection.BindingFlags.InvokeMethod, null, adoRecordset, new object[] { adoStream }); odb.Fill(ds, adoRecordset, \"Tmp_Data\");}catch (Exception ex){ clsWriteToLog.WriteToLog_E(\"oRecordSetToDatatable\", ex.Message.ToString());}finally{ odb.Dispose(); odb = null; adoStreamType = null; adoRecordsetType = null; adoStream = null; adoRecordset = null; strXML = null;} 這樣就可以將Excel傳上來的RecordSet轉換成.Net可用的物件。","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"取得該日期之對應週別","slug":"Net/2016-03-03","date":"2016-03-02T16:00:00.000Z","updated":"2016-11-27T02:28:14.743Z","comments":true,"path":"paper/2016/03/03/Net/2016-03-03/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/03/03/Net/2016-03-03/","excerpt":"","text":"取得日期對應週別,這個功能滿有用,主要是可以識別目前日期是整年的第幾週。當然,在某些公司內的週期定義,可能不是所謂的週日到週六為一週,有可能是上周五到下周四為完整一週,這樣去計算週期就會跟一般有所不同 這邊先講一般正常週別的作法,必須用到System.Globalization.Calendar類別。要宣告這個物件跟一般物件不太一樣,它必須透過CultureInfo.Calendar屬性來做宣告,換句話說就是必須定義是屬於哪一個文化的calendar,這邊因為要計算台灣週期,故採用zh-TW,若是要用其他國別就更改zh-TW設定就可以1System.Globalization.Calendar TW = new System.Globalization.CultureInfo(\"zh-TW\").Calendar; 然後透過GetWeekOfYear這方法取得今年的週期。這方法主要要傳入日期,週期定義和每週起始星期就可以1234DateTime dt = DateTime.Now;System.Globalization.Calendar TW = new System.Globalization.CultureInfo(\"zh-TW\").Calendar;Response.Write(string.Format(\"西元:{0}/{1}/{2} <br>\", dt.Year, dt.Month, dt.Day));Response.Write(\"週別:\" + TW.GetWeekOfYear(dt, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString()); 在Rule的地方有三種可以設定 FirstDay:表示第一週開始為一年第一天 FirstFourDayWeek:表示一週開始距離一年第一天有四個之前1Response.Write(\"週別:\" + TW.GetWeekOfYear(dt, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Saturday).ToString()); 其意思若是以2014/1/2為主,但是一週開始為周六,1/2距離上一個周六,離一年的第一天共間隔四天,故該日期被定義為53週,若是去加兩天變成1/4則週別就會變成第一週,因為距離1/1並無超過四天以上。不過,個人認為這部分使用上並不是很用好,彈性也較低 FirstFullWeek:這一個就可以指定是1/1開始為第一週還是指定星期開始為第一週,剛好1/2也是星期四,就會是一年的第一週 1Response.Write(\"週別:\" + TW.GetWeekOfYear(dt, System.Globalization.CalendarWeekRule.FirstFullWeek, DayOfWeek.Thursday).ToString()); 若是指定第一週為週五呢?1/2就會被歸屬到上一年度的週別了,簡而言之就是我們的週別定義就會是週五到下週四","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"Azure Web App設定虛擬網路固定IP","slug":"Azure/2016-03-03","date":"2016-03-02T16:00:00.000Z","updated":"2016-11-27T02:38:16.876Z","comments":true,"path":"paper/2016/03/03/Azure/2016-03-03/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/03/03/Azure/2016-03-03/","excerpt":"","text":"我們知道在Azure Web App的虛擬IP是採用Share,所以,無論建立幾個Web Site的虛擬IP都會是同一組,若是有需要自己一組固定的虛擬IP呢?這時候就必須在Web App上面做一些設置,才有辦法讓你的Web App會有擁有一組的固定IP,未設置前如下圖 要讓自己的Web App有固定Inbound IP,需要下列幾個步驟 建立一個規模至少必須是『基本』的Web App,這邊採用的設計規模是標準 Web Site建立好後,Web Site一定要設置一組自己的網域 另外,必須要有一組憑證,這個憑證可以在自己電腦做一組上傳,製作憑證方式,首先用系統管理員權限開啟Visual Studio Command,使用markecert指令建立 1makecert -r -pe -b 01/01/2013 -e 01/01/2014 -eku 1.3.6.1.5.5.7.3.1 -ss My -n CN=serverdnsname -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 -len 2048 相關指令用法可以參考 https://msdn.microsoft.com/zh-tw/library/bfsktky3(v=vs.100).aspx 其中CN=serverdnsname的serverdnsname改成你的網域名稱就可以了,製作的憑證必須有下列幾點特性 憑證必須包含私密金鑰。 憑證必須是為了進行金鑰交換而建立,且可匯出成個人資訊交換檔 (.pfx)。 憑證的主體名稱必須和用來存取應用程式的網域相符。如果您需要利用此憑證來供應多個網域,則必須如前文所討論,使用萬用字元值或指定subjectAltName值。 憑證至少應該要2048位元加密。 輸入指令完畢後,就會跳出要你輸入憑證密碼,此時把輸入一組你想要密碼 到建立的Web Site部分,上傳憑證 上傳憑證完畢,到SSL繫結設定你的網域去綁定剛剛上傳的憑證,這邊比較重要的一點是,必須設定以IP為主的SSL,設定完成後,建議重新啟動Web Site,這樣就會重新配置一組固定的public IP 一旦被被發固定IP後,除非是憑證到期或是刪除SSL繫結外,基本上是不會被取消這固定IP的,也可以透過nslookup確認,你的網域已經綁定SSL了,另外提到一點,這樣做法固定inbound的IP唷,並非固定Outbound IP的做法,這一點要注意!!","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"使用Powershell指令呼叫 Web API","slug":"PowerShell/2016-02-24","date":"2016-02-24T04:59:31.000Z","updated":"2016-11-27T02:40:09.151Z","comments":true,"path":"paper/2016/02/24/PowerShell/2016-02-24/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/02/24/PowerShell/2016-02-24/","excerpt":"","text":"Azure Web Site有了Web Job之後,這功能還真的非常好用,以前每次做排程,大都喜歡去用SSIS,主要透過SSIS執行Job會有一些紀錄可以看,現在Web Job也有這樣功能,雖然,目前上面不能掛載SSIS,但是,能做得東西也夠多,除了使用Console程式外,也能用PowerShell來開發唷,做一個簡單的使用PowerShell去驅動Web Api範例12$url =\"http://XXXX.azurewebsites.net/api/AAAAInvoke-RestMethod -Uri $url -Method Post 其中,主要就是透過Invoke-RestMethod驅動,這個指令可以透過Http或Https去呼叫Restful Web Service","categories":[],"tags":[{"name":"PowerShell","slug":"PowerShell","permalink":"http://edwardkuo.imas.tw/tags/PowerShell/"}],"keywords":[]},{"title":"使用Linq的Join / right Join / Left Join","slug":"Net/2016-02-23","date":"2016-02-23T14:59:31.000Z","updated":"2016-11-27T02:26:03.101Z","comments":true,"path":"paper/2016/02/23/Net/2016-02-23/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/02/23/Net/2016-02-23/","excerpt":"","text":"用Join來做資料聯集,在T-SQL指令是常會用到的一種語法,不過,對於常寫SQL語法的人要轉換到Linq語法時,往往對於Join這語句的操作就常會感到比較陌生也不習慣要怎樣使用。因此,這邊簡單說明一下,要如何操作Linq的join語法 資料表A 資料表B Join 先來做兩個資料的Join,把資料表B去顯示對應的資料表A的WeekName,Join是算是Linq比較簡單易懂的,其條件為透過資料表A的Week與資料表B的WeekSQL這兩個欄位相等之關係之資料集12345from ss in Config_WeekMappingsjoin aa in S_Student_Curriculumson new { WeekID=ss.Week} equalsnew {WeekID=aa.WeekSQL} select new { WeekSQL=ss.Week,WeekName=ss.WeekName,week=aa.Week} 跟我們熟悉的SQL語法是相同的123SELECT [t0].[Week] AS [WeekSQL], [t0].[WeekName]FROM [Config_WeekMapping] AS [t0]INNER JOIN [S_Student_Curriculum] AS [t1] ON [t0].[Week] = [t1].[WeekSQL] 若是要這Joine過程中去過濾一些資料呢?例如我只要取資料表A中的Week等於1的資料,其語法如下:123456from ss in Config_WeekMappingsjoin aa in S_Student_Curriculumson new { WeekID=ss.Week} equalsnew {WeekID=aa.WeekSQL} where ss.Week==1select new { WeekSQL=ss.Week,WeekName=ss.WeekName} 而除了一個過濾條件外,我們又想在資料表B中取出某一個學號且WeekSQL為1的資料,其語法如下:123456from ss in Config_WeekMappingsjoin aa in S_Student_Curriculumson new { WeekID=ss.Week} equalsnew {WeekID=aa.WeekSQL} where aa.S_Num==\"S20142001\" && ss.Week==1select new { WeekSQL=ss.Week,WeekName=ss.WeekName} 這樣就可以採用兩個條件做篩選,且可以分別篩選出不同資料表的條件。因此,即使在Linq中也可以很輕鬆的透過這樣語法做過濾條件,Linq轉成SQL語句是跟我們再用SQL指令的方式是相同的。 Right Join 使用Right Join在Linq中並無真正去區分Right Join或是Left Join的關鍵字。這一點跟SQL指令不太一樣,在SQL中還可以採用Right Join & Left Join去指定資料表的聯集方式。但是,在Linq這邊語法就沒有這樣直覺,Linq語法中都只有Join這指令而已,因此,先來講Right Join作法,後面再接著說Left Join,個人認為right Join比較需要換個方向思考才能與SQL相同 想要把資料表A去Right Join資料表B,其SQL語法可以這樣下:12345678SELECT [t0].[Week] AS [WeekSQL] , [t0].[WeekName] , t1.WeekFROM [dbo].[Config_WeekMapping] [t0] RIGHT JOIN ( SELECT WeekSQL , Week FROM [dbo].[S_Student_Curriculum] ) t1 ON t0.Week = t1.WeekSQL 在Linq並無Right Join語法,因此,我做法則是把資料表兩個做對調,其意義為用資料表B去Left Join資料表A,這樣就可以達到資料表A做Right Join資料表B的功能,其與法如下:123456from ss in S_Student_Curriculumsjoin aa in Config_WeekMappings on new { WeekID=ss.WeekSQL} equalsnew {WeekID=aa.Week} into tempfrom ds in temp.DefaultIfEmpty()select new { WeekSQL=ds.Week,WeekName=ds.WeekName,week=ss.Week} 而當我們在Linq語法中,無論是right join或是left Join中,要取得第一個資料表S_Student_Curriculums的欄位,直接使用上述的變數ss指向欄位即可,但是,若是要取得第二個資料表欄位Config_WeekMappings,則不是直接取用變數aa對應欄位,而是必須使用temp這個變數去對映相關欄位才可以,因此,上面語法對照的SQL語法如下:123SELECT [t1].[Week] AS [WeekSQL], [t1].[WeekName] AS [WeekName], [t0].[Week] AS [week]FROM [S_Student_Curriculum] AS [t0]LEFT OUTER JOIN [Config_WeekMapping] AS [t1] ON [t0].[WeekSQL] = [t1].[Week] 若是這邊要做一些資料篩檢的話,就跟Join方式的是相同的概念,下面篩選案例與Join中的案例相同,其語句如下:1234567from ss in S_Student_Curriculumsjoin aa in Config_WeekMappings on new { WeekID=ss.WeekSQL} equalsnew {WeekID=aa.Week} into tempfrom ds in temp.DefaultIfEmpty()where ss.S_Num==\"S20142001\" && ds.Week==3select new { WeekSQL=ds.Week,WeekName=ds.WeekName,week=ss.Week} Left Join 資料表A做left Join資料表B其語法如下,這部份跟right join是相同的,就把剛剛資料表B再與資料表A做對調即可123456from ss in Config_WeekMappings join aa in S_Student_Curriculumson new { WeekID=ss.Week} equalsnew {WeekID=aa.WeekSQL} into tempfrom ds in temp.DefaultIfEmpty()select new { WeekSQL=ss.Week,WeekName=ss.WeekName,week=ds.Week} 當然這邊SQL語法也是跟right join是相同的,只有資料表對調而已 以上就是針對Linq做Join系列的簡單作法,不過,上述案例只有針對一個條件做Join,也就是on A.XX=B.XX,若是要針對兩個欄位進行Join呢?只要針對下圖的紅框部分,依序加入欄位就可以。","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"如何字串是否包含中文","slug":"Net/2016-02-13","date":"2016-02-13T04:59:31.000Z","updated":"2016-11-27T02:27:53.999Z","comments":true,"path":"paper/2016/02/13/Net/2016-02-13/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/02/13/Net/2016-02-13/","excerpt":"","text":"最近做一個小功能,要判斷傳入字串是否含有中文,再作後續的動作。這邊記錄判斷邏輯的寫法,程式的邏輯為當傳入參數只要是字串中有任何一個中文字都會回傳True。 要多考慮中文的Unicode範圍Unicode字元範圍 3400~4DFFh:中日韓認同表意文字擴充A區,總計收容6,582個中日韓漢字 4E00~9FFFh:中日韓認同表意文字區,總計收容20,902個中日韓漢字。 A000~A4FFh:彝族文字區,收容中國南方彝族文字和字根。 AC00~D7FFh:韓文拼音組合字區,收容以韓文音符拼成的文字。 F900~FAFFh:中日韓兼容表意文字區,總計收容302個中日韓漢字。 FB00~FFFDh:文字表現形式區,收容組合拉丁文字、希伯來文、阿拉伯文、中日韓直式標點、小符號、半角符號、全角符號等。 程式碼 12345678910111213141516171819202122public static bool isChinese(string strChinese){ bool bresult = true; int dRange = 0; int dstringmax=Convert.ToInt32(\"9fff\", 16); int dstringmin=Convert.ToInt32(\"4e00\", 16); for (int i = 0; i < strChinese.Length; i++) { dRange = Convert.ToInt32(Convert.ToChar(strChinese.Substring(i, 1))); if (dRange >= dstringmin && dRange <dstringmax ) { bresult = true; break; } else { bresult = false; } } return bresult;} 要考慮到unicode範圍才會正確","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"SQL Pivot 動態陳述式","slug":"SQL/2016-02-12","date":"2016-02-11T16:00:00.000Z","updated":"2016-11-27T02:33:00.949Z","comments":true,"path":"paper/2016/02/12/SQL/2016-02-12/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/02/12/SQL/2016-02-12/","excerpt":"","text":"很多報表需求在輸出時候常需要做欄位轉置,雖然,這動作可以在.Net做,也可以在T-SQL做,至於,兩者如何取其一,將必須視當時情境決定。 自從SQL2005後已經內建Pivot功能,SQL Pivot基本用法,不過,說真的用了MS SQL Pivot Function感覺還有點陽春,只能針對兩個欄位的其中一個欄位進行轉置,一個欄位固定,這樣往往不敷企業需求,在企業報表都是會有多個固定欄位而針對一個欄位做轉置,直接使用Pivot語法就會有點虛。因此,為了針對企業需求,可以動態指定轉置欄位且可以多個固定不轉置欄位,所以,需強化原本Pivot功能。 123456789101112131415161718192021222324252627create PROCEDURE [dbo].[SP_Pivot]( @SourceTable varchar(max), @Pivot_Fix_Column varchar(5000), @Pivot_Value_Aggregate varchar(10), @Pivot_Value_Column varchar(5000), @Pivot_Column_List varchar(5000)) AS BEGIN declare @columns varchar(max) declare @sql nvarchar(max) set @sql = N'set @columns = substring((select '', [''+convert(varchar,'+@Pivot_Column_List+')+'']'' from '+@SourceTable +' group by '+@Pivot_Column_List+' order by 1 for xml path('''')),2,8000)' execute sp_executesql @sql, N'@columns varchar(max) output', @columns=@columns output set @sql = N'SELECT * FROM (SELECT '+@Pivot_Fix_Column+','+@Pivot_Column_List+','+@Pivot_Value_Column+' from '+@SourceTable+') src PIVOT ('+@Pivot_Value_Aggregate+'('+@Pivot_Value_Column+') FOR '+@Pivot_Column_List+' IN ('+@columns+') ) pvt ORDER BY 1' execute sp_executesql @sql END 輸入參數說明 SourceTable(需要轉置的資料表或是資料語法) Pivot_Fix_Column(轉置後要呈現的欄位) Pivot_Value_Aggregate(轉置同時要用的運算,example:sum,max…etc) Pivot_Value_Column(對應到需要轉置欄位的value,only column) Pivot_Column_List(需轉置欄位,only column) 使用範例1EXEC dbo.Sp_dynamicpivot '(select a,b,day,Qty from tmpA) a',' a,b','sum','QTY','Day'","categories":[],"tags":[{"name":"T-SQL","slug":"T-SQL","permalink":"http://edwardkuo.imas.tw/tags/T-SQL/"}],"keywords":[]},{"title":"ASP.NET 強制設定開啟或是關閉相容性檢視","slug":"Web/2016-02-09","date":"2016-02-09T14:59:31.000Z","updated":"2016-11-27T02:43:30.046Z","comments":true,"path":"paper/2016/02/09/Web/2016-02-09/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/02/09/Web/2016-02-09/","excerpt":"","text":"通常網頁開發上,最怕是版型跑掉,因為,網頁系統上的UI版型跑掉是最麻煩一件事情,但是往往因為,目前網頁開發技術並未統一,且又有可能有舊版的系統在使用。因此,IE上面會有相容性檢視的功能讓新版IE可以再使用舊版的系統(大都是IE8年代以前開發的系統)的版型不會跑掉。 在企業內部一般來說,因為很多年代久遠系統,所以,可能預設會把相容性檢視打該,但是,若是今天自己開發網站是用像是HTML5 + CSS3開發可能這樣版型在設定相容性模式下就會跑掉,但是,不太大可能讓使用者取消這設定,畢竟除新系統之外,還有成千上萬就系統還是要能執行。因此,我們可以在Web.config加入下面這一段,關閉相容性檢視這網站。或是開啟相容性檢視這網站 關閉相容性檢視 12345678<system.webServer> <httpProtocol> <customHeaders> <clear /> <add name=\"X-UA-Compatible\" value=\"IE=Edge\" /> </customHeaders> </httpProtocol></system.webServer> 開啟相容性檢視 12345678<system.webServer> <httpProtocol> <customHeaders> <clear /> <add name=\"X-UA-Compatible\" value=\"IE=EmulateIE7\" /> </customHeaders> </httpProtocol></system.webServer> 以上兩段就可以透過自己系統定義IE瀏覽器要不要開關相容性檢視了","categories":[],"tags":[{"name":"ASP.NET","slug":"ASP-NET","permalink":"http://edwardkuo.imas.tw/tags/ASP-NET/"}],"keywords":[]},{"title":"建立中國Azure的CDN之心得","slug":"Azure/AzureChinaDNS","date":"2016-02-05T14:59:31.000Z","updated":"2017-05-29T13:01:42.699Z","comments":true,"path":"paper/2016/02/05/Azure/AzureChinaDNS/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/02/05/Azure/AzureChinaDNS/","excerpt":"","text":"建立Azure CDN其實並不難,但是建立中國Azure的CDN真的有一點麻煩。首先我們必須先瞭解中國的Azure CDN跟我們一般建立Azure CDN的差異點在那邊,在中國因為政策因素,所以,基本上他們的CDN是屬於“雜亂型的”,雜亂的定義就是,我認為他並非像一般Azure的CDN是由Microsoft去建置的CDN。在中國的Azure CDN是:“整合國內主流 CDN,又分多業務場景加速”方式進行,因此,在中國的Azure CDN是 “整合國內多家主流 CDN 服務,提供全面的靜態網頁加速,軟體安裝包、遊戲客戶端、應用程序、影音等大文件的下載分發,以及線上視訊網站、線上教育網站等以流媒體為主的視訊點播和直播等多種業務類型加速,滿足不同類型資源的分發需求;提供包含聯通、移動、電信等主流電信運營商,以及其他 ISP 運營商,全地區的全網覆蓋,根據網路實時狀況,通過負載均衡技術和智慧排程策略,將使用者請求分配到最優節點。” 換句話說就是去跟原本就有的CDN服務業者做整合性的搭配,大陸搭配的CDN業者主要是 <北京藍汛通信技術有限責任公司 http://cn.chinacache.com> ,雖然,官方說明業者的SLA是沒問題,但是,有時還是會遇到出問題地方,但是這部分就很難去查驗了,目前,最常遇到就是發生某些檔案有時候會發生http 400錯誤,但是,重新整理幾次就好了,再者,大陸的ISP業者相當複雜,若是剛好你的用戶的ISP業者對於CDN節點頻寬不好,基本上也會是有問題的,中國的CDN POP分佈 一開始以為這多場景意義不大,其實,每個場景都有它隱含的一些規則和缓存的機制在,若是你沒搞清楚這含義,就很可能造成你的CDN緩存異常,然後就必須砍掉CDN重建,以為重建CDN很快?不,設定完成很快,但是你還要等你的ICP證號被確認是沒有錯的,才算建立成功,這部分等待時間可以從幾小時到一天都是有的 -Web加速這邊主要是網站相關的檔案,例如css,js,html 或是圖片檔案這些,基本上這些檔案不要超過20MB,換句話說主要適合網頁的一些靜態檔案 -下載加速當時看到這選項,以為是可以讓自己檔案下載非常快速意思,但是不是,這主要是針對大型檔案,就是大於20MB的檔案做CDN,沒記錯如果檔案太小,似乎就無法起作用,這部分大都運用在安裝檔或是驅動程式之類的 -VOD加速VOD視訊點播加速服務主要針對線上音視訊點播提供加速服務 -即時資料流加速流媒體直播加速服務主要針對線上視音訊播提供加速服務,搞定好這些加速類型之後,就是設定原始網域類型 開始設定 基本可以從Web到媒體服務都可以 這邊設定並不困難,這邊的自訂網域一定要設定,不然無法完成,你可以先把自訂網域設定和ICP號碼設定好,就開始去建立CDN,建立完畢後,基本上就是等待了 驗證完畢後,就會提供一個CDN結點給你,基本上命名是xxxxx.yourdomainname.mschcdn.com,只要把這CDN端點到DNS設定CNAME就可以對應。如果以為這樣就表示完成,其實還沒有,必須再去所謂的CDN高級選項內去設定一些屬性 點下管理,就會出現CDN的管理介面 在這管理介面中,可以了解你目前CDN的缓存狀況,還有他跟源頭要了多少的資料過去,這除了$$外,也考慮到相對應的網路頻寬所造成的使用者體驗的等待時間。一般來說CDN,當你源頭檔案有做修改時候,但是,你在程式沒有做版本號的變更,基本上不會馬上抓到更新過的檔案,因為檔案還在源頭並未傳遞到CDN,這時候你可以透過這管理介面中的缓存刷新直接把檔案發佈到CDN,不過,這邊在使用上有一點小小問題就是,因為檔案要被散佈到各個CDN結點,所以,並不是每個節點被更新時間是即時同步,還是會有一點時間差,如果你是用缓存更新中的整個目錄更新,那等待時間可能就更長一點點 其中最重要的就是要到這邊去做設定一下,如果你的檔案都是Public基本比較重要設定就是『配置缓存規則』這邊的設定會影響到你CDN效能 這邊缓存的定義在於,當使用者透過CDN抓取檔案時候,檔案不在CDN節點時,會再回源頭去抓取檔案,把檔案放到CDN結點做缓存,如果時間到,舉例當檔案在CDN節點超過缓存的7天之後,沒有用戶再去取這個檔案,這個檔案就會在CDN上消失,除非下次有使用者再去抓取這個檔案,因此,這時間得設置就很重要,畢竟,當輸入與輸出的頻率高。這會導致更高的儲存和資料傳輸費用,因為需要的原始請求更多。為了降低發出原始請求的需求,允許 CDN 將檔案保留更長時間。 這樣若是遇到同一個檔案不斷異動時候,又可能會造成檔案不一致性,這就要看設計如何解決,此外,如果你有用到Cookie或是LocalStorage之類,建議把『允許忽略Cookie』功能打開,不然很容易出現檔案的504或是400錯誤,目前原因還不知道,所以我都是打開這設定 此外,一般來說我們在檔案加上時間標籤,例如aaa.js?v20151230,原則上就算不同檔案版本了,CDN因該會自動再去源頭抓一份檔案回來,但是,在測試時候,這部分建議是在建立好CDN節點後大概過一天,再去做這樣嘗試,不然依舊會發生檔案抓不到或是檔案還是舊的問題發生,而官方說法建議靜態檔案的更新還是更改檔名比較安全,例如 aaa1_04.js比較好 會有這些問題,我在猜想可能跟Azure整合到的CDN服務有相關,造成還是有些狀況會發生。建議如果你的檔案不是常常同一個檔案更新的,缓存時間是可以設定久一點,如果是同一個檔案常常更新,可以利用『缓存刷新』功能去更新那一個檔案,或是使用檔案加上時間標籤讓CDN抓取源頭檔案,不過,有時會發生一點意外就是。另外一點,如果使用『缓存刷新』是刷新整個目錄,就有可能發生你檔案消失或是抓不到狀況,但是大約過一兩個小時後,基本上都會正常了 看似簡單的CDN設定,其實還是充滿意外","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"使用XML Query一次新增多筆資料","slug":"Net/2016-02-01","date":"2016-02-01T14:59:31.000Z","updated":"2016-11-27T02:24:05.000Z","comments":true,"path":"paper/2016/02/01/Net/2016-02-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/02/01/Net/2016-02-01/","excerpt":"","text":"對於一次將多筆資料新增或是更新到同一個資料表,有很多種方法 利用While + insert into 指令 這種方式資料庫連線需要開開關關,是非常消耗效能的,除非是不得已情況下,不建議採用此方式進行 利用ADO.NET底層方式加上Data Table或是Data set方式 這種方式透過ADO.NET幫我們做掉這些步驟,但是,有時候卻因為太自動化,導致在需求會有不敷使用 XML Query方式 這種方式需要在AP端與DB端建立程式,感覺比較麻煩,不過,我覺得這樣在某方面的自由度卻也比較高 以第三種方式的簡易範例 產生XML資料 定義資料欄位 1string[] strColumn = new string[6] { \"C1\", \"C2\", \"C3\", \"C4\", \"C5\", \"C6\" }; 建立XML資料 12345678910111213141516171819202122string[] strValue;string strXMLData = string.Empty;System.IO.StringWriter ser = new System.IO.StringWriter();XmlTextWriter XTW = new XmlTextWriter(ser);XTW.WriteStartElement(\"Root\");//開始主節點for (int i = 0; i < strdata.Length; i++)//判斷有幾筆資料{ strValue = strdata[i].Split(','); XTW.WriteStartElement(\"Data\"); for (int j = 0; j < strColumn.Length; j++) { XTW.WriteStartElement(strColumn[j]); XTW.WriteString(strValue[j]); XTW.WriteEndElement(); } XTW.WriteEndElement(); } XTW.WriteEndElement(); ser.Flush(); ser.Close(); 用陣列格式傳入,所以要先用Splite取得每筆的各欄資料 1string[] strdata = new string[4] { \"01,A,11,2009-10-10,1,1\", \"02,B,11,2009-10-10,2,2\", \"03,C,11,2009-10-10,3,3\",\"04,D,11,2009-10-10,4,4\" }; XML資料轉型為String,做為傳入預存程序的參數 1strXMLData = ser.ToString(); 預存程序撰寫下列程式碼 宣告傳入參數格式為XML 1ALTER PROCEDURE [dbo].[SP_Change](@ALLBINChange XML) 取出@ALLBINChange內的XML資料,這部分依照資料庫需求取得必須的資料。把XML當作一個資料表來操作即可 1234567select WIS.Data.query('./C1').value('.','varchar(15)') as C1,WIS.Data.query('./C2').value('.','varchar(15)') as C2,WIS.Data.query('./C3').value('.','varchar(50)') as C3,WIS.Data.query('./C4').value('.','datetime') as C4,WIS.Data.query('./C5').value('.','int') as C5,WIS.Data.query('./C6').value('.','int') as C6from @ALLBINChange.nodes('/Root/Data') as root(Data) 更新資料為例 12345678910update dbo.BBBB set A1=a.C1,A2=a.C2,A3=a.C3,A4=a.C4from(select WIS.Data.query('./C1').value('.','varchar(15)') as C1,WIS.Data.query('./C2').value('.','varchar(15)') as C2,WIS.Data.query('./C3').value('.','varchar(50)') as C3,WIS.Data.query('./C4').value('.','datetime') as C4,WIS.Data.query('./C5').value('.','int') as C5,WIS.Data.query('./C6').value('.','int') as C6from @ALLBINChange.nodes('/Root/Data') as root(Data))as awhere ID=a.C1 這樣就可以將資料透過XML方式做一次性的更新或是新增到資料庫中","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"Azure Storage Blob的使用","slug":"Azure/2016-02-31","date":"2016-01-31T14:59:31.000Z","updated":"2016-11-27T02:35:21.693Z","comments":true,"path":"paper/2016/01/31/Azure/2016-02-31/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/01/31/Azure/2016-02-31/","excerpt":"","text":"熟知Azure Storage的好用,但是,一直苦無實例需要用到此服務,所以,通常是觀看而已,今天剛好遇到有此需求,就來嘗試使用這服務。 在使用之前必須了解目前Azure儲存體現有的種類: * Blob 儲存體 : 可儲存檔案資料。Blob 可以是任何類型的文字或二進位資料 * 資料表儲存體 : 可儲存結構化的資料集。資料表儲存體屬於 NoSQL 索引鍵屬性資料儲存,可允許快速開發和迅速存取大量資料 * 佇列儲存體針 : 對工作流程處理及雲端服務元件間的通訊。 * 檔案儲存體: Azure 虛擬機器和雲端服務可以透過掛接的共用,在應用程式元件之間共用檔案資料 這邊先用Blob儲存體來存放網站相關的靜態檔案,這是最常被使用的種類。不過,用檔案儲存體在具有結構性的檔案分類,似乎又會比較好管理。 先建立一個儲存體 點選快速建立後,會要求輸入名稱,存放位置和設定複寫 而複寫的選擇取決你的口袋深度,所以,建議評估實用性,若是,是屬於網頁中的靜態檔案,且後續又會開啟CDN服務,那麼是否需要用到高規格的複寫就見仁見智了 要使用的Blob儲存體之前須了解Blob本身結構,其結構如下: 我們可以在Container分別去建立相關的Blob,建議把放CSS檔案就放CSS資料夾,擺放產品相關就放置產品資料夾,這樣就可以開始上傳檔案了 開發上傳檔案程式 自行開發程式上傳檔案也是可以,必須先安裝Microsoft.WindowsAzure.Storage.dll,有了這元件之後,必須加入三個類別: Microsoft.WindowsAzure.Storage,Microsoft.WindowsAzure.Storage.Auth,Microsoft.WindowsAzure.Storage.Blob 設定連線到Storage連線字串 1value="DefaultEndpointsProtocol=https;AccountName={username};AccountKey={Key}" 其餘相關關於連線字串設定可以參考https://msdn.microsoft.com/library/azure/ee758697.aspx 設定好之後,就可以進行下面開發,只要三個步驟就可以將檔案上傳 A. 建立連線 B. 取得要上傳的Container名稱 C. 上傳檔案,並命名Blob名稱 下面案例是上傳多個檔案案例,用MVC方式來開發 View1234567891011121314<div class=\"configuration k-widget k-header\"> <span class=\"infoHead\">Information</span> </div><form method=\"post\" action='@Url.Action(\"Submit\")' style=\"width:45%\"> <div class=\"demo-section\"> @(Html.Kendo().Upload() .Name(\"files\") ) <p> <input type=\"submit\" value=\"Submit\" class=\"k-button\" /> </p> </div></form> Controller1234567891011121314151617181920212223public ActionResult Submit(IEnumerable<HttpPostedFileBase> files){ if (files != null) { GetFileInfo(files); } return View();}private void GetFileInfo(IEnumerable<HttpPostedFileBase> files){ string connection = \"DefaultEndpointsProtocol=https;AccountName=XXX;AccountKey=XXX\" CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connection); CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = blobClient.GetContainerReference(\"css\"); foreach (var s in files) { CloudBlockBlob blockBlob = container.GetBlockBlobReference(s.FileName); blockBlob.UploadFromStream(s.InputStream); }} 就可以上傳檔案了,上傳完畢後,去查看Storage中的檔案,確實也上傳成功了,不過,上傳的時間似乎有一點問題,主要是因為時區的問題上面時區是以UTC為主的。","categories":[],"tags":[{"name":"Azure","slug":"Azure","permalink":"http://edwardkuo.imas.tw/tags/Azure/"}],"keywords":[]},{"title":"用Compass產生多圖檔合併並讓CSS對應位置","slug":"Web/2016-01-23","date":"2016-01-23T04:59:31.000Z","updated":"2016-11-29T08:50:39.134Z","comments":true,"path":"paper/2016/01/23/Web/2016-01-23/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/01/23/Web/2016-01-23/","excerpt":"","text":"網頁開發中常常會使用到很多小icon或是小圖,一般來說可以直接抓取網路上的font-awesome套件就可以,不過,若是今天icon或是小圖是自己設計師開發或是具有產品相關識別的話,就不能用font awesome代替了,以前的做法就是每個有需要icon地方,加上圖檔的link1<img src='http://XXXX.jpg></img> 就可以把圖檔插入到網頁中,或是在某個標籤做為背景圖放入,基本上無太大問題,但是,一旦網頁的圖檔多的時候,使用者端就必須發出很多request下載這圖檔,在效能就會慢一點,另外,就是要管理這些圖檔也不是那樣方便。 因此,在這情況下可以用雪碧(Sprite)方式,將多個圖檔合成一個檔案,這樣不僅方便,且request量也相對減少,速度也會稍快。通常這樣做法,在沒有compass之前,也是可以用photoshop去合併圖檔產生,然後在去CSS刻上相對應的圖片位置,這方式相對費工。這時候如果透過Compass產生就很簡單,也會自動在Css內mapping相對應的圖片 在使用compass之前,必須先確定好你的環境是否已經可以支援compass了,一開始,我們先設定要產生雪碧的compass程式123$Navicon-layout: 'smart';$Navicon-spacing: 5px;$Navicon: sprite-map(\"Navicon/*.png\"); 其中,Layout部分可以分為Vertical,Horizontal,Diagonal,Smart這四種Diagonal是橫向排圖,所產生的圖檔較大,我習慣用smart讓它自己決定產生的Sprint方式,Spacing主要是每個圖檔的間隔距離要多遠。 Sprite-map就是對應到你要合併成一個Spring的資料夾位置,這樣就可以將所有圖檔合併成下面這個樣子 在上面變數中可以發現都是用$Navicon開頭,Navicon主要是資料夾名稱,務必要跟資料夾名稱一樣,然後再加入下面兩行12@import "Navicon/*.png";@include all-Navicon-sprites(true); 若是後續不需要知道Sprite-map的話,關於Sprite-map這一段可以省略,直接加入@import “Navicon/*.png 這一行就可以了,就能直接去指定的資料夾中抓取所有圖檔進行合併,之後使用all-Navicon-sprites指令進行圖檔合併與產生對應的CSS,這個指令中間的Navicon也請務必和合併的資料夾名稱一樣,有設定true在CSS中就會抓取圖檔原始尺寸大小並在Css設定指定的大小這樣完畢後,就會產生下面的CSS 很快產生合併的圖檔,CSS也會對應好,然後,你只要在想要這圖檔的HTML中加入這樣語法1<button type=\"button\" class=\"Navicon-contact_b Active \"> </button> 或是你要跟font-awesome一樣,設定<i class=’XXXX’></i>,這樣也是可以的","categories":[],"tags":[{"name":"Front-End","slug":"Front-End","permalink":"http://edwardkuo.imas.tw/tags/Front-End/"}],"keywords":[]},{"title":"C# 使用For和Foreach讀取Datatable每筆資料對照寫法","slug":"Net/2016-01-21","date":"2016-01-21T14:59:31.000Z","updated":"2016-11-27T02:27:09.710Z","comments":true,"path":"paper/2016/01/21/Net/2016-01-21/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/01/21/Net/2016-01-21/","excerpt":"","text":"早期各種程式語法針對迴圈寫法,總是用for來實作,這東西真是好用且還歷久不衰,不過,到了開始有Foreach之後,很多迴圈寫法都會改用Foreach實作,畢竟,Foreach算是好物之一。但是,因為長時間習慣用for語法,要一時改變還真不簡單,所以,趁現在趕快紀錄一下避免忘記 採用For迴圈方式讀Datatable,其中邏輯是要判斷不是第一筆要處理的相關邏輯程式12345678910111213141516171819202122232425for (int i = 0; i < _dt.Rows.Count; i++){ if (strReportID != _dt.Rows[i][\"s\"].ToString()) { if (i != 0) { dr[\"R\"] = sb.ToString(); dt.Rows.Add(dr); sb = new StringBuilder(); dr = dt.NewRow(); } strReportID = _dt.Rows[i][\"s\"].ToString(); dr[\"ss\"] = _dt.Rows[i][\"ss\"].ToString(); sb.Append(_dt.Rows[i][\"Name\"] + \"<br />\"); } else { sb.Append(_dt.Rows[i][\"Name\"] + \"<br />\"); }}dr[\"R\"] = sb.ToString();dt.Rows.Add(dr); 2.用Foreach寫法後,原本判斷是否為第一筆的邏輯,就要改用boolen方式去判斷。且原本是 _dt.Rows[i]的方式就可以省略,改用Datarow物件代替12345678910111213141516171819202122232425bool bFirst = false;foreach (DataRow od in _dt.Rows){ if (strReportID != od[\"s\"].ToString()) { if(!bFirst) { dr[\"R\"] = sb.ToString(); dt.Rows.Add(dr); sb = new StringBuilder(); dr = dt.NewRow(); bFirst = true; } strReportID = od[\"s\"].ToString(); dr[\"ss\"] = od[\"ss\"].ToString(); sb.Append(od[\"Name\"] + \"<br />\"); } else { sb.Append(od[\"Name\"] + \"<br />\"); } }dr[\"R\"] = sb.ToString();dt.Rows.Add(dr);","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"透過HttpWebRequest取得網頁內容","slug":"Net/2016-01-12","date":"2016-01-12T14:59:31.000Z","updated":"2016-11-27T02:25:40.000Z","comments":true,"path":"paper/2016/01/12/Net/2016-01-12/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/01/12/Net/2016-01-12/","excerpt":"","text":"資料來源取得除了讀取DB內的資訊外,有時候也需要爬網頁的資訊取得,畢竟,有些資料不屬於自己控管,就必須透過這樣方式取得資料。 因此,在C#中可以透過HttpWebRequest方式去獲取網頁資料,再將資訊分析出來,取得屬於自己所要的資訊。大多數的網頁,都可以透過HTTP獲取,所以,透過HttpWebRequest提供WebRequest類別的HTTP 特定實作方式 使用HttpWebRequest,我們需要先初始化一個WebRequest類別,MSDN說明如下: WebRequest 是從網際網路存取資料的 .NET Framework 要求/回應模型的 abstract 基底類別。 使用要求/回應模型的應用程式可以用不驗證通訊協定 (Protocol) 的方式,從網際網路要求資料,其中應用程式和 WebRequest 類別的執行個體 (Instance) 一起作用,而特定通訊協定的子代 (Descendant) 類別會完成要求的細節。 創建WebRequest物件 創建一個WebRequest物件 1WebRequest myWebRequest = WebRequest.Create(\"Http://google.com\"); 設定呼叫時候的Timeout時間,這邊時間點是以毫秒為單位 1myWebRequest.Timeout=10000; 在公司或是需要認證的才有辦法獲取的網頁地方,需要增加認證的帳號密碼與Domain Name 1myWebRequest.Credentials = new NetworkCredential(\"Name\", \"PWD\", \"Domain Name\"); 若是需要透過proxy,也須設定proxy。在proxy設定中,我們可以設定proxy跟不需要透過proxy的IP List或是host name,或是在local端判定是否需要通過Proxy 1myWebRequest.Proxy = new WebProxy(new Uri(\"http://proxy.hinet.net:8080\"), true, strByPassIP); strByPassIP是屬於陣列型態。其設定如下,主要針對192.168.XX.XX及172.17.XX.XX網段不需要走Proxy 1string[] strByPass = new string[] { @\"192.\\.168\\..*\", @\"172\\.17\\..*\" }; 若是指定IP則方式如下: 1string[] strByPass = new string[] { \"192.1.1.1\", \"192.2.2.2\" }; 基於安全性考量,有些Proxy也會需要指定帳號密碼與Domain Name(公司內部),此時也需要設定通過Proxy之帳號密碼 1myWebRequest.Proxy.Credentials = new NetworkCredential(\"Name\", \"PWD\", \"Domain Name\"); 以上簡單幾個步驟就可以設定好WebRequest物件相關屬性完整的Code如下:123456789internal static WebRequest CreateWebRequest(){ WebRequest myWebRequest = WebRequest.Create(\"Http://google.com\"); myWebRequest.Timeout=10000; myWebRequest.Credentials = new NetworkCredential(\"Name\", \"PWD\", \"Domain Name\"); myWebRequest.Proxy = new WebProxy(new Uri(\"http://proxy.hinet.net:8080\"), true, strByPassIP); myWebRequest.Proxy.Credentials = new NetworkCredential(\"Name\", \"PWD\", \"Domain Name\"); return myWebRequest } 設定HttpWebRequest相關屬性 再來就是定義HttpWebRequest取得網頁字串相關方式1HttpWebRequest myHttpWebRequest = (HttpWebRequest)(CreateWebRequest(\"Http://google.com\")); 設定Timeout時間,這邊時間點是以毫秒為單位 1myHttpWebRequest.Timeout =10000 設定取得網頁方式 1myHttpWebRequest.Method=\"GET\" 設定用戶端瀏覽器的原始使用者代理字串 1myHttpWebRequest.UserAgent=\"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows NT 5.2; Windows NT 6.0; Windows NT 6.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; MS-RTC LM 8; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 4.0C; .NET CLR 4.0E)\" 以上屬性設定好之後,透過WebResponse物件,取得回傳的response資訊1WebResponse myWebResponse = myHttpWebRequest.GetResponse() 雖然,網頁都是文字型態,抓取網頁時還是必須要用資料流方式取的相關資訊。因此,我們需要透過GetResponseStream接收傳回來的網際網路資源的資料流,若是只單純當作字串接收,將會出現錯誤。1234567using (Stream myStream = myWebResponse.GetResponseStream()){ using (StreamReader myStreamReader = new StreamReader(myStream) { string strHtml = myStreamReader.ReadToEnd(); } } 以上方式將可以取得網頁內容回傳的資訊。 完整的Code如下: 123456789101112131415string strHtml = string.Empty;HttpWebRequest myHttpWebRequest = (HttpWebRequest)(CreateWebRequest(_strUrl));myHttpWebRequest.Timeout =10000;myHttpWebRequest.Method=\"GET\";myHttpWebRequest.UserAgent=\"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows NT 5.2; Windows NT 6.0; Windows NT 6.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; MS-RTC LM 8; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 4.0C; .NET CLR 4.0E)\";using (WebResponse myWebResponse = myHttpWebRequest.GetResponse()){ using (Stream myStream = myWebResponse.GetResponseStream()) { using (StreamReader myStreamReader = new StreamReader(myStream) { strHtml = myStreamReader.ReadToEnd(); } }}","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"用C#做查詢,建立及刪除檔案目錄功能","slug":"Net/2016-01-11","date":"2016-01-11T14:59:31.000Z","updated":"2016-11-27T02:24:33.000Z","comments":true,"path":"paper/2016/01/11/Net/2016-01-11/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/01/11/Net/2016-01-11/","excerpt":"","text":"常常會用到對作業系統進行建立資料夾或是刪除資料動作,所謂,程式寫完超過三個月就會忘記,真的是一點都沒錯。為了避免每次自己都還要去查一下MSDN來做回憶。這邊把一些相關基礎做法做一個筆記,日後也可以比較容易查閱 首先需要加入這個using System.IONamespace 判斷目錄是否存在 可以使用DirectoryInfo這個Class進行處理。這案例是我們判斷在C槽下是否有存在Temp目錄,用exists屬性來判斷,路徑的表示法C#與VB有所不同,請自行查閱。 DirectoryInfo : 公開建立、移動和全面列舉目錄和子目錄的執行個體 (Instance)方法 12345678910string strFolderPath = @\"C:\\temp\\\";DirectoryInfo DIFO = new DirectoryInfo(strFolderPath);if (DIFO.Exists){ Console.WriteLine(\"Exist\");}else{ Console.WriteLine(\"No Exist\");} 在C槽已經存在Temp目錄所以或出現Exist,其中路徑無論是寫 @”C:\\temp\\” 或是 @”C:\\temp” 其結果都是相同的 建立目錄 使用Create的方法來建立,若是該目錄已經存在則不會有所動作123string strFolderPath = @\"C:\\temp\\test1\";DirectoryInfo DIFO = new DirectoryInfo(strFolderPath);DIFO.Create(); 若是我們要在該目錄下,不斷建立該目錄的子目錄,不需要重複寫上面那一段Code然後把路徑置換,只需要使用CreateSubdirectory方法就可以1234string strFolderPath = @\"C:\\temp\\test1\\\";DirectoryInfo DIFO = new DirectoryInfo(strFolderPath);DirectoryInfo ss = DIFO.CreateSubdirectory(\"GG\");DirectoryInfo sq = ss.CreateSubdirectory(\"FF\"); 這樣就可以在test1目錄下面建立GG目錄,在GG目錄下建立FF目錄了 刪除目錄 使用Delete的方法來刪除123string strFolderPath = @\"C:\\temp\\test1\\\";DirectoryInfo DIFO = new DirectoryInfo(strFolderPath);DIFO.Delete(); 不過,這邊有一個重點,若是該目錄不是空的,執行這樣語法會出現錯誤,早期的作法可能需要將資料目錄先清空再去刪除,不過,現在已經不需要這樣麻煩,只需要在Delete中傳入,是否要一併刪除該資料內所有檔案或是目錄就可以,True是表示要刪除該資料夾下所有資料,False則反之。123string strFolderPath = @\"C:\\temp\\test1\\\";DirectoryInfo DIFO = new DirectoryInfo(strFolderPath);DIFO.Delete(true); 補充一下,取得該資料夾所有檔案的方式,藉由FileInfo取檔案名稱1234foreach (FileInfo di in DIFO.GetFiles()){ Console.WriteLine(di.FullName);} 若是找到目錄就移除該目錄,並重新建立目錄方式12345678910string strFolderPath = @\"C:\\temp\\\";DirectoryInfo DIFO = new DirectoryInfo(strFolderPath); if (DIFO.Exists){ DIFO.Delete(true);}else{ DIFO.Create(); }","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"顯示IIS所有站台列表","slug":"Net/2016-01-04","date":"2016-01-04T14:59:31.000Z","updated":"2016-11-29T12:16:47.423Z","comments":true,"path":"paper/2016/01/04/Net/2016-01-04/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/01/04/Net/2016-01-04/","excerpt":"","text":"如何讓人員在不登入IIS主機情況下,可以遠端了解IIS主機中自己的Web Site狀況以及還可以有時候能遠端重啟自己的Application Pool。 首先必須要確認IIS中有幾個站台(非一個站台下的虛擬目錄的站台),以下圖為例共有兩個站台,而在Default Web Site又有兩個網站 我們可以使用DirectoryEntry類別取得資訊。 DirectoryEntry類別:封裝 Active Directory 網域服務階層架構中的節點或物件。12345678DirectoryEntry root = new DirectoryEntry(@\"IIS://HostName/W3SVC\"); foreach (DirectoryEntry ww in root.Children) { if (ww.SchemaClassName == \"IIsWebServer\") { Response.Write(ww.Name + \"<br>\"); } } 其中ww.Name只會回傳Web Site之ID,並非真正網站名稱,若是要顯示Web Site名稱,還要加上ww.Properties[“ServerComment”].Value.ToString()就可以顯示名稱 取得網站節點後,再取得網站下的虛擬目錄名稱或是Web Stie12345DirectoryEntry root2 = new DirectoryEntry(string.Format(@\"IIS://HostName/W3SVC/{0}/root\", strID));foreach (DirectoryEntry ss in root2.Children){ Response.Write( ss.Name + \"<br>\");} 就可以取得下面所有虛擬目錄的站台 若是在管理上,我們又想知道每個虛擬目錄對應的Application Pool Name是甚麼時候,可以補上ss.Properties[“AppPoolId”].Value.ToString(),就可以取得每個站台對應的Pool Name。有了Application Pool Name就可以進行遠端管理,相關作法下一篇再說明 完整程式碼如下:12345678910111213141516171819202122private void ListWebSite(){ DirectoryEntry root = new DirectoryEntry(@\"IIS://JAIGI-PC/W3SVC\"); foreach (DirectoryEntry ww in root.Children) { if (ww.SchemaClassName == \"IIsWebServer\") { Response.Write(ww.Name + \":\"+ww.Properties[\"ServerComment\"].Value.ToString()+\"<br>\"); Response.Write(\"<br>\"); ListWeb(ww.Name); } }}private void ListWeb(string strID){ DirectoryEntry root2 = new DirectoryEntry(string.Format(@\"IIS://JAIGI-PC/W3SVC/{0}/root\", strID)); foreach (DirectoryEntry ss in root2.Children) { Response.Write( ss.Name + \":\"+ss.Properties[\"AppPoolId\"].Value.ToString()+\"<br>\"); }}","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]},{"title":"C#數值轉換整理","slug":"Net/2016-01-01","date":"2016-01-01T15:59:31.000Z","updated":"2016-11-27T02:23:45.000Z","comments":true,"path":"paper/2016/01/01/Net/2016-01-01/","link":"","permalink":"http://edwardkuo.imas.tw/paper/2016/01/01/Net/2016-01-01/","excerpt":"","text":"常常需要撰寫對資料中的數值進行資料轉換來符合規格上的需求,如:10進位轉成16進位,10進位轉ASCII…等等。這邊把常用的一些數值轉換語法,像是10進位轉二進位,10進位轉16進位…等,在此做一下整理,避免臨時有需要使用時,卻一時無法想起怎樣使用。 10進位轉2進位 12345int d = 3;//轉換資料string str = Convert.ToString(d, 2);//補足四碼str = str.PadLeft(4,'0'); 10進位轉16進位 123int dint=11//轉換16進位string strHex= String.Format(\"{0:X}\", dint); 16進位轉10進位 1234567891011121314151617string s2=\"AB\"//轉換10進位int j = 0;int result = 0;for (int i = 0; i < s2.Length; i++){ result = result * 16; j = s2[i] - 48; if (j < 10) { result = result + j; } else { result = result + j - 39; }} 或是1Convert.ToInt32(\"100\", 16) 10進位轉ASCII 123int t = 44;//資料轉換string s = Convert.ToString((char)t); ASCII轉10進位 1234string str = \",\";//資料轉換byte[] inputBytes =null;inputBytes = Encoding.ASCII.GetBytes(str); 16進位轉ASCII 這邊做法與上述轉換相同,只是將兩道程序複合運作,先執行16進位轉10進位,再做10進位轉ASCII ASCII轉16進位 這邊做法與上述轉換相同,只是將兩道程序複合運作,先執行10進位轉ASCII,再做10進位轉16進位","categories":[],"tags":[{"name":"C#","slug":"C","permalink":"http://edwardkuo.imas.tw/tags/C/"}],"keywords":[]}]}