Tag: Hugo
Posts
Hugo - Build and Deploy With GitHub Actions
要使用 GitHub Actions 建置並部署 Hugo 到 GitHub Pages,先要切到 GitHub Pages Repository 下的 Settings/Pages 頁面,在 Build and deployment 的 Source 這邊選用 GitHub Actions。
搜尋使用 Hugo GitHub Actions。
這邊會帶出 Hugo GitHub Actions 的 Workflows 設定檔,該設定檔給的是用 master branch 去做設定的內容,預設也是存放到 master branch。如果是 master branch 合用可直接存檔,不合用也只能自行修改上傳到 git。
設定完後在 Actions 左半邊就會看到剛加的 Workflows
切到剛加的 Workflows,右側可選取 Branch 運行 Workflow。
運行後會看到列表產生了對應的建置與部屬的動作。
點進去可以看到建置與部屬動作的細節。
這邊要特別注意,若是 Hugo GitHub Actions 當初設定的不為 master branch,需在 Settings/Environments 這邊設定 github-pages。
將指定的 branch 加入允許部署 GitHub Pages。
不然在 Workflows 建置與部屬時會看到下面這樣的失敗畫面。
read morePosts
Hugo - Add Content
Hugo 站台建立完後可以開始為站台加入文章,透過 Hugo 的 new content 命令,帶入文章檔名建立 Hugo 文章。
hugo new content posts/[postfilename].md 開啟建立的 Hugo 文章檔案進行文章的撰寫。
vim content/posts/[postfilename].md 文章撰寫完成可透過 Hugo 的 server 命令,帶入 –buildDrafts 或 -D 參數啟動 Hugo 站台,表示文章在草稿階段也要呈現。
hugo server --buildDrafts hugo server -D 透過瀏覽器瀏覽 http://localhost:1313/ 即可看到 Hugo 站台運行後的樣子,Hugo 站台內會有剛撰寫的 Hugo 文章。
Link Quick start | Hugo
read morePosts
Hugo - Create a Site
Hugo 裝完後,首先需要先建立站台,透過 Hugo 的 new site 命令,帶入站台的名稱。
hugo new site [sitename] 建立完後進入站台目錄。
cd [sitename] 初始化 git。
git init 透過 git submodule 將 Hugo 的 ananke theme 加入站台。
git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke 修改 hugo.toml 將 Hugo 站台套用 ananke theme。
echo "theme = 'ananke'" >> hugo.toml 本地將 Hugo 站台運行起來。
hugo server 透過瀏覽器瀏覽 http://localhost:1313/ 即可看到 Hugo 站台運行後的樣子。
Link Quick start | Hugo
read morePosts
Hugo - Install Hugo on MacOS
Hugo 在 MacOS 下可直接透過 Homebrew 安裝。
brew install hugo 安裝後可調用 Hugo 命令帶入 version 參數查閱 Hugo 版本,確認 Hugo 的安裝是否正確。
hugo version 後續 Hugo 命令使用有問題可調用 Hugo 命令帶入 –help 參數查詢 Hugo 命令的使用方式。
hugo --help Link macOS | Hugo
read moreTag: HomeBrew
Posts
Hugo - Install Hugo on MacOS
Hugo 在 MacOS 下可直接透過 Homebrew 安裝。
brew install hugo 安裝後可調用 Hugo 命令帶入 version 參數查閱 Hugo 版本,確認 Hugo 的安裝是否正確。
hugo version 後續 Hugo 命令使用有問題可調用 Hugo 命令帶入 –help 參數查詢 Hugo 命令的使用方式。
hugo --help Link macOS | Hugo
read morePosts
'HomeBrew - Error: homebrew-core is a shallow clone.'
使用 HomeBrew 如果出現 “Error: homebrew-core is a shallow clone.” 錯誤。
可照著命令列的提示帶入。
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow 即可修復該問題。
read morePosts
Percona Toolkit - Install with HomeBrew
如要在 MAC 上使用 Percona Toolkit,可透過 HomeBrew 進行安裝。
brew install percona-toolkit 安裝後可調用 Percona Toolkit 命令查驗,,確認安裝無誤。
pt-variable-advisor --version
read morePosts
jq - Install with HomeBrew
如要在 MAC 上使用 jq,可透過 HomeBrew 進行安裝。
brew install jq 安裝後可試著查驗版本確認安裝無誤。
jq --version
read morePosts
Vault - Install with HomeBrew
如要在 MAC 上使用 Vault,可透過 HomeBrew 進行 Vault 的安裝。
brew install vault 安裝後調用 Vault 命令並帶入 –version 參數,若安裝正常應可查驗到安裝的 Vault 版本。
vault --version
read morePosts
.NET Core - Update .NET Core SDK with HomeBrew
用 HomeBrew 安裝的 .NET core SDK,可直接用 HomeBrew 進行更新。
像是筆者電腦中的 .NET Core SDK 是 3.0 的版本。
dotnet --version 要升級到最新版的 .NET core SDK 3.1,可直接透過 HomeBrew cask reinstall 命令去更新 dotnet-sdk 套件。
brew cask reinstall dotnet-sdk .NET core SDK 就會被升到 3.1 最新版。
dotnet --version
read morePosts
MongoDB Compass - Install with Homebrew
要使用 Homebrew 安裝 MongoDB Compass,可以調用如下命令:
brew cask install mongodb-compass 安裝完可以透過應用程式這邊啟動 MongoDB Compass。
read morePosts
Robo 3T - Install with HomeBrew
使用 HomeBrew 安裝 Robo 3T,可透過 cask 安裝 robo-3t 套件。
brew cask install robo-3t 安裝完透過啟動台即可啟動 Robo 3T。
read morePosts
LuaRocks - Install with HomeBrew
要使用 HomeBrew 安裝 LuaRocks,可輸入下列命令。
brew install luarocks 安裝完可實際調用命令做過確認。
luarocks --version
read morePosts
Fork - Install with HomeBrew
要使用 HomeBrew 安裝 Fork,可透過 brew cask 的 Install 命令安裝 Fork 套件。
brew cask install fork 安裝完後可透過 Application 開啟安裝的套件。
read morePosts
tree - Install with HomeBrew
在 Mac 下可以透過 HomeBrew 安裝 tree 命令。
brew install tree 可能會得到像上面這樣的錯誤,這時調用指示的命令。
再次嘗試安裝即可。
安裝完就可以正常使用 tree 命令了。
read morePosts
BloomRPC - Install with Homebrew
要使用 Homebrew 安裝 BloomRPC,可以調用如下命令:
brew cask install bloomrpc 安裝完就可以在應用程式這邊看到 BloomRPC。
read morePosts
.NET Core - Install .NET Core SDK with HomeBrew
要使用 HomeBrew 安裝 .NET SDK,可以使用 brew cask 安裝 dotnet-sdk 套件。
brew cask install dotnet-sdk 安裝完後可開新的 Terminal 調用命令查詢 .NET Core SDK 版本試試,安裝成功的話應可正常看到 .NET Core SDK 的版本。
dotnet --version
read moreTag: Gauth
Posts
gauth - Host Google authenticator server
要起 gauth 服務供二階段認證使用,可將 gauth 程式碼下載下來。
git clone https://github.com/gbraadnl/gauth.git 切換到 gauth 程式碼目錄。
cd gauth 安裝 gauth 所需的 npm 套件。
npm install 然後透過 node 將 gauth 服務起起來。
node server 服務起來後用瀏覽器連至 8080 port,即可開始使用 gauth 來做二階段認證。
http://localhost:8080/ Link GitHub - gbraad/gauth
read moreTag: NuGet
Posts
NuGet - Create and publish a package with dotnet CLI
要建立 NuGet 套件,需先確認專案檔內有設計 NuGet 套件所需之資訊,像是套件識別碼、版本、作者、公司等。
<PackageId>AppLogger</PackageId> <Version>1.0.0</Version> <Authors>your_name</Authors> <Company>your_company</Company> 然後可用 dotnet pack 命令將套件打包。
dotnet pack 或是在專案檔內加設定 GeneratePackageOnBuild,讓專案在建置時自動產生。
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> 然後確定 NuGet 帳號已註冊且取得 API key。
再調用 dotnet nuget push,帶入 NuGet 套件檔的位置及 NuGet API key。
dotnet nuget push $package -k $key -s https://api.nuget.org/v3/index.json NuGet 套件即會被上傳至 NuGet server 上。
Link 使用 dotnet CLI 建立及發佈 NuGet 套件 | Microsoft Docs
read morePosts
NuGet - Can't find online packages
使用 NuGet 時,若碰到查詢線上的 NuGet 套件一直在 Loding,且透過 ‘Package Manager Console’ 下命令也無法進行套件的安裝的話。
可嘗試將 ‘%AppData%\NuGet\NuGet.config’ 刪除。
並將 Visual Studio 重啟,沒意外的話應該就會恢復正常了。
Link visual studio - Manage NugetPackage for Solution can’t find any online packages - Stack Overflow
read morePosts
NuGet - Setting up a private NuGet server
要架設一台私人的 NuGet Server,我們可以先在 Visual Studio 上開啟一個空的網頁專案。
{% img /images/posts/CreatePrivateNuGetServer/1.png %}
接著透過 NuGet 安裝 NuGet Server
{% img /images/posts/CreatePrivateNuGetServer/2.png %}
這樣一個 NuGet Server 網站就已經準備完成了,直接將之在 Visual Studio 上運行起來看看,應該可以看到 NuGet Server 實際運行起來的樣子。這邊會有一個精簡的頁面告知 NuGet Server 正在運行,並提供在 Visual Studio 上要用來設定的網址,以及怎樣發送 NuGet 套件上 NuGet Server。
{% img /images/posts/CreatePrivateNuGetServer/3.png %}
在 Visual Studio 初步的測試沒問題的話,準備將整個網站部署到 IIS 上面
{% img /images/posts/CreatePrivateNuGetServer/4.png %}
{% img /images/posts/CreatePrivateNuGetServer/5.png %}
{% img /images/posts/CreatePrivateNuGetServer/6.png %}
{% img /images/posts/CreatePrivateNuGetServer/7.png %}
記得 IIS Website 的 Application pool 這邊要設定為使用 .
read morePosts
NuGet - Reinstalling Packages
NuGet 在2.7版後開始支援重新安裝套件的功能,當碰到專案中的 NuGet 套件參考路徑錯誤,或是當專案的 .Net Framework 版本用的與 NuGet 套件用的不符時特別適用。
使用時先開啟 Package Manager Console 工具視窗,在裡面輸入命令:
Update-Package -reinstall NuGet 就會幫你重新加入所有使用到的套件。
若要指定重新安裝特定套件,可在命令後面帶上 Package
Update-Package -reinstall [Package Name] 像是要指定重新安裝 Log4Net 就可以輸入命令:
Update-Package -reinstall Log4Net {% img /images/posts/NuGetReinstallingPackages/1.png %}
若是要指定重裝特定專案內的套件,可像下面這樣加入 Project 參數,並帶上專案的名稱:
Update-Package -reinstall [Package Name] -project [Project Name] 若是要升級專案套件,用排除相依套件的方式下去重新安裝,可加入 IgnoreDependencice 參數:
Update-Package -reinstall [Package Name] -IgnoreDependencice Link Reinstalling Packages and its Pitfalls
read morePosts
NuGet - Local cache source
在安裝 NuGet 套件時,NuGet 會將使用到的 Package 存放起來以備後續重覆安裝時使用。存放的套件若有需要,可開啟 Visual Studio 的 Options 對話框,切換到 Package Manager 下的 General 頁籤,進行 Package 的清除或是瀏覽。
{% img /images/posts/NuGetLocalCacheSource/1.png %}
點選 Browse... 按鈕,可以查看 NuGet 幫我們快取了哪些 NuGet 套件。
{% img /images/posts/NuGetLocalCacheSource/2.png %}
這邊我們將該目錄位置複製下來,再次回到 Options 對話框。這次切到 Package Manager 下的 Package Sources 頁籤,在這邊添加一個 Source 。Source 位置指到我們剛剛所複製的位置,也就是 NuGet 套件快取所存放的位置。
{% img /images/posts/NuGetLocalCacheSource/3.png %}
設定好後按下 OK 按鈕將 Options 對話框關閉。接著開啟 Manage NuGet Packages 對話框,左側 Source選用剛剛我們所新加的 Source ,我們可以看到所有快取的 NuGet 套件,這代表著我們可以在此使用快取的 NuGet 套件進行安裝,即使此時網路無法連至 NuGet Server。
{% img /images/posts/NuGetLocalCacheSource/4.
read morePosts
NuGet - Package restore
使用 NuGet 安裝套件,使用到的 Nuget 套件資訊會被記載在 packages.config 檔案內,所以這些 Nuget 套件是可以被重新安裝復原的。因此一般在上版控時,會習慣性將這些套件排除 Commit ,待從版控 Pull 下來時再行 Nuget 套件的復原。
要做 Nuget 套件的復原,以前我們會在 Visual Studio 的方案上按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中,按下 Enable NuGet Package Restore 這個滑鼠右鍵選單選項。點選下去,會針對專案檔做些修改,並產生一個名為 .nuget 的方案目錄,裡面會有 Nuget.config、Nuget.target、以及 Nuget.exe 這幾個檔案,此時再次建置就會將遺失的 Nuget 套件復原。
{% img /images/posts/RestoreNugetPackage/1.png %}
這邊這個動作產生的 Nuget.config 內容會像下面這樣 該設定會告知一些版控系統(如 TFS)要對 Nuget 套件進行忽略的動作。
不過這是舊的設定方式,若使用新版,不用做任何動作,系統就會自動處理還原的動作。 預設在 Options 視窗這邊會將 Allow NuGet to download missing packages 以及 Automatically check for missing packages during build in Visual Studio 這兩個選項勾起,建置時會自動將遺失的 Nuget 套件復原。
{% img /images/posts/RestoreNugetPackage/2.
read moreTag: MongoDB
Posts
MongoDB - Creating a MongoDB replica set in single Docker container
透過 Docker 去起 MongoDB replica set,多半網路上的做法都是用多個容器去做,這邊筆者考量測試與開發上的便利性,試著用一個容器去起 MongoDB replica set。
Docker compose 檔如下:
version: '3' services: mongo: image: mongo:4.2.2 container_name: mongo ports: - "27017:27017" - "27027:27027" - "27037:27037" volumes: - ./mongodb/data:/mongodb/data - ./mongodb/log:/mongodb/log - ./mongodb/mongod.yml:/mongodb/mongod.yml environment: # provide your credentials here - MONGO_INITDB_ROOT_USERNAME=root - MONGO_INITDB_ROOT_PASSWORD=pass.123 command: sh -c ' mkdir -p /mongodb/data/db1 /mongodb/data/db2 /mongodb/data/db3 /mongodb/log/db1 /mongodb/log/db2 /mongodb/log/db3 && mongod --config /mongodb/mongod.yml --port 27017 --dbpath /mongodb/data/db1 --logpath /mongodb/log/db1/mongod.log && mongod --config /mongodb/mongod.yml --port 27027 --dbpath /mongodb/data/db2 --logpath /mongodb/log/db2/mongod.
read morePosts
MongoDB - Creating a MongoDB replica set using Docker
要用 Docker 測試 MongoDB replica set 我們要先建立 Docker network。
docker network ls docker network create mongo-cluster docker network ls 然後起第一個 MongoDB 的 Docker 容器,設定使用 Docker network,並用 –replSet 參數指定 replSet 的名稱。
docker run -p 27017:27017 --name mongo1 --net mongo-cluster mongo mongod --replSet rs0 接著起第二個 MongoDB 的 Docker 容器,一樣設定使> 用 Docker network,且用 –replSet 參數指定 replSet 的名稱。
docker run -p 27027:27017 --name mongo2 --net mongo-cluster mongo mongod --replSet rs0 最後起第三個 MongoDB 的 Docker 容器,一樣設定使用 Docker network,且用 –replSet 參數指定 replSet 的名稱。
read morePosts
MongoDB Compass - Install with Homebrew
要使用 Homebrew 安裝 MongoDB Compass,可以調用如下命令:
brew cask install mongodb-compass 安裝完可以透過應用程式這邊啟動 MongoDB Compass。
read morePosts
MongoDB - Clear system.profile collection
在做 MongoDB 的 Profiling 時,有時我們會需要清除 system.profile collection 內的資料。
像是這邊筆者已經有資料在 system.profile collection 內。
db.system.profile.count() 要將 system.profile collection 清除,先要將 Profiler 關閉,也就是透過 db.setProfilingLevel 將 Profiling 等級設為 0。
db.setProfilingLevel(0) 然後 drop system.profile collection。
db.system.profile.drop() Link profiling - How to delete system.profile collection from a MongoDB? - Stack Overflow
read morePosts
MongoDB - Check profiling level and status
MongoDB 在設定好 Profiler 後,可用 db.getProfilingLevel 查驗設定的 Profiling 層級。
db.getProfilingLevel() 或是用 db.getProfilingStatus 查驗整個 Profiling 設定。
db.getProfilingStatus()
read morePosts
MongoDB - Enable and configure database pofiling
要設定或啟用 MongoDB Profiler 功能去能監控較慢的運行,可先進入 MongoDB。
mongo 切到指定資料庫。
use $db 透過 db.setProfilingLevel 設定 Profiling 的層級與定義耗費多少毫秒是慢的處理。
db.setProfilingLevel($level, $slowms) Profiling 的層級如下:
Level Description 0 The profiler is off and does not collect any data. This is the default profiler level. 1 The profiler collects data for operations that take longer than the value of slowms. 2 The profiler collects data for all operations. 如果層級設為 0,則會停止 Profiling;設為 1,則會抓取比 slowms 久的操作;設為 2,則會抓取所有操作。
設定完實際運行程式,MongoDB Profiler 就會依 Profiling 的設定幫我們抓出慢的操作。
read moreTag: Dotnet-Counters
Posts
dotnet-counters - Monitor specified process
dotnet-counters 可用來監控 .Net Core 的 Process,像是這邊筆者準備了一份簡單的程式想要觀察其 CPU 與 Memory 這些資源上的變化狀況。
將程式運行起來。
dotnet run 運行起來後可用 dotnet-trace 查詢 Process。
dotnet-trace ps 接著就可透過 dotnet-counters 監控指定 Process 的資源使用狀態。
dotnet-counters monitor --refresh-interval $refreshInterval -p $processId 像是這邊剛剛查閱到了 dotnet run 起了兩個 Process,我們可以帶入 Process Id 監控。
dotnet-counters monitor --refresh-interval 1 -p 35603 dotnet-counters monitor --refresh-interval 1 -p 35608 dotnet-counters 會將指定 Process 的資源使用狀況依照指定的時間更新,直至程式結束。
Link Debug high CPU usage - .NET Core | Microsoft Docs
read morePosts
dotnet-counters - Install with dotnet tool
要用 dotnet tool 安裝 dotnet-counters,可調用 d otnet tool install 帶入 –global 參數指定安裝至全域,並在最後帶入 dotnet-counters 指定安裝 dotnet-counters 套件。
dotnet tool install --global dotnet-counters 安裝後可調用 dotnet-counters 命令,帶入 –version 參數,確認安裝是否正確無誤。
dotnet-counters --version Link dotnet-counters diagnostic tool - .NET CLI | Microsoft Docs
read moreTag: Dotnet-Trace
Posts
dotnet-trace - Install with dotnet tool
要用 dotnet tool 安裝 dotnet-trace,可調用 dotnet tool install 帶入 –global 參數指定安裝至全域,並在最後帶入 dotnet-trace 指定安裝 dotnet-trace 套件。
dotnet tool install --global dotnet-trace 安裝後可調用 dotnet-trace 命令,帶入 –version 參數,確認安裝是否正確無誤。
dotnet-trace --version Link dotnet-trace diagnostic tool - .NET CLI | Microsoft Docs
read moreTag: OpenSSL
Posts
OpenSSL - Encryption with the OpenSSL Command-Line Interface
要使用 OpenSSL CLI 進行加密,可先透過命令列帶入參數 -help 查閱一下 OpenSSL enc 的使用方式。
openssl enc -help 常用的參數有 -aes-256-cbc 指定使用 AES 256 CBC 加密、-base64 參數指定經過 Base64 處理、-p 參數指定印出 salt/key/iv、-k 參數指定要用來加密金鑰、-nosalt 指定加密時不加 salt。
像是要將 “hello” 透過 AES 256 CBC 加密、加密金鑰用 “world”、透過 Base64 處理的話,可像下面這樣調用。
echo "hello" | openssl enc -aes-256-cbc -base64 -p -k world 如果不加 salt,可加帶 -nosalt 參數。
echo "hello" | openssl enc -aes-256-cbc -base64 -p -k world -nosalt Link The Developer Toolbox: Encryption/Decryption with the OpenSSL Command-Line Interface | Jungle Disk Blog
read moreTag: Git
Posts
conventional-changelog-cli - Generate a changelog from git metadata
conventional-changelog-cli 是一命令列工具,能解析 Git 符合 Angular style 的 Commit log,產生對應的 Change log。
使用前先透過 Npm 安裝套件至全域。
npm install -g conventional-changelog-cli 即可開始使用。
像是顯示 Change log 會產出的內容可帶參數 -w。
conventional-changelog -p angular -i CHANGELOG.md -w -r 0 要產生 Change log 可帶參數 -s。
conventional-changelog -p angular -i CHANGELOG.md -s 這邊筆者用簡單的例子稍微示範一下。
首先先初始 Npm 專案設定檔,因為後面產生的 Change log 版號會要看這設定檔。
npm init 接著初始專案的 Git 版控。
git init 將第一版檔案加入版控。
git add . git commit 確認上版。
git log 嘗試切換專案版本至 1.0.0。
npm version 1.
read morePosts
commitlint - Lint commit messages
commitlint 是一檢測 commit message 的工具。
使用上需先全域安裝 commitlint cli。
npm install -g @commitlint/cli 加入 package.json。
npm init 加入套件 @commitlint/config-conventional。
npm install -save @commitlint/config-conventional 加入 commitlint 設定檔。
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js 準備好後可簡易的用 echo 將訊息透過 pipeline 送到 commitlint 做些測試。
echo 'foo: bar' | commitlint echo 'feat: bar' | commitlint 若要針對 git commit message 也是可以,這邊直接將當前專案加入 git 版控。
git init 設定 .gitignore。
vim .gitignore 將 node_modules 這些不必要版控的部分設定上去。
實際 commit 一個不符合規範的 commit message。
read morePosts
Commitizen - Simple commit conventions for internet citizens
Commitizen 可輔助 git 操作人員使用 commit message 的規範。
使用上先全域安裝 commitizen 命令列工具。
npm install -g commitizen 這邊準備一個 git 版控的專案。
git init 加入 package.json。
npm init 調用命令讓專案符合 commitizen friendly。
commitizen init cz-conventional-changelog --save-dev --save-exact 將修改加入版控實際做個測試。
git add . commit 時改用 git cz,會改成用互動方式輸入符合規範的 commit message。
git cz git log Link Commitizen by commitizen
read morePosts
git - Check commit message with git hook
要在 git commit 時去驗證 commit message,可在 commit 的 hook 加掛驗證的處理。
編輯 .git/hooks/commit-msg。
vim .git/hooks/commit-msg 加入驗證程式後存檔離開。這邊筆者使用 [如何使用 git commit template 與 git hooks 管理團隊的 git log | AllenHsu的技術手扎](htt ps://allen-hsu.github.io/2017/07/02/git-message-template-and-githook/) 提供的驗證程式做了些微的調整,用以檢查 commit message 符合 Angular commit style。
#!/usr/bin/env python """ Git commit hook: .git/hooks/commit-msg Check commit message according to angularjs guidelines: * https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit# """ import sys import re valid_commit_types = ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', ] commit_file = sys.argv[1] help_address = 'https://docs.
read morePosts
git - Commit template
如果 git commit 的 message 想要有一定的規範,可為 git 設定 commit template,設定完後 template 會在 commit 時帶出範本,供編輯修改 commit message。
要設定 git commit template,我們需先建立範本檔。
vim .gitmessage.txt 設定範本檔的內容。
然後將範本檔設定到設定檔中。
git config commit.template .gitmessage.txt 設定好後 commit 時就會自動帶出設定好的範本了。
git add . git commit 這邊需特別注意一點,如果使用的是 GUI 而非命令列的話,多半範本是不支援註釋的,也就是說如果範本中有使用到註釋,都需自行刪除註釋後才能 commit,不然都會當成 commit message。
Link 一份建议的git commit模板 Git 如何在Commit時加入樣板template的機制 如何使用 git commit template 與 git hooks 管理團隊的 git log | AllenHsu的技術手扎 使用 git commit template 管理 git log - Dev Chill - Medium 3.
read morePosts
Git - Reset local branch to remote state
若在本地操作 Git 錯誤,想將本地分支還原到跟遠端分支一樣狀態的話。
可以將遠端分支 fetch 下來。
git fetch ${RemoteName} ${BranchName} 然後強制將本地分支還原至遠端分支的狀態。
git reset --hard ${RemoteName}/${BranchName} 像是筆者這邊不小心做錯,搞出了 Revert Commit。
這時可以像下面這樣調用。
git fetch origin source git reset --hard origin/source 本地分支就會變為跟遠端分支一樣的狀態,本地做錯的動作就會被還原。
Link Reset a Branch to Remote State with git
read morePosts
Git - Git status pager
使用 Git 做版控的程式如果一次變動過多,使用 Git Status 查閱變動時,我們會看到所有變動會一次全部都顯示出來,無法有效的查閱程式的變動。
這時我們可以調用 Git Config 命令將 Git Status 的分頁功能開啟。
git config --global pager.status true 或是手動修改設定檔開啟也可以。
這樣 Git Status 就會一頁一頁的顯示。
read morePosts
P4Merge - Use P4Merge as git mergetool
要將 P4Merge 與 Git 整合,使用 P4Merge 去做 Merge,可以加入 Merge tool 設定。
git config --global merge.tool p4merge 設定 P4Merge 檔案的位置。
git config --global mergetool.p4merge.path [P4MergeFileLocation] 或是直接開啟 global configuration file 編輯也可以。
[merge] tool = p4merge [mergetool "p4merge"] path = C:\Program Files\Perforce\p4merge.exe 設定好後就可以使用 P4Merge 在 git 做 Merge。
git mergetool Link Setup p4merge as difftool and mergetool on Windows Git for Windows tip: Use P4Merge as mergetool – danlimerick
read morePosts
Visual Studio - Clone git repository
使用 Visual Studio clone git repository,先將 Team Explorer 視窗開啟。
在 本機 Git 儲存機制 這邊點選 複製 按鈕。
再來要設定欲 clone 的 git repository 位置,以及 clone 下來存放的位置。
填完按下 複製 按鈕開始進行 Clone。
Clone 完成會在 Team Explorer 直接列出該 Repository。
透過滑鼠右鍵快顯選單我們可以用命令提示字元或是檔案總管開啟 Clone 下來的 Repository。
read moreTag: MariaDB
Posts
pt-variable-advisor - Analyze MySQL variables and advise on possible problems
pt-variable-advisor 是 Percona Toolkit 內的工具之一,能調用 MySQL/MariaDB 的 SHOW VARIABLES 命令偵測參數值,並根據 Rule 分析給予修正的建議。
使用方式如下:
pt-variable-advisor [OPTIONS] [DSN] 像是:
pt-variable-advisor h=$host,P=$port,u=$user,p=$password Link pt-variable-advisor
read morePosts
mysqlslap - Load emulation client
mysqlslap 是 MariaDB 自帶的壓力測試工具。
使用方式可調閱命令。
mysqlslap --help 簡單的說如果資料庫不在本機,調用命令時可帶入 -h, –host=name 指定資料庫位置。
如果資料庫使用的不是預設埠號,可帶入 -P, –port=# 指定埠號。
參數 -i, –iterations=# 可指定運行的次數。
參數 -c, –concurrency=name 指定連結資料庫的 Client 數,也就是所謂的並行數。
參數 -a, –auto-generate-sql 指定自動產生測試的指令。
以一個簡單的測試來說,我們會指定運行的次數、並行 Client 數、與自動產生測試的指令。
mysqlslap -c $concurrent -i $number -a 如果要運行不同的測試次數,可用逗號隔空。
參數 -T, –debug-info 可指定印出一些更為細部的資訊。
mysqlslap -c $concurrent -i $number -a -T 參數 -e, –engine=name 可指定測試的資料庫引擎。
可用來指定測試 myisam 或是 innodb。
mysqlslap -c $concurrent -i $number -a -e $engine 參數 -F, –delimiter=name 可指定 SQL 語法的 Delimiter。
read morePosts
MariaDB - Enable performance schema
透過 MySQL CLI 查閱 Performance schema 的啟用狀態。
show variables like 'performance_schema'; 如果 Performance schema 未啟用,可開啟 MariaDB 的設定檔,加入 performance_schema=on 設定後存檔,然後將 MariaDB 服務重啟。
[mysqld] performance_schema=on Performance schema 就會被啟用。這邊可再次查詢 Performance schema 的啟用狀態做個確認。
read morePosts
MariaDB - Secure MariaDB server with mysql_secure_installation command
MariaDB 安裝完後可調用 mysql_secure_installation 命令進行一連串的安全性設定。
mysql_secure_installation 像是 root 的密碼。
是否移除匿名使用者?
是否允許 root 帳號遠端登入?
移除測試用資料庫?
是否重新載入設定?
照著設定完 MariaDB 就會有基本的安全性在。
read morePosts
MariaDB - Install on Termux
在 Termux 安裝 MariaDB,可透過 pkg 或是 apt 安裝。
pkg install MariaDB 安裝完調用 mysql_install_db 命令安裝資料庫。
mysql_install_db 調用 mysqld 命令啟動服務。
mysqld 在另一個 Session 調用 mysql 命令即可連進 MariaDB。
mysql
read morePosts
Rider - Connect to MariaDB
要透過 Rider 連線 MariaDB 做些操作,可以點選 [ View | Tool Windows | Database ] 主選單選項,開啟 Database 視窗。
然後點選 Database 視窗工具列上的新增按鈕,新增 MariaDB 的 Data Source。
點選 Data Sources and Drivers 視窗中的 MariaDB Driver 按鈕,或是自行切到 MariaDB Driver 頁籤。
在 Driver files 那邊點選下載 Driver。
下載完回到 Data Source。
帶入 Data Source 的資訊後按下 OK 按鈕。
即可在 Database 視窗透過加入的 Data Source 連線到 MariaDB,並進一步對資料庫進行操作。
read morePosts
MariaDB - List table constraints
要查詢資料庫的 Constraints 可查閱 information_schema schema 的 table_constraints table。
select * from information_schema.table_constraints order by table_schema, table_name; Link List table check constraints in MariaDB database - MariaDB Query Toolbox
read moreTag: MySQL
Posts
pt-variable-advisor - Analyze MySQL variables and advise on possible problems
pt-variable-advisor 是 Percona Toolkit 內的工具之一,能調用 MySQL/MariaDB 的 SHOW VARIABLES 命令偵測參數值,並根據 Rule 分析給予修正的建議。
使用方式如下:
pt-variable-advisor [OPTIONS] [DSN] 像是:
pt-variable-advisor h=$host,P=$port,u=$user,p=$password Link pt-variable-advisor
read morePosts
MySQLTuner - High performance MySQL tuning script
MySQLTuner 是用 Perl 撰寫的腳本,可用來分析 MySQL 或是 MariaDB 的設定,給予效能上的建議。
將 MySQLTuner 下載下來。
wget https://github.com/major/MySQLTuner-perl/tarball/master 解壓縮。
tar xf master 進到解完壓縮的目錄。
cd major-MySQLTuner-perl-037f720 輸入命令可分析資料庫的設定並給予建議,只要針對最下方的建議或是前面是 !! 的下去處理即可。
./mysqltuner.pl ./mysqltuner.pl --user $user --pass $password
read moreTag: Percona Toolkit
Posts
pt-variable-advisor - Analyze MySQL variables and advise on possible problems
pt-variable-advisor 是 Percona Toolkit 內的工具之一,能調用 MySQL/MariaDB 的 SHOW VARIABLES 命令偵測參數值,並根據 Rule 分析給予修正的建議。
使用方式如下:
pt-variable-advisor [OPTIONS] [DSN] 像是:
pt-variable-advisor h=$host,P=$port,u=$user,p=$password Link pt-variable-advisor
read morePosts
Percona Toolkit - Install with HomeBrew
如要在 MAC 上使用 Percona Toolkit,可透過 HomeBrew 進行安裝。
brew install percona-toolkit 安裝後可調用 Percona Toolkit 命令查驗,,確認安裝無誤。
pt-variable-advisor --version
read moreTag: Docker, Linux
Posts
Docker - Stop/remove all containers
Docker 容器開多了沒關,要一次停掉可以用 docker ps 命令查閱所有容器,將容器資訊帶給 docker stop,一次停掉。
docker stop $(docker ps -a -q) docker ps 要一次殺掉可以用 docker ps 命令查閱所有容器,將容器資訊帶給 docker rm,一次殺掉。
docker rm -f $(docker ps -a -q) docker ps -a Link Stop / remove all Docker containers (Example)
read moreTag: GRPC
Posts
Jaeger - Tracing with gRPC service
要使用 Jaeger 追蹤 gRPC service 程式,可先加入 Jaeger 與 OpenTracing.Contrib.Grpc 套件。
... <PackageReference Include="Jaeger" Version="0.3.6" /> <PackageReference Include="OpenTracing.Contrib.Grpc" Version="0.2.0" /> </ItemGroup> ... 修改 Startup.ConfigureServices,加入 Jaeger tracer、註冊 GlobalTracer、設定 gRPC 攔截器。
... services.AddGrpc(options => { var serviceName = AppDomain.CurrentDomain.FriendlyName; var tracer = new Tracer.Builder(serviceName) .WithSampler(new ConstSampler(true)) .Build(); GlobalTracer.Register(tracer); services.AddSingleton<ITracer>(tracer); var interceptors = options.Interceptors; interceptors.Add<ServerTracingInterceptor>(tracer); ... }); ... 實際運行程式。
選取 Service 與 Operator 下去查詢。
可看到找到的 Trace,上半部可看到時間與耗時的分佈,下半部就是簡易的列表,可看出 Trace 名稱、識別碼、是什麼時間點觸發的、耗時多久、有多少 Span。
點選感興趣的 Trace,會進入 Trace 細部資訊頁面,會將 Trace 及其組成的 Span 以圖形的方式呈現,便於找到相對耗時的操作。
read morePosts
gRPC - Custom error over RpcException
在做系統時,免不了可能會要定義自己的狀態碼供判斷系統的問題。在 gRPC 下,我們可能會為 Message 增加 StatusCode 這樣的欄位做傳遞與判讀。
這樣的做法在一般的呼叫方式並無問題,但是在用 Streaming 傳達多個小 Message 時,使用上就會有點奇怪。這邊筆者試著透過 gRPC 本身的例外機制嘗試解決這樣的問題。
先造一個自定義的例外,支援帶入 StatusCode,這邊筆者先簡單的用字串型態來做 StatusCode 的定義,實際運用時改用列舉會比較好。
Server 端透過自定義的例外拋出例外。
using System.Threading.Tasks; using Greet; using Grpc.Core; namespace GrpcService_CSharp1 { public class GreeterService : Greeter.GreeterBase { public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) { throw new MyException("ERROR2020"); } } } Server 端掛載攔截器處理例外,將例外轉為 RpcException 拋出,gRPC 支援的狀態碼較少所以筆者拿 StatusCode.Internal 狀態碼來用,Detail 這邊就帶我們自定義的狀態碼,若有額外資訊要帶入可放在 MetaData。
using System; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Interceptors; namespace GrpcService_CSharp1 { public class ExceptionInterceptor: Interceptor { public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) { try { return await base.
read morePosts
gRPC - Unable to start ASP.NET Core gRPC app on macOS
使用 ASP.NET Core 3.0 範本建立 gPRC 程式, 在 MAC 的環境下直接運行起來會發生 HTTP/2 over TLS is not supported on macOS due to mis sing ALPN support 錯誤。
System.IO.IOException: Failed to bind to address https://localhost:5001. ---> System.AggregateException: One or more errors occurred. (HTTP/2 over TLS is not supported on macOS due to missing ALPN support.) (HTTP/2 over TLS is not supported on macOS due to missing ALPN support.) ---> System.NotSupportedException: HTTP/2 over TLS is not supported on macOS due to missing ALPN support.
read morePosts
gRPC - Services logging
gRPC Service 內建的 log 可透過 appsettings.json 控制 log 層級。
預設為 Information 層級。
{ "Logging": { "LogLevel": { "Default": "Debug", "System": "Information", "Grpc": "Information", "Microsoft": "Information" } } } 所以 gRPC service 運行起來會看到 Info 或是 Warn 層級的 Log 輸出。
若是調整為 Debug 層級,可看到像是哪個 gRPC method 被調用,以及是哪個 Method type 這樣的細部資訊。
除了用 appsettings.json 設定,也可以在建立 HostBuilder 時設定。
... public class Program { ... public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => { logging.AddFilter("Grpc", LogLevel.Debug); }) .
read morePosts
gRPC - Logging with interceptor in gRPC service
要紀錄每次 gRPC 的呼叫,可以使用 gRPC interceptor 來做。
建立一個 Interceptor 類別繼承自 gRPC 的 Interceptor,建立個建構子允許注入 Logger,接著覆寫掉會用到的方法,像是 UnaryServerHandler,然後在內部將要記錄的資訊透過 Logger 寫入 Log 即可。
像是下面這邊筆者實作了一個 Interceptor,希望能紀錄每次 gRPC 的調用。
using System.Linq; using System.Text.Json.Serialization; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Interceptors; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace GrpcServiceInterceptor { public class LoggerInterceptor : Interceptor { private readonly ILogger<LoggerInterceptor> _logger; public LoggerInterceptor(ILogger<LoggerInterceptor> logger) { _logger = logger; } public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>( TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) { var response = await base.
read morePosts
gRPC - Global exception handling with interceptor in gRPC service
要做 gRPC 的全域攔截,可以使用 gRPC interceptor 來做。
建立一個 Interceptor 類別繼承自 gRPC 的 Interceptor,覆寫掉會用到的方法,像是 UnaryServerHandler,然後在內部調用基底的方法並用 try/catch 去攔截錯誤做對應的處理即可。
像是下面這邊筆者實作了一個 Interceptor,希望能在錯誤發生時顯示錯誤,並回傳錯誤訊息。
using System; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Interceptors; using Microsoft.Extensions.Logging; namespace GrpcServiceInterceptor { public class ExceptionInterceptor : Interceptor { public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) { try { return await base.UnaryServerHandler(request, context, continuation); } catch (Exception e) { Console.WriteLine(e.ToString()); var obj = (TResponse) Activator.CreateInstance(typeof(TResponse)); var prop = typeof(TResponse).
read morePosts
gRPC - Streaming
gRPC 的 Streaming 可用來做大量資料的傳輸,不論是 Client 傳到 Service,或是 Service 回給 Client。
使用上就是在 proto 檔用 stream 去定義要使用 Streaming 的地方,看是用在傳入還是回傳。
... service Greeter { ... rpc SayHellos (stream HelloRequest) returns (stream HelloReply) {} } ... 然後 Service 與 Client 透過 IServerStreamWriter 寫資料、透過 IAsyncStreamReader 讀取資即可。
以寫入來說,可透過迴圈搭配 WriteAsync() 將資料逐筆寫入,最後透過 CompleteAsync() 告知寫入完成。
foreach (var item in data) { await stream.WriteAsync(item); } await stream.CompleteAsync(); 或是引用 Grpc.Core.Utils,直接透過 WriteAllAsync() 將所有資料寫入。
... await stream.WriteAllAsync(data); ... 以讀取來說,可用迴圈搭配 MoveNext() 移至下筆可用的資料,再用 Current 取出資料做處理。
read morePosts
gRPC - Setup singleton service
ASP.NET Core 的 gRPC service 預設是沒有 Singleton 的,所以如果今天 gRPC client 發送多次訊息給 gRPC server。
gRPC server 會建多次 gRPC service 實體。
為避免這樣的情況,可在 Startup 的 ConfigureServices 內透過 services.AddSingleton 將 Service 的實體帶入。
... public class Startup { public void ConfigureServices(IServiceCollection services) { ... services.AddGrpc(); services.AddSingleton(service); ... } ... } gRPC server 就只會用指定的 gRPC service 實體去做事。
read morePosts
gRPC - Setup service options with ASP.NET Core
在 ASP.NET Core 支援設定的 gRPC service option 有:
Option Default Description SendMaxMessageSize null 最大訊息大小可以從伺服器傳送的位元組數。 嘗試傳送的訊息長度超過設定的最大訊息大小會導致例外狀況。 ReceiveMaxMessageSize 4 MB 最大訊息大小可以由伺服器接收的位元組數。 如果伺服器收到的訊息超過此限制,它會擲回例外狀況。 增加此值可讓伺服器接收較大的訊息,但可能會造成負面影響記憶體耗用量。 EnableDetailedErrors false 如果true詳細服務方法擲回例外狀況時,將會傳回給用戶端的例外狀況訊息。 預設為 false。 這個設定設為true可能會導致洩漏機密資訊。 可在 Startup 的 ConfigureServices 內透過 services.AddGrpc 針對所有 Service 下去設定。
... public class Startup { public void ConfigureServices(IServiceCollection services) { ... services.AddGrpc(options => { options.ReceiveMaxMessageSize = receiveMsgLimit; options.SendMaxMessageSize = sendMsgLimit; }); ... } ... } 也可以透過 services.AddGrpc().AddServiceOptions 針對特定 Service 下去設定。
... public class Startup { public void ConfigureServices(IServiceCollection services) { .
read morePosts
gRPC - Create service with ASP.NET Core
在 .NET Core 3.0 後,我們可透過 gRPC Service 範本建立方案或是專案,如果是用方案範本,除了 gRPC 的 Server 專案外,還會有 Client 的專案。
像是筆者這邊直接透過範本建立一個 gRPC 方案。
方案建立完會看到內含 Server 與 Client 兩個專案,需參考的套件以及要使用的 Proto 檔設定都已經設好了。
編譯檔案時會將 Proto 編譯成對應的程式碼,產生在 obj 下。
{% asset_img 5.png%}
另外是 .NET Core 3.0 的 gRPC Service 已經被整進 ASP.NET Core 去了,只要在 Startup.cs 中的 ConfigServices 將 gRPC 服務開啟。
... public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); } ... 並設定 gRPC 服務對應的處理類別,gRPC Server 就好了。
... public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { .
read morePosts
'gRPC - Create C# gRPC client'
要建立 gRPC 的 Client,須先將 GRPC.Tools、GRPC.Core、Google.Protobuf 這三個 NuGet 套件加入參考。
... <ItemGroup> <PackageReference Include="Google.Protobuf" Version="3.7.0" /> <PackageReference Include="Grpc.Core" Version="1.20.0" /> <PackageReference Include="Grpc.Tools" Version="1.20.0" /> </ItemGroup> ... 然後設定從 Proto 檔產生需要的程式部分。
<ItemGroup> <Protobuf Include="../../proto/*.proto" GrpcServices="Client" /> <Content Include="@(Protobuf)" LinkBase="" /> </ItemGroup> 編譯後可在 obj 下看到產出的檔案。
接著開始實作 Client。
然後帶入 Server 位置建立 Channel 物件。
... var channel = new Channel($"{host}:{port}", ChannelCredentials.Insecure); ... 接著帶入 Channel 建立 Service 的 Client 物件。
... var client = new HelloService.HelloServiceClient(channel); ... 透過 Service 的 Client 物件調用對應的方法。
read morePosts
'gRPC - Create C# gRPC server'
要建立 gRPC 的 Server,須先將 GRPC.Tools、GRPC.Core、Google.Protobuf 這三個 NuGet 套件加入參考。
... <ItemGroup> <PackageReference Include="Google.Protobuf" Version="3.7.0" /> <PackageReference Include="Grpc.Core" Version="1.20.0" /> <PackageReference Include="Grpc.Tools" Version="1.20.0" /> </ItemGroup> ... 然後設定從 Proto 檔產生需要的程式部分。
<ItemGroup> <Protobuf Include="../../proto/*.proto" GrpcServices="Server" /> <Content Include="@(Protobuf)" LinkBase="" /> </ItemGroup> 編譯後可在 obj 下看到產出的檔案。
接著開始實作 Service。
繼承產出的 Service 基底類別。
... public class HelloServiceImpl:HelloService.HelloServiceBase ... 並覆寫該服務的方法即可。
... public override Task<HelloResponse> SayHello(HelloRequest request, ServerCallContext context) { ... } ... 程式寫起來會像下面這樣 (這邊筆者只是簡單的將調用時送進來的人名做些加工回傳而已):
using System.Threading.Tasks; using Grpc.Core; public class HelloServiceImpl:HelloService.
read morePosts
gRPC - Protocol Buffers/gRPC Integration Into .NET Build
Grpc.Tools 在 1.17 後我們可以將 proto 檔的編譯動作直接整到 dotnet build。使用上只要在專案檔中加上 設定即可。
像是筆者這邊準備了一個 GRPC.Message 專案。加入 Grpc/Grpc.Tools/Google.Protobuf NuGet 套件參考。
proto 檔放在上上層的 proto 目錄下。
. |___ proto | |___ message.proto | |___ service.proto |___ src |___ GRPC.Message 那在 GRPC.Message 的專案檔中可以像下面這樣加入 設定,會用 Include 指定 proto 檔、ProtoRoot 指定 proto 檔中 import 語法的參考位置、OutputDir 指定輸出位置、GrpcService 指定要編譯 gRPC 的 server 還是 client…等。
... <ItemGroup> <Protobuf Include="../../**/*.proto" OutputDir="%(RelativePath)" CompileOutputs="false" GrpcService="both" /> </ItemGroup> ... 像是如果只要產生 Server 需要使用的類別就可以像這樣設定。
... <ItemGroup> <Protobuf Include="../../proto/*.proto" GrpcServices="Server" /> </ItemGroup> .
read moreTag: Jaeger
Posts
Jaeger - Tracing with gRPC service
要使用 Jaeger 追蹤 gRPC service 程式,可先加入 Jaeger 與 OpenTracing.Contrib.Grpc 套件。
... <PackageReference Include="Jaeger" Version="0.3.6" /> <PackageReference Include="OpenTracing.Contrib.Grpc" Version="0.2.0" /> </ItemGroup> ... 修改 Startup.ConfigureServices,加入 Jaeger tracer、註冊 GlobalTracer、設定 gRPC 攔截器。
... services.AddGrpc(options => { var serviceName = AppDomain.CurrentDomain.FriendlyName; var tracer = new Tracer.Builder(serviceName) .WithSampler(new ConstSampler(true)) .Build(); GlobalTracer.Register(tracer); services.AddSingleton<ITracer>(tracer); var interceptors = options.Interceptors; interceptors.Add<ServerTracingInterceptor>(tracer); ... }); ... 實際運行程式。
選取 Service 與 Operator 下去查詢。
可看到找到的 Trace,上半部可看到時間與耗時的分佈,下半部就是簡易的列表,可看出 Trace 名稱、識別碼、是什麼時間點觸發的、耗時多久、有多少 Span。
點選感興趣的 Trace,會進入 Trace 細部資訊頁面,會將 Trace 及其組成的 Span 以圖形的方式呈現,便於找到相對耗時的操作。
read morePosts
Jaeger - Tracing with ASP.NET Core
要使用 Jaeger 追蹤 ASP.NET Core 的程式,可先加入 Jaeger 與 OpenTracing.Contrib.NetCore 套件。
<Project Sdk="Microsoft.NET.Sdk.Web"> ... <ItemGroup> <PackageReference Include="Jaeger" Version="0.3.6" /> <PackageReference Include="OpenTracing.Contrib.NetCore" Version="0.6.2" /> </ItemGroup> ... </Project> 修改 Startup.ConfigureServices 啟用。
... public class Startup { ... public void ConfigureServices(IServiceCollection services) { ... services.AddOpenTracing(); var serviceName = AppDomain.CurrentDomain.FriendlyName; var tracer = new Tracer.Builder(serviceName) .WithSampler(new ConstSampler(true)) .Build(); GlobalTracer.Register(tracer); services.AddSingleton<ITracer>(tracer); ... } ... } ... 到這邊程式 Controller 的 Action 已經會送到 Jaeger 可被 Tracing 了。
若要增加額外的 Tracing 的資訊,可透過 DI 或是 GlobalTracer.
read morePosts
Jaeger - Getting started
要使用 Jaeger,最簡便的做法是直接使用 Docker 去起 jaegertracing/all-in-one 容器。
docker run -d --name jaeger \ -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \ -p 5775:5775/udp \ -p 6831:6831/udp \ -p 6832:6832/udp \ -p 5778:5778 \ -p 16686:16686 \ -p 14268:14268 \ -p 9411:9411 \ jaegertracing/all-in-one 或是從下載頁下載 Jaeger。
wget https://github.com/jaegertracing/jaeger/releases/download/v1.16.0/jaeger-1.16.0-darwin-amd64.tar.gz 解壓縮。
tar xf jaeger-1.16.0-darwin-amd64.tar.gz 運行 jaeger-all-in-one 啟動 Jaeger 服務。
jaeger-all-in-one --collector.zipkin.http-port=9411 透過瀏覽器訪問 http://localhost:16686 應該就可以看到 Jaeger 的操作界面。
Link Getting Started — Jaeger documentation
read moreTag: Redis
Posts
Redis - Setup redis cluster
這邊紀錄一下如何不透過 create-cluster 腳本一步一步建立 Redis cluster。
首先安裝 Redis,這邊為了方便筆者是直接使用 Docker 去起 Redis 容器。
docker run -it redis bash 這邊為了測試方便,會讓六個 Redis instance 放在同一個容器。所以這邊筆者建立一個目錄便於後續操作。
mkdir cluster-test cd cluster-test 接著為每個 Redis instance 建立目錄。
mkdir 7000 7001 7002 7003 7004 7005 每個 Redis instance 放置對應的 Redis 設定。
cd 7000 apt-get update && apt-get install vim vim redis.conf 設定檔內記得設定 Redis instance 的 port 號與 cluster。
port 7000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes 調用 redis-server 命令,指定設定檔,啟動 Redis instance。
read morePosts
Redis - Redis cluster with docker and create-cluster script
透過 Docker 去起 Redis cluster,多半網路上的做法都是用多個容器去做,這邊筆者考量測試與開發上的便利性,試著用一個容器搭配 create-cluster 腳本去起 Redis cluster。
為了整合 Docker,create-cluster 腳本筆者做了些調整。只留下本來腳本中的 create 與 start 兩個步驟,將兩個步驟合併,並支援透過環境變數帶入 Host 與 Port,另外因為 Redis 不支援 Domain,所以 Host 帶入後會在容器內解析為 IP 後使用。
#!/bin/bash # Settings HOSTNAME=${HOSTNAME} PORT=${PORT} TIMEOUT=2000 NODES=6 REPLICAS=1 CLUSTER_HOST=$(getent hosts $HOSTNAME | awk '{ print $1 }') # Create & start HOSTS="" ENDPORT=$((PORT+NODES)) CURRENTPORT=$PORT while [ $((CURRENTPORT < ENDPORT)) != "0" ]; do echo "Starting $CURRENTPORT" redis-server --port $CURRENTPORT --cluster-enabled yes --cluster-config-file nodes-${CURRENTPORT}.conf --logfile ${CURRENTPORT}.
read morePosts
Redis - Redis cluster with create-cluster script
Redis 安裝完後 utils/create-cluster 目錄下有提供現成的腳本可以用來起 Redis cluster 做些測試。
使用方式可參閱目錄下的 README。
或是直接調用命令參考命令的說明。
./create-cluster 簡單來說,可以用 start 將要組成 Redis cluster 的節點都先運行起來。
./create-cluster start 再用 create 將運行起來的 Redis 連結組成 Cluster。
./create-cluster create 若有需要,可用 watch 監看 Redis 的輸出。
./create-cluster watch 如 Redis log 過多,可用 clean-logs 清除 Redis log。
./create-cluster clean-logs 不使用時可用 stop 停止 Redis 服務。
./create-cluster stop 再用 clean 將 Redis 的 資料、設定、Log 都清除。
./create-cluster clean
read morePosts
Redis - Install on Linux
要在 Linux 安裝 Redis,可先將 Redis 下載下來。
wget http://download.redis.io/redis-stable.tar.gz 解壓縮下載下來的檔案。
tar xvzf redis-stable.tar.gz 進到解壓縮後產出的目錄。
cd redis-stable 進行編譯(若無法編譯,請安裝 Make 與 gcc 套件)。
Make 編譯完成使用 utils 下的內建腳本進行 Redis 服務的設定與啟用。
./utils/install_server.sh 最後實際用 redis-cli 測試確認一下 Redis 服務正常運行即可。
src/redis-cli ping
read morePosts
Redis - Generate Snowflake generator id with client info
在做分散式系統時,有些情境下免不了要給節點維一的識別號,像是在用 Snowflake 分散式 Id 演算法時會需要給予 10 bit 長的 Generator id,用以避免 Id 碰撞。
識別號有的會直接取 IP 某段,或是 Process no,這樣並不能確保值的唯一。要確保維一只能依賴自行靠設定將設定值錯開,或是設計一個演算法配給。
若是搭配 Redis 使用,最直覺的演算法可能就是在每個服務實體啟動時去 Redis 註冊一個唯一的識別值,服務實體與識別值的資訊都放置在 Redis 中,並設有過期時間。每個服務定時到 Redis 延長過期時間,如果資訊過期,則對應的識別碼要釋出給新服務用。
上面的演算法很直覺,但有兩點較大的問題,一個是實作上很麻煩,一個是定時到 Redis 延長過期時間的做法對系統來說不是很好。好在 Redis 有維護每個連線的 Client 資訊,也都取的到,透過 Redis client 的資訊實作上會簡單許多,對系統來說處理也比較沒那麼吃重。
舉個例子來說,假設我用 Redis 的 Hash 來實作,Key 假定為 generator,裡面的 field 用來放 Generator id,value 用來放 Redis client 的 Id。
generator => { {$generator-id, $redis-client-id}, ... } 這樣在第一個服務上線時,Redis 內的資料是空的。
generator => { } 這時透過 Redis 命令 CLIENT LIST 取得所有連線的 Id,與 CLIENT ID 命令取得當前連線的 Id,就可以去更新並配給 Generator id。像是所有連線 Id 問回來只有一個連線,且連線 Id 跟當前連線 Id 一樣都是 0,就會將 Generator id 0 配給 Redis client 0。
read morePosts
Redis - A simple syntax to describe how data stored
在使用 redis 時,資料怎樣在 redis 內存放常會需要設計,或是需要拿出來跟團隊溝通討論。用畫圖表述或是列表有點不方便,redis 資料結構豐富也不是很好表示。
這邊筆者嘗試定義簡易的表示方式。
String 型態表示方式…
$string-key => $string-value Hash 型態表示方式…(設計概念為 Dictionary)
$hash-key => { {$field-key, $field-value}, ... } List 型態表示方式…(設計概念為 Array)
$list-key => [ $list-value, ... ] Set 型態表示方式…(設計概念為 Set)
$set-key => { $set-value, ... } SortedSet 表示方式…(設計概念為 Tuple set)
$sorted-set-key => { ($score, $set-value), ... } 像是 Redis reliable queue 那篇的設計…
用這樣的表示方式設計就會變成這樣:
pending => [$data-id, ...] working:$worker-id => [$data-id, ...] value => { {$data-id, $data}, .
read morePosts
Redis - Reliable queue pattern
系統中如果有使用到 Redis,有時會碰到要將 Redis 內資料落地的情境。這時可能會用 Redis 的 List 做一個簡單的 Queue,將資料以先進先出的方式處理。
這樣的做法看似運作良好,但隱藏著一個潛在的問題。如果今天從 Redid 取出資料還未處理就發生錯誤,可能是機器當機重啟那種錯誤,就會有丟失資料的現象發生。
為了解決這樣的問題,可以套用 Reliable queue pattern,當資料確實被處理完才從 Redis 內移除。
簡單的說就是把資料的 Id 放在 List 之類的結構,實際的資料放在 Value,當你 Deque 時將 Id 從 Pendding 放到 Working,處理完才從 Working 清掉,順帶將 Value 對應的資料刪掉。
實作上通常 Pending 與 Working 會用 List 結構去實作,Value 會用 Hash 結構。
當資料要從 Redis 取出處理時,會先查看 Working 是否已經有資料,如果 Working 已經有資料,可能代表之前處理到一半之類的,這時資料直接由 Working 反查 Value 後吐回。如果 Working 沒資料,會從 Pending 將需要處理的 Id 透過 rpoplpush 命令轉到 Working,然後反查 Value 吐回。
資料處理完要將資料從 Redis 移除時,會將 Working 與 Value 中對應的資料移除。
read morePosts
Iedis - Client list
在 Redis Servers Tool Window 內的連線設定上按下滑鼠右鍵,點選滑鼠右鍵快顯選單上的 Client List 選單選項。
可開啟 Client List 視窗,透過該視窗可查閱所有連到 Redis 的 Client。
也可以刪除指定的 Client 連線。
read morePosts
Iedis - Advanced console
在 Redis Servers Tool Window 內的連線設定上按下滑鼠右鍵,點選滑鼠右鍵快顯選單上的 Open Terminal 選單選項,或是透過上方的工具列,抑或者是熱鍵 ⌘ + ⇧ + F10。
即可開啟 Terminal 視窗,可在 Terminal 視窗撰寫並調用 Redis 命令。
Link Iedis: Advanced Console
read morePosts
Iedis - Slow log
在 Redis Servers Tool Window 的 Redis 連線上按下滑鼠右鍵,在滑鼠右鍵快顯選單中有個 Slow Log 選單選項,點選該選單選項。
可看到 Redis 執行比較慢的記錄,會有命令名稱、執行時間等。
Link Iedis: Config Monitor
read morePosts
FastoRedis - Install on MAC
FastoRedis 是一跨平台的 Redis GUI 管理工具,可在 FastoRedis 的下載頁面下載該軟體。
下載要安裝的作業系統版本。
筆者這邊下載的是 MAC 的版本,下載後點選下載下來的 dmg 檔,按下 Agree 按鈕同意 License。
將 FastoRedis 拖進 Application 目錄。
就可以透過啟動台將 FastoRedis 軟體啟動來使用。
Link FastoRedis - cross-platform client for Redis, supported main Redis database features like: modules, cluster, sentinel, ssh tunneling.
read morePosts
Redis - LREM command
LREM 命令可以用來移除 Redis List 中指定的元素值。
其語法如下:
LREM key count value LREM 後面帶入 List 的 Key、要刪除的元素個數、要刪除的元素值,回傳值為被移除的元素數量。
其中 count 值如果為正則會從頭到尾找尋符合指定值的元素移除、如果為負則會從尾到頭移除符合指定值的元素、如果為 0 則會移除所有符合指定值的元素。
LREM 命令的時間複雜度為 O(N),N 為 List 的長度。
雖然時間複雜度為 O(N),但是因為該命令會由指定的方向遍巡,且當移除了足夠的元素數量後就會停止遍巡,因此在某些情境下命令使用恰當的話效率其實不會到 O(N) 那麼糟。
像是如果準備 1 - 10000 的 List,然後用 LREM 將資料從尾部移除 1 - 10000。
for i=1,10000 do redis.call('lpush', 'Test123', i) end for i=1, 10000 do redis.call('lrem', 'Test123', -1, i) end 這樣運行起來會是 0.23 s。
如果反過來用 LREM 將資料從頭部移除 1 - 10000。
... for i=1, 10000 do redis.
read morePosts
Redis on Windows
要在 Windows 使用 Redis,可以到這邊下載 Windows 的 Porting 版本。
點擊安裝檔進行安裝。
勾選同意授權。
設定要安裝的位置,這邊也可以勾選順帶設定環境變數。
設定 Redis 要使用的 Port 號,這邊也可以勾選順帶設定防火牆。
設定記憶體使用上限。
安裝完後在指定的安裝位置會看到 Redis 的設定檔,以及 Redis 附帶的一些 CLI Tool,像是 redis-cli、redis-server、redis-benchmark 等。
查看服務也可以看到安裝的 Redis 服務正在背後運行。
更進一步可以使用 Telnet。
或是自帶的 redis-cli 工具進行一下 Redis 的連線測試。
Link MSOpenTech/redis: Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes
read moreTag: Docker
Posts
Redis - Redis cluster with docker and create-cluster script
透過 Docker 去起 Redis cluster,多半網路上的做法都是用多個容器去做,這邊筆者考量測試與開發上的便利性,試著用一個容器搭配 create-cluster 腳本去起 Redis cluster。
為了整合 Docker,create-cluster 腳本筆者做了些調整。只留下本來腳本中的 create 與 start 兩個步驟,將兩個步驟合併,並支援透過環境變數帶入 Host 與 Port,另外因為 Redis 不支援 Domain,所以 Host 帶入後會在容器內解析為 IP 後使用。
#!/bin/bash # Settings HOSTNAME=${HOSTNAME} PORT=${PORT} TIMEOUT=2000 NODES=6 REPLICAS=1 CLUSTER_HOST=$(getent hosts $HOSTNAME | awk '{ print $1 }') # Create & start HOSTS="" ENDPORT=$((PORT+NODES)) CURRENTPORT=$PORT while [ $((CURRENTPORT < ENDPORT)) != "0" ]; do echo "Starting $CURRENTPORT" redis-server --port $CURRENTPORT --cluster-enabled yes --cluster-config-file nodes-${CURRENTPORT}.conf --logfile ${CURRENTPORT}.
read morePosts
Docker - Remove all unused local volumes
Docker 用久了本地可能會殘留許多的資料卷。
像是筆者電腦中就殘留了那麼多。
docker volume ls 這時可以透過 volume 的 prune 命令將本地沒在使用的資料卷給清除。
docker volume prune 這邊會顯示清出了多少的空間。
再次查詢做個確認,應該會看到資料卷正常的被清掉。
read morePosts
Gitea - Install with docker
透過 Docker 使用 Gitea,可用 docker pull 將 Gitea 容器拉回。
docker pull gitea/gitea:latest 然後建立一個目錄用以存放資料。
使用 docker run 啟動 Gitea 容器,將剛建立的目錄掛載為資料卷。
docker run -d --name=gitea -p 10022:22 -p 80:3000 -v /gitea:/data gitea/gitea:latest 即可使用 Gitea 服務。
Link Docker 安裝 - Docs
read moreTag: Vault
Posts
Vault - Policies
要設定 Vault 的 Policy,先建立 Policy 設定檔。
vim $policy_file 在設定檔內用 HCL (HashiCorp Configuration Language) 做 Policy 的設定。
# Normal servers have version 1 of KV mounted by default, so will need these # paths: path "secret/*" { capabilities = ["create"] } path "secret/foo" { capabilities = ["read"] } # Dev servers have version 2 of KV mounted by default, so will need these # paths: path "secret/data/*" { capabilities = ["create"] } path "secret/data/foo" { capabilities = ["read"] } 像是這邊設定的是可以在 secret/ 下做寫入的動作,只有 secret/foo 是唯讀;secret/data/ 下可寫入,但 secret/data/foo 唯讀。
read morePosts
Vault - GitHub auth method
要使用 GitHub 做 Vault 的認證,可用 vault auth enable 帶入 github 啟動 GitHub auth method。
vault auth enable [-path=$path] github 查驗一下是否正常啟用。
vault auth list
接著設定 GitHub 的 Organization。
vault write auth/github/config organization=$organization 設定 GitHub Organization 的 Team,與要使用的 Policy。
vault write auth/github/map/teams/$team value=$policy 因為用 GitHub 認證,這邊要先準備好 GitHub personal access token。
GitHub personal access token 這邊建立時要給予 read:org 權限。
建立完調用 vault login,帶入 -method 參數指定用 GitHub 登入,並帶入剛建立的 GitHub personal access token 即可。
vault login -method=github 若後續不再使用,可登回 root。
read morePosts
Vault - Install with HomeBrew
如要在 MAC 上使用 Vault,可透過 HomeBrew 進行 Vault 的安裝。
brew install vault 安裝後調用 Vault 命令並帶入 –version 參數,若安裝正常應可查驗到安裝的 Vault 版本。
vault --version
read morePosts
Vault - Token authentication
Vault 支援 Token 認證方式,在 Vault server 啟動後會顯示 Root token,可直接取用。
也可以透過 vault token create 命令建立新的 token 使用。
vault token create Token 的相關資訊可用 vault token lookup 帶入 Token 查驗。
vault token lookup $token Token 取得後可用 vault login 帶入 Token 登入。
vault login $token 若要註銷 Token,可用 vault token revoke 帶入 Token。
vault token revoke $token Token 註銷後不得使用,無法查驗 Token 資訊。
也無法用來登入。
Link Authentication
read morePosts
Vault - Secrets engines
Vault 的 Secure engine 可以是 AWS、Database、Github… 等。
資料會進哪個 Secret engine 是看 Path,像是預設開啟 kv 這個 Secret engine 在 secret 這個 Path,我們可以直接用 secret/$name 這樣的方式指定存放的位置。
若指定的位置無對應的 Secret engine,因為無 Secret engine 可以服務,因此會報錯。
vault write foo/bar a=b Secret engine 可使用 vault secrets enable 加帶 Secret engine name自行啟用,如果啟用的 Path 跟 Secret engine name 不同,可加帶 -path 參數指定。
vault secrets enable [-path=$path] $secret-engine 像是這邊筆者起了一個 kv 的 Secret engine 在 kv 這個 Path。
vault secrets enable -path=kv kv 查驗 Secret engine 列表,可看到確實已經啟用。
read morePosts
Vault - Your first secure
Vault server 起動後,實際做些資料的操作看看。
透過 vault kv put 可將資料存放到指定的 kv store。
vault kv put secret/hello foo=world 支援存放多筆資料。
vault kv put secret/hello foo=world excited=yes 放入 kv store 的資料可用 vault kv get 查看。
vault kv get secret/hello 若要查詢特定值可加帶 -field 參數指定。
vault kv get -field=excited secret/hello 也可加帶 -format 參數指定輸出格式做些進階處理。
vault kv get -format=json secret/hello | jq -r .data.data.excited 資料不要時可透過 vault kv delete 自 kv store 移除。
vault kv delete secret/hello vault kv get secret/hello Link Your First Secret
read morePosts
Vault - Starting the server
Vault 安裝後可調用 Vault server 命令起服務試試,這邊可加帶 -dev 參數起 Dev server。
vault server -dev 服務啟用後注意到特別變色的區塊,裡面有 Vault server 的位置與 Root token。
可複製新開 Terminal 後貼上,設定 VAULT_ADDR。
export VAULT_ADDR='http://127.0.0.1:8200' 以及 VAULT_DEV_ROOT_TOKEN_ID。
export VAULT_DEV_ROOT_TOKEN_ID="$token_id" 設定完後調用 vault status 命令測試看看,沒意外的話應該可以正常連到 Vault server,並將 Vault server 的資訊顯示出來。
vault status Link Starting the Server
read morePosts
Vault - Install Vault
要安裝 Vault 可到這邊下載對應系統的檔案。
像是筆者用 Android 手機在用 Termux 玩,所以是下載 ARM 版本的檔案。
wget https://releases.hashicorp.com/vault/1.3.0/vault_1.3.0_linux_arm64.zip 下載下來後解壓縮。
unzip vault_1.3.0_linux_arm64.zip 就可以直接使用解壓縮出來的二進制檔案操作。
vault Link Installing Vault
read moreTag: Termux
Posts
Vault - Install Vault
要安裝 Vault 可到這邊下載對應系統的檔案。
像是筆者用 Android 手機在用 Termux 玩,所以是下載 ARM 版本的檔案。
wget https://releases.hashicorp.com/vault/1.3.0/vault_1.3.0_linux_arm64.zip 下載下來後解壓縮。
unzip vault_1.3.0_linux_arm64.zip 就可以直接使用解壓縮出來的二進制檔案操作。
vault Link Installing Vault
read morePosts
Perl - Install on Termux
要在 Termux 上撰寫或運行 Perl,可透過套件管理工具安裝 Perl 套件。
apt install perl 安裝完調用 perl 命令,並帶入 –version 參數,確認 Perl 的安裝,若安裝無誤可看到安裝的 Perl 版本。
perl --version
read morePosts
Rust - Install on Termux
在 Termux 上安裝 Rust,可透過套件管理程式安裝 Rust 套件。
pkg install rust 安裝完後可查詢 Rust 版本做個確認。
rustc -V
read morePosts
Go - Install on Termux
要在 Termux 使用 Go,可透過 pkg 安裝 golang 套件。
pkg install golang 安裝完可調用 go 命令查閱版本,命令應該正常運作,回應安裝的 Go 版本資訊。
go version
read morePosts
Python - Install on Termux
要在 Termux 安裝 Python,可透過 pkg 安裝 python 套件。
pkg install python 安裝完可查閱 Python 版本做過確認,Python 命令應可正常運行,回應安裝的 Python 版本。
python --version
read morePosts
MariaDB - Install on Termux
在 Termux 安裝 MariaDB,可透過 pkg 或是 apt 安裝。
pkg install MariaDB 安裝完調用 mysql_install_db 命令安裝資料庫。
mysql_install_db 調用 mysqld 命令啟動服務。
mysqld 在另一個 Session 調用 mysql 命令即可連進 MariaDB。
mysql
read morePosts
Dart - Install on Termux
要在 Termux 安裝 Dart,透過 Apt 或 Pkg 去安裝 Dart 套件即可。
pkg install dart 安裝完可查詢版本做過確認,沒意外的話應該會正常運作。
dart --version
read morePosts
Termux - Vue.js in Termux
要在 Termux 內建立 Vue.js 環境,需要安裝 Vue CLI 到全域。
npm i vue-cli -g 安裝後透過 Vue CLI 初始 Vue 專案。
vue init webpack <Project> 進入初始完的專案目錄。
還原專案需要的套件。
yarn install 運行 Vue 專案。
yarn run start 訪問 http://127.0.0.1:8080 即可看到運行結果。
read morePosts
Termux - Setup Hexo blog
在 Termux 使用 Hexo 並沒什麼特別之處。
一樣是要先將 Hexo CLI 安裝到全域。
npm install hexo-cli -g 接著初始化 Blog。
hexo init <Folder> 進入剛初始化產出的目錄
運行 Hexo 服務。
hexo s 訪問 http://127.0.0.1:4000 即可看到 Blog 運行的結果。
read morePosts
Termux - Setup Jupyter Notebook
要在 Termux 安裝 Jupyter Notebook,要先安裝一些依賴的套件。
apt install clang python python-dev fftw libzmq libzmq-dev freetype freetype-dev libpng libpng-dev pkg-config 再用 pip 安裝 Jupyter。
pip install jupyter 安裝完後啟動 Jupyter。
jupyter notebook 啟動訊息會帶出 Jupyter Notebook 的位置。
訪問該位置即可開始使用 Jupyter Notebook。
read morePosts
Termux - nginx
要在 Termux 內使用 nginx,首先要透過套件管理工具安裝 nginx 套件。
nginx install nginx 安裝完輸入命令啟動。
nginx 啟動後服務會在背景運行,可以用查詢看看 process 是否有起來。
ps | grep nginx 服務有正常起來到話訪問 http://127.0.0.1:8080 就可以看到 nginx 的歡迎頁面。
如果要關閉 nginx 服務,可調用…
fuser -k 8080/tcp
read morePosts
Termux - Setup Ubuntu Linux
要在 Termux 安裝 Ubuntu Linux,首先要下載安裝用的 script。
curl https://raw.githubusercontent.com/Neo-Oli/termux-ubuntu/master/ubuntu.sh --output ubuntu.sh 然後運行下載下來的 script 安裝,安裝完會直接進入到 Arch Linux。
bash ubuntu.sh 如果要去 Ubuntu Linux 退出,可調用 exit 命令。
要再次進入 Ubuntu Linux 的話,只要運行 start-ubuntu.sh 即可。
Link termux-ubuntu Ubuntu - Termux Wiki
read morePosts
Termux - Setup Arch Linux
要在 Termux 安裝 Arch Linux,首先要下載安裝用的 script。
curl https://raw.githubusercontent.com/sdrausty/TermuxArch/master/setupTermuxArch.sh --output setupTermuxArch 然後運行下載下來的 script 安裝,安裝後會直接進入到 Arch Linux。
如果要從 Arch Linux 退出,可調用 exit 命令。
要再次進入 Arch Linux 的話,只要運行 arch/startarch 即可。
Link Arch
read morePosts
'Termux - Termux:API'
要讓 Termux 可以獲取手機資訊或是跟手機進行互動,可以安裝 Termux:API application。
然後在 Termux 安裝 termux-api。
pkg install termux-api Termux:API 提供如下功能:
termux-battery-status Get the status of the device battery. termux-brightness Set the screen brightness between 0 and 255. termux-call-log List call log history. termux-camera-info Get information about device camera(s). termux-camera-photo Take a photo and save it to a file in JPEG format. termux-clipboard-get Get the system clipboard text. termux-clipboard-set Set the system clipboard text. termux-contact-list List all contacts.
read morePosts
Termux - Custom welcome screen
要修改 Termux 的歡迎畫面,可以開啟 $PREFIX/etc/motd。
vim $PREFIX/etc/motd 開啟後可以看到 Termux 的歡迎畫面。
將之修改成自己的歡迎畫面後存檔退出。
開啟新的 session 即可看到設定好的歡迎畫面。
read morePosts
Termux - zsh
要設定 Termux zsh,可以下載 termux-ohmyzsh 並運行安裝。
sh -c "$(curl -fsSL https://github.com/Cabbagec/termux-ohmyzsh/raw/master/install.sh)" 安裝過程會詢問要使用的背景色。
以及字型。
依自己喜好下去設定即可,後續如要變更,可呼叫命令重設。
~/termux-ohmyzsh/install.sh 安裝好後開啟 zsh 的設定。
vim .zshrc 可以設定 zsh 的主題,有 agnoster、robbyrussell、jaischeema、re5et、junkfood、cloud、random 可供設定。
設定完起一個新的 session 就會看到 Termux 的 zsh 主題被套用上去了。
read morePosts
Termux - Internal and external storage
Termux 裝完後預設只能看到 Termux 空間內的資料,若要讓 Termux 能使用到 Android 的內外部空間,需要自行呼叫命令開啟。
開啟只要呼叫下列命令:
termux-setup-storage 開啟時會確認是否授權,點選允許完成授權動作。
命令跑完 Termux 下會多個 ~/storage 目錄。
透過該目錄就可以存取到 Android 的內外部空間了。
Link Internal and external storage Termux-setup-storage
read morePosts
Termux - Getting started
要使用 Termux,首先需透過 Google Play 商店或是 F-Droid 下載安裝。
安裝後點選 Termux 圖示啟動。
Termux 啟動後會看到如下終端機畫面,終端機畫面上會提供一些參考的資源,以及套件管理的常用操作。
為了使用較新的套件,這邊可先進行更新。
apt update && apt upgrade 為了便於使用 Termux 在操作上也做了些巧思,像是長按螢幕可叫出選單,便於複製貼上。
MORE… 內也有些功能可供使用,像是 Kill process 可終止目前的 process (輸入 exit 離開也可以)、Help 可直接開啟 Termux wiki。
上音量鍵是特殊鍵,可做的功能有…
Volume Up+E → Escape key Volume Up+T → Tab key Volume Up+1 → F1 (and Volume Up+2 → F2, etc) Volume Up+0 → F10 Volume Up+B → Alt+B, back a word when using readline Volume Up+F → Alt+F, forward a word when using readline Volume Up+X → Alt+X Volume Up+W → Up arrow key Volume Up+A → Left arrow key Volume Up+S → Down arrow key Volume Up+D → Right arrow key Volume Up+L → | (the pipe character) Volume Up+H → ~ (the tilde character) Volume Up+U → _ (underscore) Volume Up+P → Page Up Volume Up+N → Page Down Volume Up+.
read morePosts
Termux - Package management
Termux 除了可以使用 apt & apt-get 來做套件管理外,也提供 pkg 來做套件管理。
使用方式可直接帶入 help 命令查閱。
pkg help 像是可用 search 命令搜尋是否有指定套件可供安裝。
pkg search <query> 找到指定套件後可用 show 命令進一步查看套件資訊。
pkg show <packages> 套件安裝可用 install 命令,並帶入要安裝的套件。
pkg install <packages> 安裝完後可用 list-installed 命令做個檢查。
pkg list-installed Link Package Management
read moreTag: .NET Core
Posts
.NET Core - Uninstall with shell script
若非使用 HomeBrew 安裝 .NET Core,沒辦法使用 HomeBrew 命令直接反安裝,需就官方解除安裝的步驟進行反安裝。
不過官方反安裝步驟繁瑣,需自行去多個目錄清除資料,非常不便。所以這邊直接使用 dotnet/cli 提供的腳本來進行反安裝。
先下載腳本。
wget https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/uninstall/dotnet-uninstall-pkgs.sh 運行下載下來的腳本。
sudo sh dotnet-uninstall-pkgs.sh .NET Core 就會被反安裝了。
dotnet --version && dotnet --list-sdks && dotnet --list-runtimes
read morePosts
.NET Core - Update .NET Core SDK with HomeBrew
用 HomeBrew 安裝的 .NET core SDK,可直接用 HomeBrew 進行更新。
像是筆者電腦中的 .NET Core SDK 是 3.0 的版本。
dotnet --version 要升級到最新版的 .NET core SDK 3.1,可直接透過 HomeBrew cask reinstall 命令去更新 dotnet-sdk 套件。
brew cask reinstall dotnet-sdk .NET core SDK 就會被升到 3.1 最新版。
dotnet --version
read morePosts
.NET Core - Install .NET Core SDK with HomeBrew
要使用 HomeBrew 安裝 .NET SDK,可以使用 brew cask 安裝 dotnet-sdk 套件。
brew cask install dotnet-sdk 安裝完後可開新的 Terminal 調用命令查詢 .NET Core SDK 版本試試,安裝成功的話應可正常看到 .NET Core SDK 的版本。
dotnet --version
read morePosts
.NET Core - Getting started
要使用 .NET Core,首先需至 Getting started with .NET Core 這邊下載對應的安裝檔案。
{% img /images/posts/DotnetCoreGettingStarted/1.png %}
接著執行下載下來的安裝包進行安裝。
{% img /images/posts/DotnetCoreGettingStarted/2.png %}
{% img /images/posts/DotnetCoreGettingStarted/3.png %}
{% img /images/posts/DotnetCoreGettingStarted/4.png %}
{% img /images/posts/DotnetCoreGettingStarted/5.png %}
{% img /images/posts/DotnetCoreGettingStarted/6.png %}
{% img /images/posts/DotnetCoreGettingStarted/7.png %}
接著開啟命令列,建立一個專案目錄,在專案目錄下輸入命令 dotnet new 建立 .NET Core 的專案,建立的專案內應該會含有 NuGet.Config、Program.cs、project.json 這三個檔案。
{% img /images/posts/DotnetCoreGettingStarted/8.png %}
接著我們要呼叫命令 dotnet restore 將依賴的套件進行還原。
{% img /images/posts/DotnetCoreGettingStarted/9.png %}
還原後輸入命令 dotnet run 運行專案即可。
{% img /images/posts/DotnetCoreGettingStarted/10.png %}
Link Getting started with .
read moreTag: Medis
Posts
Medis - Reunning locally
要在本地運行 Medis,先要將 Medis 下載下來。
git clone https://github.com/luin/medis 進入 Media 目錄。
cd medis 安裝需要的 npm 套件。
npm install 建置。
npm run build 因為運行需依賴 electron,若未安裝,這邊可進行全域安裝。
npm install -g electron 最後使用 npm 的 start 命令啟用程式即可。
npm start
read moreTag: Dotnet-Dump
Posts
dotnet-dump - Analyze .Net Core dump file
Dump 出 .Net Core 的 Dump file 後。
可使用 dotnet-dump analyze 帶上 Dump file 的位置進行 Dump 檔的分析。
dotnet-dump analyze $dump_file 分析是使用 SOS 命令,像是要查詢 Thread,可輸入 clrthreads 命令。
clrthreads 要查詢呼叫堆疊,可輸入 clrstack 命令。
clrstack 要查看是什麼錯誤導致程式死掉,可使用 pe 命令。
pe -lines
read morePosts
dotnet-dump - Installation
要安裝 dotnet-dump 可使用 dotnet tool install –global 將 dotnet-dump 安裝到全域。
dotnet tool install --global dotnet-dump 安裝完設定路徑。
export PATH="$PATH:/root/.dotnet/tools" 查驗版本確認安裝無誤即可。
dotnet-dump --version
read moreTag: MongoDB Compass
Posts
MongoDB Compass - Install with Homebrew
要使用 Homebrew 安裝 MongoDB Compass,可以調用如下命令:
brew cask install mongodb-compass 安裝完可以透過應用程式這邊啟動 MongoDB Compass。
read moreTag: Snowflake
Posts
Redis - Generate Snowflake generator id with client info
在做分散式系統時,有些情境下免不了要給節點維一的識別號,像是在用 Snowflake 分散式 Id 演算法時會需要給予 10 bit 長的 Generator id,用以避免 Id 碰撞。
識別號有的會直接取 IP 某段,或是 Process no,這樣並不能確保值的唯一。要確保維一只能依賴自行靠設定將設定值錯開,或是設計一個演算法配給。
若是搭配 Redis 使用,最直覺的演算法可能就是在每個服務實體啟動時去 Redis 註冊一個唯一的識別值,服務實體與識別值的資訊都放置在 Redis 中,並設有過期時間。每個服務定時到 Redis 延長過期時間,如果資訊過期,則對應的識別碼要釋出給新服務用。
上面的演算法很直覺,但有兩點較大的問題,一個是實作上很麻煩,一個是定時到 Redis 延長過期時間的做法對系統來說不是很好。好在 Redis 有維護每個連線的 Client 資訊,也都取的到,透過 Redis client 的資訊實作上會簡單許多,對系統來說處理也比較沒那麼吃重。
舉個例子來說,假設我用 Redis 的 Hash 來實作,Key 假定為 generator,裡面的 field 用來放 Generator id,value 用來放 Redis client 的 Id。
generator => { {$generator-id, $redis-client-id}, ... } 這樣在第一個服務上線時,Redis 內的資料是空的。
generator => { } 這時透過 Redis 命令 CLIENT LIST 取得所有連線的 Id,與 CLIENT ID 命令取得當前連線的 Id,就可以去更新並配給 Generator id。像是所有連線 Id 問回來只有一個連線,且連線 Id 跟當前連線 Id 一樣都是 0,就會將 Generator id 0 配給 Redis client 0。
read moreTag: Try .NET
Posts
Try .NET - Installation
要安裝 Try .NET,可透過 dotnet tool install 將 dotnet-try 安裝到全域。
dotnet tool install --global dotnet-try 安裝完就可以開始使用。
dotnet try -h 若無法運行,可查驗一下是否為路徑問題。
export PATH="$PATH:/root/.dotnet/tools" 若有需要可透過 dotnet tool update 更新 dotnet-try 套件。
dotnet tool update -g dotnet-try
read moreTag: Migrate
Posts
migrate - MongoDB driver
migrate 要對 MongoDB 進行資料庫的 Migration,Migration 檔案內要放置要給 MongoDB 用 db.runCommand 運行的命令,附檔名為 json。
migrate 的資料庫這邊要參照下列格式設定。就可以透過 migrate 做資料庫的 Migration。
mongodb://user:password@host:port/dbname?query 運行 Migration 後資料庫內會多個 schema_migrations collection,用以存放 Migration 的資訊。
Link MongoDB
read morePosts
migrate - MySQL/MariaDB driver
migrate 要對 MySQL/MariaDB 進行資料庫的 Migration,migrate 的資料庫這邊要參照下列格式設定。
mysql://user:password@tcp(host:port)/dbname?query Migration 檔案用 SQL 語法下去撰寫。
就可以透過 migrate 做資料庫的 Migration。
運行 Migration 後資料庫內會多個 schema_migrations 資料表,用以存放 Migration 的資訊。
schema_migrations 資料表內只會有一筆紀錄,只會有 version 與 dirty 資訊,沒有 Migration 的版本紀錄,也沒有 CRC 檢查碼驗證。
Link MySQL
read morePosts
migrate - Force set version without run migration
migrate 的 force 命令可不運行 migration 就強制設定版本。
像是筆者這邊有個沒套過 migration 的資料庫。
migrate -source $source -database $database version 筆者強制設定資料庫版本。
migrate -source $source -database $database force $version 資料庫版本就會被強制設為指定的版本。
migrate -source $source -database $database version
read morePosts
migrate - Getting started
migrate 安裝後可調用命令查閱 CLI 使用方式。
migrate -help 使用方式如下:
Usage: migrate OPTIONS COMMAND [arg...] migrate [ -version | -help ] Options: -source Location of the migrations (driver://url) -path Shorthand for -source=file://path -database Run migrations against this database (driver://url) -prefetch N Number of migrations to load in advance before executing (default 10) -lock-timeout N Allow N seconds to acquire database lock (default 15) -verbose Print verbose logging -version Print version -help Print usage Commands: create [-ext E] [-dir D] [-seq] [-digits N] [-format] NAME Create a set of timestamped up/down migrations titled NAME, in directory D with extension E.
read morePosts
migrate - Install migrate CLI on Linux (*.deb package)
要在 Linux 上安裝 migrate,先將 migrate 的金鑰加入。
curl -L https://packagecloud.io/golang-migrate/migrate/gpgkey | apt-key add - 將 migrate 加入套件來源清單。
echo "deb https://packagecloud.io/golang-migrate/migrate/ubuntu/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/migrate.list 更新套件清單。
apt-get update 進行 migrate 套件安裝。
apt-get install -y migrate 最後調用命令查閱 migrate 版本,確認安裝無誤。
migrate -version Link migrate CLI
read moreTag: Fody
Posts
MethodBoundaryAspect.Fody - Altering asynchronous method behavior
MethodBoundaryAspect.Fody 要修改非同步方法的回傳值,可在 OnExit 方法實作時將 MethodExecutionArgs.ReturnValue 屬性值轉回 Task,用 ContinueWith 串接處理,並將之塞回 MethodExecutionArgs.ReturnValue。
if (args.ReturnValue is Task<...> t) { args.ReturnValue = t.ContinueWith(...); } 像是如果要撰寫一個可將方法回傳值變大寫的 Attribute 的話,可像下面這樣撰寫。
using System.Threading.Tasks; using MethodBoundaryAspect.Fody.Attributes; namespace MethodBoundaryAspect.Fody.Demo { public sealed class UpperAttribute : OnMethodBoundaryAspect { public override void OnExit(MethodExecutionArgs args) { if (args.ReturnValue is Task<string> t) { args.ReturnValue = t.ContinueWith(task => t.Result.ToUpper()); } else { args.ReturnValue = (args.ReturnValue as string).ToUpper(); } } } } 在要做大寫轉換的方法上加掛 Attribute。
using System; using System.
read morePosts
MethodBoundaryAspect.Fody - Altering method behavior
MethodBoundaryAspect.Fody 要修改方法的回傳值,可在 OnExit 方法實作時透過 MethodExecutionArgs.ReturnValue 屬性填入新的方法值。
像是如果要撰寫一個可將方法回傳值變大寫的 Attribute 的話,可像下面這樣撰寫。
using MethodBoundaryAspect.Fody.Attributes; namespace MethodBoundaryAspect.Fody.Demo { public sealed class UpperAttribute : OnMethodBoundaryAspect { public override void OnExit(MethodExecutionArgs args) { args.ReturnValue = (args.ReturnValue as string).ToUpper(); } } } 在要做大寫轉換的方法上加掛 Attribute。
using System; namespace MethodBoundaryAspect.Fody.Demo { class Program { [Log] static void Main(string[] args) { Console.WriteLine(GetData()); } [Upper] static string GetData() { return "hello world!"; } } } 程式在編譯時即會加掛對應的處理,方法運行後可看到回傳值會被轉為大寫。
read morePosts
MethodBoundaryAspect.Fody - A Fody weaver which allows to decorate methods and hook into method start, method end and method exceptions
MethodBoundaryAspect.Fody 能透過 Fody 在程式編譯時將進出方法與方法丟出錯誤時的處理掛入系統中。
使用時需先引用 MethodBoundaryAspect.Fody 套件。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="MethodBoundaryAspect.Fody" Version="2.0.113" /> </ItemGroup> </Project> 然後加入 FodyWeavers.xml 檔,指示 Fody 要使用 MethodBoundaryAspect。
<?xml version="1.0" encoding="utf-8"?> <Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> <MethodBoundaryAspect /> </Weavers> 接著開一個 Attribute 類別繼承 OnMethodBoundaryAspect,在 OnEntry 撰寫方法進入時的處理、OnExit 撰寫方法離開時的處理、OnException 撰寫方法發生例外時的處理。
using System; using MethodBoundaryAspect.Fody.Attributes; namespace MethodBoundaryAspect.Fody.Demo { public sealed class LogAttribute : OnMethodBoundaryAspect { public override void OnEntry(MethodExecutionArgs args) { Console.WriteLine("OnEntry..."); } public override void OnExit(MethodExecutionArgs args) { Console.
read morePosts
ModuleInit.Fody - Adds a module initializer to an assembly
ModuleInit.Fody 能透過 Fody 在程式編譯時將初始化處理掛入系統程式中,能在系統一開始運行時做初始的動作。
使用時需先引用 ModuleInit.Fody 套件。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="ModuleInit.Fody" Version="2.0.0" PrivateAssets="All" /> </ItemGroup> </Project> 然後加入 FodyWeavers.xml 檔,檔案內容如下,指示 Fody 要使用 ModuleInit。
<?xml version="1.0" encoding="utf-8"?> <Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> <ModuleInit /> </Weavers> 接著在 ModuleInitializer 的 Initialize 方法撰寫初始化的部分。
運行後可看到程式會在啟動時先運行初始化程式。
Link Fody/ModuleInit: Adds a module initializer to an assembly
read morePosts
MethodTimer.Fody - Injects some very basic method timing code
MethodTimer.Fody 能透過 Fody 在程式編譯時將用來計算時間的程式放入掛有 TimeAttribute 的方法。
使用時需先引用 MethodTimer.Fody 套件。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="MethodTimer.Fody" Version="3.0.0" PrivateAssets="All" /> </ItemGroup> </Project> 然後加入 FodyWeavers.xml 檔,檔案內容如下,指示 Fody 要使用 MethodTimer。
<?xml version="1.0" encoding="utf-8"?> <Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> <MethodTimer /> </Weavers> 接著在 MethodTimeLogger 的 Log 方法撰寫時間計算的部分。
using System; using System.Reflection; namespace Fody.MethodTimer { public static class MethodTimeLogger { public static void Log(MethodBase methodBase, long milliseconds, string message) { Console.WriteLine($"[{methodBase.DeclaringType.Name}.{methodBase.Name}] {message} {milliseconds} ms"); } } } 然後在要計算時間的部分加掛 TimeAttribute,TimeAttribute 可掛在方法、類別、模組上,掛上時可順帶帶入對應的訊息。
read moreTag: SchemaSync
Posts
>-
SchemaSync 使用方式如下:
schemasync [options] <source> <target> # source/target format: mysql://user:pass@host:port/database # output format: <database>[_<tag>].YYYYMMDD.(patch|revert)[_<version>].sql -h, --help show this help message and exit -V, --version show version and exit. -r, --revision increment the migration script version number if a file with the same name already exists. -a, --sync-auto-inc sync the AUTO_INCREMENT value for each table. -c, --sync-comments sync the COMMENT field for all tables AND columns --tag=TAG tag the migration scripts as <database>_<tag>.
read morePosts
SchemaSync - Installing the latest development version
要安裝 SchemaSync 最新的開發版,先將 SchemaSync 用 git clone 下來。
git clone git://github.com/mmatuson/SchemaSync.git 然後切到 clone 下來的目錄。
cd SchemaSync 透過 Python 調用 setup.py 進行安裝。
sudo python setup.py install 安裝完可調用命令查驗版本,確認安裝無誤。
schemasync -V Link Schema Sync a MySQL Schema Versioning and Migration Utility
read moreTag: Flyway
Posts
Flyway - Enable out of order migrations
在使用 Flyway 時,預設 Migration 是會被限制只允許照順序套用的。
像是筆者這邊套上 V2 與 V3 的 Migration 後再準備 V1 的 Migration。
因為已經套到了 V3,所以較低版本的 V1 會無法套用,顯示為 Ignore 狀態。
如過要讓低於當前版本的 Migration 可被套用,可開啟 Flyway 設定檔,將 flyway.outOfOrder 設計值設為 true。
flyway.outOfOrder=true 設定後就不會因為 Migration 版本低於當前版本而被 Ignore。
也能被 Migrate 到資料庫。
只是狀態會是 Out of Order,不會是 Success。
read morePosts
Flyway - Disable Clean command
Flyway 的 Clean 命令是比較危險的命令,因此在上正式環境時會透過設定將之關閉。
開啟設定檔將 flyway.cleanDisable 設定值設定為 true 後存檔離開。
flyway.cleanDisable=true Clean 命令就會被禁止使用了。
read morePosts
Flyway - Repairs the schema history table
Flyway 的 Repair 功能可用來修復 Flyway 存放在資料庫內的資料。
像是 Migrate 發生錯誤,可用來清楚錯誤狀態。或是重新套用 Migration,去修復 Migration type/description/checkchecksum。
像是這邊筆者的資料庫狀態如下…
因為沒有造資料表所以塞資料的 Migration migrate 時會出錯。
這時資料庫內的 Migration 的狀態會是 Failed。
這時使用 Repair 功能…
flyway repair 資料庫內的 Migration 會回到 Pending 狀態。
read morePosts
Flyway - Drops all objects in the configured schemas
Flyway 的 Clean 功能能將資料庫內所有東西都清除,不論是 Table、View、還是 Procedure。
通常用在測試 Migration 時。
像是這邊有一個已經 Migration 過的資料庫。
Clean 以後…
flyway clean 資料庫內的資料都會被清掉。
我們就可以調整 Migration,重新將 Migration migrate 到資料庫,反覆操作,藉此將 Migration 調到我們預期的效果。
read morePosts
Flyway - Validates the applied migrations against the available ones
Flyway 的 Validate 可依據資料庫的 Migrate 資料與本地的 Migration 資訊做些驗證。
如果資料庫的 Migrate 資料與本地的 Migration 比對,Migration 的名字、類型、Checksum 不同,驗證錯誤。
如果資料庫的 Migrate 資料在本地已找不到對應的 Migration,驗證錯誤。
如果本地的 Migration 還未 Migrate 到資料庫,驗證錯誤。
像是這邊筆者這邊本地的 Migration 未 Migrate 到資料庫。
驗證會錯誤。
flyway validate 將 Migration migrate 到資料庫。
flyway migrate 驗證就會通過了。
flyway validate
read morePosts
Flyway - Baselines an existing database
在使用 Flyway 時,若已有現有的資料庫,可以透過 Flyway baseline 為現有資料庫打上一個版本。
像是這邊筆者就先將現有的資料庫打上 Baseline。
flyway baseline 接著就可以照著正常 Migrate 流程下去走了。
read morePosts
Flyway - Prints the details and status information about all the migrations
要透過 Flyway 查閱 Migration 的資訊或是運行狀態,可透過 Flyway 的 info 命令。
flyway info Flyway info 會將資料庫內的 Migration 資訊與本地的 Migration 整理後呈現。
像是這邊筆者有一個空的資料庫,本地放了兩個 Migration 檔,運行 Flyway info 後會看到兩個在 Pending 狀態的 Migration。
flyway info 將 Migration migrate 進資料庫。
flyway migrate 再次調用 Flyway info,可看到兩個 Migration 都切到了 Success 狀態。
flyway info
read morePosts
Flyway - Migrates the schema to the latest version
Flyway 把所有的資料庫變更都稱為 Migration,套用資料庫變更的動作即為 Migrate。
Migration 分為 Versioned、 Undo、 Repeatable 三種。
Versioned Migration 是一般的 Migration,帶有版號,且只能運行一次。檔案格式如下:
Undo Migration 是用來還原 Versioned Migration 用的 Migration。檔案格式如下:
Repeatable Migration 是可重複運行的 Migration。檔案格式如下:
這邊筆者實際放入個檔名為 V1__Create_person_table.sql 的 Versioned Migration 到 sql 目錄,表示第一版變更,變更內容為 Create person table。
Migration 內容如下,只是簡單的建立一個名為 PERSON 的資料表。
create table PERSON ( ID int not null, NAME varchar(100) not null ); 調用 Flyway migrate 命令套用資料庫的變更。
flyway migrate 連進資料庫可看到確實套上了資料庫的變更,連帶多了一張 flyway_schema_history 的資料表,裡面存放 Flyway 套用變更的紀錄。
Migrate 時會依這紀錄檢查是否需要套用資料庫的變更。
read morePosts
Flyway - Config MariaDB
Flyway 要連結 MariaDB,可開啟 Flyway 設定檔。
vim conf/flyway.conf 設定 MariaDB 的位置與帳密。位置部分可遵循下列格式:
jdbc:mariadb://host:port/database 設定上會像下面這樣:
flyway.url=jdbc:mariadb://localhost:3306/db1 flyway.user=root flyway.password=pass.123
read morePosts
Flyway - Install on Linux
Flyway 要在 Linux 上使用,可到 Flyway 的下載頁面,複製 Linux 上要運行的命令。
運行命令,會進行檔案的下載、解壓縮、建立連結。
wget -qO- https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/5.2.4/flyway-commandline-5.2.4-linux-x64.tar.gz | tar xvz && ln -s `pwd`/flyway-5.2.4/flyway /usr/local/bin 進到 Flyway 目錄調用命令,查驗 Flyway 版本,確認安裝正確無誤。
flyway -v
read moreTag: Blazor
Posts
Blazor - Dependency injection
Blazor component 若需要使用 Service,可透過 DI 注入。
像是 Blazor 範本內就有一個 Service。
using System; using System.Linq; using System.Threading.Tasks; namespace WebApplication1.Data { public class WeatherForecastService { private static string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate) { var rng = new Random(); return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = startDate.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }).ToArray()); } } } 這個 Service 會在 Startup.
read morePosts
Blazor - Route to components
Blazor component 在未加掛 @page directive 時只能像 HTML element 一樣嵌入頁面使用。
如果要能直接當成頁面透過 Routing 訪問,可在 Blazor component 最前面加掛 @page directive,指定 Blazor component 的 routing。
@page "/counter" ... 像是下面這樣撰寫。
@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="@IncrementCount">Click me</button> @code { int currentCount = 0; [Parameter] private int IncrementAmount { get; set; } = 1; void IncrementCount() { currentCount += IncrementAmount; } } 就可以透過 Routing 導到該 Blazor component,像是範本內的 Counter 就可以透過 https://localhost:5001/counter 訪問。
read morePosts
Blazor - Component parameters
若想讓 Blazor component 在畫面上使用時帶上參數做些設定,可以為 Component 加上 Parameter。
只要在 code 區塊中加入帶有 ParameterAttribute 的 property 即可。
... @code{ ... [Parameter] private int IncrementAmount { get; set; } = 1; ... } 在畫面上就可以透過 Component parameter 對 Component 做些設定。
... <Counter IncrementAmount="10" /> ... 像是 Blazor 範本的 Counter component 可以改成像下面這樣:
@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="@IncrementCount">Click me</button> @code { int currentCount = 0; [Parameter] private int IncrementAmount { get; set; } = 1; void IncrementCount() { currentCount += IncrementAmount; } } 加入 IncrementAmount parameter 供外部設定,IncrementCount 方法會依照 IncrementAmount 的值去增加 currentCount。
read morePosts
Blazor - Build components
Blazor component 是 Blazor 的元件,類似控制項,是 Blazor 中可重複使用的最小單位。
Blazor component 以 razor 為副檔名,它跟 ASP.NET MVC 的 Razor page 很像,會用 HTML 與 Razor 語法排版畫面。程式碼放在 @code {…} 內,程式碼可定義 Component 會用到的變數與方法,在畫面排版那邊可取用程式碼區塊中定義的變數與方法。
這邊可參閱 Blazor 範本的 Counter 程式。程式碼那邊定義了一個 currentCount 的變數,以及一個 IncrementCount 方法,IncrementCount 方法只是很單純的將 currentCount 變數值加一。畫面這邊透過 @onclick="@IncrementCount" 指定畫面元素被按下時調用 IncrementCount 方法,並透過 @currentCount 將變數的值呈現在畫面上。
<h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="@IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } } Blazor component 做好後,可以直接將它當成 HTML element 使用,像是要將剛剛建立的 Counter component 加入使用,可以像下面這樣撰寫:
read morePosts
Blazor - Getting started
要運行 Blazor,可先安裝 .Net Code 3.0 SDK,然後安裝 Blazor 範本。
dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.0.0-preview6.19307.2 再來透過範本建立 client 程式。
dotnet new blazor -o $project 或是 Server side 程式。
dotnet new blazorserverside -o $application 透過範本建立好後將程式運行起來。
dotnet run 透過瀏覽器訪問 http://localhost:5000 或是 https://localhost:5001,即可看到 Blazor 運行起來的樣子。
read moreTag: Ghz
Posts
ghz - Benchmark with template data
在用 ghz 做 gRPC 的 Benchmark 時,如果需要打入不同的測試資料,又不想要撰寫程式的話,可使用 ghz 的 Template data。
ghz 提供的 Template data 如下:
// call template data type callTemplateData struct { // unique worker ID WorkerID string // unique incremented request number for each request RequestNumber int64 // fully-qualified name of the method call FullyQualifiedName string // shorter call method name MethodName string // the service name ServiceName string // name of the input message type InputName string // name of the output message type OutputName string // whether this call is client streaming IsClientStreaming bool // whether this call is server streaming IsServerStreaming bool // timestamp of the call in RFC3339 format Timestamp string // timestamp of the call as unix time TimestampUnix int64 } 裡面有 Worker 編號、Request 編號、Method 名稱、Service 名稱、傳入的 Message 名稱、傳出的 Message 名稱、是否 Streaming、RFC3339 格式的時間、Unix 時間。
read morePosts
ghz - Benchmark with CLI
要用 ghz CLI 打 Benchmark,可先參考 ghz CLI 的使用說明。
usage: ghz [<flags>] [<host>] Flags: -h, --help Show context-sensitive help (also try --help-long and --help-man). --config= Path to the JSON or TOML config file that specifies all the test run settings. --proto= The Protocol Buffer .proto file. --protoset= The compiled protoset file. Alternative to proto. -proto takes precedence. --call= A fully-qualified method name in 'package.Service/method' or 'package.Service.Method' format. -i, --import-paths= Comma separated list of proto import paths.
read morePosts
ghz - Install on Linux
要在 Linux 安裝 ghz,可到 Release page 找到要使用的版本,然後下載下來。
wget $url 下載後解壓縮。
tar zxvf $file 就可以開始使用了。
ghz -v Link ghz - Simple gRPC benchmarking and load testing tool
read moreTag: Gollum
Posts
gollum - Start service
gollum 安裝好後,可到 wiki 的 git repository 目錄下,調用命令啟動 gollum 服務。
gollum 服務預設監聽 4567 埠,服務啟動後可透過瀏覽器訪問 http://localhost:4567。
因為 gollum 服務依賴 git 去做版控,如果在非 git 目錄下啟動服務,透過瀏覽器訪問會看到如下的錯誤頁面。這時可查驗一下當前所在的目錄位置,如果位置無誤只是還未使用 git 控管,可初始 git 後再次嘗試。
正常應該要看到像下面這樣的頁面,可以直接透過gollum 在本地管理 wiki。
read morePosts
gollum - Install on Ubuntu
要在 Ubuntu 安裝 gollum,可先透過 apt-get 安裝必要套件。
apt-get install ruby ruby-dev make zlib1g-dev libicu-dev build-essential git cmake 然後透過 RubyGems 安裝 gollum 即可。
gem install gollum Link Installation - gollum / gollum
read moreTag: Rust
Posts
Rust - Lints
Rust 內建程式碼分析功能,在編譯時會針對程式碼進行分析。
分析出來的問題分為 allow、warn、deny、forbid 這幾個等級。
allow 是被允許的問題,預設是不會顯示的,若有需要可手動將它轉成其它等級。
在編譯時可帶入 -W、-D、-F 將指定的 allow 等級問題轉為 warn、deny、forbid 等級,這樣就可以在編譯時看到問題。
rust -W $issue rust -D $issue rust -F $issue 如果是 allow 等級以外的問題,直接編譯就可以偵測到。
像是 warn。
deny…
或是 forbid。
如要轉換問題等級,除了用上面提到的命令參數外,也可以透過 attribute 的方式指定。
Link Lint levels - The rustc book
read morePosts
Rust - Getting started
Rust 安裝後來撰寫個簡單的程式上手一下。
開啟編輯器撰寫如下程式:
fn main() { println!("Hello, world!"); } 程式只是很簡單的輸出 Hello, world!,程式記得存檔的副檔名為 rs。
然後調用命令編譯程式。
rustc $file 調用編譯出來的檔案即可看到程式運行的結果。
read morePosts
Rust - Install on Termux
在 Termux 上安裝 Rust,可透過套件管理程式安裝 Rust 套件。
pkg install rust 安裝完後可查詢 Rust 版本做個確認。
rustc -V
read moreTag: Go
Posts
Go - Install on Termux
要在 Termux 使用 Go,可透過 pkg 安裝 golang 套件。
pkg install golang 安裝完可調用 go 命令查閱版本,命令應該正常運作,回應安裝的 Go 版本資訊。
go version
read moreTag: Python
Posts
Python - Install on Termux
要在 Termux 安裝 Python,可透過 pkg 安裝 python 套件。
pkg install python 安裝完可查閱 Python 版本做過確認,Python 命令應可正常運行,回應安裝的 Python 版本。
python --version
read morePosts
Visual Studio Code - Analyze Python with Pylint
要在 Visual Studio Code 中開發 Python 並使用 Pylint 進行程式碼的分析,Visual Studio Code 要先安裝 Python 的套件,完成 Python 開發環境的設定。
然後安裝 Pylint,不同環境有不同的安裝方式,因為筆者用的是 Mac,所以是用 pip 安裝。
沒有 pip 的話要先進行安裝。
開啟 Visual Studio Code 運行 Python 程式,Visual Studio Code 偵測到 Pylint 沒安裝的話會彈出通知,並提供安裝的按鈕。
點選安裝的按鈕,安裝命令會帶到 TERMINAL 視窗調用。
如果有權限問題的話,還是需要自己調整命令後再調用。
安裝好後就可以支援 Python 的分析。
Link Pylint - code analysis for Python | www.pylint.org
read morePosts
Visual Studio Code - Python on Visual Studio Code
要在 Visual Studio Code 使用 Python,可安裝 Visual Studio Code 的 Python 套件。
套件安裝完按下熱鍵打開 Command Palette (Windows 為 Ctrl+ Shift + P, OS X 為CMD + SHIFT + P),搜尋並運行 Tasks: Configure Task Runner。
接著選取 TypeScript - tsconfig.json。
修改 tasks.json 設定,command 設為 python、args 設為 ${file}、showOutput 設為 always。
設定修改完存檔,按下熱鍵運行 Tasks: Run Build Task (Windows 為 Ctrl+ Shift + B, OS X 為CMD + SHIFT + B),即可運行 Python 程式。
Link Python with Visual Studio Code [Python] 使用 Visual Studio Code 作為開發環境
read morePosts
Hello, Tkinter
Tkinter._test()
form = Tk() … form.mainloop()
form = Tk() form.title(“HelloWorld Demo”) form.geometry(“300x200”)
lbl = Label(form, text=“Hello, world!”) lbl.pack()
form.mainloop()
read morePosts
Tkinter.TK
form = Tk()
form.title(“Tkinter.TK Demo”) form.geometry(“300x200+10+10”) form.iconbitmap(‘Icon.ico’) #form.resizable(False, False) form.minsize(300, 200) form.maxsize(600, 400) #form.attributes("-toolwindow", 1) form.attributes("-topmost", 1) #form.state(“zoomed”) #form.iconify() #form.deiconify() form.configure(background=‘black’)
form.mainloop()
read morePosts
Tkinter's grid geometry manage
form = Tk()
form.columnconfigure(0, weight=0) form.columnconfigure(1, weight=1) form.rowconfigure(0, weight=0) form.rowconfigure(1, weight=0) form.rowconfigure(2, weight=1)
Label(form, text=“First”).grid(row=0, sticky=W) Label(form, text=“Second”).grid(row=1, sticky=W)
Entry(form).grid(row=0, column=1, sticky=W+E) Entry(form).grid(row=1, column=1, sticky=W+E)
Button(form, text=“GO”).grid(row=2, column=0, columnspan=2, padx=5, pady=5, sticky=W+E+S+N)
form.mainloop()
read morePosts
Tkinter's pack geometry manager
lbl = Label(form, text=“pack test2”, bg=“yellow”) lbl.pack()
lbl = Label(form, text=“pack test3”, bg=“blue”) lbl.pack() …
lbl = Label(form, text=“fill test2”, bg=“yellow”) lbl.pack(side=LEFT, fill=Y)
lbl = Label(form, text=“fill test2”, bg=“blue”) lbl.pack(fill=BOTH, expand=1) …
lbl = Label(form, text=“ipad test”, bg=“blue”) lbl.pack(fill=X, ipadx=5, ipady=5) …
read morePosts
Tkinter's place geometry manager
lbl = Label(form, text=“place test2”, bg=“white”) lbl.place(x=20, y=20) …
lbl = Label(form, text=“place test4”, bg=“yellow”) lbl.place(y=150, anchor=E, relx=1)
lbl = Label(form, text=“place test5”, bg=“yellow”) lbl.place(y=180, relx=0.5, anchor=CENTER) …
form = Tk() form.geometry(“300x200”)
lbl = Label(form, text=“place test0”, bg=“gray”) lbl.place(x=5, y=5, relwidth=1, relheight=1, width=-10, height=-10)
lbl = Label(form, text=“place test1”, bg=“red”) lbl.place(x=10, y=10, width=100, height=100)
lbl = Label(form, text=“place test2”, bg=“white”) lbl.place(x=20, y=20)
lbl = Label(form, text=“place test3”, bg=“yellow”) lbl.place(y=120, relx=0.
read morePosts
Tkinter's tkColorChooser
print tkColorChooser.askcolor(title=“test”) print tkColorChooser.askcolor(“red”) print tkColorChooser.askcolor(initialcolor=“red”)
read morePosts
Tkinter's tkFileDialog
if fs: print fs.name else: print “Without selected!” …
print files
if files: for fs in files: print fs.name else: print “Without selected!” …
print tkFileDialog.asksaveasfile(**options).name …
options = {} options[‘filetypes’] = [(“allfiles”,""),(“text”,".txt")] options[‘initialdir’] = “c:" options[‘multiple’] = True
options[’title’] = “tkFileDialog.askopenfilename” print tkFileDialog.askopenfilename(**options) or “Without selected!”
options[’title’] = “tkFileDialog.askopenfilenames” print Tk().tk.splitlist(tkFileDialog.askopenfilenames(**options)) or “Without selected!”
options[’title’] = “tkFileDialog.askopenfile” fs = tkFileDialog.askopenfile(**options)
if fs: print fs.name else: print “Without selected!”
read morePosts
Tkinter's tkMessageBox
tkMessageBox.showinfo(“showinfo demo”, “Info”) tkMessageBox.showwarning(“showwarning demo”, “Warning”) tkMessageBox.showerror(“showerror demo”, “Error”)
print “askquestion’s dialogresult: %s” % tkMessageBox.askquestion(“askquestion demo”, “Sure?!”) print “askokcancel’s dialogresult: %s” % tkMessageBox.askokcancel(“askokcancel demo”, “OK?! CANCEL?!”, default = “ok”) print “askyesno’s dialogresult: %s” % tkMessageBox.askyesno(“askyesno demo”, “Yes?! No?!”, default = “no”) print “askretrycancel’s dialogresult: %s” % tkMessageBox.askretrycancel(“askretrycancel demo”, “Retry?! Cancel?!”, default = “cancel”)
read moreTag: Dart
Posts
Dart - const variable
Dart 的 const 關鍵字可用來指定編譯時常數,指定編譯後就不會變動的值。
使用時只要在變數宣告前面加上 const 關鍵字即可。
const pi = 3.1415926; 像是下面這樣的程式:
main(){ const pi = 3.1415926 pi = 3.14; } 運行起來就會發生錯誤,因為透過 const 宣告的是常數,沒有 Setter 可以改變它的值。
另外看一個比較複雜的例子,這邊用 const 去接建立出來的物件。
class Person { 2 void say() { 3 print("Hello World"); 4 } 5 } 6 void main() { 7 const larry = new Person(); 8 larry = new Person(); 9 larry.say(); 10 } 運行後會出錯,因為編譯時常數無法接運行時才產生的物件。
read morePosts
Dart - final variable
Dart 的 final 關鍵字可用來指定運行時常數,指定其運行時值不允許變更。
使用時只要在變數宣告前面加上 final 關鍵字即可。
final pi = 3.1415926; 像是下面這樣的程式:
main(){ final pi = 3.1415926; pi = 3.14; } 運行起來就會發生錯誤,因為透過 final 宣告的是常數,沒有 Setter 可以改變它的值。
接著來看複雜一點的例子,物件會透過建構子將值塞給 final 常數,物件初始後會嘗試變更其值。
class Person { final String name; Person(this.name); } void main() { var person = new Person('larry'); person.name = 'larrynung'; } 運行起來一樣會出錯,因為透過 final 宣告的常數在物件初始化塞完值後就不能再去變更了。
read morePosts
Dart - Comments
Dart 內的註解分為單行註解與多行註解。
單行註解用 // 。
... // Display 'Hello World' to console ... 多行註解用 /* */ 。
/* Author: LarryNung Date: 2019/06/15 Description: Comments example */ 程式撰寫起來會像下面這樣。
/* Author: LarryNung Date: 2019/06/15 Description: Comments example */ main() { // Display 'Hello World' to console print('Hello World'); } 註解不會影響程式的運行。
read morePosts
Vim - Install dart-vim-plugin with Vundle
使用 Vim 撰寫 Dart,可透過 Vundle 安裝 dart-vim-plugin 套件。
開啟 ~/.vimrc 檔。
vim ~/.vimrc 設定 Vundle 與 dart-vim-plugin。
... set nocompatible filetype off set rtp+=~/.vim/bundle/Vundle.vim call vundle#begin() Plugin 'VundleVim/Vundle.vim' Plugin 'dart-lang/dart-vim-plugin' call vundle#end() filetype plugin indent on ... 然後調用命令進行 Vim plugin 的安裝。
vim +PluginInstall +qall 安裝好後 Dart 程式碼會支援 Highlight。
也支援排版的功能。
:DartFmt 甚至是程式碼的分析。
:DartAnalyzer
read morePosts
Dart - Getting started
Dart 安裝好後,不免俗的要先寫個簡單的 Hello World 程式,用以了解程式的撰寫與運行會要怎樣處理。
開啟編輯器開始撰寫程式。撰寫 main() 方法用來定義程式的進入點,main() 裡面透過 print() 將訊息顯示出來。
main() { print('Hello World'); } 檔名記得以 dart 為副檔名。
程式撰寫好透過 dart 命令帶入檔名運行即可。
dart $DartFile
read morePosts
Dart - Install on Termux
要在 Termux 安裝 Dart,透過 Apt 或 Pkg 去安裝 Dart 套件即可。
pkg install dart 安裝完可查詢版本做過確認,沒意外的話應該會正常運作。
dart --version
read moreTag: Robo 3T
Posts
Robo 3T - Install with HomeBrew
使用 HomeBrew 安裝 Robo 3T,可透過 cask 安裝 robo-3t 套件。
brew cask install robo-3t 安裝完透過啟動台即可啟動 Robo 3T。
read moreTag: GitLab
Posts
GitLab - Manage wiki with git repository
GitLab wiki 其實背後是放在一個 Git repository 內,所以除了支援線上編輯外,也支援離線編輯。
要離線編輯我們先要找到 GitLab wiki repository 位置。
用 Git 將 GitLab wiki repository clone 下來。
Clone 下來後就可透過喜好的 Markdown 文件撰寫工具來撰寫 Wiki。
這邊注意因為 Wiki 支援線上撰寫,所以建議 Follow 線上撰寫的文件配置方式,可實際線上撰寫後用 Git Pull 下來參考。
這邊筆者簡單放置個 Markdown 文件與其用到的圖檔做個測試。
將檔案加入、Commit、推到遠端。
回到 GitLab wiki 就可以看到剛離線編輯的內容了。
read morePosts
GitLab - Cherry-pick changes
要使用 GitLab 做 Cherry-pick,先要進入要 Cherry-pick 的 commit。
展開右上方的 Options 下拉清單點選 Cherry-pick 選單選項。
在 Cherry-pick this commit 對話框中選取要 merge 到的 branch,如果要發送 Merge request 可勾選下方的 Start a new merge request with these changes 勾選框,最後按下下方的 Cherry-pick 按鈕。
如果沒有勾選 Start a new merge request with these changes 勾選框,則 Cherry-pick 會立即 merge。
如果有勾選,則會走回一般 Merge request 的流程。
Link Cherry-pick changes | GitLab
read morePosts
GitLab - Change default branch
GitLab 在建立 Merge Request 時,Target branch 會幫我們自動帶入預設的 branch,也就是 master branch。
在某些情境這樣的設定並不恰當,也可能會增加操作錯誤的風險。
這時我們可以開啟專案的 General project settings。
將 Default Branch 從預設的 master。
切換至其它更為適當的 Branch。
這樣設定完後新開的 Merge Request 所帶出的 Target branch 就會是我們指定的 Branch。
read morePosts
GitLab - Build project with GitLab CI
GitLab Runner 設定好後,可以開始使用 GitLab CI 來建置我們的專案。
只要在 Repository 中加入 GitLab CI 的設定檔 (.gitlab-ci.yml),在設定檔中設定要如何建置專案即可。像是 .NET 程式的話,就是在這設定檔中指定使用 MSBuild 來建置專案。
stages: - build job: stage: build script: '"C:\Windows\Microsoft.NET\Framework644.0.30319\msbuild.exe" "Project.sln"' 因為筆者已經有現成的批次檔,所以設定檔這邊只是很單純的調用批次檔。
設定檔設置並放置到 Repository 後,當程式碼 Commit 到 GitLab 時即會觸發建置的動作,建置後可切換至 [GitLab | CI/CD | Jobs]。
查閱運行的情況。
如果要運行的細部結果,可在 Job 的紀錄上點擊,做進一步的查閱。
Link gitlab - Using GitLabCI with C# - Stack Overflow
read morePosts
GitLab - Setup Specific GitLab Runner
要設定 Specific GitLab Runner,需先至 GitLab 的 CI/CD 設定頁面。
找到 Runner settings。
這邊會顯示 GitLab Runner 註冊時需要的 URL 與 Token。
接著回到命令列調用 GitLab Runner 的 register,設定剛剛拿到的 URL 位置、Token、Runner 描述…等資訊。
Specific GitLab Runner 就設定完成了。
read morePosts
GitLab - Install GitLab Runner on Windows
要在 Windows 使用 GitLab Runner,可至 Install GitLab Runner on Windows - GitLab Documentation 這邊下載 GitLab Runner。
下載後可視需要變更檔名,像是改為 gitlab-runner。然後帶入 install 調用命令,即可進行 GitLab Runner 服務的安裝。
gitlab-runner install GitLab Runner 服務安裝好後,可帶入 start 調用命令,啟動 GitLab Runner 服務。
gitlab-runner start 若不在使用 GitLab Runner,可帶入 stop 調用命令,停用 GitLab Runner 服務。
gitlab-runner stop 然後帶入 uninstall 調用命令,將 GitLab Runner 服務移除。
gitlab-runner uninstall Link GitLab Runner - GitLab Documentation Install GitLab Runner on Windows - GitLab Documentation
read moreTag: Vim
Posts
Vim - Install dart-vim-plugin with Vundle
使用 Vim 撰寫 Dart,可透過 Vundle 安裝 dart-vim-plugin 套件。
開啟 ~/.vimrc 檔。
vim ~/.vimrc 設定 Vundle 與 dart-vim-plugin。
... set nocompatible filetype off set rtp+=~/.vim/bundle/Vundle.vim call vundle#begin() Plugin 'VundleVim/Vundle.vim' Plugin 'dart-lang/dart-vim-plugin' call vundle#end() filetype plugin indent on ... 然後調用命令進行 Vim plugin 的安裝。
vim +PluginInstall +qall 安裝好後 Dart 程式碼會支援 Highlight。
也支援排版的功能。
:DartFmt 甚至是程式碼的分析。
:DartAnalyzer
read morePosts
Vundle - The plug-in manager for Vim
Vundle 是 Vim 的套件管理程式,安裝可直接透過 git 下載。
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim 下載後開啟 Vim 設定檔。
vi ~/.vimrc 加入設定 (不需要的套件請自行移除)。
set nocompatible " be iMproved, required filetype off " required " set the runtime path to include Vundle and initialize set rtp+=~/.vim/bundle/Vundle.vim call vundle#begin() " alternatively, pass a path where Vundle should install plugins "call vundle#begin('~/some/path/here') " let Vundle manage Vundle, required Plugin 'VundleVim/Vundle.vim' " The following are examples of different formats supported. " Keep Plugin commands between vundle#begin/end.
read morePosts
Vim - Display line numbers
Vim 預設 Line number 是關閉的。
如有需要將開啟 Vim 的設定檔。
vi ~/.vimrc 在設定檔內加上設定開啟 Line number。
set number 再次進入 Vim 就會看到 Line number 已被開啟。
如果只是暫時要開關 Line number,可以不用修改到設定檔。
可以直接輸入命令暫時開啟。
set number set nu 或是直接輸入命令暫時關閉。
set nonumber set nonu Link Display line numbers
read morePosts
Vim - Setup encoding
使用 Vim 時若因編碼導致文字無法正常顯示。
可開啟編輯 Vim 的設定檔。
vi ~/.vimrc 加上 encoding 設定後存檔。
set encoding = <Encoding> Vim 就可以用正確的編碼顯示文字。
read morePosts
Vim - Setting up Vim in Windows
Vim 要在 Windows 使用,可下載 Windows 安裝包下來安裝。
安裝完設定環境變數,在 Path 這邊加上 Vim 的目錄位置。
這樣在 MS-DOS 視窗就可以直接調用 Vim 命令了。
若是使用的是 cmder,那可以開啟 [cmder folder]endor\init.bat 進行設定。
找到 Path 設定的部分。
添加 Vim 目錄位置後存檔。
在 cmder 內就可以調用 Vim 了。
Link Vim in Windows – Medium Setting up Vim in Windows – Medium How To Install and Configure Vi / Vim Editor on Windows OS
read moreTag: LuaRocks
Posts
LuaRocks - Install with HomeBrew
要使用 HomeBrew 安裝 LuaRocks,可輸入下列命令。
brew install luarocks 安裝完可實際調用命令做過確認。
luarocks --version
read moreTag: Rider
Posts
Rider - Connect to MariaDB
要透過 Rider 連線 MariaDB 做些操作,可以點選 [ View | Tool Windows | Database ] 主選單選項,開啟 Database 視窗。
然後點選 Database 視窗工具列上的新增按鈕,新增 MariaDB 的 Data Source。
點選 Data Sources and Drivers 視窗中的 MariaDB Driver 按鈕,或是自行切到 MariaDB Driver 頁籤。
在 Driver files 那邊點選下載 Driver。
下載完回到 Data Source。
帶入 Data Source 的資訊後按下 OK 按鈕。
即可在 Database 視窗透過加入的 Data Source 連線到 MariaDB,並進一步對資料庫進行操作。
read morePosts
Rider - Plugin update
要更新 Rider 的套件,可以透過 Rider 的更新自動偵測,當偵測到套件有更新時,Rider 的右下方會看到更新通知框,人框告知哪些套件可供更新,點選更新通知框內的 update 連結。
在 IDE and Plugin Updates 對話框中查閱套件的更新資訊。
勾選要套用更新的套件,然後按下 Update 按鈕。
套件即會開始進行更新的動作。
更新完成重啟 Rider,套件更新即會生效。
除了透過更新通知框,也可以將 Preferences 對話框,左側切到 Plugins 頁籤,右側切到 Updates,挑選要更新的套件按下 Update 按鈕進行套件的更新。
read morePosts
Rider - Add NuGet source feed
要在 Rider 使用自己的 NuGet feed 去抓取 NuGet 套件,可點選 [ Tools | NuGet | Show NuGet Sources ] 主選單選項。
切到 Sources 頁籤,左側選取 Config 檔案,右側切到 Feeds 頁籤,然後點選 New feed 那列後方的 + 按鈕。
填入 NuGet feed 資訊後按下 OK 按鈕即可。
read morePosts
Rider - Config SQL dialect
Rider 如果沒設定 SQL dialect,開啟 SQL 檔時上方會有提示訊息,按下 Change dialect to… 按鈕即可設定 SQL dialect。
或是透過滑鼠右鍵快顯選單也可以。
SQL dialect 的設定可分為 Global、Project、與 File 幾個層級。
設定好後按下 Save 按鈕儲存。
SQL dialect 設好後 Rider 就會知道怎麼正確解讀 SQL 檔。
因此能做些對應的支援處理,像是排版、…等。
read morePosts
Rider - Sync settings
要讓 Rider 在不同裝置有一致的設定,可開啟 Rider 的同步設定功能。
點選 Rider 的 [ File | Sync Settings to JetBrains Account… ] 主選單選項。
點選 Enable Settings Sync 按鈕啟動 Rider 設定同步。啟動後 Rider 會開始同步界面、編輯器、熱鍵、外掛等設定。
同步啟動後本來的 [ File | Sync Settings to JetBrains Account… ] 主選單選項會變為 [ File | IDE Settings Sync ]。如果要關閉同步,可點選 [ File | IDE Settings Sync | Disable Sync…] 主選單選項。
然後評估是否刪除雲端的同步資料,決定是否勾選勾選框,最後按下 Disable Settings Sync 按鈕,即可關閉同步功能。
如果雲端已有同步的設定,其它裝置要使用同步設定,或是同裝置關閉同步後想重新同步,一樣點選 [ File | Sync Settings to JetBrains Acc ount… ] 主選單選項,然後點選 Get Settings from Account 按鈕從雲端設定同步回本機。或是點選 Keep and Sync Local Settings 按鈕以本地的設定為主,將本地的設定同步到雲端。
read morePosts
Iedis - Client list
在 Redis Servers Tool Window 內的連線設定上按下滑鼠右鍵,點選滑鼠右鍵快顯選單上的 Client List 選單選項。
可開啟 Client List 視窗,透過該視窗可查閱所有連到 Redis 的 Client。
也可以刪除指定的 Client 連線。
read morePosts
Iedis - Advanced console
在 Redis Servers Tool Window 內的連線設定上按下滑鼠右鍵,點選滑鼠右鍵快顯選單上的 Open Terminal 選單選項,或是透過上方的工具列,抑或者是熱鍵 ⌘ + ⇧ + F10。
即可開啟 Terminal 視窗,可在 Terminal 視窗撰寫並調用 Redis 命令。
Link Iedis: Advanced Console
read morePosts
Iedis - Slow log
在 Redis Servers Tool Window 的 Redis 連線上按下滑鼠右鍵,在滑鼠右鍵快顯選單中有個 Slow Log 選單選項,點選該選單選項。
可看到 Redis 執行比較慢的記錄,會有命令名稱、執行時間等。
Link Iedis: Config Monitor
read morePosts
Iedis - Key operations
透過 Redis Servers Tool Window 加完 Redis 連線後,在連線上連點即可連到對應的 Redis。
連線後可看到 Redis 內含的 Key,左上方的區塊可以做 Key 的過濾,上方的工具列可以做 DataBase 的切換、Key 的新增、TTL 的設定等。
如果要新增 Key,可直接透過點擊上方工具列的 + 按鈕。
設定 Key 的名稱及型態,按下 OK 按鈕繼續。
接著設定 Key 的值,按下存擋即可。
在左邊顯示 Key 的列表這邊,按下滑鼠右鍵,透過滑鼠右鍵快顯選單也可以做很多 Key 的操作,像是新增 Key、Key 更名、刪除 Key、設定 TTL 等。
Link Iedis: Key Operations
read morePosts
Iedis - Configure server
安裝完 Iedis 套件後,Rider 會多出 [View | Tool Windows | Redis Servers] 主選單選項,點選可帶出 Redis Servers Tool Window。
Redis Servers Tool Window 的 + 按鈕可用來新增 Redis 連線。
設定連線的名稱、連線的主機、連線阜、及密碼,按下 Test Connection 按鈕可進行連線的測試。
確認連線資料正確且連線測試無誤,可按下 OK 按鈕完成連線設定。
Redis Servers Tool Window 就會顯示加入的連線。
透過 Redis Servers Tool Window 還可以編輯、移除、展開、折疊連線等動作。
Link Iedis: Servers Window Iedis: Configure Server
read morePosts
Iedis - Install Rider plugin
要在 Rider 安裝 Iedis 套件,可開啟 Perferences 視窗。
切到 Plugins,搜尋套件,點選 Install 按鈕進行安裝。
重啟 IDE 後即可開始使用 Iedis。
read morePosts
Rider - Markdown support plugin
Rider 原生對 Markdown 並未支援,在 Markdown 的編寫上就是類似一般的文字編輯器。
撰寫起來並不是特別方便。如果要讓 Rider 支援 Markdown,可加裝 Markdown support plugin。
點選 [JetBrains Rider | Perferences…] 主選單選項開啟 Perferences 視窗。
點選切換到 Plugins,搜尋 Markdown support 套件。
點選 Install 按鈕進行套件的安裝。
安裝完後重啟 Rider。
Rider 就可以支援 Markdown 了,像是可以直接看到 Markdown 的預覽。
Link Markdown support - Plugins | JetBrains
read morePosts
Rider - NuGet package management
要用 Rider 管理 Nuget 套件,可點選 [Tools | NuGet | Manage NuGet Packages for Solution] 主選單選項。
NuGet Tool Window 會被帶出,在搜尋框中搜尋要安裝的套件。
在 Available Packages 那邊選取要安裝的套件。
這邊可以選取要安裝的版本與 Registry,選取後面的 + 按鈕安裝套件到方案中。
或是選取下面專案後方的 + 按鈕安裝套件到指定專案中。
安裝完後安裝的套件會在 NuGet Tool Window 的 Installed Packages 那邊,剛剛的 + 按鈕會變為 - 按鈕,按下後可進行套件的移除。
read moreTag: Fork
Posts
Fork - Install with HomeBrew
要使用 HomeBrew 安裝 Fork,可透過 brew cask 的 Install 命令安裝 Fork 套件。
brew cask install fork 安裝完後可透過 Application 開啟安裝的套件。
read moreTag: Appcmd
Posts
appcmd - Add site binding
要使用 appcmd 設定站台的 Binding,可以使用 appcmd set site,使用 /site.name 指定要綁定的站台名稱,用 /+bindings 指定 Binding 的資訊,像是 Protocol、IP、Port、與 Host 名稱。
appcmd set site /site.name: "${SiteName}" /+bindings.[protocol='${Protocol}',bindingInformation='${IP}:${Port}:${HostName}'] 像是要幫 Default Web Site 綁定本地用的 SSL,就可以像下面這樣輸入命令。
appcmd set site /site.name: "Default Web Site" /+bindings.[protocol='https',bindingInformation='*:443:localhost'] 命令運行後站台的 Binding 就做完了。
Link Setting Host name on SSL Binding on IIS7
read moreTag: Wget
Posts
wget - Download file via proxy
要讓 wget 透過 proxy 抓取檔案,可設定 http_proxy、https_proxy、或是 ftp_proxy。
如果一次性的調用,可直接在終端機手動輸入 Proxy 設定。
export http_proxy=http://${ProxyServer}:${port} export https_proxy=$http_proxy export ftp_proxy=$http_proxy 如果每次都需要走 Proxy,可修改 .wgetrc 檔。
vim ~/.wgetrc 在 .wgetrc 中做 Proxy 設定。
http_proxy = http://${ProxyServer}:${port} https_proxy = http://${ProxyServer}:${port} ftp_proxy = http://${ProxyServer}:{port} 調用 wget 時可用 –proxy 決定是否透過 proxy 連線。
wget --proxy=on|off 或是直接在 .wgetrc 中設定是否是否透過 Proxy 連線。
use_proxy = on 如果 Proxy 設需要驗證,且 Proxy 設定未輸入驗證資訊,可透過 –proxy-user 與 –proxy-password 將 Proxy 的驗證資訊帶入。
Link How to use wget to download file via proxy – The Geek Diary
read moreTag: Mocha
Posts
'Mocha - the fun, simple, flexible JavaScript test framework'
Mocha 是 Node.js 上的單元測試框架。該單元測試框架能讓我們撰寫測試案例、運行單元測試、及產生測試報告等。
使用前先從 Registry 下載套件。
npm install mocha --save-dev 然後透過 Mocha 提供的 describe、it、before、after、beforeEach、afterEach 這幾個方法撰寫單元測試。
describe 用來設定描述測試的功能或情境,it 用來設定測試案例,before 用來設定測試情境下所有測試案例運行前要做的動作,after 用來設定測試情境下所有測試案例運行後要做的動作,beforeEach 用來設定每個測試案例運行前要做的動作,afterEach 用來設定每個測試案例運行後要做的動作。
像是下面這樣:
describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { ... }); }); }); 單元測試的斷言部份 Mocha 並未提供,需額外使用 Chai 之類的斷言套件搭配撰寫。
所以如果用 Mocha 搭配 Chai 撰寫,程式就會像下面這樣:
var assert = require('assert'); describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { assert.
read moreTag: Node.js
Posts
'Mocha - the fun, simple, flexible JavaScript test framework'
Mocha 是 Node.js 上的單元測試框架。該單元測試框架能讓我們撰寫測試案例、運行單元測試、及產生測試報告等。
使用前先從 Registry 下載套件。
npm install mocha --save-dev 然後透過 Mocha 提供的 describe、it、before、after、beforeEach、afterEach 這幾個方法撰寫單元測試。
describe 用來設定描述測試的功能或情境,it 用來設定測試案例,before 用來設定測試情境下所有測試案例運行前要做的動作,after 用來設定測試情境下所有測試案例運行後要做的動作,beforeEach 用來設定每個測試案例運行前要做的動作,afterEach 用來設定每個測試案例運行後要做的動作。
像是下面這樣:
describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { ... }); }); }); 單元測試的斷言部份 Mocha 並未提供,需額外使用 Chai 之類的斷言套件搭配撰寫。
所以如果用 Mocha 搭配 Chai 撰寫,程式就會像下面這樣:
var assert = require('assert'); describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { assert.
read morePosts
Chai - A BDD / TDD assertion library for node
Chai 是 Node.js 的 BDD / TDD 斷言套件。
使用前先從 Registry 下載套件。
npm install chai --save-dev Chai 有三種撰寫風格,should、expect、assert,assert 是比較偏向傳統的斷言方式,expect 與 should 則是偏向 BDD style 的斷言方式。
無論哪個撰寫風格在撰寫前都需引用 Chai 套件。
const chai = require('chai'); should 撰寫風格使用上要先告知 Chai 套件使用 should 撰寫風格。
chai.should(); 接著用目標值應該是…、目標值應該等於…、目標值應該有…類似這樣的寫法撰寫斷言。
... target.should.be.a(type); target.should.eaequal(value); target.should.have.lengthOf(length); ... 程式寫起來會像下面這樣:
const chai = require('chai'); const foo = "bar"; const beverages = { tea: [ 'chai', 'matcha', 'oolong' ] }; chai.should(); foo.should.be.a('string'); foo.should.equal('bar'); foo.should.have.lengthOf(3); beverages.should.have.property('tea').with.lengthOf(3); 如果斷言錯誤,可以看到像下面這樣斷言錯誤的訊息。
read morePosts
Node.Js - Getting started
Node.Js 安裝完後,開個 Js 檔來撰寫簡單的 Hello World 程式。
console.log("Hello World"); 然後調用 node 命令並帶入程式位置。
node ${file} 即可運行程式,顯示程式運行後的結果。
再來看一下稍微複雜點的 Hello World。
var http = require("http"); var port = 3000; http.createServer(function(reqst, resp) { resp.writeHead(200, {'Content-Type': 'text/plain'}); resp.end('Hello World!'); }).listen(port); console.log('Load http://127.0.0.1:' + port + ' and watch the magic'); 會在特定 Port 號起一個 http 服務,該服務會回應 “Hello World!” 字樣。
將服務啟動。
用瀏覽器訪問服務的位置,即可看到服務回應我們預期的結果。
read morePosts
>-
cheerio 是一用來解析 HTML 的套件,該套件使用方式跟 jQuery 類似。
使用前需先用安裝套件。
npm install cherrio 安裝完後載入 cherrio 模組。
const cheerio = require('cheerio'); 然後用 load 方法將 HTML 載入,載入後就可以像一般使用 jQuery 般帶入 Selector 去選取元素操作。
const $ = cheerio.load(html) 像是下面這樣:
const cheerio = require('cheerio'); const $ = cheerio.load('<h2 class="title">Hello world</h2>') console.log($('h2').text()); 使用起來跟在一般網頁上用 jQuery 是差不多的。更多操作可參閱 cheeriojs/cheerio: Fast, flexible, and lean implementation of core jQuery designed specifically for the server. 這邊。
const cheerio = require('cheerio'); const $ = cheerio.load('<div class="title"><h2>Hello world</h2></div>') console.
read morePosts
Node.js - Transform stream
Transform stream 可以將輸入串流的資料讀入,將讀入的內容轉換,然後輸出到輸出串流。
像是內建的 Gzip transform stream 就能將輸入的資料做 Gzip 壓縮然後輸出。
const zlib = require('zlib'); const gzip = zlib.createGzip(); const fs = require('fs'); const input = fs.createReadStream('index.js'); const output = fs.createWriteStream('index.js.gz'); input.pipe(gzip).pipe(output); 如果要自行撰寫 Transform stream,我們可以撰寫個繼承自 Transform 的類別,然後在 _transform 內撰寫每次收到資料要做的處理,以及在 _flush 內撰寫清空緩衝區時要做的處理,在撰寫這兩個方法時,如果資料轉換完畢,可以用 this.push 將資料輸出。如果處理完成,則要記得調用 callback 方法。
'use strict'; const Transform = require('stream').Transform; class MyTransformStream extends Transform { _transform(data, encoding, callback) { ... //this.push(data); ... callback(); } _flush(callback) { ... //this.push(data); ... callback(); } } 像是筆者寫的這隻 AnalyzeStream,其功能為將 HTML 輸入,依照檢查的 Rule 分析,最後將分析的結果輸出。因為要分析的資料需要完整的 HTML,所以 _transform 這邊只有很簡單的將收到的資料存放起來,然後調用 callback 告知處理完成。在 _flush 這邊會將存放的資料套用 Rule 分析,將分析的結果用 this.
read morePosts
Mochawesome - A Gorgeous HTML/CSS Reporter for Mocha.js
Mochawesome 能讓 Mocha 支援產出 HTML 的測試報告。
使用前需安裝 Mochawesome 套件。
npm install --save-dev mochawesome 調用 Mocha 並使用 -reporter 參數指定使用 Mochawesome 產出測試報告。
mocha --reporter mochawesome 產出的測試報告會存放在 mochawesome-report 下的 mochawesome.html。
Link Mochawesome
read morePosts
bulk-require - require whole directory of trees in bulk
在撰寫 Node.js 時需要的模組我們需要載入才可以使用,bulk-require 套件能讓我們快速的載入目錄內的模組,不需要一個一個載入。
使用上需先安裝 bulk-require 套件。
npm install bulk-require 接著載入 bulk-require 模組。
const bulk = require('bulk-require'); 然後指定模組所在的目錄位置以及要載入的檔案 pattern 即可。
const sections = bulk(folderPath, ['*.js']); 像是下面這樣簡單的程式,我們載入了 folderPath 下所有副檔名為 js 的模組,並將載入的資訊顯示出來。
const bulk = require('bulk-require'); ... const sections = bulk(folderPath, ['*.js']); console.log(sections); 可看到載入的資訊會像下面這樣。
我們可以進一步利用這些載入的模組資訊,將載入的類別都建置實體,便於後續使用。
const bulk = require('bulk-require'); ... const sections = bulk(folderPath, ['*.js']); Object.keys(sections).forEach((element) => this.rules.push(new sections[element]()) ); Link substack/bulk-require: require whole directory of trees in bulk
read morePosts
n - Node version management
n 是一 Node version management,可以管理 Node.js 的版本。安裝時可先將 npm 的快取清掉。
sudo npm cache clean -f 然後用 npm 安裝 n 即可。
sudo npm install -g n 安裝好後就可以用 n 來進行 Node.js 版本的管理。
像是要使用最新版本的 Node.js。
n stable 要使用指定版本的 Node.js。
n <version> 要使用最新版本的 Node.js。
n latest 要切換已經安裝的 Node.js。
n 要移除指定版本的 Node.js。
n rm <version> 要移除當前位使用的 Node.js 版本。
n prune Link tj/n: Node version management Node.js各作業系統更新方式 - eddychang.me
read moreTag: Chai
Posts
Chai - A BDD / TDD assertion library for node
Chai 是 Node.js 的 BDD / TDD 斷言套件。
使用前先從 Registry 下載套件。
npm install chai --save-dev Chai 有三種撰寫風格,should、expect、assert,assert 是比較偏向傳統的斷言方式,expect 與 should 則是偏向 BDD style 的斷言方式。
無論哪個撰寫風格在撰寫前都需引用 Chai 套件。
const chai = require('chai'); should 撰寫風格使用上要先告知 Chai 套件使用 should 撰寫風格。
chai.should(); 接著用目標值應該是…、目標值應該等於…、目標值應該有…類似這樣的寫法撰寫斷言。
... target.should.be.a(type); target.should.eaequal(value); target.should.have.lengthOf(length); ... 程式寫起來會像下面這樣:
const chai = require('chai'); const foo = "bar"; const beverages = { tea: [ 'chai', 'matcha', 'oolong' ] }; chai.should(); foo.should.be.a('string'); foo.should.equal('bar'); foo.should.have.lengthOf(3); beverages.should.have.property('tea').with.lengthOf(3); 如果斷言錯誤,可以看到像下面這樣斷言錯誤的訊息。
read moreTag: DotLiquid
Posts
DotLiquid - Drops
使用 DotLiquid 做範本渲染時,如果需要使用到非基礎型別當作參數,我們可以為其建立對應的 Drop 型別。
該 Drop 型別繼承自 DotLiquid 的 Drop 型別,在建構子將原型別實體帶入,將原型別具有的成員屬性封裝並開出。
using System.Drawing; namespace DotLiquid.Drops.Model { public class PointDrop : Drop { private readonly Point _point; public PointDrop(Point point) { _point = point; } public int X { get => _point.X; } public int Y { get => _point.Y; } } } 渲染時將參數改成自建的 Drop 型別帶入即可。
... var model = new {points = points.Select(item => new PointDrop(item)).ToArray()}; return Generate(templateContext, model); .
read morePosts
DotLiquid - LiquidTypeAttribute
使用 DotLiquid 做範本渲染時,如果需要使用到自訂型別當作參數,自訂型別可加掛 LiquidTypeAttribute 指定範本會使用到的屬性。
using System; namespace DotLiquid.LiquidType.Model { [LiquidType(nameof(Person.Id), nameof(Person.Name), nameof(Person.NickName))] public class Person { public string Id { get; set; } public string Name { get; set; } public string NickName { get; set; } public Person() { } public Person(string name) { this.Id = Guid.NewGuid().ToString(); this.Name = name; this.NickName = name; } } } 加掛 Attribute 後範本就可以使用自訂型別來渲染。
{% for person in persons -%} hi {{person.NickName}}({{person.Id}}, {{person.Name}})~ {% endfor -%} 渲染時注意要設定使用 CSharpNamingConvention,不然會使用到 Ruby 的命名規則,設定的屬性名稱會被轉為小寫且用底線隔開,會找不到對應的屬性。
read morePosts
DotLiquid - Getting started
要在 DotNet 中使用 Liquid 範本,可先加入 DotLiquid 套件參考。
套件參考加入後,開始撰寫程式部分。
程式撰寫起來很簡單,只要解析範本,然後將範本需要的資料帶進去渲染即可。
... var template = Template.Parse("hi {{name}}"); var result = template.Render(Hash.FromAnonymousObject(new { name = "Larry" })); ... 運行起來就會看到 DotLiquid 將資料帶進範本渲染出來的結果。
最後提供比較完整的使用範例,筆者將範本放在內嵌資源中,從內嵌資源讀出範本、透過 DotLiquid 將範本與資料帶入渲染。
using System; using System.IO; using System.Reflection; using System.Threading.Tasks; namespace DotLiquid.GettingStarted { class Program { static void Main(string[] args) { var result = GenerateHelloWorld("Larry", "Mylin", "Andrew"); Console.WriteLine(result); } static string Generate(string templateContext, object model) { var template = Template.Parse(templateContext); return template.
read moreTag: Mac
Posts
tree - Install with HomeBrew
在 Mac 下可以透過 HomeBrew 安裝 tree 命令。
brew install tree 可能會得到像上面這樣的錯誤,這時調用指示的命令。
再次嘗試安裝即可。
安裝完就可以正常使用 tree 命令了。
read morePosts
BloomRPC - Install with Homebrew
要使用 Homebrew 安裝 BloomRPC,可以調用如下命令:
brew cask install bloomrpc 安裝完就可以在應用程式這邊看到 BloomRPC。
read morePosts
iTerm2 - Install on Mac
要在 Mac 上安裝 iTerm2,可在官網下載 iTerm2 程式。
點選下載下來的程式。
點選 Move to Applications Folder 按鈕將 iTerm2 程式搬到應用程式目錄。
就可以在應用程式這邊看到 iTerm2 。
read morePosts
.NET Core - Install .NET Core SDK with HomeBrew
要使用 HomeBrew 安裝 .NET SDK,可以使用 brew cask 安裝 dotnet-sdk 套件。
brew cask install dotnet-sdk 安裝完後可開新的 Terminal 調用命令查詢 .NET Core SDK 版本試試,安裝成功的話應可正常看到 .NET Core SDK 的版本。
dotnet --version
read morePosts
Mac - Enable dark mode
Mac OS 在 Mojave 這版開始支援 Dark mode,可以把外觀顏色調成深色。
可開啟系統偏好設定。
開啟一般設定。
將外觀顏色調成深色即可。
read morePosts
Mac - Open an app from an unidentified developer
在 Mac 上運行的程式若是 unidentified developers 的 app 的話,app 的運行可能會被擋住。
要繼續運行的話,可開啟 System Perferemces。
點選開啟 Security & Privacy。
如果只是暫時要繼續運行,只要按下 Open Anyway 按鈕。
再按下 Open 按鈕。
即可暫時放行被擋住的 app。
如果覺得每次 unidentified developers 的 app 都被擋住很麻煩的話,可直接放寬設定。
先點選左下角的鎖。
輸入帳密解鎖。
將設定改為 Anywhere 即可,
Link macOS Sierra: Open an app from an unidentified developer
read morePosts
Permission denied for a Mac OSX Dropbox app
最近 Mac 的 Dropbox 突然出問題,可能是前陣子搬動家目錄所導致,想將他進行重裝還原,但過程中總是會跟我要求提升權限:
{% img /images/posts/DropboxPermissionDenied/1.png %}
輸入密碼後權限好像都沒取道,怎樣都出現權限錯誤的問題。
{% img /images/posts/DropboxPermissionDenied/2.png %}
查了一下要在 Terminal 下下列指令:
mv ~/.dropbox ~/.Trash sudo mv /Library/DropboxHelperTools ~/.Trash 指令下完後重新安裝就可以了。
Link Dropbox asking for permissions to wrong folder after changing account name - Ask Different IPG EMEA Deployment Knowledge Base: After migrating a Mac user’s profile, Dropbox fails to open: keeps asking for permissions
read morePosts
Mac - Add new applications to Launchpad
要將 Application 加入 Launchpad,只要將要加入的 Application 檔案拖曳至 Application Folder。
{% img /images/posts/AddAppsToLaunchpad/1.png %}
{% img /images/posts/AddAppsToLaunchpad/2.png %}
加進 Application Folder 後,我們就可以在 Launchpad 中看到加入的 Application。
{% img /images/posts/AddAppsToLaunchpad/3.png %}
read moreTag: BloomRPC
Posts
BloomRPC - Install with Homebrew
要使用 Homebrew 安裝 BloomRPC,可以調用如下命令:
brew cask install bloomrpc 安裝完就可以在應用程式這邊看到 BloomRPC。
read moreTag: CSharp
Posts
'gRPC - Create C# gRPC server'
要建立 gRPC 的 Server,須先將 GRPC.Tools、GRPC.Core、Google.Protobuf 這三個 NuGet 套件加入參考。
... <ItemGroup> <PackageReference Include="Google.Protobuf" Version="3.7.0" /> <PackageReference Include="Grpc.Core" Version="1.20.0" /> <PackageReference Include="Grpc.Tools" Version="1.20.0" /> </ItemGroup> ... 然後設定從 Proto 檔產生需要的程式部分。
<ItemGroup> <Protobuf Include="../../proto/*.proto" GrpcServices="Server" /> <Content Include="@(Protobuf)" LinkBase="" /> </ItemGroup> 編譯後可在 obj 下看到產出的檔案。
接著開始實作 Service。
繼承產出的 Service 基底類別。
... public class HelloServiceImpl:HelloService.HelloServiceBase ... 並覆寫該服務的方法即可。
... public override Task<HelloResponse> SayHello(HelloRequest request, ServerCallContext context) { ... } ... 程式寫起來會像下面這樣 (這邊筆者只是簡單的將調用時送進來的人名做些加工回傳而已):
using System.Threading.Tasks; using Grpc.Core; public class HelloServiceImpl:HelloService.
read morePosts
'C# 8.0 - Target-typed new-expressions'
C# 8.0 的 Target-typed new-expressions 能讓開發人員在使用 new 關鍵字建立物件實體時省略帶入型別,編譯器編譯時會依照 Context 幫我們帶入。
以簡單的例子來說,假設已經宣告了變數 p 型別為 Point,那在用 new 關鍵字建立實體時就可以省略帶入 Point。
... Point p = new (1, 2); 反組譯看可以看到編譯器會幫我們在 new 關鍵字後面帶入正確的型別。
複雜一點的情境像是陣列元素的宣告也是支援。
... Point[] ps = { new (1, 2), new (2, 2) };
read morePosts
'C# 7.0 - Throw expressions'
C# 7.0 開始支援 Throw expressions。
三元運算中可以視需要直接丟出 exception。
... this.FirstName = firstName == null ? throw new ArgumentNullException(nameof(firstName)) : firstName; ... ?? 運算式中也可以直接丟出 exception。
... this.LastName = lastName ?? throw new ArgumentNullException(nameof(lastName)); ... Expression bodied member 也可以丟出 exception。
... public override string ToString() => throw new NotImplementedException(); ... 最後附上完整的測試範例:
class Program { static void Main(string[] args) { var person = new Person("Larry", "Nung"); Console.WriteLine(person.ToString()); } } struct Person { public string FirstName { get; set; } public string LastName { get; set; } public Person(string firstName, string lastName) { this.
read morePosts
'C# 7.0 - More expression bodied members'
C# 7.0 擴展了 Expression bodied。
開始支援建構子。
... class Program { ... public Program() => Console.WriteLine("Program()"); ... } ... 支援解構子。
... class Program { ... ~Program() => Console.WriteLine("~Program()"); ... } ... 支援 property accessors。
... private string _myProperty; public string MyProperty { get => _myProperty; set => _myProperty = value; } ... 支援 event accessors。
... public event EventHandler MyEvent { add => _myEvent += value; remove => _myEvent -= value; } .
read morePosts
'C# 7.0 - Deconstruction'
C# 7.0 新增 Deconstruction,可將 Tuple、結構、類別的成員拆解使用。
以 Tuple 為例,若想要將 Tuple 值拆解使用,可以用小括弧宣告出多個區域變數,並將 Value Tuple 指派過去,Value Tuple 的屬性值就會依序塞入這些區域變數。
(var v1, var v2) = GetTuple(); var (v1, v2) = GetTuple(); 若是結構或是類別,則要建一個 public 的 Deconstruct 方法,方法的參數用 out 將拆解出來的值依序傳出,編譯時編譯器就會自行幫我們調用 Deconstruct 方法將值拆解。
(var v1, var v2) = new MyClass(); ... class MyClass() { ... public void Deconstruct(out string v1, out string v2) { v1 = this.V1; v2 = this.V2; } } 若有需要 Deconstruct 也支援多載。
(var v1, var v2) = new MyClass(); .
read morePosts
'C# 7.0 - Tuple'
C# 7.0 新增了 Value Type 的 Tuple,因為是 Value Type,所以對 GC 的負擔會比較少。另外增加了一些語法糖,改進了本來 Tuple 類別可讀性不佳的問題。
使用上需先加入 System.ValueTuple 套件。
若不加入該套件編譯時會看到 System.ValueTuple is not defined or imported 的錯誤。
套件加入引用後我們可以看一下該套件的內容,可以看到有一堆泛型的 ValueTuple struct,裡面的成員屬性跟以往的 Tuple 一樣都是 Item1 ~ ItemN。
使用上可以直接建立 ValueTuple,然後在建立的同時指定其型態與值,在要取值的地方用 Item1 ~ ItemN 屬性來取值。
也可以用小括弧包住屬性值直接宣告。
但這樣的宣告方式跟舊的 Tuple 類別一樣有著可讀性不佳的問題,因此在用小括弧包住屬性值宣告的同時,我們將屬性名稱也一併指定,取值時就可以用指定的屬性名稱來取值。
編譯器在編譯時會自動幫你將程式轉換成 Item1 ~ ItemN。
若想要將 Tuple 值拆解使用,可以用小括弧宣告出多個區域變數,並將 Value Tuple 指派過去,Value Tuple 的屬性值就會依序塞入這些區域變數。
這些功能即使套用在方法的回傳值上也一樣適用。
Link Tackling Tuples: Understanding the New C# 7 Value Type - Our ComponentOne C# 7.0 – Tuples – CsharpStar Tuple deconstruction in C# 7 | Thomas Levesque’s .
read morePosts
C# 7.0 - Digit separators
以前在開發 C# 時,如果數值過大,在閱讀上會十分不易。
C# 7.0 以後提供了 Digit separators 功能,允許開發人員使用 _ 將數值做些分隔,有效解決了上述問題。最普遍的用法就是將數值做千分位分隔,像是下面這樣:
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var values = new int[] { 1_000, 1_000_000, 0b1_000 }; foreach (var value in values) { Console.WriteLine(value.ToString()); } } } } {% img /images/posts/CSharp7DigitSeparators/1.png %}
Link C# 7 features preview · Anton Sizikov Exploring Visual Studio “15” Preview and Playing with C# 7 Test driving C# 7 features in Visual Studio “15” Preview » Thomas Levesque’s .
read morePosts
C# 7.0 - Binary literals
在程式開發時,有時我們會需要使用二進制的數值,像是在使用標有 FlagsAttribute 的列舉值做權限時就會用到。在 C 7.0# 前我們必需要使用十進制數值表示法,確保他是二進制的數值。
在 C# 7.0 後開始支援二進制數值表示法,使用上只需用 0b 當做前綴即可,像是 0 可以寫成 0b00、1 可以寫成 0b01、2 可以寫成 0b10、4 可以寫成 0b100,以此類推。
using System; namespace ConsoleApplication1 class Program { static void Main(string[] args) { var values = new int[] { 0b00, 0b01, 0b10, 0b100, 0b1000 }; foreach (var value in values) { Console.WriteLine(value.ToString()); } } } } {% img /images/posts/CSharp7Binaryliterals/1.png %}
Link A glance at C# vNext - CodeProject
read morePosts
C# 7.0 - Local functions
有時候我們在開發程式時,會碰到一些情境是需要建立個方法,但這個方法只有某個地方會用到,這時我們多半是用委派去做掉,但帶來的問題就是會有額外的記憶體耗費,而且無法被 inline 處理。
C# 7.0 後,我們可以改用 Local functions 功能去處理。使用方式很簡單,就是一般的方法宣告,只是是寫在方法裡面。像是:
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { void SayHello(string name) { Console.WriteLine(string.Format("Hello~{0}", name)); } SayHello("Larry"); } } } 這邊也可以搭配使用 C# 6.0 的 Expression Bodied Members,程式碼會更為精簡。
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { void SayHello(string name) => Console.WriteLine(string.Format("Hello~{0}", name)); SayHello("Larry"); } } } 運行結果如下:
{% img /images/posts/CSharp7LocalFunctions/1.png %}
反組譯看一下:
{% img /images/posts/CSharp7LocalFunctions/2.
read morePosts
T4 Template - JsResource.tt
在撰寫 ASP.NET 時,.NET 程式部分可用 Resource 去做多語的部分,JavaScript 這邊雖然也有 L10N 的解決方案,但是若走不同的解決方案,難以避免有些詞彙會重複定義。
這邊筆者嘗試使用 T4 來解決這樣的問題。
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ assembly name="System.Windows.Forms" #> <#@ assembly name="System.Core" #> <#@ assembly name="System.Xml" #> <#@ assembly name="EnvDTE" #> <#@ assembly name="Microsoft.VisualStudio.OLE.Interop" #> <#@ assembly name="Microsoft.VisualStudio.Shell" #> <#@ assembly name="Microsoft.VisualStudio.Shell.Interop" #> <#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #> <#@ import namespace="System.Resources" #> <#@ import namespace="System.Diagnostics" #> <#@ import namespace="System.Collections" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.
read morePosts
T4 template - CultureNames.tt
.NET 在操作 Culture 時,免不了要帶入 CultureInfo 的 Name,多半是用 Hard code 的形式帶入,像是下面這樣:
... var currentThread = Thread.CurrentThread; currentThread.CurrentCulture = CultureInfo.GetCultureInfo("zh-tw"); ... {% img /images/posts/T4CultureNames/1.png %}
這邊筆者做了個 T4 Template,期望能解決這樣的問題。
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Globalization" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> namespace System.Globalization { public static class CultureNames { <# var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures); var length = cultures.
read morePosts
CShell - A simply, yet powerful, C# scripting IDE
Cshell 是一 C# interactive tool,適合用於 C# 語言的學習或是用來做些簡單的小測試。
{% img /images/posts/Cshell/1.png %}
程式主檔可在 Github Project Page 下載。
{% img /images/posts/Cshell/2.png %}
下載完解壓點擊運行即可。
{% img /images/posts/Cshell/3.png %}
{% img /images/posts/Cshell/4.png %}
程式啟動後預設會幫我們含有兩個檔案,內含一些教學步驟,建議剛接觸的使用者可以先從這邊入手。
{% img /images/posts/Cshell/5.png %}
該工具雖然精簡,但該有的功能也都有,像是 Intellisense。
{% img /images/posts/Cshell/6.png %}
視窗版面的調整。
{% img /images/posts/Cshell/7.png %}
組件的參考等。
{% img /images/posts/Cshell/8.png %}
{% img /images/posts/Cshell/9.png %}
在使用上,它有提供些好用的內建命令,可輔助我們使用,有需要可以輸入 help 查閱。
{% img /images/posts/Cshell/10.png %}
像是 Describe 方法可回傳帶入的物件型別描述、ShowUsing 方法可查閱命名空間的引用狀況
{% img /images/posts/Cshell/11.png %}
ShowVars 方法可查閱區域變數的宣告狀況
read morePosts
C# 6.0 - Await in catch/finally
C# 6.0 以前 await 無法用在 catch/finally 區塊,C# 6.0 後開始支援。
using System; using System.Threading.Tasks; namespace ConsoleApplication10 { class Program { static void Main(string[] args) { Test(); System.Threading.Thread.Sleep(10000); } private static async void Test() { try { throw new Exception(); } catch { Console.WriteLine("Catch..."); await Task.Delay(500); } finally { Console.WriteLine("Finally..."); await Task.Delay(500); } } } }
read morePosts
C# 6.0 - Extension Add methods in collection initializers
C# 6.0 以前,集合類別可以像下面這樣透過 Collection Initializers 初始集合成員:
... var blogs = new List< Blog> { new Blog( "Level Up 1", "http://www.dotblogs.com.tw/larrynung" ), new Blog( "Level Up 2", "http://larrynung.github.io" ) }; ... {% endcodeblock%} <br/> 但無法像 VB 10 以後的版本一樣透過擴充方法客製處理 Collection Initializers 的動作,一直到 C# 6.0 才被加入 C# 內。 <br/> 只要為集合撰寫 Add 擴充方法即可客製處理 Collection Initializers,像是如果預期要讓 List<Blog> 的初始可以直接帶入 name 與 url,就會像下面這樣撰寫: ```c# ... public static class BlogExtension { public static void Add(this List<Blog> list, string name, string url) { list.
read morePosts
C# 6.0 - Parameterless constructors in structs
在 C# 6.0 以前,Struct 會自帶 Parameterless Constructors,且不允許我們自行實作,像是下面這樣的程式碼:
... public Blog() : this( string.Empty, string.Empty) { Console.WriteLine( "Blog.Ctor()..."); } public Blog(string name, string url) { this.Name = name; this.Url = url; } ... 運行在 C# 6.0 以前,編譯器就會告知錯誤:
{% img /images/posts/ParamlessStructConstructor/1.png %}
如果想要在 Parameterless Constructors 自行加些處理,像是用建構子鏈導到別的建構子去建構,在 C# 6.0 以前都沒辦法。
在 C# 6.0 以後,就比較沒有這樣的限制了,我們可以自行撰寫自己的 Paramless Constructor,加上自己想要的處理動作。唯一要注意的是需要透過 new 語法建立的才會觸發自己撰寫的 Paramless Constructor。
... var blog = default( Blog); DumpBlog(blog); blog = new Blog() { Name = "Larry Nung", Url = "http://larrynung.
read morePosts
C# 6.0 - Index initializers
以往我們在撰寫 C#,有 Object Initializer 與 Collection Initializer 可輔助我們作初始的動作,雖然可以初始大多數的資料,但在 Index 與 Event 這邊卻無法直接初始。
如果以 Dictionary 來說,因為他還是屬於集合的一種,所以仍舊可以像下面這樣透過 Collection Initializer 在初始的同時就將內容一併放入:
... var blog1 = new Dictionary<string , string >() { { "Name", "Level Up" }, { "Url", "http://larrynung.github.io/index.html" } }; ... 但並不是所有的情況下都可以用 Collection Initializer 來做 Index 的初始,所以在 C# 6.0 導入了 Index initializers,寫起來會像下面這樣,就像透過索引子塞值一般:
... var blog = new Dictionary<string , string >() { [ "Name"] = "Level Up" , [ "Url"] = "http://larrynung.github.io/index.html" }; .
read morePosts
C# 6.0 - String interpolation
以往在做比較簡單的字串串接,我們可能會用 + 運算符號進行串接,或是用 String.Format 帶入 Pattern 與要串接的字串去處理,像是下面這樣:
... Console.WriteLine((++idx).ToString("D2") + ". " + blog.Name + " (" + blog.Url + ")"); Console.WriteLine( String.Format( "{0:D2}. {1} ({2})", ++idx, blog.Name, blog.Url)); ... 在 C# 6.0 導入了 String Interpolation,可以像下面這樣簡化寫法:
... Console.WriteLine( "\{++idx, 5 :D2 }. \{blog.Name } (\{blog.Url ?? String.Empty})" ); ... 有點像是本來 String.Format 的 Pattern 內直接用斜線與大括號包住帶入運算式,且支援 optional alignment 與 format specifiers 的設定。
這邊來看個完整的使用範例:
using System; using System.Collections.Generic; public class Program { static void Main(string[] args) { var blog = new Blog { Name = "Level Up", Url = "http://larrynung.
read morePosts
Clr C# Heap Allocation Analyzer
Clr C# Heap Allocation Analyzer 是 Diagnostic Analyzers 的套件,功能上有點類似 ReSharper - Heap Allocation Viewer Extension,能對 Heap 的操作部分做些 Highlight。
這邊可先參閱一下影片的介紹:
該套件提供兩種安裝方式,一種是選擇安裝 VSIX,用 Extension Manager 搜尋安裝或是自 NuGet Gallery | Clr C# Heap Allocation Analyzer 1.0.0.5 下載安裝,好處是可以將效果套用至所有專案。
{% img /images/posts/HeapAllocationAnalyzer/1.png %}
一種則是用 NuGet By 專案安裝,好處是可以只套用至特定的專案。
{% img /images/posts/HeapAllocationAnalyzer/2.png %}
安裝完後,在程式編輯時即會呈現進行對應的分析,像是筆者這邊的程式即被偵測出有 Boxing 的動作。
{% img /images/posts/HeapAllocationAnalyzer/3.png %}
Link NuGet Gallery | Clr C# Heap Allocation Analyzer 1.0.0.5 Clr Heap Allocation Analyzer extension
read morePosts
C# 6.0 - Expression bodied members
Expression bodied members 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 當撰寫簡單的成員方法或是屬性時,Expression bodied members 能讓我們將程式碼精簡。
在使用上就只要將屬性或方法的宣告後面直接接上 Lambda 表示式即可。
像是成員屬性的處理會像下面這樣,少了本來大括弧的區塊,也少了 Get 區塊。
... public string ID => Guid.NewGuid().ToString(); ... 如果是成員方法處理上也類似,只是本來大括弧區塊內的內容用 Lambda 取代。
... public override string ToString() => this.Name; ... 這邊可以看到用這樣的寫法可能會造成很難區別是屬性還是方法,使用上要特別注意小心,基本上差異只在於後面有沒有接小括弧區塊及方法的參數。
最後看個完整的範例:
using System; public class Program(string name) { public string ID => Guid.NewGuid().ToString(); public string Name { get; private set ; } = name; public override string ToString() => this.
read morePosts
C# 6.0 - Nameof expressions
Nameof expressions 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 CTP3 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> Nameof expressions 能讓開發人員輕易的在程式中取得變數或是類別名稱。
以往我們是無法取得變數名稱的,所以像是在撰寫參數檢查,當丟出的例外需要帶入參數名稱時,多半是自己填入字串帶入。但這樣的做法不是很恰當,因為拼錯時並不容易發現,且當重構參數名稱時很容易遺漏要配合修改。
至於類別名稱的取得,相較於變數名稱的取得是簡單了許多。但是名稱的取得需要 Runtime 進行解析,這樣的做法有時又多了一些無謂的耗費。
Nameof expressions 的出現能幫助開發人員解決這樣的問題,使用上只要叫用nameof,並帶入欲取得名稱的類別或變數即可。
nameof( 欲取得名稱的類別或變數 ) 這邊直接看個完整的使用範例:
using System; namespace ConsoleApplication10 { class Program { static void Main(string[] args) { var blog = new Blog { Name = "Level Up" , Url = "http://larrynung.github.io/" }; DumpBlogInfo(blog); DumpBlogInfo(null); } static void DumpBlogInfo(Blog blog) { Console.WriteLine( string.Format( "Dump data (Type is {0})..." , nameof(Blog ))); if (blog == null) throw new ArgumentNullException(nameof (blog)); Console.
read morePosts
C# 6.0 - Null propagation
— layout: post title: “C# 6.0 - Null propagation” date: 2014-08-21 00:03:00 comments: true tags: [CSharp, CSharp 6.0] keywords: “C#” description: “C# 6.0 - Null propagation”
read morePosts
C# 6.0 - Exception filters
Exception filters 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 或是透過 .Net Fiddle 也可以,Compiler 那邊選取 Roslyn 就可以了。
Exception filters 能讓開發人員很容易的在攔截例外時順帶做些過濾的動作,藉此處理符合過濾條件的例外,且不對例外呼叫堆疊造成不良的影響。
以往我們必須要先將例外攔截,接著進行比對過濾,最後將符合的例外做對應的處理,不符合的例外繼續讓它向外擴出。但是這樣的作法會讓例外呼叫堆疊看不到實際發生的例外點,只看到重新擴出例外的點,造成除錯上的困難。
{% img /images/posts/ExceptionFilters/1.png %}
Exception filters 的出現能幫助開發人員解決這樣的問題。
它的語法很直覺,簡單來說就只是在 Try/Catch 的 Catch 後面加上 if 條件式進行過濾。
try {...} catch(Exception e) if (...) {...} 程式寫起來會像下面這樣:
反組譯看一下,可以看到 Exception filters 這邊會被編譯成 filter 區塊的部份,從 IL 這邊就直接支援。
{% img /images/posts/ExceptionFilters/2.png %}
這樣的寫法不僅直覺,且不會對例外呼叫堆疊造成不良的影響。
{% img /images/posts/ExceptionFilters/3.png %}
最後這邊做個新舊方法的測試比較:
可以看到效能的部份其實是差不多的,新語法感覺是沒有任何的效能優化。
read morePosts
C# 6.0 - Using static members
Using static members 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 或是透過 .Net Fiddle 也可以,Compiler 那邊選取 Roslyn 就可以了。
Using static members 能讓開發人員更方便的對指定類別的靜態成員做存取。對於程式中有大量的靜態成員存取操作時特別好用。
使用上與 Namespace 的 Using 類似,只是後面帶的不是到 Namespace 而已,而是進一步再向下帶到 Class。用 Using 指定要存取的類別後,在程式中就可以直接存取該類別的靜態成員,就如同自身的成員一般。
以一個較完整的例子來看,程式寫起來會像下面這樣:
可以看到這邊程式的一開始就先使用 Using 引用 Console 類別,後續我們就可以在程式中直接存取 Console 類別的靜態成員,像是取用 Title 、或是呼叫 WriteLine 方法。
反組譯看一下,可以發現其實該語法也只是編譯器幫我們在編譯時做了些處理。
{% img /images/posts/UsingStaticMembers/1.png %}
read morePosts
C# 6.0 - Auto-property initializers
Auto-property initializers 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 或是透過 .Net Fiddle 也可以,Compiler 那邊選取 Roslyn 就可以了。
Auto-property initializers 能讓開發人員在宣告 Auto-property 的同時就順道做初始的動作。不用另行在建構子中設定。也不再寫用回一般的 Property 寫法,然後在 Field 宣告時設定。
它的語法很直覺,簡單來說就是本來的 Auto-property 後面直接接上賦值的語法。像是:
public string Property { get; set; } = "Value"; 除了一般可讀可寫的 Property 外,唯讀的甚至是靜態的 Property 該語法也都支援。
以一個較完整的例子來看,程式寫起來會像下面這樣:
程式寫起來可以看到比以往精簡許多,運行後屬性也都有正確的賦值。
反組譯看一下,可以看到比較接近透過變數初始器去做賦值的動作,會在基底類別初始前宣告,也會標注 beforefieldinit。
{% img /images/posts/AutoPropertyInitializers/1.png %}
{% img /images/posts/AutoPropertyInitializers/2.png %}
read morePosts
.NET - A Simple Finite State Machine Solution
想要用實現有限狀態機的功能,看了一下網路上的解決方案以及 State Pattern,覺得都不怎麼適用,因此利用 Tuple 與 Dictionary 去實作了一個簡易又可重複使用的 State Machine:
public sealed class StateMachine<TState, TCommand> { #region Fields Dictionary<Tuple<TState, TCommand>, TState> _transitions; #endregion Fields #region Properties /// <summary> /// Gets the m_ transitions. /// </summary> /// <value> /// The m_ transitions. /// </value> private Dictionary<Tuple<TState, TCommand>, TState> m_Transitions { get { return _transitions ?? (_transitions = new Dictionary<Tuple<TState, TCommand>, TState>()); } } /// <summary> /// Gets the state of the current. /// </summary> /// <value> /// The state of the current.
read morePosts
.NET - Access Embeded Resource
Embeded Resource 可以將程式需要的檔案內嵌在程式組件內,會增加組件的大小,但是使用者看不到該檔案,也不會因為檔案位置錯誤造成程式出錯。當系統中存在有必要的檔案,且不希望讓使用者能夠輕易動到的話, 使用 Embeded Resource 是不錯的選擇。
要設定 Embedded Resource ,只要將檔案加入專案,然後在屬性視窗中將 Build Action 設為 Embeded Resource。
要取用時透過 Assembly.GetExecutingAssembly() 取得當前組件,然後叫用 GetManifestResourceStream() 並帶入 Resource Name 取得指定 Embeded Resource 的 Stream,最後再從 Stream 讀出我們所要的資料就可以了。
所以像是純文字檔,就可以像下面這樣處理:
private static string ReadAllTextFromEmbededResource(string resourceName) { var assembly = Assembly.GetExecutingAssembly(); using (var stream = assembly.GetManifestResourceStream(resourceName)) using (var reader = new StreamReader(stream)) { return reader.ReadToEnd(); } } Link c# - How to read embedded resource text file - Stack Overflow How to read Embedded Resource in c# | Hadjloo’s Daily Notes 如何使用 Visual C# 內嵌和存取資源
read morePosts
ODP.NET - Oracle Data Provider for .NET
要用 C# 存取 Oracle,通常我們會使用 ODP.NET。
ODP.NET 目前有 x86、 x64 與 Managed 三個版本可供使用。
Managed 版本為純 .NET 的解決方案,具備位元適應性, 能兼容於 x86 與 x64 的環境,可不安裝 Oracle client 使用,只是目前尚未支援 UDT 操作。
x86 與 x64 版本的 ODP.NET 不具位元適應性,需依運行環境使用正確的組件,且需安裝對應的 Oracle client,或是將會用到的 Oracle client 組件一併發佈,使用起來較 Managed 的麻煩,但能使用完整的功能。
不論選用哪個版本做開發,使用前都需先將組件加入參考,這邊可直接透過 NuGet 安裝對應的套件。
{% img /images/posts/ODP.NET/1.png %}
{% img /images/posts/ODP.NET/2.png %}
{% img /images/posts/ODP.NET/3.png %}
{% img /images/posts/ODP.NET/4.png %}
組件載入後,程式撰寫起來跟一般的 ADO.NET 程式沒什麼兩樣。
首先要先建立資料庫的連線。
using(var conn = new OracleConnection(connstring)) { ... } 接著將建立的資料庫連線開啟。
read morePosts
WCF - Self hosting service
要 Self hosting WCF 的服務。首先要先將 System.ServiceModel 加入參考。
{% img /images/posts/WCFSelfHosting/1.png %}
接著在程式設計中建立 ServiceHost。建立的同時要指定欲運行的 Service 型態,以及要 Host 的位置。
var serviceUrl = "http://localhost:6525/ExecuteService"; var serviceUri = new Uri( serviceUrl ); using (var host = new ServiceHost (typeof(WcfServiceLibrary1. ExecuteService), serviceUri)) { ... } 再來要建立 ServiceMetadataBehavior 並對其做些對應的設定,像是啟用 HttpGet。
... var smb = new ServiceMetadataBehavior (); smb.HttpGetEnabled = true; smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; ... 將剛建立的 ServiceMetadataBehavior 加到 ServiceHost.Description.Behaviors。
... host.Description.Behaviors.Add(smb); ... 在開始需要服務時,叫用 ServiceHost 的 Open 方法啟用 WCF 服務。
read morePosts
T4 template - Auto generate ConnectionString's wrapper class
在 .Net 程式中要使用資料庫的連線字串,多半我們會將資料庫的連線字串設定在 Config 檔中,然後透過 ConfigurationManager.ConnectionStrings 帶入對應的 Key 去將之取出來使用。
用這樣的撰寫方式,連線字串名稱打錯無法立即的被意識到,連線字串名稱調動時也很容易漏改,造成系統運行時的錯誤。因此有的人會將連線字串這邊再包一層,透過這層物件的屬性去取得連線字串,將連線字串的修改都在這層處理,減少人為造成的錯誤。
然而這樣的做法並無法完全解決問題,因為多包的那層還是人工下去做的,仍舊是無法避免連線名稱鍵錯的問題,連線字串變動時仍是會有改錯的可能。故這邊筆者嘗試使用 T4 template,讀取專案的 config 檔,動態產生強型別物件,提供連線字串給系統使用。
首先我們要為專案加入一個 t4 template 檔。
然後將其程式碼替換成下面這樣。
<#@ template debug ="true" hostspecific="True" language= "C#" #> <#@ assembly name ="EnvDTE" #> <#@ assembly name ="System.Core.dll" #> <#@ assembly name ="System.Configuration" #> <#@ assembly name ="System.Xml" #> <#@ import namespace ="System.Collections.Generic" #> <#@ import namespace ="System.Configuration" #> <#@ import namespace ="EnvDTE" #> <#@ import namespace ="System.Xml" #> <#@ output extension =".
read morePosts
.NET 4.5 - Multicore JIT
以往我們的程式要增快啟動速度時,我們會使用 ngen 去產生原生映像檔,讓程式運行時改運行預先編譯過的原生映像檔,以減少 JIT 編譯的耗費。
然而 ngen 這種改善方案只適用於某些情境下,像是有安裝包的部署。並不是所有的情境都可以套用 ngen 這種改善方案。故在 .Net Framework 4.5 出現了 Multicore JIT 的概念,以並行編譯的方式來提升程式的啟動速度,預期可加速約 20% - 50% 。
微軟官方也有提供一些比較數據可供參考。
{% img /images/posts/MultiCoreJIT/1.png %}
{% img /images/posts/MultiCoreJIT/2.png %}
Multicore JIT 的運作原理主要是將運行分為兩種 Mode。一個是 Recording mode,於程式第一次運行時啟動,會將跟 Compile 要求的編譯紀錄到指定的 Profile 檔案。
{% img /images/posts/MultiCoreJIT/3.png %}
一個是 Plackback mode,會依照 Recording mode 所紀錄的 Profile 用另外一個 CPU 下去在背景編譯。
{% img /images/posts/MultiCoreJIT/4.png %}
以程式面來說,Asp.Net 4.5 與 Silverlight 5 這邊會自動啟用 Multicore JIT 功能,不需要做什麼特別的設定,如果有需要也可以修改 web.config 去將之關閉。
<system.web> <compilation profileGuidedOptimizations="None" /> </system.
read morePosts
WPF - Refresh / Update WPF controls
相信大家都知道若要釋放些資源去讓畫面得以更新,若不將運算處理切離主執行緒,我們可能會偷懶用 DoEvents 來做。然而, DoEvents 這個方法的功用只是釋放資源,而釋放出的資源為誰所用,這部分我們無法掌控。因此釋放出的資源可能會被拿去做不相干的處理,造成效能嚴重低落。
在 WinForm 的世界裡,這樣的問題比較好處理,因為有許多現成的方法可以指定特定元件去做更新,像是 Update、Refresh、或是 Invalidate。
在 WPF 的世界裡,我們沒現有的方法可以直接叫用,只能用些小技巧兜出類似的功能。像是將下面這段擴充方法加入…
public static class ExtensionMethods { private static Action EmptyDelegate = delegate() { }; public static void Refresh(this UIElement uiElement) { uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); } } 程式在撰寫時就可以像下面這樣直接透過 UI 元件觸發更新。
control.Refresh(); Link Refresh / Update WPF controls
read morePosts
Check if run as administrator
要判斷當前使用者是否具有管理者權限,我們可以先取得當前使用的 WindowsIdenty。
var wi = WindowsIdentity.GetCurrent(); 接著帶入剛取得的 WindowsIdenty,建立對應的 WindowsPrinciple。
var wp = new WindowsPrincipal(wi); 透過 WindowsPrinciple 的 IsInRole 方法判斷當前的使用者是否為 WindowsBuiltInRole.Administrator。
var isAdmin = wp.IsInRole(WindowsBuiltInRole.Administrator); 所以整個程式會像下面這樣 :
private bool IsRunAsAdministrator() { var wi = WindowsIdentity.GetCurrent(); var wp = new WindowsPrincipal(wi); return wp.IsInRole(WindowsBuiltInRole.Administrator); } Link AntsCode: Running a ClickOnce Application as Administrator
read morePosts
Check empty folder with IsDirectoryEmplty Win32 API
在判斷目錄是否為空這邊,.NET 4.0 以前,很多人都會很直覺的去使用 Directory.GetFiles 、Directory.GetDirectories 、或 Directory.GetFileSystemEntries 方法,用個數判斷是否為空。
public bool IsDirectoryEmplty(string directory) { //return !Directory.GetFiles(directory).Any() && !Directory.GetDirectories(directory).Any(); return !Directory.GetFileSystemEntries(directory).Any(); } 用這樣的方式處理,必須等待所有檔案都找出來後回傳才能進行空目錄的判斷,效能十分的低落。
在 .NET 4.0 後可改用 Directory.EnumerateFiles 、Directory.EnumerateDirectories 、或 Directory.EnumerateFileSystemEntries 替代。
public bool IsDirectoryEmplty(string directory) { //return !Directory.EnumerateFiles(directory).Any() && !Directory.EnumerateDirectories(directory).Any(); return !Directory.EnumerateFileSystemEntries(directory).Any(); } 相較於 .NET 4.0 以前的處理方式,檔案變成找到就立刻回傳,因此我們找到一個檔案就可以將搜尋的動作中斷,效能問題獲得了改善。
雖然效能的問題解決了,不過像這樣的處理方式會受限於 .NET Framework 的版本,不是一個比較通用的解法。而且空目錄判斷這樣的動作其實跟前面提到的取得目錄大小一樣,用 Win32 API 去跟 OS 問多半是最快的方式。
以這邊來說,我們可以將之改用 IsDirectoryEmplty API 去處理。
[ DllImport("Shlwapi.dll" , EntryPoint = "PathIsDirectoryEmpty")] [ return: MarshalAs (UnmanagedType.Bool)] public static extern bool IsDirectoryEmplty([MarshalAs (UnmanagedType.
read morePosts
Remote desktop with Microsoft Terminal Services control
要使用.NET來開發具備遠端桌面功能的程式,我們可以使用 Microsoft Terminal Services control 這個 Com 元件來做。
首先將 Microsoft Terminal Servics control 這個 Com 元件加入工具箱,並將之拖曳至設計頁面擺放至適當的位置。
{% img /images/posts/MicrosoftTerminalServicesControl/1.png %}
然後接著進行程式的開發動作。
設定遠端桌面的 Server 位置。
設定Domain。
設定使用者名稱與密碼。
這邊的設定都很單純,只有密碼這塊設定需要特別的處理,需要叫用 GetOcx 方法取得 IMsTscNonScriptable 物件,再對其 ClearTextPassword 欄位設定。
該做的設定做完後,呼叫 Connect 方法就可以開始進行遠端桌面的連線。
若要斷開遠端桌面連線,可呼叫 Disconnect 方法。
另外連線的狀態可透過 Connected 欄位取得,欄位值是1時代表正在連線。所以在程式撰寫的時候我們可以在連線時進行連線狀態的確認,依此狀態決定是否要先將連線斷開。
最後附上完整的程式範例。
運行起來會像下面這樣:
{% img /images/posts/MicrosoftTerminalServicesControl/2.png %}
若有需要,範例程式也可至 larrynung / RDPDemo 這邊下載。
Link Remote Desktop using C#.NET - CodeProject
read morePosts
[.NET Resource]透過BoxCop偵測程式是否存在Boxing與UnBoxing
namespace ConsoleApplication25 { class Program { static void Main(string[] args) { Console.WriteLine(“Blog: {0}{1}Article count:{2}”, “Level Up”, Environment.NewLine, 549 ); } } }
read morePosts
[C#][Extension Method]Get directory size
namespace ConsoleApplication8 { class Program { static void Main(string[] args) { GetFolderSize(@“C:\Program Files”); GetDirSize(@“C:\Program Files”); DirSize(new DirectoryInfo(@“C:\Program Files”));
var sw = Stopwatch.StartNew(); Console.WriteLine(GetFolderSize(@"C:\Program Files")); Console.WriteLine(sw.ElapsedMilliseconds); sw.Stop(); sw.Reset(); sw.Start(); Console.WriteLine(GetDirSize(@"C:\Program Files")); Console.WriteLine(sw.ElapsedMilliseconds); sw.Stop(); sw.Reset(); sw.Start(); Console.WriteLine(DirSize(new DirectoryInfo(@"C:\Program Files"))); Console.WriteLine(sw.ElapsedMilliseconds); } static long GetDirSize(string path) { return (from item in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories) select new FileInfo(item).Length).Sum(); } static long GetFolderSize(string folder) // 取得資料夾大小 { return long.Parse((new Scripting.FileSystemObjectClass()).GetFolder(folder).Size.ToString()); } public static long DirSize(DirectoryInfo d) { long Size = 0; // Add file sizes.
read morePosts
[C#][Extension Method]String extension method(IsNull、IsNullOrEmpty、IsNullOrWhiteSpace、IsMatch)
namespace ConsoleApplication1 { public static class StringExtension { public static Boolean IsNull(this string str) { return str == null; }
public static Boolean IsNullOrEmpty(this string str) { return string.IsNullOrEmpty(str); } public static Boolean IsNullOrWhiteSpace(this string str) { return string.IsNullOrWhiteSpace(str); } public static bool IsMatch(this string str, string pattern) { if (str.IsNullOrEmpty()) throw new ArgumentNullException("str"); if (pattern.IsNullOrEmpty()) throw new ArgumentNullException("pattern"); return Regex.IsMatch(str, pattern); } } } namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string nullStr = null; string emptyStr = string.
read morePosts
[C#][JavaScript]WinForm與WebPage的JavaScript互通(一)
namespace WindowsFormsApplication3 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) { webBrowser1.DocumentText = @"<script>function ShowAlert(alertMessage) {alert (alertMessage);}</script>"; } private void button1_Click(object sender, EventArgs e) { webBrowser1.Document.InvokeScript("ShowAlert", new object[] { "alert message..." }); } } }
namespace WindowsFormsApplication3 { [PermissionSet(SecurityAction.Demand, Name = “FullTrust”)] [ComVisible(true)] public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) { webBrowser1.
read morePosts
[C#][JavaScript]WinForm與WebPage的JavaScript互通(二) - 動態加入並調用JavaScript
private void button1_Click(object sender, EventArgs e) { MessageBox.Show(webBrowser1.Document.InvokeScript("GetVar", new object[] { "executeCount" }).ToString()); } public void OnWebPageReady() { HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0]; HtmlElement script = webBrowser1.Document.CreateElement("script"); IHTMLScriptElement element = (IHTMLScriptElement)script.DomElement; element.text = "function GetVar(varName) { return eval('(' + varName + ')'); }"; head.AppendChild(script); } }</pre></div> public void OnWebPageReady() { webBrowser1.Document.InvokeScript("ShowAlert", new object[] { "WebPage Ready..." }); HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0]; HtmlElement script = webBrowser1.Document.CreateElement("script"); IHTMLScriptElement element = (IHTMLScriptElement)script.DomElement; element.text = "function GetJsonValue(json, member) { return eval('(' + json + '.
read morePosts
[C#][VB.NET]Path.GetTempFileName的IOException
namespace ConsoleApplication9 { class Program { static void Main(string[] args) { var sw = new Stopwatch(); for (int i = 1; i <= 65536; ++i) { sw.Start(); Console.WriteLine(String.Format("{0} {1}", Path.GetTempFileName(), sw.ElapsedMilliseconds.ToString())); sw.Stop(); sw.Reset(); } } } }
read morePosts
[C#][VB.NET]使用MFT Scanner遍巡USN Journal,快速找出磁碟內的所有檔案
public class MFTScanner { private static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); private const uint GENERIC_READ = 0x80000000; private const int FILE_SHARE_READ = 0x1; private const int FILE_SHARE_WRITE = 0x2; private const int OPEN_EXISTING = 3; private const int FILE_READ_ATTRIBUTES = 0x80; private const int FILE_NAME_IINFORMATION = 9; private const int FILE_FLAG_BACKUP_SEMANTICS = 0x2000000; private const int FILE_OPEN_FOR_BACKUP_INTENT = 0x4000; private const int FILE_OPEN_BY_FILE_ID = 0x2000; private const int FILE_OPEN = 0x1; private const int OBJ_CASE_INSENSITIVE = 0x40; private const int FSCTL_ENUM_USN_DATA = 0x900b3;
read morePosts
[C#][VB.NET]自定義例外對話框
<pre> ExceptionDialog.ShowBugWindowOnError()</pre> <pre class="alt"> <span class="kwrd">End</span> Sub</pre> <pre><span class="kwrd">Imports</span> System.Threading</pre> <pre class="alt"><span class="kwrd">Imports</span> System.Text</pre> <pre> </pre> <pre class="alt"><span class="kwrd">Public</span> <span class="kwrd">Class</span> ExceptionDialog</pre> <pre> </pre> <pre class="alt"><span class="preproc">#Region</span> <span class="str">"Const"</span></pre> <pre> <span class="kwrd">Const</span> OpenDetailButtonText <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="str">"v 詳細資料"</span></pre> <pre class="alt"> <span class="kwrd">Const</span> CloseDetailButtonText <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="str">"^ 詳細資料"</span></pre> <pre><span class="preproc">#End Region</span></pre> <pre class="alt"> </pre> <pre> </pre> <pre class="alt"> </pre> <pre><span class="preproc">#Region</span> <span class="str">"Var"</span></pre> <pre class="alt"> <span class="kwrd">Private</span> _isDetailOpened <span class="kwrd">As</span> <span class="kwrd">Boolean</span></pre> <pre><span class="preproc">#End Region</span></pre> <pre class="alt"> </pre> <pre> </pre> <pre class="alt"> </pre> <pre><span class="preproc">#Region</span> <span class="str">"Public Shared Method"</span></pre> <pre class="alt"> </pre> <pre> <span class="rem">'***************************************************************************</span></pre> <pre class="alt"> <span class="rem">'Author: Larry Nung</span></pre> <pre> <span class="rem">'Date: 2009/4/9</span></pre> <pre class="alt"> <span class="rem">'Purpose: </span></pre> <pre> <span class="rem">'Memo: </span></pre> <pre class="alt"> <span class="rem">'***************************************************************************</span></pre> <pre> <span class="rem">''' <summary></span></pre> <pre class="alt"> <span class="rem">''' Shows the bug window on error.
read morePosts
[C#]Command Line Parser Library
[OptionArray("o", "output", HelpText = "The output files to generate.")] public string[] OutputFiles { get; set; } [OptionList("k", "keywords", Separator = ':', HelpText = "Specify keywords to search the text, separated by a colon.")] public List<string> Keywords { get; set; } [ValueList(typeof(List<string>), MaximumElements = 3)] public List<string> Items { get; set; } ... }</pre></div> [HelpOption] public string GetUsage() { ... } }</pre></div> help.AddPreOptionsLine(" "); help.AddPreOptionsLine("CommandLine parser library demo..."); help.AddPreOptionsLine(" "); help.
read morePosts
[C#]DateTime 與 ISO8601 格式字串的相互轉換
return sucessed ? new DateTime?(dt) : null; }</pre></div>
read morePosts
[C#]Decode Unicode Character
if (!match.Success) return string.Empty; var code = match.Groups["code"].Value; int value = Convert.ToInt32(code, 16); return ((char)value).ToString(); }</pre>
read morePosts
[C#]DropBox開發系列 - 使用DropNet上傳檔案至DropBox
... var selectedNode = treeView1.SelectedNode; if (selectedNode == null) return; var metaData = selectedNode.Tag as MetaData; if (metaData == null) return; if (!metaData.Is_Dir) { MessageBox.Show("Please select a folder first."); return; } if (tbxFile.Text.Length == 0) { MessageBox.Show("Please select a file to upload first."); return; } if (!File.Exists(tbxFile.Text)) { MessageBox.Show("File not found."); return; } m_DropNetClient.UploadFile(metaData.Path, Path.GetFileName(tbxFile.Text), File.ReadAllBytes(tbxFile.Text)); ...</pre></div> namespace DropNetDemo { public partial class Form1 : Form { #region Var private DropNetClient _dropNetClient; #endregion
read morePosts
[C#]DropBox開發系列 - 使用DropNet下載DropBox內存放的檔案
var metaData = selectedNode.Tag as MetaData; if(metaData == null) return; using (var saveFileDialog = new SaveFileDialog()) { saveFileDialog.FileName = metaData.Name; if(saveFileDialog.ShowDialog() == DialogResult.OK) { var fileData = m_DropNetClient.GetFile(metaData.Path); File.WriteAllBytes(saveFileDialog.FileName, fileData); } } ...</pre></div> namespace DropNetDemo { public partial class Form1 : Form { #region Var private DropNetClient _dropNetClient; #endregion
#region Private Property private DropNetClient m_DropNetClient { get { return _dropNetClient ?? (_dropNetClient = new DropNetClient(tbxAppKey.Text, tbxAppSecret.Text)); } set { _dropNetClient = value; } } #endregion public Form1() { InitializeComponent(); } private void SetSecretAndToken(string secret, string token) { Settings.
read morePosts
[C#]DropBox開發系列 - 使用DropNet進行DropBox的OAuth認證
... dialog.Controls.Add(browesr); dialog.ShowDialog(); ... }</pre></div> if (DoOAuth(callbackUrl, cancelCallbackUrl, size) == DialogResult.OK) { var accessToken = m_DropNetClient.GetAccessToken(); } ... private DialogResult DoOAuth(string callbackUrl, string cancelCallbackUrl, System.Drawing.Size size) { using (var dialog = new Form()) { var browesr = new WebBrowser() { Dock = DockStyle.Fill }; m_DropNetClient.GetToken(); var authUrl = m_DropNetClient.BuildAuthorizeUrl(); browesr.Navigated += (s, ex) => { var url = ex.Url.ToString(); if (url.Equals(callbackUrl)) { dialog.DialogResult = DialogResult.OK; } else if (url.Equals(cancelCallbackUrl)) { dialog.
read morePosts
[C#]DropBox開發系列 - 使用DropNet進行DropBox的二次登入
return; } ... if (DoOAuth(callbackUrl, cancelCallbackUrl, size) == DialogResult.OK) { var accessToken = m_DropNetClient.GetAccessToken(); Properties.Settings.Default.SECRET = accessToken.Secret; Properties.Settings.Default.TOKEN = accessToken.Token; Properties.Settings.Default.Save(); }</pre></div> namespace DropNetDemo { public partial class Form1 : Form { #region Var private DropNetClient _dropNetClient; #endregion
#region Private Property private DropNetClient m_DropNetClient { get { return _dropNetClient ?? (_dropNetClient = new DropNetClient(tbxAppKey.Text, tbxAppSecret.Text)); } set { _dropNetClient = value; } } #endregion public Form1() { InitializeComponent(); } private void SetSecretAndToken(string secret, string token) { Settings.
read morePosts
[C#]DropBox開發系列 - 使用DropNet遍巡DropBox內存放的檔案
FillTreeView(); return; } var callbackUrl = "https://www.dropbox.com/1/oauth/authorize"; var cancelCallbackUrl = "https://www.dropbox.com/home"; var size = new Size(1024, 600); if (DoOAuth(callbackUrl, cancelCallbackUrl, size) == DialogResult.OK) { var accessToken = m_DropNetClient.GetAccessToken(); Properties.Settings.Default.SECRET = accessToken.Secret; Properties.Settings.Default.TOKEN = accessToken.Token; Properties.Settings.Default.Save(); FillTreeView(); } }
private void FillTreeView() { treeView1.Nodes.Clear(); var metaData = m_DropNetClient.GetMetaData("/");
FillDirOrFileToTreeView(null, metaData); }
private void FillDirOrFileToTreeView(TreeNode parentNode, MetaData metaData) { if (metaData.Contents == null) return;
var nodes = (parentNode == null) ? treeView1.
read morePosts
[C#]Export PowerPoint file to photos
var ppt = application.Presentations.Open(file, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse); var index = 0; var fileName = Path.GetFileNameWithoutExtension(file); foreach (Slide slid in ppt.Slides) { ++index; slid.Export(Path.Combine(outputPath, string.Format("{0}{1}.jpg", fileName, index)), "jpg", Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); } ppt.Close(); application.Quit(); GC.Collect(); }</pre></div> void ConvertPptToJpg(string file, string outputPath) { Type t = Type.GetTypeFromProgID("PowerPoint.Application"); object o = Activator.CreateInstance(t); object p = t.InvokeMember( "Presentations", BindingFlags.Public | BindingFlags.GetProperty, null, o, null, null); Type t2 = p.GetType(); object ppt = t2.InvokeMember("Open", BindingFlags.Public | BindingFlags.
read morePosts
[C#]Json.NET - A high performance Json library
public String NickName { get; set; } public DateTime Birthday { get; set; } public int Age { get { return (int)((DateTime.Now - Birthday).TotalDays / 365); } } }</pre></div> Person Larry = new Person { Name = "Larry Nung", NickName = "蹂躪", Birthday = new DateTime(1980,4,19) }; var json = JsonConvert.SerializeObject(Larry, Formatting.Indented); ... var person = JsonConvert.DeserializeObject<Person>(json); ...</pre></div> public String NickName { get; set; } public DateTime Birthday { get; set; } public int Age { get { return (int)((DateTime.
read morePosts
[C#]Json.NET - Reducing Serialized JSON Size
public String NickName { get; set; } public DateTime Birthday { get; set; } public int Age { get { return (int)((DateTime.Now - Birthday).TotalDays / 365); } } }
Person Larry = new Person { Name = “Larry Nung”, Birthday = new DateTime(1980,4,19) };
var json = JsonConvert.SerializeObject(Larry, Formatting.Indented);
Console.WriteLine(json);
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public String NickName { get; set; } ... public bool ShouldSerializeNickName() { return !string.IsNullOrEmpty(NickName); } }</pre></div> protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.
read morePosts
[C#]Linq在使用Distinct去除重複資料時如何指定所要依據的成員屬性
/// <summary> /// Gets or sets the name. /// </summary> /// <value>The name.</value> public string Name { get; set; } #endregion #region Public Method /// <summary> /// Returns a <see cref="System.String"/> that represents this instance. /// </summary> /// <returns> /// A <see cref="System.String"/> that represents this instance. /// </returns> public override string ToString() { return Name; } #endregion</pre> public bool Equals(Person x, Person y) { return x.Name.Equals(y.Name); } public int GetHashCode(Person obj) { return obj.
read morePosts
[C#]ListBox如何偵測Item的新增、插入、與刪除
switch (m.Msg) { case LB_ADDSTRING: itemValue = Marshal.PtrToStringUni(m.LParam); OnItemAdded(EventArgs.Empty); break; case LB_INSERTSTRING: itemIndex = (int)m.WParam; itemValue = Marshal.PtrToStringUni(m.LParam); OnItemInserted(EventArgs.Empty); break; case LB_DELETESTRING: itemIndex = (int)m.WParam; OnItemDeleted(EventArgs.Empty); break; default: break; } base.WndProc(ref m); } </pre></div> namespace WindowsFormsApplication4 { public partial class Form1 : Form { class ListBoxEx : ListBox { #region Const private const int LB_ADDSTRING = 0x180; private const int LB_INSERTSTRING = 0x181; private const int LB_DELETESTRING = 0x182; #endregion
read morePosts
[C#]MEF開發系列 - Managed Extensibility Framework(MEF)的概念與簡介
public MainForm() { InitializeComponent(); var catalog = new DirectoryCatalog(Environment.CurrentDirectory, "*.dll"); var container = new CompositionContainer(catalog); container.ComposeParts(this); foreach (IModule module in Modules) { module.Host = this; 模組MToolStripMenuItem.DropDownItems.Add(module.Name, null, Module_Click).Tag = module; } } ... } }
read morePosts
[C#]PE檔案格式簡易介紹與PE檔案的檢測
typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; } IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
// Verify file starts with "MZ" signature. if ((bytes[0] != 0x4d) || (bytes[1] != 0x5a)) { // Not a PE file. return false; } // OFFSET_TO_PE_HEADER_OFFSET = 0x3c s.Seek(0x3c, SeekOrigin.Begin); // read the offset to the PE Header uint offset = r.ReadUInt32(); // go to the beginning of the PE Header s.Seek(offset, SeekOrigin.Begin); bytes = r.ReadBytes(4); // Verify PE header starts with 'PE '.
read morePosts
[C#]Process.Exited事件觸發的執行緒會受Process.SynchronizingObject屬性設定的影響
namespace WindowsFormsApplication13 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) { var process = Process.Start("calc.exe"); process.EnableRaisingEvents = true; process.Exited += new EventHandler(process_Exited); textBox1.Text = "Main Thread ID:" + Thread.CurrentThread.ManagedThreadId.ToString(); Console.Read(); } void process_Exited(object sender, EventArgs e) { MessageBox.Show("Process Thread ID:" + Thread.CurrentThread.ManagedThreadId.ToString()); } } }
namespace WindowsFormsApplication13 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
read morePosts
[C#]Set Windows 7 Progress Bar's State
#region DllImport [DllImport("user32.dll", CharSet = CharSet.Auto)] internal static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam); #endregion #region Private Method void SetPaused(ProgressBar progressBar) { SendMessage(progressBar.Handle, PBM_SETSTATE, PBST_PAUSE, 0); } void SetError(ProgressBar progressBar) { SendMessage(progressBar.Handle, PBM_SETSTATE, PBST_ERROR, 0); } void SetNormal(ProgressBar progressBar) { SendMessage(progressBar.Handle, PBM_SETSTATE, PBST_NORMAL, 0); } #endregion</pre></div> namespace WindowsFormsApplication3 { public partial class Form1 : Form { #region Const const int PBM_SETPOS = 0x402; const int PBM_GETPOS = 0x0408; const int PBM_SETSTATE = 0x410; const int PBST_PAUSE = 0x0003; const int PBST_ERROR = 0x0002; const int PBST_NORMAL = 0x0001; #endregion
read morePosts
[C#]仿照Chrome的Multi-process Architecture
var options = new Options(); ICommandLineParser parser = new CommandLineParser(); if (parser.ParseArguments(args, options)) { m_ReceiverHandel = (IntPtr)options.Handle; if (options.IsBrowser) { var browserTab = new WebBrowserPage() { StartPosition = FormStartPosition.Manual, Top = -3200, Left = -3200, Width = 0, Height = 0 }; browserTab.TextChanged += browserTab_TextChanged; Application.Run(browserTab); return; } } Application.Run(new MainForm()); }</pre> var host = new ApplicationHost() { File = Application.ExecutablePath, Arguments = string.Format("-b -h {0}", this.Handle), HideApplicationTitleBar = true, Dock = DockStyle.
read morePosts
[C#]使用BitmapDecoder快速取用圖檔內含的縮圖
public Image GetThumbnail(string file) { var decoder = BitmapDecoder.Create(new Uri(file), BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); var frame = decoder.Frames.FirstOrDefault();
return (frame.Thumbnail == null) ? null : frame.Thumbnail.GetBitmap(); } …
namespace WindowsFormsApplication33 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
public Image GetThumbnail(string file) { var decoder = BitmapDecoder.Create(new Uri(file), BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); var frame = decoder.Frames.FirstOrDefault(); return (frame.Thumbnail == null) ? null : frame.Thumbnail.GetBitmap(); } private void button1_Click(object sender, EventArgs e) { if (openFileDialog1.
read morePosts
[C#]使用ExifLibrary簡易快速的擷取圖片的Exif資訊
namespace WindowsFormsApplication34 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void btnLoad_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { var photoFile = openFileDialog1.FileName; ExifFile exifFile = ExifFile.Read(photoFile); pbxThumbnail.Image = exifFile.Thumbnail.ToBitmap(); tbxMessage.Clear(); foreach (ExifProperty item in exifFile.Properties.Values) { tbxMessage.Text += string.Format("{0}:{1} “, item.Name, item.Value); } } } } }
read morePosts
[C#]使用Faker.Net輔助建立假的數據資料
namespace ConsoleApplication11 { class Program { static void Main(string[] args) { for (int i = 0; i < 3; ++i) { ShowFakeUserInfo(); Console.WriteLine(new String(’=’, 50)); } }
static void ShowFakeUserInfo() { Console.WriteLine(String.Format("User: {0}", Faker.Name.FullName())); Console.WriteLine(String.Format("Phone: {0}", Faker.Phone.Number())); Console.WriteLine(String.Format("Email1: {0}", Faker.Internet.Email())); Console.WriteLine(String.Format("Email2: {0}", Faker.Internet.FreeEmail())); Console.WriteLine(String.Format("Company: {0}", Faker.Company.Name())); Console.WriteLine(String.Format("Country: {0}", Faker.Address.Country())); } } }
read morePosts
[C#]使用FindFirstFile、FindNextFile API實做EnumerateFiles
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] private static extern IntPtr FindFirstFile(string pFileName, ref WIN32_FIND_DATA pFindFileData); [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] private static extern bool FindNextFile(IntPtr hndFindFile, ref WIN32_FIND_DATA lpFindFileData); [DllImport( "kernel32.dll" , SetLastError = true )] private static extern bool FindClose(IntPtr hndFindFile); [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto), BestFitMapping(false)] internal struct WIN32_FIND_DATA { public FileAttributes dwFileAttributes; public uint ftCreationTime_dwLowDateTime; public uint ftCreationTime_dwHighDateTime; public uint ftLastAccessTime_dwLowDateTime; public uint ftLastAccessTime_dwHighDateTime; public uint ftLastWriteTime_dwLowDateTime; public uint ftLastWriteTime_dwHighDateTime; public uint nFileSizeHigh; public uint nFileSizeLow; public int dwReserved0; public int dwReserved1; [MarshalAs(UnmanagedType.
read morePosts
[C#]使用InternetGetConnectedState API偵測目前電腦網路的連線狀態
namespace ConsoleApplication21 { class Program { [DllImport(“wininet”)] public static extern bool InternetGetConnectedState( ref uint lpdwFlags, uint dwReserved );
static void Main(string[] args) { uint flags = 0x0; var isNetworkAvailable = InternetGetConnectedState(ref flags, 0); Console.WriteLine(string.Format("Network available: {0} ({1})", isNetworkAvailable.ToString(), flags.ToString())); } } }
read morePosts
[C#]使用Microsoft Translator Soap API實作翻譯功能
if (String.IsNullOrEmpty(text)) return DEFAULT_DETECTED_LANG; const string DETECT_API_URI_PATTERN = "http://api.microsofttranslator.com/V2/Http.svc/Detect?appId={0}&text={1}"; const string MATCH_PATTERN = "<[^<>]*>([^<>]*)<[^<>]*>"; WebRequest req = WebRequest.Create(String.Format(DETECT_API_URI_PATTERN, APP_ID, text)); WebResponse resp = req.GetResponse(); string local = DEFAULT_DETECTED_LANG; using (StreamReader reader = new StreamReader(resp.GetResponseStream())) { local = reader.ReadToEnd(); local = Regex.Match(local, MATCH_PATTERN).Groups[1].Value; } return local; }</pre> if (!langs.Contains(lang)) lang = "en"; return client.Speak(APP_ID, tbxSource.Text, lang, "audio/wav", string.Empty); }</pre> var langNames = (from lang in langs.AsParallel() select new { Name = Client.
read morePosts
[C#]使用Mutex實現單一程式執行個體的注意事項
namespace WindowsFormsApplication10 { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);
Boolean bCreatedNew; //Create a new mutex using specific mutex name Mutex m = new Mutex(false, "myUniqueName", out bCreatedNew); if (bCreatedNew) Application.Run(new Form1()); } } }
//Create a new mutex using specific mutex name Mutex m = new Mutex(false, "myUniqueName", out bCreatedNew); GC.Collect(); if (bCreatedNew) Application.
read morePosts
[C#]使用Reflection檢查指定類別是否含有預設建構子
namespace ConsoleApplication17 { class Program { static void Main(string[] args) { Console.WriteLine(HasDefaultConstructor1<TestClass1>()); Console.WriteLine(HasDefaultConstructor2<TestClass1>());
Console.WriteLine(HasDefaultConstructor1<TestClass2>()); Console.WriteLine(HasDefaultConstructor2<TestClass2>()); } private static Boolean HasDefaultConstructor1<T>() { var type = typeof (T); foreach (var c in type.GetConstructors(BindingFlags.Instance | BindingFlags.Public)) { if (c.GetParameters().Length ==0) return true; } return false; } private static Boolean HasDefaultConstructor2<T>() { var type = typeof (T); return type.GetConstructor(Type.EmptyTypes) != null; } } internal class TestClass1 { public TestClass1() { } public TestClass1(int arg1) { } } internal class TestClass2 { public TestClass2(int arg1) { } } }
read morePosts
[C#]使用SharpShell實現Shell Icon Overlay功能
namespace ReadOnlyFileIconOverlayHandler { /// <summary> /// The ReadOnlyFileIconOverlayHandler is an IconOverlayHandler that shows /// a padlock icon over files that are read only. /// </summary> [ComVisible(true)] public class ReadOnlyFileIconOverlayHandler : SharpIconOverlayHandler { /// <summary> /// Called by the system to get the priority, which is used to determine /// which icon overlay to use if there are multiple handlers. The priority /// must be between 0 and 100, where 0 is the highest priority.
read morePosts
[C#]使用SHEmptyRecycleBin API清除資源回收桶
<td valign="top" width="200">No dialog box confirming the deletion of the objects will be displayed.</td> </tr> <tr> <td valign="top" width="200"><strong>SHERB_NOPROGRESSUI</strong></td> <td valign="top" width="200">No dialog box indicating the progress will be displayed.</td> </tr> <tr> <td valign="top" width="200"><strong>SHERB_NOSOUND</strong></td> <td valign="top" width="200">No sound will be played when the operation is complete.</td> </tr>
read morePosts
[C#]使用ShowCaret amp; HideCaret控制元件上的插入符號
[DllImport("user32.dll")] static extern bool HideCaret(IntPtr hWnd);</pre></div> namespace WindowsFormsApplication22 { public partial class Form1 : Form { [DllImport(“user32.dll”)] static extern bool ShowCaret(IntPtr hWnd);
[DllImport("user32.dll")] static extern bool HideCaret(IntPtr hWnd); public Form1() { InitializeComponent(); } private void timer1_Tick(object sender, EventArgs e) { if (rbtnShowCaret.Checked) { ShowCaret(textBox1.Handle); } else { HideCaret(textBox1.Handle); } } } }
read morePosts
[C#]偵測系統Power狀態的改變以及是否進入Sleep mode
namespace WindowsFormsApplication15 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) { SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged); } void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) { textBox1.Text += e.Mode.ToString() + Environment.NewLine; } } }
namespace WindowsFormsApplication15 { public partial class Form1 : Form { private const int WM_POWERBROADCAST = 0x218; private const int PBT_APMSUSPEND = 0x4; private const int PBT_APMRESUMESUSPEND = 0x7; private const int PBT_APMRESUMEAUTOMATIC = 0x12; public Form1() { InitializeComponent(); }
read morePosts
[C#]取用.picasa.ini內存的現有資訊來做臉部偵測
rect64(3f845bcb59418507) break this number into 4 16-bit numbers by using substrings: ‘3f845bcb59418507’.substring(0,4) //“3f84” ‘3f845bcb59418507’.substring(4,8) //“5bcb” ‘3f845bcb59418507’.substring(8,12) // “5941” ‘3f845bcb59418507’.substring(12,16) // “8507” convert each obtained substring to an integer and divide it by the highest 16-bit number (2^16 = 65536), which should give 0 < results < 1. these are the relative coordinates of the crop rectangle (left,top,right,bottom): parseInt(“3f84”,16)/65536 //0.24810791015625 - left parseInt(“5bcb”,16)/65536 //0.3585662841796875 - top parseInt(“5941”,16)/65536 //0.3486480712890625 - right parseInt(“8507”,16)/65536 //0.
read morePosts
[C#]在.NET程式中要如何指定Windows的ClassName去接收視窗的訊息
protected override CreateParams CreateParams { get { base.CreateParams.ClassName = "test"; return base.CreateParams; } } }</pre></div> #region Delegate delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); #endregion #region DllImport /// <summary> /// Registers the class W. /// </summary> /// <param name="lpWndClass">The lp WND class.</param> /// <returns></returns> [DllImport("user32.dll", SetLastError = true)] static extern UInt16 RegisterClassW( [In] ref WNDCLASS lpWndClass ); /// <summary> /// Creates the window ex W. /// </summary> /// <param name="dwExStyle">The dw ex style.
read morePosts
[C#]如何使用TraceListener實作類似Visual Studio的輸出視窗
/// <summary> /// Initializes a new instance of the <see cref="ListBoxLogTraceListener"/> class. /// </summary> /// <param name="listBox">The list box.</param> public ListBoxLogTraceListener(ListBox listBox) { m_ListBox = listBox; } /// <summary> /// Writes the output to the OutputDebugString function and to the <see cref="M:System.Diagnostics.Debugger.Log(System.Int32,System.String,System.String)"/> method, followed by a carriage return and line feed ( ). /// </summary> /// <param name=“message”>The message to write to OutputDebugString and <see cref=“M:System.Diagnostics.Debugger.Log(System.Int32,System.String,System.String)”/>.</param> /// <PermissionSet> /// <IPermission class=“System.
read morePosts
[C#]如何使用Windows Shell做Zip檔的壓縮與解壓縮
public static void Compress(string sourceFolderPath, string zipFile) { if (!Directory.Exists(sourceFolderPath)) throw new DirectoryNotFoundException(); if (!File.Exists(zipFile)) File.Create(zipFile).Dispose(); ShellCopyTo(sourceFolderPath, zipFile); } public static void DeCompress(string zipFile, string destinationFolderPath) { if (!File.Exists(zipFile)) throw new FileNotFoundException(); if (!Directory.Exists(destinationFolderPath)) Directory.CreateDirectory(destinationFolderPath); ShellCopyTo(zipFile, destinationFolderPath); } </pre> public class ZipEntry { #region Private Property private FolderItem m_ShellItem { get; set; } private IEnumerable<ZipEntry> _entrys; #endregion #region Public Property /// <summary> /// Gets the name. /// </summary> /// <value>The name.
read morePosts
[C#]如何取出最近在Windows上所使用的文件檔案
return targetFile; } public static IEnumerable<string> GetRecentlyFiles() { var recentFolder = Environment.GetFolderPath(Environment.SpecialFolder.Recent); return from file in Directory.EnumerateFiles(recentFolder) where Path.GetExtension(file) == ".lnk" select GetShortcutTargetFile(file); } }</pre></div> namespace WindowsFormsApplication2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) { listBox1.Items.Clear(); foreach (var file in RecentlyFileHelper.GetRecentlyFiles()) { listBox1.Items.Add(file); } var recentFolder = Environment.GetFolderPath(Environment.SpecialFolder.Recent); fileSystemWatcher1.Path = recentFolder; fileSystemWatcher1.Created += new System.IO.FileSystemEventHandler(fileSystemWatcher1_Created); } void fileSystemWatcher1_Created(object sender, System.
read morePosts
[C#]如何取得Process的Owner
if (processObj == null) throw new ArgumentException("Process not exists!"); var argList = new string[2]; int returnVal = Convert.ToInt32(processObj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { return string.Join(@"\", argList.Reverse().ToArray()); } return null; }</pre></div> if (processObj == null) throw new ArgumentException("Process not exists!"); var argList = new string[2]; int returnVal = Convert.ToInt32(processObj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { return string.Join(@"\", argList.Reverse().ToArray()); } return null; } }
read morePosts
[C#]如何在程式中內嵌其它應用程式
if (HideApplicationTitleBar) SetWindowLong(handle, GWL_STYLE, WS_VISIBLE);
SetParent(handle, this.Handle);
MoveWindow(handle, 0, 0, this.Width, this.Height, true); …
if (handle != IntPtr.Zero) MoveWindow(handle, 0, 0, this.Width, this.Height, true); }</pre>
read morePosts
[C#]如何解決在Vista以後開啟檔案FileSystemWatcher無法觸發LastAccess的問題
static void fw_Changed(object sender, FileSystemEventArgs e) { }</pre>
read morePosts
[C#]實作UDP Broadcast的傳送與接收
private static void BroadcastMessage(byte[] message, int port) { using (var sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { sock.EnableBroadcast = true; sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); var iep = new IPEndPoint(IPAddress.Broadcast, port); sock.SendTo(message, iep); } }</pre></div> private void ReceiveBroadcastMessage(Action<EndPoint, byte[]> receivedAction, int port) { using (var sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { var ep = new IPEndPoint(IPAddress.Any, port) as EndPoint; sock.Bind(ep);
while (true) { var buffer = new byte[1024]; var recv = sock.
read morePosts
[C#]將指定的檔案刪除並送到資源回收桶
#region Dllimport /// <summary> /// SHs the file operation. /// </summary> /// <param name="FileOp">The file op.</param> /// <returns></returns> [DllImport("shell32.dll", CharSet = CharSet.Auto)] public static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp); #endregion #region Const public const int FO_DELETE = 3; public const int FOF_ALLOWUNDO = 0x40; public const int FOF_NOCONFIRMATION = 0x10; #endregion #region Public Static Method public static void DeleteFileToRecyclebin(string file, Boolean showConfirmDialog = false) { var shf = new SHFILEOPSTRUCT(); shf.
read morePosts
[C#]平行處理網路傳輸時因連線數不足發生連線Timeout的解決方案
namespace ConsoleApplication15 { class Program { public static string url = “https://www.google.com/images/srpr/logo3w.png"; private static List<WaitHandle> finished = new List<WaitHandle>(); public static void Main() { ServicePointManager.DefaultConnectionLimit = 200;
finished.Clear(); for (var idx = 0; idx < 5; ++idx ) { finished.Add(new ManualResetEvent(false)); Download(idx, url); } WaitHandle.WaitAll(finished.ToArray()); Console.WriteLine(“Done…”);
}
private static void Download(int idx, string url) { var wc = new WebClient(); wc.OpenReadCompleted += wc_OpenReadCompleted; wc.OpenReadAsync(new Uri(url), idx); } private static void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { Console.
read morePosts
[C#]從PE檔中讀取組件資訊
/// <summary> /// AssemblyDetails is used in the update builder, wyBuild (http://wyday.com/wybuild/), /// to automagically detect .NET assemblies properties, namely: /// - if they are compiled with a Strong Name, /// - CPUVersion the assembly was compiled as, /// - .NET Framework the assembly was compiled for (.NET 2.0 or 4.0) /// </summary> public class AssemblyDetails { /// <summary> /// The CPUVersion the assembly was compiled with. /// </summary> public CPUVersion CPUVersion;
read morePosts
[C#]忽略在 HTTP 剖析期間發生的驗證錯誤
if (anInstance != null) { //Locate the private bool field that tells the framework is unsafe header parsing should be allowed or not FieldInfo aUseUnsafeHeaderParsing = aSettingsType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance); if (aUseUnsafeHeaderParsing != null) { aUseUnsafeHeaderParsing.SetValue(anInstance, true); return true; } } } } return false; }</pre>
read morePosts
[C#]擷取Picasa資料庫(_.PMP)內現有的資料
var type = br.ReadInt16(); if (0x1332 != br.ReadInt16()) { throw new Exception("Incorrect format"); } if (0x00000002 != br.ReadInt32()) { throw new Exception("Incorrect format"); } if (type != br.ReadInt16()) { throw new Exception("Incorrect format"); } if (0x1332 != br.ReadInt16()) { throw new Exception("Incorrect format"); } var number = br.ReadInt32(); switch (type) { case 0x00: DumpStringField(br, number); break; case 0x01: Dump4ByteField(br, number); break; case 0x02: DumpDateField(br, number); break; case 0x03: DumpByteField(br, number); break; case 0x04: Dump8ByteField(br, number); break; case 0x05: Dump2ByteField(br, number); break; case 0x06: DumpStringField(br, number); break; case 0x07: Dump4ByteField(br, number); break; default: throw new Exception("Incorrect format"); } } } .
read morePosts
[C#]簡易的Backoff window實現類別
namespace ConsoleApplication12 { public class BackOff { #region Var private int _level; private Random _random; #endregion
#region Private Property private ReadOnlyCollection<int> m_BackOffWindows { get; set; } private Random m_Random { get { if (_random == null) _random = new Random(Guid.NewGuid().GetHashCode()); return _random; } } #endregion #region Public Property /// <summary> /// Gets or sets the level. /// </summary> /// <value>The level.</value> public int Level { get { return _level; } set { if (value <= 0) throw new Exception("Level value must be bigger than zero!
read morePosts
[C#]設定WebBrowser Control運行的User Agent版本
64 bit: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
read morePosts
[C#]透過PerformanceCounter取得特定Process的CPU使用率
var instances = category.GetInstanceNames(); foreach (var instance in instances) { using (var counter = new PerformanceCounter(category.CategoryName, "ID Process", instance, true)) { int val = (int)counter.RawValue; if (val == pid) { return instance; } } } throw new ArgumentException("Invalid pid!"); }</pre> var lastUpdateTime = default(DateTime); m_UpdateTimePool.TryGetValue(pid, out lastUpdateTime); var interval = DateTime.Now - lastUpdateTime; if (interval.TotalSeconds > 1) { m_CpuUsagePool[pid] = (int)(m_CounterPool[pid].NextValue() / Environment.ProcessorCount); } return m_CpuUsagePool[pid]; }</pre> public static class ProcessExtension { #region Private Static Var private static Dictionary<int, PerformanceCounter> _counterPool; private static Dictionary<int, DateTime> _updateTimePool; private static Dictionary<int, int> _cpuUsagePool; #endregion
read morePosts
[Performance][C#]ToString V.S Enum.GetName
class Program { static void Main(string[] args) { var count = 1000000; Console.WriteLine("ToString: {0} ms", DoTest(count, () => { var temp = MyEnum.EnumItem1.ToString(); }).ToString()); Console.WriteLine("Enum.GetName: {0} ms", DoTest(count, () => { var temp = Enum.GetName(typeof(MyEnum), MyEnum.EnumItem1); }).ToString()); } static long DoTest(int count, Action action) { var sw = Stopwatch.StartNew(); for(int i = 0;i<count;++i) { action(); } return sw.ElapsedMilliseconds; } } } private static string InternalFormat(RuntimeType eT, object value) { if (eT.
read morePosts
[Visual Studio][C#]Visual Studio Achievements API
namespace AchievementsAPIDemo { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private string GetHTMLSourceCode(string url) { HttpWebRequest request = (WebRequest.Create(url)) as HttpWebRequest; HttpWebResponse response = request.GetResponse() as HttpWebResponse; using (StreamReader sr = new StreamReader(response.GetResponseStream())) { return sr.ReadToEnd(); } } private void Form1_Load(object sender, EventArgs e) { var obj = new VSAchievements.Achievement(GetHTMLSourceCode("http://channel9.msdn.com/achievements/visualstudio?json=true")); foreach (var achievement in obj.Achievements) { flowLayoutPanel1.Controls.Add(new PictureBox() { ImageLocation = achievement.IconSmall }); flowLayoutPanel1.Controls.Add(new Label() { Text = achievement.
read morePosts
FlickrNet開發系列- FlickrNet基本功能開發(一)
MessageBox.Show(string.Format( @“FullName: {0} UserId: {1} UserName: {2}”, user.FullName, user.UserId, user.UserName)); }
var photoSets = m_Flickr.PhotosetsGetList(userID); foreach (var photoSet in photoSets) { var pic = new PictureBox() { ImageLocation = photoSet.PhotosetThumbnailUrl, BorderStyle = BorderStyle.FixedSingle, SizeMode = PictureBoxSizeMode.AutoSize }; container.Controls.Add(pic); } var photos = m_Flickr.PhotosGetNotInSet(); foreach (var photo in photos) { var pic = new PictureBox() { ImageLocation = photo.ThumbnailUrl, SizeMode = PictureBoxSizeMode.AutoSize }; container.Controls.Add(pic); } form.Controls.Add(container); form.ShowDialog(); }</pre> foreach (var photo in photos) { var pic = new PictureBox() { ImageLocation = photo.
read morePosts
FlickrNet開發系列- FlickrNet基本功能開發(二)
for (int i = 0; i < photos.Count; ++i) { var photo = photos[i]; var pic = new PictureBox() { ImageLocation = photo.ThumbnailUrl, BorderStyle = BorderStyle.FixedSingle, SizeMode = PictureBoxSizeMode.AutoSize, Tag = photo }; container.Controls.Add(pic); pic.Click += (sender, e) => { photo = (sender as PictureBox).Tag as FlickrNet.Photo; var sizes = m_Flickr.PhotosGetSizes(photo.PhotoId); var hasLargePhoto = (from item in sizes where string.Equals(item.Label, "Large", StringComparison.CurrentCultureIgnoreCase) select item).Count() > 0; var dialog = new Form(); var photoBox = new PictureBox() { ImageLocation = hasLargePhoto ?
read morePosts
How to customize .NET 4.0's System.Runtime.Caching.ChangeMonitor
namespace CustomChangeMonitorDemo { public class ClipboardChangeMonitor : ChangeMonitor { #region Var private string _clipboardText; private Timer _timer; private string _uniqueID; #endregion
#region Private Property private string m_ClipboardText { get { return _clipboardText ?? string.Empty; } set { if (_clipboardText == value) return; _clipboardText = value; OnChanged(value); } } private System.Windows.Forms.Timer m_Timer { get { return _timer ?? (_timer = new System.Windows.Forms.Timer()); } } #endregion #region Public Property public override string UniqueId { get { return _uniqueID ?
read morePosts
How to use MetaWeblogSharp
return Login(connectionInfo); } private static Client Login(BlogConnectionInfo connectionInfo) { var client = new Client(connectionInfo); var blog = client.GetUsersBlogs().FirstOrDefault(); connectionInfo.BlogID = blog.BlogID; connectionInfo.BlogURL = blog.URL; return client; }</pre>
read morePosts
Recursive ContainerFromItem
if (dp != null) return dp; foreach (var item in itemsControl.Items) { var currentTreeViewItem = itemsControl.ItemContainerGenerator.ContainerFromItem(item); var childDp = ContainerFromItem(currentTreeViewItem as ItemsControl, value); if (childDp != null) return childDp; } return null; }</pre> public static class ItemsControlExtension { public static DependencyObject ContainerFromItem(this ItemsControl itemsControl, object value) { var dp = itemsControl.ItemContainerGenerator.ContainerFromItem(value);
if (dp != null) return dp; foreach (var item in itemsControl.Items) { var currentTreeViewItem = itemsControl.ItemContainerGenerator.ContainerFromItem(item); var childDp = ContainerFromItem(currentTreeViewItem as ItemsControl, value); if (childDp !
read morePosts
Use ResourceDictionary to do multi-language in WPF
private void ApplyMultiLanguageResource() { ApplyMultiLanguageResource(CultureInfo.CurrentCulture); } private void ApplyMultiLanguageResource(CultureInfo cultureInfo) { var cultureName = cultureInfo.Name; var resourceFile = string.Empty; try { resourceFile = @"StringResources." + cultureName + ".xaml "; } catch (Exception) { } if (string.IsNullOrEmpty(resourceFile)) resourceFile = @"StringResources.xaml"; var rd = Application.LoadComponent(new Uri(resourceFile, UriKind.Relative)) as ResourceDictionary; var existsRD = this.Resources.MergedDictionaries.Where(item => item.Source.OriginalString.Equals(resourceFile, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault(); if (existsRD != null) this.Resources.MergedDictionaries.Remove(existsRD); this.Resources.MergedDictionaries.Add(rd); } }</pre></div>
read morePosts
Use Windows Error Reporting(WER) to collect user-mode dumps
namespace ConsoleApplication46 { class Program { static void Main(string[] args) { var x = 1; var y = x - 1; var result = x / y; } } }
read morePosts
[C#][Control]BitsControl概念與簡易實做
int bitWith = width / 8; bit8.Width = bitWith; bit7.Width = bitWith; bit6.Width = bitWith; bit5.Width = bitWith; bit4.Width = bitWith; bit3.Width = bitWith; bit2.Width = bitWith; bit1.Width = bitWith; int bitHeight = flowLayoutPanel1.ClientSize.Height - bit8.Margin.Top * 2; bit8.Height = bitHeight; bit7.Height = bitHeight; bit6.Height = bitHeight; bit5.Height = bitHeight; bit4.Height = bitHeight; bit3.Height = bitHeight; bit2.Height = bitHeight; bit1.Height = bitHeight; }</pre> public void LoadBitsState(string hexValue) { LoadBitsState(Convert.ToInt32(hexValue, 16)); }</pre> namespace WindowsFormsApplication6 { public partial class BitsControl : UserControl { public BitsControl() { InitializeComponent(); }
read morePosts
[C#][Control]指撥開關控制項的概念與簡易實作
private SwitchState _state; public SwitchState State { get { return _state; } set { if (_state == value) return; _state = value; AdjustOnOffButton(); } } private void AdjustOnOffButton() { switch (State) { case SwitchState.On: OnOffButton.Dock = DockStyle.Top; break; case SwitchState.Off: OnOffButton.Dock = DockStyle.Bottom; break; default: break; } }</pre> private void OnOffButton_Click(object sender, EventArgs e) { Toggle(); }</pre> namespace WindowsFormsApplication3 { public partial class SwitchButton : UserControl {
public enum SwitchState { On, Off } private SwitchState _state; public SwitchState State { get { return _state; } set { if (_state == value) return; _state = value; AdjustOnOffButton(); } } public SwitchButton() { InitializeComponent(); State = SwitchState.
read morePosts
[C#][WPF]WPF程式接收視窗訊息
namespace WpfApplication2 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.SourceInitialized += new EventHandler(MainWindow_SourceInitialized); }
void MainWindow_SourceInitialized(object sender, EventArgs e) { IntPtr hwnd = new WindowInteropHelper(this).Handle; HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc)); } IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { //... } return IntPtr.Zero; } } }
read morePosts
[C#]Enable UAC Shield icons and run as administrator
#region Private Method private static bool AtLeastVista() { return (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major >= 6); } private static void SetButtonShield(Button btn, bool showShield) { if (!AtLeastVista()) return; btn.FlatStyle = FlatStyle.System; SendMessage(new HandleRef(btn, btn.Handle), BCM_SETSHIELD, IntPtr.Zero, showShield ? new IntPtr(1) : IntPtr.Zero); } #endregion</pre> public static class ButtonExtension { #region DllImport [DllImport(“shell32.dll”, EntryPoint = “#680”, CharSet = CharSet.Unicode)] private static extern bool IsUserAnAdmin();
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr SendMessage(HandleRef hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); #endregion #region Const const int BCM_SETSHIELD = 0x0000160C; #endregion #region Private Method private static bool AtLeastVista() { return (Environment.
read morePosts
[.Net concept]使用方法與屬性時適時為其值做快取
//Calculate count.... ... return count; }
int count = myObj.Count; for (int i = 0; i < count; ++i) { for (int j = 0; j < count; ++j) ... } }
read morePosts
[C#].NET 4.5 New Feature - Regex match with timeout
AppDomain.CurrentDomain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromSeconds(2)); isMatch = IsMatch(input, pattern); Console.WriteLine(); isMatch = IsMatch(input, pattern, TimeSpan.FromSeconds(4)); } static Boolean IsMatch(string input, string pattern) { try { return Regex.IsMatch(input, pattern, RegexOptions.None); } catch (RegexMatchTimeoutException ex) { // handle exception Console.WriteLine("Match timed out!"); Console.WriteLine("- Timeout interval specified: " + ex.MatchTimeout); Console.WriteLine("- Pattern: " + ex.Pattern); Console.WriteLine("- Input: " + ex.Input); } return false; } static Boolean IsMatch(string input, string pattern, TimeSpan timeout) { try { return Regex.
read morePosts
[C#]RaiseEvent Extension Method (二)
public static void RaiseEvent(this object obj, EventHandler handler, Func<EventArgs> func) { if (handler == null) return; handler(obj, func()); } public static void RaiseEvent<TEventArgs>(this object obj, EventHandler<TEventArgs> handler, TEventArgs e) where TEventArgs : EventArgs { RaiseEvent(obj, handler, () => e); } public static void RaiseEvent<TEventArgs>(this object obj, EventHandler<TEventArgs> handler,Func<TEventArgs> func) where TEventArgs : EventArgs { if (handler == null) return; handler(obj, func()); } }</pre></div> namespace ConsoleApplication14 { class Program { static void Main(string[] args) { Person Larry = new Person(); Larry.
read morePosts
[C#][Linq]Linq to Wikipedia
private IQueryable<WikipediaKeywordSearchResult>KeyWordSearch(string keyWord) { return from item in (new WikipediaContext()).KeywordSearch where item.Keyword == keyWord select item; }</pre></div>
read morePosts
[C#]取得網卡的IPV6位置
namespace ConsoleApplication13 { class Program { static void Main(string[] args) { foreach (var ip in GetLocalIPV6IP()) { Console.WriteLine(ip); } }
private static IEnumerable<String> GetLocalIPV6IP() { return (from adapter in NetworkInterface.GetAllNetworkInterfaces() where adapter .NetworkInterfaceType == NetworkInterfaceType.Ethernet from AddressInfo in adapter.GetIPProperties().UnicastAddresses.OfType<UnicastIPAddressInformation>() where AddressInfo.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6 let ipAddress = AddressInfo.Address.ToString() select ipAddress); } } }
read morePosts
[.Net Concept]理解事件的宣告方式與用法
#region Event event NameChangingEventHandler NameChanging; event NameChangedEventHandler NameChanged; #endregion</pre> #region Event event EventHandler<FriendEventArgs> FriendAdded; #endregion
#region Protected Method protected void OnFriendAdded(FriendEventArgs e) { if (FriendAdded == null) return; FriendAdded(this, e); } #endregion
#region Public Method public void AddFriend(Person friend) { Friends.Add(friend); OnFriendAdded(new FriendEventArgs(friend.Name)); } #endregion
…
class FriendEventArgs : EventArgs { #region Var private String _name; #endregion
#region Property public String Name { get { if (_name == null) return String.
read morePosts
[C#]DictService
namespace DictServceDemo { public partial class Form1 : Form {
#region Var private DictService _dictService; #endregion #region Private Property public DictService m_DictService { get { if (_dictService == null) _dictService = new DictService(); return _dictService; } } #endregion #region Constructor public Form1() { InitializeComponent(); } #endregion #region Event Process private void Form1_Load(object sender, EventArgs e) { cbxDict.DisplayMember = "Name"; cbxDict.DataSource = m_DictService.DictionaryList(); cbxStrategy.DisplayMember = "Id"; cbxStrategy.DataSource = m_DictService.StrategyList(); } private void lbxResult_SelectedIndexChanged(object sender, EventArgs e) { if (cbxDict.
read morePosts
[C#]Stream.Write Extension Method
public static class StreamExtension { public static void Write(this Stream targetStream, byte[] buffer) { if (!targetStream.CanWrite) throw new ArgumentException(“targetStream”, “Unwritable stream”);
targetStream.Write(buffer, 0, buffer.Length); } public static void Write(this Stream targetStream, Stream sourceStream) { if (!targetStream.CanWrite) throw new ArgumentException("targetStream", "Unwritable stream"); if (sourceStream == null) throw new ArgumentNullException("sourceStream"); if (!sourceStream.CanRead) throw new ArgumentException("sourceStream", "Unreadable stream"); targetStream.Write(sourceStream, 1024, null); } public static void Write(this Stream targetStream, Stream sourceStream, int bufferSize, Action<object, System.
read morePosts
[C#][Linq]LINQ To WMI
foreach (Win32_UserAccount account in query) { Console.WriteLine(account.Name); } } }
read morePosts
[C#][Linq]BLinq - Linq To Bing
private IEnumerable<ImageSearchResult> SearchImages(string keyWord) { return from item in m_Bing.Images where item.Query == keyWord select item; }</pre>
read morePosts
[.Net Concept]理解並善用String pool
Console.WriteLine(string.Format("ReferenceEquals(str1, str2) = {0}", ReferenceEquals(str1, str2))); Console.WriteLine(string.Format("ReferenceEquals(str1, str3) = {0}", ReferenceEquals(str1, str3))); Console.WriteLine(string.Format("ReferenceEquals(str1, str4) = {0}", ReferenceEquals(str1, str4))); </pre></div> Console.WriteLine(string.Format("ReferenceEquals(str1, str2) = {0}", ReferenceEquals(str1, str2))); Console.WriteLine(string.Format("ReferenceEquals(str1, str3) = {0}", ReferenceEquals(str1, str3))); </pre></div> str2 = string.Intern(str2); str3 = string.Intern(str3); Console.WriteLine(string.Format("ReferenceEquals(str1, str2) = {0}", ReferenceEquals(str1, str2))); Console.WriteLine(string.Format("ReferenceEquals(str1, str3) = {0}", ReferenceEquals(str1, str3)));</pre></div> str1 = string.Intern(str1); Console.WriteLine(string.Format(@"String.IsInterned(str1) = {0}", String.IsInterned(str1) != null));</pre></div> private static void Test(int testCount, int stringLength) { NormalCompare1(string.Empty, string.Empty); NormalCompare2(string.
read morePosts
[C#]LevelUp.Lazy
namespace LazyDemo { class Program { static void Main(string[] args) { var count = 10; LevelUpLazy.Lazy<string>[] lazys = new LevelUpLazy.Lazy<string>[count]; for (int i = 0; i < count; i++) { lazys[i] = new LevelUpLazy.Lazy<string>(DoWork); }
lazys[3].ValueInited += new EventHandler(laz3_ValueInited); lazys[3].BeginInit();
lazys[2].BeginInit();
Stopwatch sw = Stopwatch.StartNew(); Console.WriteLine(“lazy1 result = {0}”, lazys[1].Value); Console.WriteLine(“lazy1 Elapsed Time = {0} ms”, sw.ElapsedMilliseconds);
sw.Restart(); Console.WriteLine(“lazy1 result = {0}”, lazys[1].Value); Console.WriteLine(“lazy1 Elapsed Time = {0} ms”, sw.
read morePosts
土豆視頻開發系列-依影集分類查詢
XmlNodeList nodes = xmlDom.SelectNodes(@"/result/results/AlbumInfo"); foreach (XmlNode node in nodes) { // Name = node.ChildNodes[1].InnerText // picUrl = node.ChildNodes[2].InnerText // … … } … }
read morePosts
[C#]取得檔案內容中的詳細資料
using System.Linq;
using System.Text;
using Shell32;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ViewDetailColumn();
Console.WriteLine(new string(’=’, 50));
var file = @“C:\Users\Public\Music\Sample Music\Kalimba.mp3”;
ViewDetailValue(file, “Album”);
ViewDetailValue(file, “Size”);
}
static IEnumerable<KeyValuePair<string, int>> GetDetailColumn()
{
ShellClass sh = new ShellClass();
Folder dir = sh.NameSpace(@“c:");
int idx = 0;
string columnName = dir.GetDetailsOf(0, idx);
do
{
yield return new KeyValuePair<string, int>(columnName, idx);
columnName = dir.GetDetailsOf(0, ++idx); } while (!
read morePosts
[C#]原子能委員會輻射監控非官方API
namespace LevelUp.RadiationAPI.Demo { public partial class Form1 : Form { private RadiationAgent _radiationAgent; private RadiationAgent m_RadiationAgent { get { if (_radiationAgent == null) { _radiationAgent = new RadiationAgent(); _radiationAgent.AutoUpdateInterval = 5000; _radiationAgent.EnableAutoUpdate = true; } return _radiationAgent; } }
public Form1() { InitializeComponent(); } private void UpdateRadiationValue() { listView1.Items.Clear(); listView1.BeginUpdate(); foreach (var data in m_RadiationAgent.RadiationDatas) { listView1.Items.Add(data.City).SubItems.AddRange(new string[] { data.RadiationValue.ToString(), data.State.ToString() }); } listView1.EndUpdate(); } private void timer1_Tick(object sender, EventArgs e) { UpdateRadiationValue(); } private void Form1_Load(object sender, EventArgs e) { UpdateRadiationValue(); m_RadiationAgent.
read morePosts
[C#]Everything SDK
namespace Everything { /// <summary> /// /// </summary> public class EverythingAPI { #region Const const string EVERYTHING_DLL_NAME = “Everything.dll”; #endregion
#region DllImport [DllImport(EVERYTHING_DLL_NAME)] private static extern int Everything_SetSearch(string lpSearchString); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_SetMatchPath(bool bEnable); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_SetMatchCase(bool bEnable); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_SetMatchWholeWord(bool bEnable); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_SetRegex(bool bEnable); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_SetMax(int dwMax); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_SetOffset(int dwOffset); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_GetMatchPath(); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_GetMatchCase(); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_GetMatchWholeWord(); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_GetRegex(); [DllImport(EVERYTHING_DLL_NAME)] private static extern UInt32 Everything_GetMax(); [DllImport(EVERYTHING_DLL_NAME)] private static extern UInt32 Everything_GetOffset(); [DllImport(EVERYTHING_DLL_NAME)] private static extern string Everything_GetSearch(); [DllImport(EVERYTHING_DLL_NAME)] private static extern StateCode Everything_GetLastError(); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_Query(); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_SortResultsByPath(); [DllImport(EVERYTHING_DLL_NAME)] private static extern int Everything_GetNumFileResults(); [DllImport(EVERYTHING_DLL_NAME)] private static extern int Everything_GetNumFolderResults(); [DllImport(EVERYTHING_DLL_NAME)] private static extern int Everything_GetNumResults(); [DllImport(EVERYTHING_DLL_NAME)] private static extern int Everything_GetTotFileResults(); [DllImport(EVERYTHING_DLL_NAME)] private static extern int Everything_GetTotFolderResults(); [DllImport(EVERYTHING_DLL_NAME)] private static extern int Everything_GetTotResults(); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_IsVolumeResult(int nIndex); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_IsFolderResult(int nIndex); [DllImport(EVERYTHING_DLL_NAME)] private static extern bool Everything_IsFileResult(int nIndex); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_GetResultFullPathName(int nIndex, StringBuilder lpString, int nMaxCount); [DllImport(EVERYTHING_DLL_NAME)] private static extern void Everything_Reset(); #endregion #region Enum enum StateCode { OK, MemoryError, IPCError, RegisterClassExError, CreateWindowError, CreateThreadError, InvalidIndexError, InvalidCallError } #endregion #region Property /// <summary> /// Gets or sets a value indicating whether [match path].
read morePosts
[C#]More Effective C# 條款四十九: 考慮為大型物件使用弱引用
private static WeakReference m_ObjectCache { get { if (_objectCache == null) _objectCache = new WeakReference(null); return _objectCache; } } private static Object m_Cache { get { if (m_ObjectCache.Target == null) m_ObjectCache.Target = CreateBigObj(); return m_ObjectCache.Target; } } static void Main(string[] args) { Console.WriteLine(m_Cache); Console.WriteLine(m_Cache); GC.Collect(); Console.WriteLine(m_Cache); } ...</pre>
read morePosts
[C#]Effective C# 條款十七:盡量減少裝箱與拆箱
namespace ConsoleApplication18 { class Program { static void Main(string[] args) { Person p = new Person() { Name=“Larry”};
object o1 = (object)p; // boxing object o2 = p; // Implicit boxing ArrayList array = new ArrayList(); array.Add(p); //Implicit boxing //Unboxing Person p1 = (Person)o1; Person p2 = (Person)o2; p1.Name = "Larry1"; p2.Name = "Larry2"; Person p3 = (Person)array[0]; p3.Name = "Larry3"; Console.WriteLine(string.Format("p = {0}", p)); Console.WriteLine(string.Format("p1 = {0}", p1)); Console.
read morePosts
IEnumerable amp; IEnumerator介面的實作
PersonCollection persons = new PersonCollection ( new Person[]{new Person("Larry")}); foreach (Person person in persons) { Console.WriteLine(person.Name); } foreach (Person person in persons) { Console.WriteLine(person.Name); } } } public class Person { public string Name { get; set; } public Person(string name) { this.Name = name; } } public class PersonCollection : IEnumerable,IEnumerator { private Person[] _peoples; private int position = -1; public PersonCollection(Person[] list) { _peoples = list; } public bool MoveNext() { position++; return (position < _peoples.
read morePosts
[C#]Effective C# 條款十五:利用using和try/finally語句來清理資源.
conn.Open(); cmd.ExecuteNonQuery(); cmd.Dispose(); conn.Dispose(); }</pre> conn.Open(); cmd.ExecuteNonQuery(); } finally { if (cmd != null) cmd.Dispose(); if (conn != null) conn.Dispose(); } }</pre>
read morePosts
[C#]Effective C# 條款十四:利用建構子鏈
public string FirstName { get; set; } public string LastName { get; set; } public SexType Sex { get; set; } public int Age { get; set; } public string Common { get; set; } public Person(string firstName , string lastName) { this.FirstName = firstName; this.LastName = lastName; } public Person(string firstName, string lastName,int age) { this.FirstName = firstName; this.LastName = lastName; this.Age = age; } }</pre> public Person(string firstName, string lastName) { Init(firstName, lastName, 0); } public Person(string firstName, string lastName, int age) { Init(firstName, lastName, age); } private void Init(string firstName, string lastName, int age) { this.
read morePosts
.NET 4.0 New Feature - System.Device.Location
GeoCoordinate location = watcher.Position.Location; if (location.IsUnknown) return; Console.WriteLine("Time: {0}", e.Position.Timestamp); Console.WriteLine("Longitude: {0}", location.Longitude); //經度 Console.WriteLine("Latitude: {0}", location.Latitude); //緯度 Console.WriteLine("Altitude: {0}", location.Altitude); //高度 Console.WriteLine("Course: {0}", location.Course); //角度 Console.WriteLine("Speed: {0}", location.Speed); //速度 CivicAddressResolver resolver = new CivicAddressResolver(); CivicAddress realLocation = m_addressResolver.ResolveAddress(location); if (realLocation.IsUnknown) return; Console.WriteLine("Address1: {0}", realLocation.AddressLine1); //實際地址 Console.WriteLine("Address2: {0}", realLocation.AddressLine2); Console.WriteLine("Building: {0}", realLocation.Building); //門牌號碼 Console.WriteLine("City: {0}", realLocation.City); //縣市 Console.WriteLine("CountryRegion: {0}", realLocation.CountryRegion); //國家 Console.WriteLine("PostalCode: {0}", realLocation.PostalCode); //郵遞區號 Console.WriteLine("StateProvince: {0}", realLocation.StateProvince); //省份 Console.
read morePosts
使用反射(Reflection)實現應用程式擴充元件機制
public IHost Host { get { return _host; } set { _host = value; } } public PlugInController(IHost host) { this.Host = host; } IModule GetModule(Assembly asm, string fullTypeName) { Type t = asm.GetType(fullTypeName); IModule module = null; if (!(t.IsNotPublic || t.IsAbstract)) { object objInterface = t.GetInterface("IModule", true); if (objInterface != null) { module = asm.CreateInstance(t.FullName) as IModule; module.Host = Host; return module; } } return null; } IModule GetModule(Assembly asm, Type moduleType) { return GetModule(asm, moduleType.
read morePosts
.Net 4.0 New Feature - SortedSet
int[] array = new int[setData1.Count]; setData1.CopyTo(array); foreach (var value in array) setData1.Add(value); System.Console.WriteLine("setData1"); System.Console.WriteLine(string.Join(",", setData1)); System.Console.WriteLine("setData2"); System.Console.WriteLine(string.Join(",", setData2)); System.Console.WriteLine("setData1 IsSubsetOf setData2"); System.Console.WriteLine(string.Join(",", setData1.IsSubsetOf(setData2))); System.Console.WriteLine("setData1 Overlaps setData2"); System.Console.WriteLine(string.Join(",", setData1.Overlaps(setData2))); System.Console.WriteLine("setData1 UnionWith setData2"); var setUnion = new SortedSet<int>(setData1); setUnion.UnionWith(setData2); System.Console.WriteLine(string.Join(",", setUnion)); System.Console.WriteLine("(setData1 UnionWith setData2) Reverse"); System.Console.WriteLine(string.Join(",", setUnion.Reverse())); System.Console.WriteLine("(setData1 UnionWith setData2) Min"); System.Console.WriteLine(string.Join(",", setUnion.Min)); System.Console.WriteLine("(setData1 UnionWith setData2) Max"); System.Console.WriteLine(string.Join(",", setUnion.Max)); System.Console.WriteLine("(setData1 UnionWith setData2) GetViewBetween({0},{1})", (setUnion.Min + setUnion.Max) / 2, setUnion.Max); System.Console.WriteLine(string.Join(",", setUnion.GetViewBetween((setUnion.Min + setUnion.
read morePosts
[.NET Concept]throw V.S throw ex
namespace ConsoleApplication6 { class Program {
static void Main() { TestThrow(); TestThrowEx(); } static void ThrowException() { throw new Exception(); } static void TestThrow() { try { try { ThrowException(); } catch (Exception) { throw; } } catch (Exception ex) { Console.WriteLine("TestThrow"); Console.WriteLine(ex.StackTrace); Console.WriteLine(new string('=',50)); } } static void TestThrowEx() { try { try { ThrowException(); } catch (Exception ex) { throw ex; } } catch (Exception ex) { Console.
read morePosts
.NET 4.0 New Feature - IObservablelt;Tgt; amp; IObserverlt;Tgt;
public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer) { this.m_Observers = observers; this.m_Observer = observer; } public void Dispose() { if (m_Observer != null && m_Observers.Contains(m_Observer)) { m_Observers.Remove(m_Observer); } } }</pre> public class Observable<T> : IObservable<T> { #region Class private class Unsubscriber : IDisposable { private List<IObserver<T>> m_Observers { get; set; } private IObserver<T> m_Observer { get; set; }
public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer) { this.m_Observers = observers; this.m_Observer = observer; } public void Dispose() { if (m_Observer !
read morePosts
.NET 4.0 New Feature - Environment.Is64BitProcess amp; Environment.Is64BitOperatingSystem
namespace ConsoleApplication4 { class Program { static void Main(string[] args) { Console.WriteLine(“64位元作業系統: {0}",Environment.Is64BitOperatingSystem); Console.WriteLine(“64位元處理序: {0}”, Environment.Is64BitProcess); } } }
read morePosts
LINQ to CSV library
Read<T>(string fileName) Read<T>(string fileName, CsvFileDescription fileDescription) Read<T>(StreamReader stream) Read<T>(StreamReader stream, CsvFileDescription fileDescription)
[CsvColumn(Name = "LastName", FieldIndex = 1)] public String LastName { get; set; } [CsvColumn(Name = "Sex", FieldIndex = 2)] public String Sex { get; set; } [CsvColumn(Name = "Birthday", FieldIndex = 3)] public String Birthday { get; set; } public String Memo { get; set; } public override string ToString() { return string.Join(",", new string[] { FirstName, LastName, Sex, Birthday, Memo }); } }</pre> CsvContext cc = new CsvContext(); Person[] persons = new Person[] { new Person() { FirstName = "Larry", LastName = "Nung", Sex = "Boy", Birthday = "1980/04/19" } }; cc.
read morePosts
[C#][VB.NET]最大公因數 amp; 最小公倍數
private int LCM(int num1, int num2) { return num1 * num2 / GCD(num1, num2); }</pre></div> Private Function LCM(ByVal num1 As Integer, ByVal num2 As Integer) As Integer Return num1 * num2 / GCD(num1, num2) End Function</pre></div> namespace ConsoleApplication1 { class Program { private static int GCD(int num1, int num2) { int min = 0; int max = 0; int maxModMin = 0; min = Math.Min(num1, num2); max = Math.Max(num1, num2); maxModMin = max % min; return maxModMin > 0 ?
read morePosts
Linq To Excel Provider
using System.Linq; using System.ComponentModel;
[ExcelSheet(Name=“Sheet1”)] public class Person: INotifyPropertyChanged {
private double _id; private string _firstname; private string _lastname; private DateTime _birthdate; public event PropertyChangedEventHandler PropertyChanged; protected virtual void SendPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } [ExcelColumn(Name="ID", Storage="_id")] public double ID { get { return _id;} set { _id = value; SendPropertyChanged("ID"); } } [ExcelColumn(Name="FirstName", Storage="_firstname")] public string FirstName { get { return _firstname;} set { _firstname = value; SendPropertyChanged("FirstName"); } } [ExcelColumn(Name="LastName", Storage="_lastname")] public string LastName { get { return _lastname;} set { _lastname = value; SendPropertyChanged("LastName"); } } [ExcelColumn(Name="BirthDate", Storage="_birthdate")] public DateTime BirthDate { get { return _birthdate;} set { _birthdate = value; SendPropertyChanged("BirthDate"); } } }
read morePosts
Linq To Excel
//自己可自行加要過濾的條件,這邊只是示範 var linq = from item in excel.Worksheet(sheetName) select item; ...</pre> //這邊會取使用Sheet1的工作表內容去做查詢動作 var linq = from item in excel.Worksheet() select item; ...</pre> var linq = from item in excel.Worksheet<Blogger>(sheetName) where item.Sex==SexType.Boy select item; ...</pre> namespace ConsoleApplication1 { class Blogger { public int ID { get; set; } public String FirstName { get; set; } public String LastName { get; set; } public SexType Sex { get; set; } public int Age { get; set; } public String Blog { get; set; }
read morePosts
.NET 4.0 New Feature - Environment.SpecialFolder
CDBurning C:\Documents and Settings[User Account]\Local Settings\Application Data\Microsoft\C D Burning
CommonAdminTools C:\Documents and Settings\All Users\「開始」功能表\程式集\系統管理工具
CommonDocuments C:\Documents and Settings\All Users\Documents
CommonMusic C:\Documents and Settings\All Users\Documents\My Music
CommonOemLinks
CommonPictures C:\Documents and Settings\All Users\Documents\My Pictures
CommonStartMenu C:\Documents and Settings\All Users\「開始」功能表
CommonPrograms C:\Documents and Settings\All Users\「開始」功能表\程式集
CommonStartup C:\Documents and Settings\All Users\「開始」功能表\程式集\啟動
CommonDesktopDirectory C:\Documents and Settings\All Users\桌面
CommonTemplates C:\Documents and Settings\All Users\Templates
CommonVideos C:\Documents and Settings\All Users\Documents\My Videos
Fonts C:\WINDOWS\Fonts
MyVideos
NetworkShortcuts C:\Documents and Settings[User Account]\NetHood
read morePosts
.NET 4.0 New Feature - Environment.FailFast
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { try { Environment.FailFast(“A castrophic failure has occured.”, new DivideByZeroException ()); } catch (Exception) { Console.WriteLine(“catch…”); } finally { Console.WriteLine(“finally…”); } } } }
read morePosts
.NET 4.0 New Feature - System.Runtime.Caching
namespace CacheItemPolicyDemo { class Program { static void Main(string[] args) { ContentProvider textFile = new ContentProvider(); Stopwatch sw = new Stopwatch(); while (true) { sw.Reset(); sw.Start(); Console.WriteLine(DateTime.Now.ToString()); Console.WriteLine(textFile.Content); sw.Stop(); Console.WriteLine(“Elapsed Time: {0} ms”, sw.ElapsedMilliseconds); Console.WriteLine(new string(’=’, 50)); Console.ReadLine(); } } }
public class ContentProvider { public String Content { get { const string CACHE_KEY = "Content"; string content = m_Cache[CACHE_KEY] as string; if (content == null) { CacheItemPolicy policy = new CacheItemPolicy(); policy.
read morePosts
.NET 4.0 New Feature - Stream.CopyTo
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { using (MemoryStream sourceStream = new MemoryStream(512)) { using (StreamWriter sw = new StreamWriter(sourceStream)) { sw.WriteLine(“Test Stream.CopyTo”); sw.Flush();
sourceStream.Seek(0, SeekOrigin.Begin); using (FileStream targetStream = new FileStream("Test.Txt", FileMode.Create)) { sourceStream.CopyTo(targetStream); } } } } } }
read morePosts
.NET 4.0 New Feature - String.Concat
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { String[] stringCollection = { “123”, “456”, “789” }; int[] intCollection = { 123, 456, 789 }; Object[] objCollection = { 123, “456”, 789.0f }; float[] floatCollection = { 123.0f, 456.0f, 789.0f };
ShowValue<String>("stringCollection", stringCollection); ShowValue<int>("intCollection", intCollection); ShowValue<Object>("objCollection", objCollection); ShowValue<float>("floatCollection", floatCollection); } static void ShowValue<T>(string title, IEnumerable<T> values) { Console.WriteLine("{0}: {1}", title, string.Concat<T>(values)); } } }
read morePosts
.NET 4.0 New Feature - String.IsNullOrWhiteSpace
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string[] values = { null, String.Empty, “ABCDE”, new String(’ ‘, 20), " “, new String(’\u2000’, 10), };
Console.WriteLine(new String('=', 50)); Console.WriteLine("IsNullOrWhiteSpaceDemo..."); IsNullOrWhiteSpaceDemo(values); Console.WriteLine(new String('=', 50)); Console.WriteLine("MSDNCustomIsNullOrWhiteSpaceDemo..."); MSDNCustomIsNullOrWhiteSpaceDemo(values); Console.WriteLine(new String('=', 50)); Console.WriteLine("CustomIsNullOrWhiteSpaceDemo..."); CustomIsNullOrWhiteSpaceDemo(values); } public static void IsNullOrWhiteSpaceDemo(string[] values) { foreach (string value in values) Console.WriteLine("String.IsNullOrWhiteSpace({0}): {1}", value, String.IsNullOrWhiteSpace(value)); } public static void MSDNCustomIsNullOrWhiteSpaceDemo(string[] values) { foreach (string value in values) Console.
read morePosts
.NET 4.0 New Feature - String.Join
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { String[] stringCollection = { “123”, “456”, “789” }; int[] intCollection = { 123, 456, 789 }; Object[] objCollection = { 123, “456”, 789.0f }; float[] floatCollection = { 123.0f, 456.0f, 789.0f };
ShowValue<String>("stringCollection", stringCollection); ShowValue<int>("intCollection", intCollection); ShowValue<Object>("objCollection", objCollection); ShowValue<float>("floatCollection", floatCollection); } static void ShowValue<T>(string title, IEnumerable<T> values) { Console.WriteLine("{0}: {1}", title, string.Join(",", values)); } } }
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { String[] stringCollection = { “123”, “456”, “789” }; int[] intCollection = { 123, 456, 789 }; Object[] objCollection = { 123, “456”, 789.
read morePosts
.NET 4.0 New Feature - Tuple
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var var1 = Tuple.Create(1, 2, 1); var var2 = Tuple.Create(1, 1, 2);
Console.WriteLine("Var1 : {0}", var1); Console.WriteLine("Var2 : {0}", var2); Console.WriteLine("Var1 == Var2 : {0}", var1 == var2); Console.WriteLine("Var1.Equals(Var2) : {0}", var1.Equals(var2)); Console.WriteLine("(Var1 as IComparable).CompareTo(Var2) : {0}", (var1 as IComparable).CompareTo(var2)); Console.WriteLine(); Console.WriteLine("Original Array..."); var tupeArray = new Tuple<int, int, int>[] { var1, var2 }; foreach (var item in tupeArray) Console.
read morePosts
使用C#呼叫VB.NET的CallByName函式
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { DataTable dt = new DataTable(); … foreach (DataRow dr in dt.Rows) { foreach (DataColumn dc in dt.Columns) { Versioned.CallByName(obj, dc.ColumnName, CallType.Set, dr(dc.ColumnName)); } } } } }
read morePosts
Brahma Command Line Parser
/* Simple commandline argument parser written by Ananth B. http://www.ananthonline.net */ static class CommandLine { public class Switch // Class that encapsulates switch data. { public Switch(string name, Action<IEnumerable<string>> handler, string shortForm) { Name = name; Handler = handler; ShortForm = shortForm; }
public Switch(string name, Action<IEnumerable<string>> handler) { Name = name; Handler = handler; ShortForm = null; } public string Name { get; private set; } public string ShortForm { get; private set; } public Action<IEnumerable<string>> Handler { get; private set; } public int InvokeHandler(string[] values) { Handler(values); return 1; } } /* The regex that extracts names and comma-separated values for switches in the form (<switch>[="value 1",value2,.
read morePosts
Linq to GPU (Brahma)
// Create a data-parallel array and fill it with data var data = new DataParallelArray<float>(computationProvider, new[] { 0f, 1f, 2f, 3f, 4f, 5f, 6f }); // Compile the query CompiledQuery query = computationProvider.Compile<DataParallelArray<float>> ( d => from value in d select value * 2f ); // Run the query on this data IQueryable result = computationProvider.Run(query, data); // Print out the results foreach (float value in result) Console.WriteLine(value); // Get rid of all the stuff we created computationProvider.
read morePosts
使用Extension Method計算漢字筆畫
public static int GetStrokesNumber(this char c) { String hex = BitConverter.ToString(Encoding.GetEncoding("Big5").GetBytes(new char[] { c })).Replace("-", string.Empty); for (int i = 0; i < _strokesNumberData.Length; ++i) { for (int j = 0; j < _strokesNumberData[i].Length; j += 2) { if (hex.CompareTo(_strokesNumberData[i][j]) >= 0 && hex.CompareTo(_strokesNumberData[i][j + 1]) <= 0) return i+1; } } return 0; } }</pre></div> Module CharExtension
Private _strokesNumberData As String()() = { _ New String() {"A440", "A441"}, _ New String() {"A442", "A453", "C940", "C944"}, _ New String() {"A454", "A47E", "C945", "C94C"}, _ New String() {"A4A1", "A4FD", "C94D", "C95C"}, _ New String() {"A4FE", "A5DF", "C95D", "C9AA"}, _ New String() {"A5E0", "A6E9", "C9AB", "C959"}, _ New String() {"A6EA", "A8C2", "CA5A", "CBB0"}, _ New String() {"A8C3", "AB44", "CBB1", "CDDC"}, _ New String() {"AB45", "ADBB", "CDDD", "D0C7", "F9DA", "F9DA"}, _ New String() {"ADBC", "B0AD", "D0C8", "D44A"}, _ New String() {"B0AE", "B3C2", "D44B", "D850"}, _ New String() {"B3C3", "B6C3", "D851", "DCB0", "F9DB", "F9DB"}, _ New String() {"B6C4", "B9AB", "DCB1", "E0EF", "F9D6", "F9D8"}, _ New String() {"B9AC", "BBF4", "E0F0", "E4E5"}, _ New String() {"BBF5", "BEA6", "E4E6", "E8F3", "F9DC", "F9DC"}, _ New String() {"BEA7", "C074", "E8F4", "ECB8", "F9D9", "F9D9"}, _ New String() {"C075", "C24E", "ECB9", "EFB6"}, _ New String() {"C24F", "C35E", "EFB7", "F1EA"}, _ New String() {"C35F", "C454", "F1EB", "F3FC"}, _ New String() {"C455", "C4D6", "F3FD", "F5BF"}, _ New String() {"C3D7", "C56A", "F5C0", "F6D5"}, _ New String() {"C56B", "C5C7", "F6D6", "F7CF"}, _ New String() {"C5C8", "C5C7", "F6D6", "F7CF"}, _ New String() {"C5F1", "C654", "F8A5", "F8ED"}, _ New String() {"C655", "C664", "F8E9", "F96A"}, _ New String() {"C665", "C66B", "F96B", "F9A1"}, _ New String() {"C66C", "C675", "F9A2", "F9B9"}, _ New String() {"C676", "C67A", "F9BA", "F9C5"}, _ New String() {"C67B", "C67E", "F9C6", "F9DC"}} <Extension()> _ Public Function GetStrokesNumber(ByVal c As Char) As Integer Dim hex As [String] = BitConverter.
read morePosts
.NET 4.0 New Feature - Generic Lazy class
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Lazy<Boolean> lazy = new Lazy<Boolean>(() => { Console.WriteLine(“Initializing…”); System.Threading.Thread.Sleep(10000); Console.WriteLine(“Initialized…”); return true; });
Console.WriteLine("IsValueCreated = {0}", lazy.IsValueCreated); Stopwatch sw = Stopwatch.StartNew(); Console.WriteLine("result = {0}", lazy.Value); //Console.WriteLine("result = {0}", lazy.ToString()); Console.WriteLine("Elapsed Time = {0} ms", sw.ElapsedMilliseconds); Console.WriteLine(new string('=', 50)); Console.WriteLine("IsValueCreated = {0}", lazy.IsValueCreated); sw.Restart(); Console.WriteLine("result = {0}", lazy.Value); //Console.WriteLine("result = {0}", lazy.ToString()); Console.WriteLine("Elapsed Time = {0} ms", sw.ElapsedMilliseconds); } } }
read morePosts
[C#]使用WM_SYSCOMMAND訊息控制螢幕模式切換
const int SC_MONITORPOWER = 0xF170; const int WM_SYSCOMMAND = 0x0112; ... SendMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER , -1); SendMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER , 1); SendMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER , 2); </pre></div> <p> </p> <p>這邊為方便後續使用,將程式整理成類別,有需要的自行取用。</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c3cd5a55-1615-41d4-9ccd-45dd058acb8b" class="wlWriterSmartContent"><pre name="code" class="c#"> public static class MonitorControler { [DllImport(“user32.dll”)] private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);
const int SC_MONITORPOWER = 0xF170; const int WM_SYSCOMMAND = 0x0112; //const int SC_SCREENSAVE = 0xF140; public enum MonitorMode : int { MONITOR_ON = -1, MONITOR_STANBY = 1, MONITOR_OFF } public static void ChangeMonitorState(MonitorMode mode) { SendMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER, (int)mode); } public static void MonitorOff() { ChangeMonitorState(MonitorMode.
read morePosts
.NET 4.0 New Feature - 程式碼合約(Code Contracts) (三) Contract.Assert Contract.Assume
public static int CalculateSomeValues() { Contract.Ensures(Contract.Result<int>() > 0); return 1; }</pre></div> <p> </p> <p>由於在CalculateSomeValues函式內,已經用後置條件去驗證了函式回傳值,因此在Main裡面的Contract.Assert就可以確定x變數一定會滿足驗證條件,故整個程式在做靜態分析時是會通過驗證的。</p> <p> </p> <p>而若今天我們的函式並未用後置條件去確保有正確的函式回傳值的話,這樣的程式在Contract.Assert那段就會被檢查出有問題。因為回傳值不確定,這個Assert在靜態分析中就無法被驗證,也就無法確定x變數一定會大於零。 </p> <p><img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="image" width="398" height="244" src="\images\posts\17802\image_thumb_2.png" /></a> </p> <p><a href="http://files.dotblogs.com.tw/larrynung/1009/.NET4.0NewFeatureCodeContracts_B520/image_4.png"><img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="image" width="447" height="129" src="\images\posts\17802\image_thumb_1.png" /></a></p> <p> </p> <p>這時若仍不想為函式加入後置方法,讓整個驗證更為嚴謹的話,可以使用Contract.Assume來做驗證的動作。</p> <p><a href="http://files.dotblogs.com.tw/larrynung/1009/.NET4.0NewFeatureCodeContracts_B520/image_8.png"><img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="image" width="404" height="247" src="\images\posts\17802\image_thumb_3.png" /></a></p> <p><a href="http://files.
read morePosts
.NET 4.0 New Feature - 程式碼合約(Code Contracts) (二) 三大合約
[ContractInvariantMethod]
void ObjectInvariant()
{
Contract.Invariant(MyProperty >= 0); }
public int MyProperty { get; set; }
[ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(MyProperty >= 0); } 這邊我們來反組譯了解一下其運作原理,反組譯後可發現Code Contract偷偷的幫我們在裡面造了兩個私有欄位<MyProperty>k_backingField與$evaluatingInvariant$。 <img alt="" src="\images\posts\17516
read morePosts
[C#]使用Win32 API為編輯框與下拉方塊加上提示字串
const int EM_SETCUEBANNER = 0x1501; private string _cueText; [Localizable(true)] public string CueText { get { if (_cueText == null) return string.Empty; return _cueText; } set { _cueText = value; updateCue(); } } private void updateCue() { SendMessage(this.Handle, EM_SETCUEBANNER, 0, CueText); } }</pre></div>
read morePosts
[Linq]Linq程式逐步執行與偵錯
foreach (var item in linq) { Console.WriteLine(item); } }</pre></div> For Each item In linq Console.WriteLine(item) Next End Sub</pre>
read morePosts
[Extension Method]使用擴充方法來做二維陣列排序
T[] tempArray = new T[count]; for (int idx = 0; idx < count; ++idx) { tempArray[idx] = array[idx, d2Idx]; } Array.Sort(tempArray); for (int idx = 0; idx < count; ++idx) { T tempValue = tempArray[idx]; for (int idx2 = idx+1; idx2 < count; ++idx2) { if (array[idx2, d2Idx].Equals(tempValue)) { array.Swap(idx, d2Idx, idx2, d2Idx); int d2Idx2 = (d2Idx == 0) ? 1 : 0; array.Swap(idx, d2Idx2, idx2, d2Idx2); } } } } public static void Swap<T>(this T[,] array, int idx1, int idx2, int targetIdx1, int targetIdx2) { T temp; temp = array[targetIdx1, targetIdx2]; array[targetIdx1, targetIdx2] = array[idx1, idx2]; array[idx1, idx2] = temp; } 使用上呼叫Sort方法,並傳入要排序依據的索引即可。
read morePosts
[C#]用Stopwatch計算累計耗費時間的注意事項
for (int i = 1; i <= count; i++) { sw.Reset(); sw.Start(); string guid = Guid.NewGuid().ToString(); sw.Stop(); total += sw.ElapsedMilliseconds; } Console.WriteLine(total); sw.Reset(); for (int i = 1; i <= count; i++) { sw.Start(); string guid = Guid.NewGuid().ToString(); sw.Stop(); } Console.WriteLine(sw.ElapsedMilliseconds); }</pre></div> for (int i = 1; i <= count; i++) { sw.Reset(); sw.Start(); System.Threading.Thread.Sleep(10); sw.Stop(); total += sw.ElapsedMilliseconds; } Console.WriteLine(total); sw.Reset(); for (int i = 1; i <= count; i++) { sw.
read morePosts
[C#][VB.NET]FullScreen the winform
static class FullScreenExtension { #region Struct struct FullScreenData { public FormBorderStyle FormBorderStyle { get; set; } public FormWindowState WindowState { get; set; }
public FullScreenData(FormBorderStyle formBorderStyle, FormWindowState windowState):this() { this.FormBorderStyle = formBorderStyle; this.WindowState = windowState; } } #endregion #region Var private static Dictionary<Form, FullScreenData> _fullScreenDataPool; #endregion #region Private Property private static Dictionary<Form, FullScreenData> m_FullScreenDataPool { get { if (_fullScreenDataPool == null) _fullScreenDataPool = new Dictionary<Form, FullScreenData>(); return _fullScreenDataPool; } } #endregion #region Public Method public static void FullScreen(this Form frm) { if (m_FullScreenDataPool.
read morePosts
[Performance][C#]絕對值的取得
namespace WindowsFormsApplication35 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
static int ABS1(int value) { return value < 0 ? -value : value; } static int ABS2(int value) { return Math.Abs(value); } private void button1_Click(object sender, EventArgs e) { int count = (int)numericUpDown1.Value; int value = -1; textBox1.AppendText("Count: " + count.ToString() + Environment.NewLine); Stopwatch sw = Stopwatch.StartNew(); for (int idx = 0; idx < count; ++idx) ABS1(value); sw.
read morePosts
[Performance][C#]String.Empty V.S ldquo;rdquo;
Console.Clear(); int count = 1000000000; for (int idx = 0; idx < 3; ++idx) { EmptyString1(count); EmptyString2(count); EmptyString3(count); Console.WriteLine(); } } private static void EmptyString1(int count) { String test; Stopwatch sw = Stopwatch.StartNew(); for (int idx = 0; idx < count; ++idx) { test = ""; } sw.Stop(); Console.WriteLine("EmptyString1: " + sw.ElapsedMilliseconds.ToString()); } private static void EmptyString2(int count) { String test; Stopwatch sw = Stopwatch.StartNew(); for (int idx = 0; idx < count; ++idx) { test = string.
read morePosts
[Performance][C#]同時判斷多個字串是否為數值型態
sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric2_1(values); } sw.Stop(); Console.WriteLine("Method2-1: " + sw.ElapsedMilliseconds + " ms"); sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric2_2(values); } sw.Stop(); Console.WriteLine("Method2-2: " + sw.ElapsedMilliseconds + " ms"); sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric3(values); } sw.Stop(); Console.WriteLine("Method3: " + sw.ElapsedMilliseconds + " ms"); sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric4(values); } sw.
read morePosts
[C#]透過API移除表單的控制功能表方塊中的功能表項目
const Int32 MF_BYPOSITION = 1024;//&H400 public enum SystemMenuItemType { Restore, Move, Size, Min, Max, Seperator, Close } public static void RemoveSystemMenuItem(Form form, SystemMenuItemType menuItem) { RemoveMenu(GetSystemMenu(form.Handle.ToInt32(), 0),(int)menuItem, MF_BYPOSITION); } public static void RemoveRestoreSystemMenuItem(Form form) { RemoveSystemMenuItem(form, SystemMenuItemType.Restore); } public static void RemoveMoveSystemMenuItem(Form form) { RemoveSystemMenuItem(form, SystemMenuItemType.Move); } public static void RemoveSizeSystemMenuItem(Form form) { RemoveSystemMenuItem(form, SystemMenuItemType.Size); } public static void RemoveMinSystemMenuItem(Form form) { RemoveSystemMenuItem(form, SystemMenuItemType.Min); } public static void RemoveMaxSystemMenuItem(Form form) { RemoveSystemMenuItem(form, SystemMenuItemType.
read morePosts
[C#]Effective C# 條款十一: 優先採用foreach迴圈
foreach (int i in foo) Console.WriteLine(i.ToString()); for (int index = 0; index < len; index++) Console.WriteLine(foo[index].ToString()); for (int index = 0; index < foo.Length; index++) Console.WriteLine(foo[index].ToString()); }</pre>
read morePosts
[C#]Effective C# 條款九: 理解幾個相等判斷之間的關係
//兩個有一個為空=>return false; if ((left == null) || (right == null)) return false; //透過left.Equals判斷是否相等 return left.Equals(right); }
//檢查是否與自身是相同物件 if (object.ReferenceEquals(this, obj)) return true; //檢查是否型態相等 if (this.GetType() != obj.GetType()) return false; //比較內容是否相等 return CompareMembers(this, obj); }</pre> //檢查是否與自身是相同物件 if (object.ReferenceEquals(this, obj)) return true; //檢查是否型態相等 if (this.GetType() != obj.GetType()) return false; //叫用基底類別的Equals方法 if(!base.Equals(obj)) return false; //比較內容是否相等 return CompareMembers(this, obj); }</pre>
read morePosts
[C#]Effective C# 條款八: 確保0為值類型的有效狀態
struct Person { public String Name; public Sex Sex; public Person(String name, Sex sex) { this.Name = name; this.Sex = sex; } }</pre> struct Person { public String Name; public Sex Sex; public Person(String name, Sex sex) { this.Name = name; this.Sex = sex; } }</pre>
read morePosts
[C#]Effective C# 條款七: 將值類型盡可能實現為具有常量性與原子性的類型
public string Line { get { return _line; } set { _line = value; } } public string City { get { return _city; } set { _city = value; } } public string State { get { return _state; } set { ValidateState(value); _state = value; } } public int ZipCode { get { return _zipCode; } set { ValidateZip(value); _zipCode = value; } } ... }</pre> public string Line { get { return _line; } } public string City { get { return _city; } } public string State { get { return _state; } } public int ZipCode { get { return _zipCode; } } public Address(string line,string city,string state,int zipCode) { _line = line; _city = city; _state = state; _zipCode = zipCode; ValidateState(state); ValidateZip(zipCode); } }</pre> public PhoneList(Phone[] ph) { _phones = ph; } .
read morePosts
[C#]Effective C# 條款六: 明辨值類型與參考類型的使用場合
MyData data= GetData();
MyData data= GetData();
IMyInterface data= GetData();
C var = new C();
public void Pay(BankAccount b) { b.Balance -= _salary; } }
public void Pay(BankAccount b) { b.Balance -= _salary; } }
read morePosts
[C#]Effective C# 條款四: 使用ConditionalAttribute替代#if條件編譯
[Conditional(“B”)] static void DoIfAandB() { // Code to execute when both A and B are defined… } static void HelloWord() { Console.WriteLine("Hello~"); } static void SayHello1() { #if DEBUG HelloWord(); #endif }
[System.Diagnostics .Conditional ("DEBUG")] static void SayHello2() { HelloWord(); }</pre> private static void Main(string[] args) { HelloWord(); SayHello1(); //SayHello2被編譯器拿掉 } private static void SayHello1() { //內容被編譯器拿掉 } [Conditional("DEBUG")] private static void SayHello2() { HelloWord(); } }
read morePosts
[C#]使用DebuggerDisplayAttribute自訂除錯監看訊息
[System.Diagnostics.DebuggerDisplay("Name = {Name}, Year = {Year}")] class Person { [System.Diagnostics.DebuggerDisplay("Name = {Name}")] string Name { get; set; } int Year { get; set; } public Person(string name, int year) { this.Name = name; this.Year = year; } }</pre></div>
read morePosts
[C#]使用GetSystemPowerStatus API查看目前電源使用狀態
<td valign="top" width="499">表示目前充電狀態。 <br />1為High(66%以上電力)、2為Low(33%以上電力)、4為Critical(5%以下電力)、8為Charging、128為NoBattery、255為UnKnow</td> </tr> <tr> <td valign="top" width="200">BatteryFullLifeTime</td> <td valign="top" width="499">表示充滿電力可使用多久時間(-1為不詳)。</td> </tr> <tr> <td valign="top" width="200">BatteryLifePercent</td> <td valign="top" width="499">表示電力剩餘多少百分比,其正常值為0~100,255為電力不詳。</td> </tr> <tr> <td valign="top" width="200">BatteryLifeTime</td> <td valign="top" width="499">表示剩餘電力可使用多久時間(-1為不詳)。</td> </tr> <tr> <td valign="top" width="200">ACLineStatus</td> <td valign="top" width="499">表示電源狀態。 <br />0為offline、1為online、255為unknow。</td> </tr> namespace Battery { [Flags] public enum BatteryChargeStatus : byte { High = 1, Low = 2, Critical = 4, Charging = 8, NoSystemBattery = 128, Unknown = 255 }
read morePosts
[C#][VB.NET].NET 4.0 Barrier Class
Module Module1
Private sync As Barrier Sub Main(ByVal args() As String) sync = New Barrier(3) Dim charlie = New Thread(Sub() DriveToBoston("Charlie", TimeSpan.FromSeconds(1))) charlie.Start() Dim mac = New Thread(Sub() DriveToBoston("Mac", TimeSpan.FromSeconds(2))) mac.Start() Dim dennis = New Thread(Sub() DriveToBoston("Dennis", TimeSpan.FromSeconds(3))) dennis.Start() charlie.Join() mac.Join() dennis.Join() Console.ReadKey() End Sub Sub DriveToBoston(ByVal name As String, ByVal timeToGasStation As TimeSpan) Console.WriteLine("[{0}] Leaving House", name) ' Perform some work Thread.Sleep(timeToGasStation) Console.WriteLine("[{0}] Arrived at Gas Station", name) ' Need to sync here sync.
read morePosts
[C#]C# 4.0 動態繫結 (Dynamic Lookup)
namespace ConsoleApplication16 { class Program { static void Main(string[] args) { dynamic[] ds = new dynamic[2]; ds[0] = new System.Windows.Forms.TextBox(){Name=“TextBox”}; ds[1] = new Person() { Name = “Larry” }; foreach (dynamic d in ds) { Console.WriteLine(d.Name); } } } class Person { public string Name { get; set; } } } 由於不用把型態從Object轉回匿名型別,因此動態繫結也可以用在匿名型別上,真的方便許多,看來以後若要偷懶直接傳遞匿名型別也可以了(不建議也不鼓勵濫用)。 using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace ConsoleApplication19 { class Program { static void Main(string[] args) { dynamic d = new { Name = “Larry” }; Console.
read morePosts
[C#]利用FlowLayoutPanel控制項合併大量圖片
namespace WindowsFormsApplication5 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK ) { listBox1.Items.Clear(); listBox1.Items.AddRange(openFileDialog1.FileNames); } } private void button2_Click(object sender, EventArgs e) { flowLayoutPanel1.Controls.Clear(); foreach(string file in listBox1.Items){ flowLayoutPanel1.Controls.Add(new PictureBox() { Image = new Bitmap(file), SizeMode = PictureBoxSizeMode.AutoSize, Margin=new Padding(0)}); } } private void button3_Click(object sender, EventArgs e) { if (saveFileDialog1.ShowDialog() == DialogResult.OK) { Bitmap b = new Bitmap(flowLayoutPanel1.
read morePosts
[C#]C# 4.0 選擇性參數 (Optional Parameters)
Sub SayHello(Optional ByVal name As String = "無名氏") Console.WriteLine("Hello~My name is " & name) End Sub</pre> static void SayHello(String name = "無名氏") { Console.WriteLine("Hello~My name is " + name); }</pre> namespace SayHello { class Program { static void Main(string[] args) { SayHello(); SayHello(name:“Larry”); SayHello(“Larry”); } static void SayHello() { Console.WriteLine(“Hi~”); } static void SayHello(object name) { Console.WriteLine(“Hi~My name is” + name.ToString()); } static void SayHello(String name = “無名氏”) { Console.
read morePosts
[C#][VB.NET]擴充方法 (Extension Method)
public static class EnumExtension { public static string GetName(this Enum e) { return Enum.GetName(e.GetType(), e); } } class Program { static void Main(string[] args) { Console.WriteLine(Grade.APlus.GetName()); } }</pre></div> Enum Grade APlus A B C D End Enum
Module Module1 Sub Main() Console.WriteLine(Grade.APlus.GetName) End Sub End Module
Module EnumExtension <Extension()> _ Public Function GetName(ByVal e As [Enum]) As String Return [Enum].GetName(e.GetType, e) End Function End Module
class Program { static void Main(string[] args) { string str = null; Console.
read morePosts
[Performance][C#]StringBuilder與String.Join串接字串時的效能比較
namespace ConsoleApplication17 { class Program { static void Main(string[] args) { int testTimes = 10; int dataCount = 1000000; GoTest(dataCount, testTimes); }
static void GoTest(int dataCount,int testTimes) { //Let JIT compiler precompiler Test1(1); Test2(1); //Test performance Stopwatch sw; long[] elapsedTimes = new long[testTimes]; Console.WriteLine("String.Join..."); for (int i = 0; i < testTimes; i++) { sw = Stopwatch.StartNew(); Test1(dataCount); elapsedTimes[i] = sw.ElapsedMilliseconds; Console.WriteLine("Elapsed Time: " + elapsedTimes[i]); } Console.WriteLine("Average Elapsed Time: " + elapsedTimes.
read morePosts
[C#][VB.NET]彩色濾鏡
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]反轉圖片顏色
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]彩色圖片轉為黑白圖片
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]壓縮.NET程式的記憶體用量
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#]HashSet 集合型別
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]Isolated Storage 隔離儲存區
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[Control][C#]WebCamPictureBox Control
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[Performance][C#]List V.S SortedList
<pre><span class="kwrd">using</span> System.Collections.Generic;</pre> <pre class="alt"><span class="kwrd">using</span> System.ComponentModel;</pre> <pre><span class="kwrd">using</span> System.Data;</pre> <pre class="alt"><span class="kwrd">using</span> System.Drawing;</pre> <pre><span class="kwrd">using</span> System.Linq;</pre> <pre class="alt"><span class="kwrd">using</span> System.Text;</pre> <pre><span class="kwrd">using</span> System.Windows.Forms;</pre> <pre class="alt"><span class="kwrd">using</span> System.Collections;</pre> <pre><span class="kwrd">using</span> System.Diagnostics;</pre> <pre class="alt"> </pre> <pre><span class="kwrd">namespace</span> HashTableVSSortedList</pre> <pre class="alt">{</pre> <pre> <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> Form1 : Form</pre> <pre class="alt"> {</pre> <pre> <span class="kwrd">public</span> Form1()</pre> <pre class="alt"> {</pre> <pre> InitializeComponent();</pre> <pre class="alt"> }</pre> <pre> </pre> <pre class="alt"> <span class="kwrd">private</span> <span class="kwrd">void</span> button1_Click(<span class="kwrd">object</span> sender, EventArgs e)</pre> <pre> {</pre> <pre class="alt"> button1.
read morePosts
[.NET Concept][C#][VB.NET].NET兩個表單間的資料互通
Public Class Form2 … Public MainForm As Form1 … ‘Form2透過Form1傳進的物件參考控制Form1 MainForm.Value = Me.NumericUpDown1.Value … End Class
read morePosts
[C#][VB.NET]自定義.NET WindowForm表單介面(二)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]使用AxWindowsMediaPlayer撥放多媒體
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]使用AxMediaPlayer撥放多媒體
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[.NET Concept][C#][VB.NET]四捨六入五成雙
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]XML序列化私有欄位
#Region “Enum” Enum SexType Boy Girl End Enum #End Region
#Region “Var” Private _name As String Private _year As Integer Private _sex As SexType Private _friendNames As New List(Of String) #End Region
#Region “Property” Public Property Name() As String Get If String.IsNullOrEmpty(_name) Then Return String.Empty End If Return _name End Get Set(ByVal value As String) _name = value End Set End Property
Public Property Year() As Integer Get Return _year End Get Set(ByVal value As Integer) _year = value End Set End Property Public Property Sex() As SexType Get Return _sex End Get Set(ByVal value As SexType) _sex = value End Set End Property #End Region
read morePosts
[C#][VB.NET]自製桌面小玩意
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove If PictureBox1.Capture = True Then '如果滑鼠按著拖曳 '設定新的視窗位置 Me.Top = e.Y + nOldWndTop - nClickY Me.Left = e.X + nOldWndLeft - nClickX '更新紀錄的視窗位置 nOldWndLeft = Me.Left nOldWndTop = Me.Top End If End Sub</pre></div><p> </p><p>C#</p><p> </p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f0c57834-e54e-4456-896a-5ebc58634d32" class="wlWriterSmartContent"><pre class="c#" name="code"> private void PictureBox1_MouseDown(object sender, MouseEventArgs e)
read morePosts
[C#][VB.NET]自定義.NET WindowForm表單介面
Private Sub pnlTitleBar_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pnlTitleBar.MouseMove If pnlTitleBar.Capture = True Then '如果滑鼠按著拖曳 '設定新的視窗位置 Me.Top = e.Y + nOldWndTop - nClickY Me.Left = e.X + nOldWndLeft - nClickX '更新紀錄的視窗位置 nOldWndLeft = Me.Left nOldWndTop = Me.Top End If End Sub</pre></div><p> </p><p>C#</p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:0d2adec9-5189-493d-821d-1272f208c5e0" class="wlWriterSmartContent"><pre class="c#" name="code"> private void pnlTitleBar_MouseDown(object sender, MouseEventArgs e) { //紀錄滑鼠點選時的視窗位置與滑鼠點選位置 nOldWndLeft = this.
read morePosts
[C#][VB.NET]設定.NET透明表單
Abstract Introduction Form.Opacity屬性設定不透明度 Form.TransparencyKey屬性設定透明的顏色 Form.Opacity VS Form.TransparencyKey Conclusion Introduction 在.NET WinForm程式中,要設定透明表單有兩種方式。一種是用Form.Opacity屬性來設定表單的不透明度,一種則是用Form.TransparencyKey屬性來設定表單上視為透明的顏色。本篇將會對兩種方法做個簡單的介紹,並針對兩者做點小小的比較。
Form.Opacity屬性設定不透明度 以Form.Opacity屬性為例,該屬性值所設定的是0~1之間的雙精度浮點數(Double),用以表示表單的不透明度比例。如下圖所示,該值越小越透明、越大則越不透明。
完整範例如下:
VB.NET
C#
Form.TransparencyKey屬性設定透明的顏色 要用Form.TransparencyKey屬性來設定表單透明度,只須把該屬性設為欲透明的顏色,則當表單上存在著被設為透明色的顏色區塊時,該顏色區塊就會被視為是透明的。用該方法設定的透明效果跟用Form.Opacity的方法是不同的。該方法的透明是完全的透明(透明度100%),且若用滑鼠點選在表單中透明的區塊上,滑鼠的點選動作會穿透目前的表單點選到目前表單下方的視窗,而Form.Opacity的透明除非是設為完全透明,不然無法穿透目前的表單。
**P.S.**Form.Opacity = 0 雖然也可以完全穿透目前表單,但是表單上面的元件也會跟著透明。
Form.Opacity VS Form.TransparencyKey 可調整透明度比例 點選表單透明區塊可穿透表單 可設定表單一部份為透明區塊,只會影響跟設定相同顏色的區塊 點選表單不完全透明區塊(Form.Opacity != 0)不可穿透表單 透明度會影響整個表單上的元件 不可調整透明度比例 Conclusion 本篇介紹了WinForm中改變表單透明度的兩種方法。雖然兩種方法都可以達到透明表單的效果,但在實際的應用上,我個人覺得用Form.TransparencyKey來設定表單透明度較為實用。雖此方法無法調整透明程度,但是其所具備的穿透透明區塊與可透明表單中部分區塊的特性,大幅增加了應用上的彈性。
read morePosts
[C#][VB.NET].NET捷徑(ShortCut)控制
Function GetLnkWorkingDirectory(ByVal shortCutFile As String) As String Return GetLnkObj(shortCutFile).WorkingDirectory End Function
Function GetLnkPath(ByVal shortCutFile As String) As String Return GetLnkObj(shortCutFile).Path End Function C# private String GetLnkArguments(string shortCutFile) { return GetLnkObj(shortCutFile).Arguments; }
private String GetLnkWorkingDirectory(string shortCutFile) { return GetLnkObj(shortCutFile).WorkingDirectory; }
private String GetLnkPath(string shortCutFile) { return GetLnkObj(shortCutFile).Path; } 這邊須注意的是,使用此方法建立捷徑時,若捷徑檔不存在於指定位置,則須先建立個空的捷徑檔案,才可取得ShellLinkObject物件。VB.NET If Not My.Computer.FileSystem.FileExists(shortCutFile) Then File.Create(shortCutFile).Close() End If C# if (!My.Computer.FileSystem.FileExists(shortCutFile)) { File.Create(shortCutFile).Close(); } 取得ShellLinkObject物件後,捷徑的建立與寫入也就只是設定對應的屬性值後呼叫Save方法。VB.NET lnkObj = GetLnkObj(shortCutFile) With lnkObj .Arguments = arguments .
read moreTag: NSaga
Posts
NSaga - Getting started
使用 NSaga 來做 Saga pattern,需先透過 NuGet 安裝 NSaga 套件。
PM> Install-Package NSaga 接著要定義 Transaction 中的每一個動作,也就是 NSaga 中的 Message。
這邊要注意 NSaga 必須特別定義 Transaction 中的第一個 Message,定義的方式就是造一個專屬的 Message Class,並實作 IInitiatingSagaMessage 介面。
public class StartSagaMessage: IInitiatingSagaMessage { public Guid CorrelationId { get; set; } } IInitiatingSagaMessage 介面只有一個屬性 CorrelationId,用來接 Transaction Id 用,可用來識別這次觸發的 Transaction。除了介面定義的屬性外,若是需要額外的資料也可以自己附加。
第一個 Message 定義完其它後面的 Message 定義方式就一樣了,只要造專屬的 Message Class,並實作 ISagaMessage 介面即可。
public class SagaMessage: ISagaMessage { public Guid CorrelationId { get; set; } } 接著要定義 Transaction 要儲存的資訊,簡單造個 Model 類別即可。
read moreTag: Saga
Posts
NSaga - Getting started
使用 NSaga 來做 Saga pattern,需先透過 NuGet 安裝 NSaga 套件。
PM> Install-Package NSaga 接著要定義 Transaction 中的每一個動作,也就是 NSaga 中的 Message。
這邊要注意 NSaga 必須特別定義 Transaction 中的第一個 Message,定義的方式就是造一個專屬的 Message Class,並實作 IInitiatingSagaMessage 介面。
public class StartSagaMessage: IInitiatingSagaMessage { public Guid CorrelationId { get; set; } } IInitiatingSagaMessage 介面只有一個屬性 CorrelationId,用來接 Transaction Id 用,可用來識別這次觸發的 Transaction。除了介面定義的屬性外,若是需要額外的資料也可以自己附加。
第一個 Message 定義完其它後面的 Message 定義方式就一樣了,只要造專屬的 Message Class,並實作 ISagaMessage 介面即可。
public class SagaMessage: ISagaMessage { public Guid CorrelationId { get; set; } } 接著要定義 Transaction 要儲存的資訊,簡單造個 Model 類別即可。
read moreTag: CSharp 8.0
Posts
'C# 8.0 - Static local functions'
C# 8.0 開始支援靜態的 Local functions,只要直接在 Local functions 前面加掛 static 關鍵字即可。
using System; namespace StaticLocalFunctions { class Program { static void Main(string[] args) { static void SayHello(string name) => Console.WriteLine(string.Format("Hello~{0}", name)); //static void SayHello(string name) //{ // Console.WriteLine(string.Format("Hello~{0}", name)); //} SayHello("Larry"); } } } Static Local functions 在使用上跟一般的靜態方法一樣,需要使用的資料需從參數傳入,或是直接使用靜態的變數值,如果直使用 static Local functions 外的區域變數編譯器會報錯。
using System; namespace StaticLocalFunctions { class Program { static void Main(string[] args) { var name = "Larry"; static void SayHello() => Console.
read morePosts
'C# 8.0 - Indices and ranges'
C# 8.0 提供了 Index 與 Range。
要取得陣列指定位置的元素本來需要帶入 int 型態的索引位置到索引子,現在可改帶入 Index,Index 的數值表示寫法跟一般的整數數值類似,只是從尾部倒過來的索引可直接在前面加上 ^ 符號表示,像是最後一筆資料的索引位置可用 ^1 表示,比起以前自己要用陣列長度推算方便了許多。
... var lastData = data[^1]; ... 除了上面類似數值的表示方式外,也可以直接使用 Index 類別來撰寫。
... var firstData = data[Index.Start]; var secondData = data[Index.FromStart(1)]; //var secondData = data[new Index(1)]; var lastData = data[Index.FromEnd(1)]; //var secondData = data[new Index(1, true)]; ... 完整的範例會像下面這樣:
using System; using System.Linq; namespace Indices { class Program { static void Main(string[] args) { var data = Enumerable.Range(1, 5).ToArray(); //var firstData = data[0]; //var secondData = data[1]; //var lastData = data[^1]; var firstData = data[Index.
read morePosts
'C# 8.0 - Using declarations'
C# 8.0 以前使用 using 釋放物件,會在 using 後用小刮號包住要釋放的物件,然後在下面用大括號指示物件的生命週期範圍。
... using(var obj = new DisposableClass()) { ... } ... 程式寫起來會像下面這樣:
using System; namespace UsingDeclarations { class Program { static void Main(string[] args) { using (var obj = new DisposableClass()) { Console.WriteLine(obj.ToString()); } } } class DisposableClass : IDisposable { public void Dispose() { Console.WriteLine("Dispose..."); } } } C# 8.0 後支援 Using declarations,可以直接在變數宣告前面加掛 using 關鍵字,一樣可以達到物件釋放的效果。
... using var obj = new DisposableClass(); ... 程式寫起來會像下面這樣:
read morePosts
'C# 8.0 - Target-typed new-expressions'
C# 8.0 的 Target-typed new-expressions 能讓開發人員在使用 new 關鍵字建立物件實體時省略帶入型別,編譯器編譯時會依照 Context 幫我們帶入。
以簡單的例子來說,假設已經宣告了變數 p 型別為 Point,那在用 new 關鍵字建立實體時就可以省略帶入 Point。
... Point p = new (1, 2); 反組譯看可以看到編譯器會幫我們在 new 關鍵字後面帶入正確的型別。
複雜一點的情境像是陣列元素的宣告也是支援。
... Point[] ps = { new (1, 2), new (2, 2) };
read moreTag: Azure
Posts
Azure - Create a function app from the Azure portal
使用 Azure portal 建立函數應用程式,要先選取建立資源。
在計算資源這邊找到函數應用程式。
輸入資源的名稱、資源群組、作業系統、主機位置、儲存體等資訊後按下建立按鈕。
建立完成後,所建立的函數應用程式可在資源群組中查閱。
Link Create a function app from the Azure portal
read morePosts
Azure - Create a Linux VM with Azure Cloud Shell
要使用 Azure Cloud Shell 建立 Linux VM,可以使用 az vm create 命令,用 –name 指定 VM 的名稱、–resource-group 指定資源群組 (Resource groups)、–image 指定 VM 的映像 (e.x. UbuntuLTS)、–location 指定放置的區域、–size 指定 VM 的大小 (處理器速度、記憶體大小…等)、–admin-username 指定 VM 的使用者名稱、–generate-ssh-keys 建立用以登入 VM 的 SSH key。
az vm create \ --name $vmName \ --resource-group $resourceGroup \ --image $image \ --location $location \ --size $size \ --admin-username $adminUser \ --generate-ssh-keys 當 VM 建立並啟動成功,可以用 az vm get-instance-view 命令查看。
az vm get-instance-view \ --name $vmName \ --resource-group $resourceGroup \ --output table Link 建立虛擬機器 | Microsoft Docs
read moreTag: Android
Posts
Photo Editor - Change photo size
要使用 Photo Editor 在 Android 上進行圖片大小的調整。
可先選取要處理的圖片,選取分享。
將圖片分享至 Photo Editor。
然後在 Photo Editor 下方找到變更尺寸按鈕。
透過下方的按鈕或是拖曳下方水平 bar 調整適當的尺寸,如果要輸入指定尺寸,可按下左下方畫有筆的按鈕輸入設定。
尺寸調整完按下右上方的勾勾按鈕確認圖片尺寸變更。
最後按下左上方的箭頭。
按下儲存。
將變更尺寸的圖片儲存起來。
read morePosts
Photo Editor - Clip photo
要使用 Photo Editor 在 Android 上進行圖片的裁切。
可先選取要處理的圖片,選取分享。
將圖片分享至 Photo Editor。
然後在 Photo Editor 下方找到裁切按鈕。
按下裁切按鈕後框出裁切後要留下來的部份,按下右上方的勾勾按鈕確認裁切。
圖片會被裁切成只剩下剛所框出的部份。
最後按下左上方的箭頭,儲存裁切的結果即可。
read morePosts
Android - Disable Bluetooth HCI snoop log
如果 Android 手機空間莫名大量變少,可確認一下手機內是否有 btsnoop_hci.log 這個檔案。
如果確實手機空間是被該檔佔用,我們可以開啟手機的設定。
進到開發人員選項。
將 “啟用藍芽 HCI 窺探紀錄” 選項關閉。
系統就不會再因為寫入該檔案而吃掉大量手機空間。
read moreTag: Photo Editor
Posts
Photo Editor - Change photo size
要使用 Photo Editor 在 Android 上進行圖片大小的調整。
可先選取要處理的圖片,選取分享。
將圖片分享至 Photo Editor。
然後在 Photo Editor 下方找到變更尺寸按鈕。
透過下方的按鈕或是拖曳下方水平 bar 調整適當的尺寸,如果要輸入指定尺寸,可按下左下方畫有筆的按鈕輸入設定。
尺寸調整完按下右上方的勾勾按鈕確認圖片尺寸變更。
最後按下左上方的箭頭。
按下儲存。
將變更尺寸的圖片儲存起來。
read morePosts
Photo Editor - Clip photo
要使用 Photo Editor 在 Android 上進行圖片的裁切。
可先選取要處理的圖片,選取分享。
將圖片分享至 Photo Editor。
然後在 Photo Editor 下方找到裁切按鈕。
按下裁切按鈕後框出裁切後要留下來的部份,按下右上方的勾勾按鈕確認裁切。
圖片會被裁切成只剩下剛所框出的部份。
最後按下左上方的箭頭,儲存裁切的結果即可。
read moreTag: Tmux
Posts
tmux - Window operation
要對 tmux window 做操作,需先進入 tmux session。
tmux 要建立新的 window,可按下熱鍵 Ctrl + b,再按下 c。
要切到上一個 window,可按下熱鍵 Ctrl + b,再按下 p。
切到下一個 window 可按下熱鍵 Ctrl + b,再按下 n。
要變更 window 名稱,可按下熱鍵 Ctrl + b,再按下 ,。
window 名稱即會變更成設定的名稱。
要列出 window 清單去選取切換 window,可按下熱鍵 Ctrl + b,再按下 w。
上下移動按下 Enter 選取即可切換至指定 window。
若知道 window 關鍵字想要列出符合的 window 清單去選取切換 window,可按下熱鍵 Ctrl + b,再按下 f,輸入關鍵字後按下 Enter。
可看到符合關鍵字的 window 列表,上下移動按下 Enter 選取即可切換至指定 window。
要刪除當前 window,可按下熱鍵 Ctrl + b,再按下 &。
read morePosts
tmux - Session operation
要起用一個新的 tmux session,可直接調用 tmux 命令。
tmux tmux session 建立後會自動 attach。
可調用命令查閱 session。
tmux ls 要 detach session 可按下熱鍵 Ctrl + b,再按下 d,即可跳離 session。
再次調用命令建立新的 session。
可以從左下方中刮弧內的數值查驗當前的 session 編號,很明顯的這不是一開始建立的 session。
查驗 session,可看到確實是建立了新的 session。
tmux ls 如果在 detach session 的狀態要 attach session,可調用命令。
tmux attach -t <ID> 可 attach 回指定的 session。
如果本來就在 attach 的狀態,可按下熱鍵 Ctrl + b,再按下 s,透過方向鍵選取 session 切換。
要關閉指定 session,不是當前 session 的話,可像下面輸入命令,指定 session 的 ID 去做關閉。
tmux kill-session -t <ID> 實際在使用上可能會起多個 session 同時處理不同的事,每個 session 視需要也可以有不同的畫面切割。
read morePosts
tmux - Pane operation
tmux 的 Pane 可用來將一個 Terminal 視窗切成多個區塊。
使用前先進入 tmux 的 session。
tmux 要進行水平切割可按熱鍵 Ctrl + b,再按下 %。
要進行垂直切割可按熱鍵 Ctrl + b,再按下 “。
要在不同的 Pane 切換,可按下熱鍵 Ctrl + b,再按下對應的方向鍵。
要將當前 Pane 關閉,可輸入 exit 命令,或是按下熱鍵 Ctrl + b,再按下 x。
如果 Layout 需要調整,可按下熱鍵 Ctrl + b,再按下空白鍵,連續幾次直到滿意 Layout 為止。
熟悉 Pane 的操作,我們可以依不同的使用情境做不同的切割,讓 Terminal 的使用上更方便。
像是一邊運行命令一邊查閱資源使用的狀況,或是一邊 ssh 登入遠端查問題一邊在本機打到遠端測試。
read morePosts
tmux - Getting started
tmux 在 Ubuntu 可透過 apt-get 安裝。
apt-get install tmux 安裝完可查閱版本確認安裝是否正常。
tmux -V 使用方式可帶入 –help 參數查詢。
tmux --help 若要較詳細的使用說明,可使用 man 查閱。
man tmux 在使用上需先調用命令進入 tmux。
tmux 進入 tmux 後即可對 panel/session/window 做些管控。
要離開 tmux 的話調用 exit 命令即可。
exit
read moreTag: Iedis
Posts
Iedis - Client list
在 Redis Servers Tool Window 內的連線設定上按下滑鼠右鍵,點選滑鼠右鍵快顯選單上的 Client List 選單選項。
可開啟 Client List 視窗,透過該視窗可查閱所有連到 Redis 的 Client。
也可以刪除指定的 Client 連線。
read morePosts
Iedis - Advanced console
在 Redis Servers Tool Window 內的連線設定上按下滑鼠右鍵,點選滑鼠右鍵快顯選單上的 Open Terminal 選單選項,或是透過上方的工具列,抑或者是熱鍵 ⌘ + ⇧ + F10。
即可開啟 Terminal 視窗,可在 Terminal 視窗撰寫並調用 Redis 命令。
Link Iedis: Advanced Console
read morePosts
Iedis - Slow log
在 Redis Servers Tool Window 的 Redis 連線上按下滑鼠右鍵,在滑鼠右鍵快顯選單中有個 Slow Log 選單選項,點選該選單選項。
可看到 Redis 執行比較慢的記錄,會有命令名稱、執行時間等。
Link Iedis: Config Monitor
read morePosts
Iedis - Key operations
透過 Redis Servers Tool Window 加完 Redis 連線後,在連線上連點即可連到對應的 Redis。
連線後可看到 Redis 內含的 Key,左上方的區塊可以做 Key 的過濾,上方的工具列可以做 DataBase 的切換、Key 的新增、TTL 的設定等。
如果要新增 Key,可直接透過點擊上方工具列的 + 按鈕。
設定 Key 的名稱及型態,按下 OK 按鈕繼續。
接著設定 Key 的值,按下存擋即可。
在左邊顯示 Key 的列表這邊,按下滑鼠右鍵,透過滑鼠右鍵快顯選單也可以做很多 Key 的操作,像是新增 Key、Key 更名、刪除 Key、設定 TTL 等。
Link Iedis: Key Operations
read morePosts
Iedis - Configure server
安裝完 Iedis 套件後,Rider 會多出 [View | Tool Windows | Redis Servers] 主選單選項,點選可帶出 Redis Servers Tool Window。
Redis Servers Tool Window 的 + 按鈕可用來新增 Redis 連線。
設定連線的名稱、連線的主機、連線阜、及密碼,按下 Test Connection 按鈕可進行連線的測試。
確認連線資料正確且連線測試無誤,可按下 OK 按鈕完成連線設定。
Redis Servers Tool Window 就會顯示加入的連線。
透過 Redis Servers Tool Window 還可以編輯、移除、展開、折疊連線等動作。
Link Iedis: Servers Window Iedis: Configure Server
read morePosts
Iedis - Install Rider plugin
要在 Rider 安裝 Iedis 套件,可開啟 Perferences 視窗。
切到 Plugins,搜尋套件,點選 Install 按鈕進行安裝。
重啟 IDE 後即可開始使用 Iedis。
read moreTag: BusyBox
Posts
BusyBox - cp command
cp 命令可用來做檔案的複製。
直接調用命令可查閱使用說明。
cp 要將單檔複製到指定位置,可直接在命令後帶入來源檔案位置與目的檔案位置調用。
cp [SourceFile] [TargetFile] 允許使用多組來源檔案,目的位置也可以使用目錄。
cp [SourceFile]... [TargetFolder] 可使用萬用字元過濾篩選來源檔案。
cp [SourceFileFilter] [TargetFolder] 來源位置也可以指定目錄,的來源目錄複製到目的目錄。
cp [SourceFolder] [TargetFolder]
read morePosts
BusyBox - ls command
ls 命令可用來查看系統中的檔案。
使用方式如下:
只是要顯示當前目錄下的檔案與目錄,可直接調用命令。
ls 帶入參數 -1,可指定輸出只有一欄。
ls -1 帶入參數 -a,可指定 . 開頭的檔案或目錄也要輸出。
ls -a 帶入參數 -l,可指定輸出比較詳細的資料,除了檔名外,還有檔案權限、檔案大小、建立時間等資訊。
ls -l 帶入參數 -p,可在輸出時加一個 “/” 在目錄的後面,幫助目錄與檔案的識別。
ls -p 帶入參數 -n,與 -l 參數效果類似,都是輸出詳細的資訊,只是 names 換成了 UUIDs 與 GIDS。
ls -n 帶入參數 -r,可將查詢內容反轉輸出。
ls -r 帶入參數 -R,可遞迴將目錄內的資料都輸出。
ls -R
read morePosts
BusyBox - mv command
mv 命令可以用來做檔案的搬移或更名。
可直接不帶參數調用命令查閱使用方式。
mv 要搬移檔案或是變更檔名,只要在調用命令時指定檔案的來源位置與目的位置。
mv [SourceFile] [TargetFile] 如果目的位置有檔案,預設會被覆蓋過去。
跟帶入 -f 參數一樣,檔案會直接覆蓋,不會有任何的提示。
mv -f [SourceFile] [TargetFile] 如果要在覆蓋前提示,可帶入參數 -i。
mv -i [SourceFile] [TargetFile] 若是不要做檔案的覆寫,可帶入參數 -n。
mv -n [SourceFile] [TargetFile] 要是要將檔案大小目錄內,目的位置可指定目錄位置。
mv [SourceFile] [TargetFolder] 要一次搬移多個檔案,來源位置也可以使用萬用字元的方式指定。
mv [SourceFileFilter] [TargetFolder]
read morePosts
BusyBox - rm command
rm 命令提供 Linux 系統檔案刪除的功能。
可直接不帶參數調用命令查閱使用方式。
rm 要移除指定檔案可以直接在命令後帶入檔案位置調用。
rm [File] 加帶參數 -i 讓刪除前再做一次確認。
rm -i [File] 刪除的位置可帶入多組,也可以使用萬用字元的方式模糊指定。
rm [Filter] 若是要刪除目錄,可加帶參數 -r。
rm -r [Folder]
read moreTag: Telegram
Posts
Telegram - Add stickers from message
如果看到別人在 Telegram 使用的 Sticker 不錯,自己也想要使用的話,可以直接點選別人送出的 Sticker。
點選後可看到 Stickers 的名稱以及內含的 Sticker,若是確定要用,可點選右下方的 ADD STICKERS 按鈕。
就可以使用該 Stickers 了。
read moreTag: ITerm2
Posts
iTerm2 - Install on Mac
要在 Mac 上安裝 iTerm2,可在官網下載 iTerm2 程式。
點選下載下來的程式。
點選 Move to Applications Folder 按鈕將 iTerm2 程式搬到應用程式目錄。
就可以在應用程式這邊看到 iTerm2 。
read moreTag: FastoRedis
Posts
FastoRedis - Open console
要透過 FastoRedis 以 Console 的方式跟 Redis 互動,我們可在 Redis 連線後在左側的樹狀節點上按下滑鼠右鍵,選取滑鼠右鍵快顯選單中的 Open console 選單選項。
輸入要調用的 Redis 命令後按下 Execute 按鈕運行命令。
命令調用結果即會呈現下方的 Output,Fasto Redis 提供不同的輸出格式可供切換。
若有重複調用的需求,可勾選 Advanced options 選項,然後設定重複次數,以及中間的間隔時間,再按下 Execute 按鈕運行即可。
若是命令常會調用,這邊也提供儲存與讀取的功能,可將常用命令存起來需要時再載入調用。
read morePosts
FastoRedis - View keys
要透過 FastoRedis 查找 Redis 的 Key,可在 Redis 連線後在左側的樹狀節點上面按下滑鼠右鍵,選取滑鼠右鍵快顯選單中的 View keys 選單選項。
在彈出的視窗中輸入要用來過濾 Key 的 Pattern,按下 Search 按鈕。
就可以查找 Redis 內符合過濾 Pattern 的 Key。
read morePosts
FastoRedis - Create key
要透過 FastoRedis 寫入資料到 Redis,可在 Redis 連線後在左側的樹狀節點中找到要寫入資料的 Database,在上面按下滑鼠右鍵,選取滑鼠右鍵快顯選單中的 Create key 選單選項。
在彈出的視窗中選取要寫入的資料型態、Key 的名稱、以及要寫入的值,設完後按下 OK 按鈕。
指定的資料就會寫入到 Database 中。
需要的話可透過點選左側的樹狀節點查看資料的內容。
read morePosts
FastoRedis - Connect to redis
要透過 FastoRedis 連線到 Redis,可點選 [File | Connect…] 主選單選項。
在 Connections 視窗中點選 + 按鈕。
在 Select connection… 視窗中確認 Database 為 Redis 後按下 OK 按鈕。
在 Connection Settings 視窗中設定連線名稱、IP、Port,按下 Test 按鈕進行連線測試。
若沒意外的話應該可以正常的連線到 Redis 服務。
按下 Save 按鈕將連線存擋。
Connections 視窗下面的連線清單這邊就會看到剛所加入的連線設定,點選連線設定。
即可連線到 Redis 服務。
read morePosts
FastoRedis - Install on MAC
FastoRedis 是一跨平台的 Redis GUI 管理工具,可在 FastoRedis 的下載頁面下載該軟體。
下載要安裝的作業系統版本。
筆者這邊下載的是 MAC 的版本,下載後點選下載下來的 dmg 檔,按下 Agree 按鈕同意 License。
將 FastoRedis 拖進 Application 目錄。
就可以透過啟動台將 FastoRedis 軟體啟動來使用。
Link FastoRedis - cross-platform client for Redis, supported main Redis database features like: modules, cluster, sentinel, ssh tunneling.
read moreTag: Grafana
Posts
Grafana - Get started with Grafana Cloud
要使用 Grafana Cloud,可在 Grafana 首頁按下 Get Grafana 按鈕。
點選 Get yout free Instance now 按鈕。
填入電子郵件後按下 Sign up Free 按鈕。
設定帳號、密碼,勾選同意服務條款,然後按下 Create my account 按鈕。
註冊的確認信會寄到信箱內。
開啟確認信點擊確認。
註冊確認完成。
接著設定 Grafana Cloud 的 Plan 與網址,設定完後按下 Start your Grafana Cloud Instance 按鈕。
按下 Continue 按鈕。
等待 Grafana Cloud 準備完成。
準備完成後火箭會升空,按下 Go to 按鈕。
Grafana Cloud 認證通過。
就可以開始使用 Grafana Cloud 了。
read morePosts
Grafana - Install Grafana on Ubuntu Debian
參照 Grafana Download page。
下載 Grafana 套件。
wget https://dl.grafana.com/oss/release/grafana_6.0.0_amd64.deb 安裝 Grafana 套件。
sudo dpkg -i grafana_6.0.0_amd64.deb 啟動 Grafana 服務。
sudo service grafana-server start 訪問 http://localhost:3000,輸入預設帳密 admin/admin。
更換預設帳號的密碼。
就可以開始使用 Grafana 了。
read moreTag: HAProxy
Posts
HAProxy - HAProxy Statistics
要啟動 HAProxy Statistics,需將 HAProxy 設定檔開啟進行設定。
sudo vim /etc/haproxy/haproxy.cfg 將設定檔加上如下設定:
# HAProxy Statistics listen stats bind :9000 mode http stats enable # Enable stats page stats hide-version # Hide HAProxy version stats realm Haproxy\ Statistics # Title text for popup window stats uri /haproxy_stats # Stats URI stats auth Username:Password # Authentication credentials 設定檔的 bind、uri 與 auth 資訊需視需要調動。
接著調用命令啟動 HAProxy。
sudo service haproxy start 訪問設定的 HAProxy Statistics 網址。
帶入設定檔 auth 那邊設定的帳密。
read morePosts
HAProxy - Install on ubuntu
要在 Ubuntu 使用 HAProxy,可直接透過 apt-get 進行 HAProxy 的安裝。
apt-get install haproxy 安裝完後可調用命令並帶入參數 -v 確認安裝無誤。
haproxy -v
read moreTag: Oracle
Posts
Oracle - Generating HTML Reports from SQL*Plus
要用 SQL*Plus 將查詢的資料輸出成 HTML 報表,可以準備像下面這樣的 SQL 檔。
開啟 MARKUP HTML 與 SPOOL。
SET MARKUP HTML ON SPOOL ON 然後指定 SPOOL 要輸出的檔案。
SPOOL <File> 接著撈出要產出的資料。
然後將 MARKUP HTML 與 SPOOL 關掉即可。
SET MARKUP HTML OFF SPOOL OFF 用 SQL*Plus 運行剛撰寫的 SQL 檔。
HTML 報表即會被輸出到指定的輸出檔案。
Link Generating HTML Reports from SQL*Plus
read morePosts
Oracle - v$version table
v$version 資料表主要存放著 Oracle 核心元件的版本資訊,要查閱版本資訊的話可直接查閱該表。
SELECT * FROM v$version; Link V$VERSION Oracle / PLSQL: Retrieve Oracle version information
read moreTag: Kobo EReader
Tag: LinkedIn
Posts
LinkedIn - Withdrawing an Invitation
當 LinkedIn 不小心按到邀請按鈕。
可以切到 My Network。
點選 Manage all。
切到 Sent 頁籤。
點選 Withdraw。
就可以將不小心送出的邀請收回。
Link Withdrawing an Invitation | LinkedIn Help
read morePosts
'Resumonk - Resume Builder, Cover Letter Templates, CV Maker'
Resumonk 能將 LinkedIn Profile 匯入套用模版變成漂亮的個人化履歷。
使用時需先按下首頁上方的 Create your resume 按鈕。
點選 Import from LinkedIn 按鈕。
將 LinkedIn Profile 匯出成 PDF 檔,然後點選 Browse PDF File 按鈕。
選取匯出的 LinkedIn Profile 檔。
點選 Upload & Process LinkedIn PDF 按鈕。
匯入完後若有需要也可直接在 Resumonk 上做些編輯。
切至 Preview & Download 頁籤,可選取喜歡的 Resume 範本。
也可調整文字的字型/間隔/顏色。
都選好後點選 Download 按鈕。
點選要下載的檔案格式即可取得產出的 Resume 檔。
Link Resumonk - Resume Builder, Cover Letter Templates, CV Maker | Resumonk
read morePosts
LinkedIn - Saving a Profile in a PDF Format
要將 LinkedIn profile 匯出成 PDF 檔,可以點選 LinkedIn 右上角的帳號圖示,點選 View profile 按鈕切換至 LinkedIn profile。
點選 More… 按鈕。
再點選 Save to PDF。
LinkedIn profile 即會被下載成 PDF 檔。
值得注意的是該功能目前只支援英文的 profile。
Link Saving a Profile in a PDF Format | LinkedIn Help
read morePosts
LinkedIn - Customize public profile url
LinkedIn 在剛申請完,會配給你一個預設的 Public Profile Url,這個 Public Profile Url 會長得像下面這樣。
http://linkedin.com/pub/johndoe/40/263/205 這樣的 Url 不僅不便於記憶,對於 SEO 來說也不是很好。一般來說我們會傾向將 Public Profile Url 帶上自己的 English Name,這樣在搜尋時會比較會被搜尋到。所以我們需要將 Public Profile Url 進行客製,第一步就是要先連到我們的 Public Profile (這邊因為筆者已經改過了,所以網址看起來不會像上面提的那樣)。
{% img /images/posts/CustomizeLinkedInProfileUrl/1.png %}
開啟的 Public Profile 頁面會像下面這樣。
{% img /images/posts/CustomizeLinkedInProfileUrl/2.png %}
將之向下捲動,在右側這邊會看到 Yor public profile URL 這個區塊,找到後點擊 Public Profile Url 後面的鉛筆圖示進行編輯。
{% img /images/posts/CustomizeLinkedInProfileUrl/3.png %}
將之改為我們期望的網址後按下 Save 按鈕即可。
{% img /images/posts/CustomizeLinkedInProfileUrl/4.png %}
Link Customizing Your Public Profile URL | LinkedIn Help Center
read moreTag: Consul
Posts
Consul - Install on Windows
要在 Windows 安裝 Consul,要先在 Download Consul - Consul by HashiCorp 這邊找到 Consul 檔案位置。
下載 Consul 檔案後解壓縮。
Consul 的安裝就完成了,可以簡單的輸入 Consul 命令做個測試。
Link Install Consul | Consul - HashiCorp Learn Download Consul - Consul by HashiCorp
read morePosts
Consul - KV Data
Consul 支援簡易的 Key-Value Store 功能。
可用 consul kv put 將資料存入 Key-Value Store。
consul kv put <Key> <Value> 用 consul kv get 將資料取出。
consul kv get <Key> 可加帶 -detailed 參數取出更為詳細的資料,像是 Flags、ModifyIndex…等。
consul kv get -detailed <Key> 如果要設置資料的 Flags,可在放入資料時加帶 -flags 參數指定 Flags。
consul kv put -flags=<Flags> <Key> <Value> 若要列出所有存放的資料,可用 consul kv get 加帶 -recurse 參數。
consul kv get -recurse 要刪除存放的特定資料,可使用 consul kv delete 帶入要刪除的 Key。
consul kv delete <Key> 要刪除存放的所有資料,可使用 consul kv delete 加帶 -recurse 參數。
read morePosts
Consul - Registering health checks
Consul health check 可透過 Consul config 設定,在 Consul config 加入 check definition。
像是可以定義用定時去 ping 服務的方式去檢查服務的健康狀態。
echo '{"check": {"name": "ping", "args": ["ping", "-c1", "google.com"], "interval": "30s"}}' > /etc/consul.d/ping.json 或是定義定時用 curl 檢查服務的健康狀態。
echo '{"service": {"name": "web", "tags": ["rails"], "port": 80, "check": {"args": ["curl", "localhost"], "interval": "10s"}}}' > /etc/consul.d/web.json 定義好後啟用 Consul Agent,並帶入 enable_script_checks 參數。
啟動後 Consul 會依設定定時去檢查服務的狀態,如果有檢測到服務異常,可在 Consul Agent 的訊息中看到警告訊息會標示服務目前是 Critical。
要抓出異常服務的話,可用 HTTP API 檢測狀態為 Critical 的服務。
curl http://<IP>:<Port>/v1/health/state/critical 或是用 DNS API 直接檢測服務也可以,異常的服務不會正常的給予回應。
read morePosts
Consul - Web UI
要啟動 Consul Web UI 可在調用 Consul 命令時帶入 -ui 參數,如果是用開發人員模式 (帶入-dev 參數),-ui 參數可忽略不帶。
consul agent -dev -ui 訪問 http://<Url>/ui,即可看到 Consul Web UI。
如果要使用舊的 Consul Web UI 畫面,可將 CONSUL_UI_LEGACY 環境變數設定為 true。
在次起動 Consul Agent,會看到 Consul Web UI 畫面變成舊版畫面。
如果運行環境比較複雜的(像是筆者在 Vagrant 的虛擬機內啟用 Consul Agent),在啟用 Consul Web UI 後可能會有訪問被拒的現象。
在 Consul Agent 起動時再加帶 -client 參數應該就可以了。
consul agent -dev -client=0.0.0.0 Link Web UI | Consul - HashiCorp Learn
read morePosts
Consul - Registering services
要使用 Consul 註冊服務,先準備一個目錄用來存放 Consul 的設定。
mkdir <ConfigDir> 在建立的設定檔目錄內放置 Consul 的設定檔,設定檔內會指定服務的名稱、Tag、與服務的 Port。
{"service": {"name": "<Name>", "tags": ["<Tag>"], "port": <Port>}} 設定檔準備好後,啟動 Consul agent,使用 -config-dir 參數指定設定檔目錄。
consul agent -dev -config-dir=<ConfigDir> 啟動後可用 DNS API 做個測試。
dig @<IP> -p <Port> <ServiceName>.service.consul 或是用 HTTP API 測試也可以。
curl http://<IP>/v1/catalog/service/<ServiceName> Link Registering Services | Consul - HashiCorp Learn
read morePosts
Consul - Consul cluster
要設定 Consul Cluster,我們可以在一台電腦上用 Consul 命令啟用 Server 模式的 Agent。
consul agent -server -bootstrap-expect=1 \ -data-dir=<DataDir> -node=<NodeName> -bind=<IP> \ -enable-script-checks=true -config-dir=<ConfigDir> 然後在另外一台電腦用 Consul 命令啟用 Client 模式的 Agent。
consul agent -data-dir=<DataDir> -node=<NodeName> \ -bind=<IP> -enable-script-checks=true -config-dir=<ConfigDir> 使用 Consul 的 join 命令將他們加到同一個 Cluster。
consul join <IP> 調用 Consul 的 members 命令可查驗 Cluster 的組成,確認 Cluster 是否設定成功。
consul members Link Consul Cluster | Consul - HashiCorp Learn
read morePosts
Consul - Run the Consul agent
要簡單的將 Consul agent 跑起來玩玩,可以用 development 模式將 Consul agent 跑起來。
consul agent -dev 跑起來後可用 members 指令查閱節點。
consul members 或是用 HTTP API 查閱。
curl <IP>/v1/catalog/nodes 抑或是用 DNS 去查詢。
dig @<IP> -p <Port> <DNSEntries> 要停止 Consul agent 的話用熱鍵 Ctrl + C 即可。
Link Run the Consul Agent | Consul - HashiCorp Learn
read morePosts
Consul - Install on Ubuntu
要在 Ubuntu 安裝 Consul,要先在 Download Consul - Consul by HashiCorp 這邊找到 Consul 檔案位置。
下載 Consul 檔案。
wget <ConsulFileUrl> 將下載下來的 Consul 檔案進行解壓縮。
apt-get install unzip unzip <ConsulFile> 將檔案搬至 /usr/local/bin 下。
mv consul /usr/local/bin/consul Consul 的安裝就完成了,可以簡單的輸入 Consul 命令做個測試。
Link Install Consul | Consul - HashiCorp Learn Download Consul - Consul by HashiCorp
read moreTag: Ubuntu
Posts
Consul - Install on Ubuntu
要在 Ubuntu 安裝 Consul,要先在 Download Consul - Consul by HashiCorp 這邊找到 Consul 檔案位置。
下載 Consul 檔案。
wget <ConsulFileUrl> 將下載下來的 Consul 檔案進行解壓縮。
apt-get install unzip unzip <ConsulFile> 將檔案搬至 /usr/local/bin 下。
mv consul /usr/local/bin/consul Consul 的安裝就完成了,可以簡單的輸入 Consul 命令做個測試。
Link Install Consul | Consul - HashiCorp Learn Download Consul - Consul by HashiCorp
read moreTag: Sameroom
Posts
Sameroom - Connect Slack and Skype with Sameroom
要將 Slack 與 Skype 串接,可在 Slack 中加入 Sameroom App。
在 Samefoom 這邊選取連接 Skype。
點選 add the Skype BridgeBot。
按下 Add to Contacts 按鈕將 Sameroom 加入 Skype 通訊人。
在要跟 Sameroom 連接的聊天室加入 Sameroom,然後發送 -sameroom portal 命令。Sameroom 會傳送一個連結,點擊該連結。
在開啟的頁面設定要連接的 Slack 帳號以及 channel。
連接後我們在 Skype 發送的訊息就會被 Sameroom 轉送到 Slack 的指定 channel 上,在 Slack 中回應也會被 Sameroom 轉送到 Skype 上。
Link Sameroom
read moreTag: Skype
Posts
Sameroom - Connect Slack and Skype with Sameroom
要將 Slack 與 Skype 串接,可在 Slack 中加入 Sameroom App。
在 Samefoom 這邊選取連接 Skype。
點選 add the Skype BridgeBot。
按下 Add to Contacts 按鈕將 Sameroom 加入 Skype 通訊人。
在要跟 Sameroom 連接的聊天室加入 Sameroom,然後發送 -sameroom portal 命令。Sameroom 會傳送一個連結,點擊該連結。
在開啟的頁面設定要連接的 Slack 帳號以及 channel。
連接後我們在 Skype 發送的訊息就會被 Sameroom 轉送到 Slack 的指定 channel 上,在 Slack 中回應也會被 Sameroom 轉送到 Skype 上。
Link Sameroom
read morePosts
Skype - High CPU usage
最近在筆者工作的電腦上,一直以來都運作良好的 Skype 突然開始狂吃 CPU 。查閱了一下資料,這段時間發現很多人也都碰到這個問題,不過同樣的現象卻未在同事的電腦上出現,感覺是要滿足特定的條件才會發生。
像這邊筆者的電腦就吃了 25% 左右,筆者的電腦是四核心,相當於一整顆 CPU 被吃掉了。
{% img /images/posts/SkypeCPUHigh/1.png %}
當這樣的問題發生時,電腦上的預設瀏覽器多半是設定為 Chrome 。而解決這問題的方法也就是將預設瀏覽器設為 IE ,或是設為其它瀏覽器。
{% img /images/posts/SkypeCPUHigh/2.png %}
修改完預設瀏覽器後, 將 Skype 重開,沒意外的話就會看到 CPU 使用率恢復正常的狀態。
{% img /images/posts/SkypeCPUHigh/3.png %}
另外還有一種解法就是改安裝舊版的 Skype ,然後將自動更新功能關閉,避免它更新到有問題的版本。
目前造成該問題的原因還不明確,同樣的版本同樣的預設瀏覽器設定也不一定能重現,在官方尚未修正好前暫時也只能先這樣避開問題。
Link 【問題】Skype之CPU使用量迷思 Getting extremely high CPU usage? SKYPE 讓cpu使用率過高 [問題]開啟Skype電腦變LAG
read moreTag: Slack
Posts
Sameroom - Connect Slack and Skype with Sameroom
要將 Slack 與 Skype 串接,可在 Slack 中加入 Sameroom App。
在 Samefoom 這邊選取連接 Skype。
點選 add the Skype BridgeBot。
按下 Add to Contacts 按鈕將 Sameroom 加入 Skype 通訊人。
在要跟 Sameroom 連接的聊天室加入 Sameroom,然後發送 -sameroom portal 命令。Sameroom 會傳送一個連結,點擊該連結。
在開啟的頁面設定要連接的 Slack 帳號以及 channel。
連接後我們在 Skype 發送的訊息就會被 Sameroom 轉送到 Slack 的指定 channel 上,在 Slack 中回應也會被 Sameroom 轉送到 Skype 上。
Link Sameroom
read morePosts
'Simple Poll - Simple, native polls right within Slack'
要在 Slack 使用投票功能,可在 Slack 中加入 Simple Pool App。
App 加入時會需要授權,若可以接受 App 要求授予的權限的話,按下 Authorize 按鈕。
回到 Slack 會看到 App 詢問是否接受 Terms of Service and Private Policy,若允許的話則按下 Accept 按鈕。
接著使用 pool 命令發起投票即可。
/pool "<Question>" ["<Option1>" ... "<OptionN>"] Link Simple Poll | Slack App Directory Simple Poll for Slack
read morePosts
Chrome - Neutral Face Emoji Tools
Netural Face Emoji Tools 是 Chrome 的外掛套件,可讓 Slack 支援表情符號拖曳上傳。
外掛套件安裝後,Slack 上傳表情符號的頁面上方會多出一塊上傳區,將要上傳的表情符號拖曳至上傳區。
即完成表情符號的上傳。
Link Neutral Face Emoji Tools - Chrome Web Store
read morePosts
Slack - Add RSS feeds to Slack
要整合 Slack 與 RSS feeds,可在 Slack 中加入 RSS app。
按下 Add RSS Integration 按鈕。
設定要訂閱的 RSS feed 以及要發送到的 Channel。
訂閱的 RSS 資料就會送到 Slack 的指定 Channel 上。
Link Add RSS feeds to Slack – Slack Help Center RSS | Slack App Directory
read morePosts
Slack - OneDrive for Slack
要整合 Slack 與 OneDrive,可在 Slack 中加入 Microsoft OneDrive App。
按下 Authentcate your OneDrive account 按鈕進行 OneDrive 的授權。
OneDrive 授權完 Slack 與 OneDrive 的整合就完成了。
在 Slack 中貼入 OneDrive 檔案的位置,Slack 會詢問是否將之匯入,按下 Yes, allow 按鈕。
就會幫我們帶上對應的檔案。
帶入的檔案可被搜尋。
也可在 Files 這邊查閱。
同樣的檔案不會被放入多份。
檔案的 Detail 這邊可查閱被參照的點。
Link Microsoft OneDrive | Slack App Directory OneDrive for Slack – Slack Help Center
read morePosts
Slack - Integrate GitLab's Slack notifications service
要使用 Slack 接收 GitLab CI 的通知訊息,可在 Slack 中加入 Incoming WebHooks App。
選取 GitLab CI 通知訊息收到後要顯示在哪個 Channel。
複製 Webhook URL 後續在 GitLab 設定那邊使用。
設置 App 的名字、描述、圖示等,設置完後按下 Save Settings 按鈕存檔。
開啟 GitLab 的 Integrations 專案設定。
點選 Slack notifications。
設定何時要通知 Slack,以及要通知到哪個 Channel。
設定 Slack 的 Wabhook URL,按下 Test settings and save changes 按鈕測試並存檔。
Slack 就會收到 GitLab 傳來的通知訊息。
Link Slack Notifications Service | GitLab 【SLACK】串接 gitlab 事件到 slack – 進擊的 Tool’ s – Medium
read morePosts
Slack - Post Jenkins build notifications to a channel in Slack
要使用 Slack 接收 Jenkins CI 的建置通知訊息,可在 Slack 中加入 Jenkins CI App。
選取 Jenkins CI 建置通知訊息收到後要顯示在哪個 Channel,然後按下 Add Travis CI Integration 按鈕。
然後照著指示設定 Jenkins。
像是透過 Jenkins 的外掛程式管理為 Jenkins 加裝 Slack Notification 套件。
接著進入設定系統。
設定 Global Slack Notifier Settings 的 Base URL 與 Integration Token,按下儲存按鈕。
進到 Job 的組態設定。
在建置後動作加入 Slack Notifications。
設定要通知的事件。
當對應事件發生時 Slack 就會收到 Jenkins 的通知訊息。
Link Jenkins CI | Slack App Directory
read morePosts
Slack - Setting up Slack build notification in Travis CI
要使用 Slack 接收 Travis CI 的建置通知訊息,可在 Slack 中加入 Travis CI App。
選取 Travis CI 建置通知訊息收到後要顯示在哪個 Channel。
選好後按下 Add Travis CI Integration 按鈕。
接著照著教學設置 Travis CI 的設定檔。
再接著設置 Travis CI App 的名字、描述、圖示等,設置完後按下 Save Settings 按鈕存檔。
後續 Travis CI 建置時。Slack 就可以在指定的 Channel 收到對應的建置通知。
Link
read moreTag: PhantomJS
Posts
PhantomJS - Support ES6/ES2015 Features
PhantomJS 目前版本為 2.1 版,是不支援 ES6/ES2015 的,所以在某些情境下使用 PhantomJS 會被受限,像是網站使用到 let 之類的語法就會無法使用 PhantomJS。
PhantomJS 的預計在 2.5 版對 ES6/ES2015 進行支援,但從 用Python做爬蟲的各位,不要再用PhantomJS了- 知乎 這邊看起來 PhantomJS 已經停止了開發,一度在 Support ES6/ES2015 Features · Issue #14506 · ariya/phantomjs 這邊釋出的 2.5 版也被拿掉。
目前要用 PhantomJS 支援 ES6/ES2015 只能從 phantomjs25-beta - npm 這邊取得使用,除了透過 npm 套件安裝,若有需要也可以從這裡面提供的位置下載下來使用,位置是 https://bitbucket.org/takuhii/phantomjs25-beta/downloads/。
Link
read morePosts
PhantomJS - Remote debugging
使用 PhantomJS 時,若是光靠訊息不好除錯,可進一步使用 PhantomJS 的遠端除錯。
使用上只要調用 PhantomJS 時帶入參數 –remote-debugger-port 去指定連結埠。
phantomjs --remote-debugger-port=<Port> <Script> 但這樣啟動不會自動運行腳本,需在 Console 頁面調用 __run() 命令才會運行。
可以在調用 PhantomJS 時加帶 –remote-debugger-autorun 參數指定自動運行腳本。
phantomjs --remote-debugger-port=<Port> --remote-debugger-autorun=yes <Script> 在調用上會像下面這樣:
調用完用瀏覽器訪問 http://localhost:,點選連結…
就會看到類似開發人員工具的介面,可透過該介面對腳本進行進一步的除錯。
Link Troubleshooting | PhantomJS
read morePosts
PhantomJS - Examples
PhantomJS 下載下來解壓縮,裡面有個 examples 目錄,放置著 PhantomJS 提供的範例程式。
可透過 PhantomJS 將範例運行起來學習。
像是運行 hello.js 學習如何顯示訊息到主控台視窗。
phantomjs hello.js 運行 arguments.js 學習如何傳遞參數給 PhantomJS。
phantomjs arguments.js [arg1] [arg2] ... 運行 colorwheel.js 學習如何渲染並擷取畫面。
phantomjs colorwheel.js 還有很多的範例可以一一的運行起來測試、學習。
Link Examples | PhantomJS
read morePosts
PhantomJS - Hello world
要使用 PhantomJS ,可以直接調用 PhantomJS 進入交互模式,輸入要調用的 Script。
像是簡單的秀出 Hello world 字樣。
或是將要調用的 Script 寫入檔案。
用 PhantomJS 帶上檔名調用也可。
Link Quick Start | PhantomJS
read morePosts
PhantomJS - Install PhantomJS on Windows
要在 Windows 上使用 PhantomJS,可到 PhantomJS 官網的下載頁面。
下載 PhantomJS Windows 版本。
下載下來後解壓縮。
運行 bin 下的 PhantomJS.exe。
進到交互模式確認運作正常即可。
Link
read moreTag: Jenkins
Posts
Jenkins - Setup slave nodes
要設定 Jenkins 的 Slave 節點,先將 Jenkins 切到設定全域安全性。
設定 JNLP agent 要走的 TCP port。
存檔離開。
然後進到管理節點。
點選新增節點。
設定節點名稱後按下 OK 按鈕。
接著進行節點細部設定,像是執行程式數量這邊可以設定要讓該節點運同時運行多少的任務,遠端檔案系統根目錄這邊設定該節點電腦存放必要程式的位置,設定完成按下儲存按鈕。
節點清單中會出現剛所加入的節點,點選該節點。
這邊會提示節點電腦的設置。
這邊可以下載他所提供的 JNLP 檔。
將下載下來的 JNLP 檔放至 Slave 節點電腦運行,只要 JRE 有安裝就能直接用滑鼠連點開啟運行。
運行後剛在節點設定那邊所指定的位置就會存放運行必要的檔案。
Jenkins 節點清單這邊也會看到節點有正常的被連接。
除了用下載的 JNLP 檔案外,我們也可以用命令的方式啟動 Slave 節點服務。
如要將 Slave 節點服務註冊成 Windows 服務,可透過 JNLP 檔運行後開出的視窗,點選 [File | Install as a service] 主選單選項。
然後點選 OK 按鈕做 Windows 服務的註冊。
read morePosts
Slack - Post Jenkins build notifications to a channel in Slack
要使用 Slack 接收 Jenkins CI 的建置通知訊息,可在 Slack 中加入 Jenkins CI App。
選取 Jenkins CI 建置通知訊息收到後要顯示在哪個 Channel,然後按下 Add Travis CI Integration 按鈕。
然後照著指示設定 Jenkins。
像是透過 Jenkins 的外掛程式管理為 Jenkins 加裝 Slack Notification 套件。
接著進入設定系統。
設定 Global Slack Notifier Settings 的 Base URL 與 Integration Token,按下儲存按鈕。
進到 Job 的組態設定。
在建置後動作加入 Slack Notifications。
設定要通知的事件。
當對應事件發生時 Slack 就會收到 Jenkins 的通知訊息。
Link Jenkins CI | Slack App Directory
read morePosts
Jenkins - Categorized Jobs View Plugin
Jenkins 的 Categorized Jobs View 套件可用來分類整理 Jenkins job,允許指定多個不同的分類 Rule,View 內的 Job 會依照指定的 Rule 進行分類。
要使用 Categorized Job View,可先到外掛程式管理這邊搜尋 Categorized Jobs View 套件,下載並安裝。
安裝完建立一個新的 View。
選取剛安裝的 Categorized Jobs View。
勾選加入要在這 View 看到的 Job。
並設定 Grouping rule 。
回到剛新加的 View,即會看到 Job 依照 Grouping rule 進行了分類。
read morePosts
Jenkins - Quality Gates Plugin
Jenkins 安裝 SonarQube Plugin 後,雖然能用 Jenkins 分析程式並將分析結果送至 SonarQube,但是不論分析的結果是否有通過 SonarQube Quality Gate, Jenkins 的 job 都是會過。
若要讓 Jenkins job 依照 SonarQube Quality Gate 通過與否去決定建置的成功狀態,可以為 Jenkins 安裝 Quality Gate Plugin。
安裝完後進入 Jenkins 的 設定系統 頁面。
在 Quality Gates 這邊按下 ADD SONAR INSTANCE。
設定 SonarQube 的名稱與位置。
接著到 Job 組態這邊設定建置後動作,使用 Quality Gates 套件,帶入 Project Key。
這樣 Job 在運行時最後就會開始運行 Quality Gates 套件。
Job 的建置狀態就會依 Quality Gates 通過與否去決定。
read morePosts
Jenkins - SonarQube Plugin
如果要將 SonarQube 整合 Jenkins,讓 Jenkins 幫我們運行並將分析送到 SonarQube,可以使用 Jenkins 的 SonarQube Plugin。
先將 Jenkins 安裝 SonarQube Plugin。
安裝完後開啟 Jenkins 的組態設定,設定 SonarQube Server 的資訊。
接著開啟 Jenkins 的 Global Tool Configuration,讓 Jenkins 進行 SonarQube Scanner 的安裝。
安裝與設定都好了後,就可以在 job 的建置這邊使用 Execute SonarQube Scanner 做 SonarQube 分析的設定,語法可參閱 SonarQube Scanner 的設定方式(主要的設定就是 projectKey、projectName、與 sources)。
read morePosts
Jenkins - Installing Jenkins on Ubuntu
要在 Ubuntu 上安裝 Jenkins CI Server,首先要呼叫命令將金鑰下載並加入。
wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add - 接著呼叫命令將jenkins package的來源位置加入 apt-get 的 reposity 來源。
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list' 呼叫命令更新套件清單。
sudo apt-get update 最後再呼叫命令進行 Jenkins 的安裝。
sudo apt-get install jenkins 安裝完後呼叫命令將 Jenkins 服務啟動。
sudo /etc/init.d/jenkins start 服務啟動後開啟瀏覽器訪問 http://127.0.0.1:8080 位置,沒意外的話應該可以看到 Jenkins 運行的畫面。
read moreTag: Colaboratory
Posts
Colaboratory - Code snippets
Colaboratory 內建提供了一些程式碼片段可供使用,可點開左側選單切至代碼段頁籤使用。
或是透過點選 [插入 | 代碼段…] 主選單選項,甚至是用熱鍵開啟代碼段業僉也可以。
代碼段頁籤內含許多程式碼片段,點選程式碼片段下方會帶出程式碼片段的介紹,以及會插入的程式碼片段,選好程式碼片段後連點或是按下下方的插入連結插入程式碼片段。
read morePosts
Colaboratory - Show line numbers
要將 Colaboratory 程式碼區塊的行數開啟,可點選 [工具 | 偏好設定] 主選單選項。
在開啟的偏好設定視窗中勾選顯示行號,然後按下保存按鈕。
程式碼區塊前方就會顯示程式所在的行數。
read morePosts
Colaboratory - Enable hardware accelerator
要啟用 Colaboratory 的硬體加速功能,可點選 [代碼執行程序 | 更改運行時類型] 主選單選項。
在開啟的筆記本設置這邊可調整硬件加速器,可調整成 GPU 或是 TPU 加速,調整完後按下保存退出即可開始使用硬體加速功能。
read morePosts
Colaboratory - Getting started
Colaboratory 是免費的 Jupyter Notebook。
使用上可先新建記事本。
記事本中內建會有一個代碼區塊,在裡面輸入要運行的程式。
點選代碼區塊前方的執行按鈕。
程式運行的結果就會被顯示在代碼區塊下方。
最後一提,Colaboratory 的檔案會被存放在雲端硬碟。
Link Colaboratory Overview of Colaboratory Features - Colaboratory
read moreTag: Chrome
Posts
Chrome - Neutral Face Emoji Tools
Netural Face Emoji Tools 是 Chrome 的外掛套件,可讓 Slack 支援表情符號拖曳上傳。
外掛套件安裝後,Slack 上傳表情符號的頁面上方會多出一塊上傳區,將要上傳的表情符號拖曳至上傳區。
即完成表情符號的上傳。
Link Neutral Face Emoji Tools - Chrome Web Store
read moreTag: OneDrive
Posts
Slack - OneDrive for Slack
要整合 Slack 與 OneDrive,可在 Slack 中加入 Microsoft OneDrive App。
按下 Authentcate your OneDrive account 按鈕進行 OneDrive 的授權。
OneDrive 授權完 Slack 與 OneDrive 的整合就完成了。
在 Slack 中貼入 OneDrive 檔案的位置,Slack 會詢問是否將之匯入,按下 Yes, allow 按鈕。
就會幫我們帶上對應的檔案。
帶入的檔案可被搜尋。
也可在 Files 這邊查閱。
同樣的檔案不會被放入多份。
檔案的 Detail 這邊可查閱被參照的點。
Link Microsoft OneDrive | Slack App Directory OneDrive for Slack – Slack Help Center
read moreTag: Hubot
Posts
hubot-cron - Crontab like scheduling messages for Hubot
要讓 Hubot 支援排程發送訊息,可以安裝 hubot-cron 套件。
npm install hubot-cron --save 然後在 external-scripts.json 加入 hubot-cron。
接著將 Hubot 運行起來。
就可以在 Hubot 內加入排程訊息。
<Hubot> new job <Cron> <Msg> 有需要的話可以查閱加入的排程。
<Hubot> list jobs 也可以移除加入的排程。
<Hubot> rm job <ID> Link
read morePosts
Hubot - Interact with Jenkins CI server
要將 Hubot 整合 Jenkins 服務,可為 Hubot 加裝 hubot-jenkins 套件。
npm i hubot-jenkins 開啟 external-scripts.json,加上 hubot-jenkins 設定,存檔後關閉。
然後要透過 HUBOT_JENKINS_URL 環境變數設定 Jenkins 服務的位置。
set HUBOT_JENKINS_URL=<JenkinsUrl> 透過 HUBOT_JENKINS_AUTH 環境變數設定 Jenkins 服務的帳密 (使用 user:password 這樣的格式做設定)。
set HUBOT_JENKINS_AUTH=<Auth> 將 Hubot 啟動,可對 Hubot 調用命令查閱 Jenkins 服務上有的 Job。
<Hubot> jenkins list 可查詢指定的 Jenkins Job。
<Hubot> jenkins describe <Job> 可用 Jenkins Job Name 去建置特定的 Jenkins Job。
<Hubot> jenkins build <Job> 或是用編號建置特定的 Jenkins Job。
<Hubot> jenkins b <No> 也可以查詢特定 Jenkins Job 最後一次建置。
read morePosts
Hubot - Using with SSH
要將 Hubot 整合 SSH,可以安裝 hubot-sshbot。
npm install --save hubot-sshbot 安裝完後透過 HUBOT_SSH_HOST_KEY 環境變數指定 SSH key。
set HUBOT_SSH_HOST_KEY=<SSHKey> 透過 HUBOT_SSH_POST 環境變數指定要使用的 Port (預設是使用 3050)。
set HUBOT_SSH_PORT=<Port> 透過 HUBOT_SSH_HOST 環境變數指定 Host 的位置 (預設是 0.0.0.0)。
將 Hubot 運行起來並指定使用 SSH adapter。
hubot -a sshbot 接著透過 SSH 連進去。
就可以看到 SSH Hubot 的畫面。
可以透過 SSH Hubot 調用 Hubot 命令。
Link kylemacey/hubot-sshbot: An SSH based Hubot adapter to allow Hubot to be accessed from an SSH client.
read morePosts
Hubot - Using with slack
要將 Hubot 整合 Slack,首先要先在 Slack 上建立 Hubot App。
在 Slack 上點選加入 Apps。
選取安裝 Hubot App。
點選 Install 按鈕。
為加進 Slack 的 Hubot 取個名字,然後按下 Add Hubot Integration 按鈕。
複製 API Token 供後續使用,設定 Hubot 的名字、圖示…等資訓。
按下 Save Integration 按鈕。
Slack 的 Apps 那區就會顯示剛所建立的 Hubot App。
接著安裝 Hubot 要用到的 Slack adapter。
npm install hubot-slack --save 將剛剛複製的 API Token 設到環境變數。
set HUBOT_SLACK_TOKEN=<Token> 將 Hubot 運行起來並指定使用 Slack adapter。
hubot --adapter slack Hubot 與 Slack 就做完整合的動作了,可直接對 Slack 的 Hubot app 調用 Hubot 的命令。
read morePosts
Hubot - Create first script
Hubot scripting 支援 Coffee script 與 Javascript,script 放置於 scripts 目錄下, 內含範本 example.coffee 可以參閱。
在 scripts 目錄內建立 script 檔,像是筆者這邊就準備了一個簡單的 script,當監聽到 hello 就會回應 Hello world!。
module.exports = function(bot){ bot.respond(/hello/, function(res){ res.send('Hello world!'); }); } 將 Hubot 運行起來即可正常運作。
Link Scripting
read morePosts
Hubot - Getting started
Hubot 安裝環境內需先有 Node.js,然後透過 Node.js 套件管理工具安裝 Yeoman 與 Hubot 到全域。
npm install -g yo generator-hubot 透過 Yeoman 建立 Hubot 專案。
yo hubot Hubot 專案建立後會幫我們產生必要的檔案。
ls -a 一開始我們只是簡單的測試,不需要使用 Redis 與 Heroku,所以開啟 external-scripts.json 設定檔。
vim external-scripts.json 將 Redis 與 Heroku 設定移除後存檔。
另外可以移除 hubot-scripts.json 設定檔,避免後面操作因為空的設定看到警告訊息。
rm hubot-scripts.json 運行 Hubot。
bin/hubot 運行時可用參數 –Name 為 Hubot 命名。
bin/hubot --name <Name> Hubot 啟動後可用一下基本指令,像是 help 指令可查詢可使用的指令。
<Name> help ping 指令可測試回應。
<Name> ping time 指令可查詢時間。
<Name> time echo 指令可回送發送過去的訊息。
read moreTag: Travis
Posts
Slack - Setting up Slack build notification in Travis CI
要使用 Slack 接收 Travis CI 的建置通知訊息,可在 Slack 中加入 Travis CI App。
選取 Travis CI 建置通知訊息收到後要顯示在哪個 Channel。
選好後按下 Add Travis CI Integration 按鈕。
接著照著教學設置 Travis CI 的設定檔。
再接著設置 Travis CI App 的名字、描述、圖示等,設置完後按下 Save Settings 按鈕存檔。
後續 Travis CI 建置時。Slack 就可以在指定的 Channel 收到對應的建置通知。
Link
read morePosts
Travis CI - Restore package with Yarn
要讓 Travis CI 使用 Yarn 去還原套件,最簡單的方式就是將 yarn.lock 一併簽入版控,Travis CI 偵測到 yarn.lock 後就會改使用 Yarn 去做套件的還原。
當然我們也可以自己處理,只要在 travis.yml 內的 before_install 安裝 Yarn,然後在 install 這邊使用 yarn 指定使用 Yarn 來還原套件即可。
設定完 Travis CI 建置時就會改使用 Yarn 來還原套件了。
Link Using Yarn on Travis-CI
read morePosts
Hexo - Auto deploy with Travis CI
要使用 Travis CI 自動幫我們發佈 Hexo 部落格,先參閱筆者 Travis CI - Free Hosted Continuous Integration Platform for the Open Source Community | Level Up 這篇,登入 Travis CI ,給予授權,並為 Repository 啟用 Travis CI。
接著要準備一組 Personal access token 給 Travis CI。先將 GitHub 的 Settings 開啟。
切到 Personal access tokens 頁面。
按下 Generate new token 按鈕建立一組 token。
為這組 Token 設定一個名稱,並給予它 repo 的權限。
Token 產生後複製留存以供後續使用。
再來要準備 Travis CI 的設定檔 .travis.yml,放置於 Repository 的根目錄,內容大概像這樣 (branches 位置、使用者名稱、與電子郵件位置請自行替換):
language: node_js node_js: - '0.
read morePosts
Travis CI - Trigger build with service hook test
一般來說, Travis CI 在使用時會主動在程式碼 Push 到 Server 時自動做建置的動作,但難以避免的,有的時候我們還是會需要在特定時機點手動觸發建置。這時如果為此特意 Commit ,整個版控紀錄會變得很亂,所以要透過 GitHub 的 Test Service Hook 功能去觸發 Travis CI 建置。
使用前要先進入 Repository 的 Service Hooks 頁面。
這邊可直接由 GitHub repository’s setting 進入, 或是由 Travis CI 進入。
{% img /images/posts/TravisCIServiceHookTest/1.png %}
進入後會看到像這樣的畫面:
{% img /images/posts/TravisCIServiceHookTest/2.png %}
往下捲動找到 Travis CI 後點擊。
{% img /images/posts/TravisCIServiceHookTest/3.png %}
接著點選 Test Hook 按鈕觸發 Travis CI 建置就可以了。
{% img /images/posts/TravisCIServiceHookTest/4.png %}
{% img /images/posts/TravisCIServiceHookTest/5.png %}
read morePosts
Travis CI - Build Status images
Travis CI 支援 Build status image,能讓我們將 Repository 建置的狀態嵌至網站上。
使用時只要開啟 Travis CI,將左側這邊切換至 My Repositories。
{% img /images/posts/TravisCIBuildStatusImages/1.png %}
切換至欲使用的 Repository ,在右側的建置資訊這邊,可以看到右上方有個圖片表示著這個 Repository 的建置狀態,這就是我們要拿來內嵌的圖片。
{% img /images/posts/TravisCIBuildStatusImages/2.png %}
滑鼠點擊後會出現像下面這樣的對話框。
{% img /images/posts/TravisCIBuildStatusImages/3.png %}
對話框裡面有提供嵌入用的語法,將之複製並貼入欲嵌入的位置就可以了。
多半我們會將它嵌在 GitHub 的 README.md 內。
{% img /images/posts/TravisCIBuildStatusImages/4.png %}
瀏覽 Repository 時就能一眼看出是否能成功的建置。
{% img /images/posts/TravisCIBuildStatusImages/5.png %}
Link [Travis CI: Status Images] (http://about.travis-ci.org/docs/user/status-images/)
read morePosts
Travis CI - Build .NET project
Travis CI 內建支援 C、C++、Clojure、Erlang、Go、Groovy、Haskell、Java、Python、Ruby 等語言,卻沒有支援 .Net 的,這表示官方並不特別的去做 .Net 語言的支援。然而 Travis CI 具備有相當程度的彈性,經由設定能在建置前先進行套件的安裝,因此我們還是能透過安裝 Mono 套件去建置 .Net 的專案。
在設定檔的撰寫上,Language 這邊指定語言為 C ,因為前面提到的 Travis CI 並不支援 C# 。
language: c install 這邊透過 apt-get 安裝 mono-devel 、 mono-gmcs 。
install: - sudo apt-get install mono-devel mono-gmcs script 這邊直接叫用 xbuild 去建置我們的專案或是方案就可以了。
script: - xbuild Source/LevelUp.Extensions.Core/LevelUp.Extensions.Core.csproj - xbuild Source/LevelUp.Extensions.Control/LevelUp.Extensions.Control.csproj 整個設定檔撰寫起來會像下面這個樣子:
Travis CI Integration language: c install: - sudo apt-get install mono-devel mono-gmcs script: - xbuild Source/LevelUp.Extensions.Core/LevelUp.Extensions.Core.csproj - xbuild Source/LevelUp.
read morePosts
Travis CI - Free Hosted Continuous Integration Platform for the Open Source Community
Travis CI 是免費的 CI 服務,支援 C、C++、Clojure、Erlang、Go、Groovy、Haskell、Java、Python、Ruby等語言。能用來建置 GitHub 上的 Repository, 為 GitHub 加上 CI 的能力,不需另行為此架設 CI Server。只要在 Repository 放置個 Travis CI 的設定檔,並授權給 Travis CI,最後再將 Service Hook 啟用就可以了。
此外,Travis CI 也提供狀態貼紙的功能,能將建置的狀態內嵌在想放置的位置,讓建置狀態一目了然。
使用時需先至 Travis CI 做 GitHub 的登入
{% img /images/posts/TravisCI/1.png %}
登入後會 Travis CI 會向我們要求授權
{% img /images/posts/TravisCI/2.png %}
若對要求的權限沒什麼意見,可以進一步按下 Allow access 按鈕授予權限。
{% img /images/posts/TravisCI/3.png %}
授予權限時,為了安全起見,GitHub 會再次請求輸入密碼。
{% img /images/posts/TravisCI/4.png %}
密碼確認無誤,Travis CI 即會開始將我們的 Repository 給拉回來。
{% img /images/posts/TravisCI/5.png %}
read moreTag: Cake
Posts
Cake - Cleans the specified directories
要使用 Cake 清除特定目錄,可以參閱 CleanDirectories 的使用方式。
調用上可以直接帶入目錄的集合,或是目錄的 match pattern。
像是用 match pattern 去清除目錄腳本撰寫起來就會像下面這樣。
... Task("Clean") .Does(() => { CleanDirectories("./**/bin/" + configuration); CleanDirectories("./**/obj/" + configuration); }); ... Cake 任務運行後。
指定目錄的檔案就會被清除。
最後附上完整的 Cake 腳本。
/////////////////////////////////////////////////////////////////////////////// // ARGUMENTS /////////////////////////////////////////////////////////////////////////////// var target = Argument("target", "Default"); var configuration = Argument("configuration", "Release"); /////////////////////////////////////////////////////////////////////////////// // SETUP / TEARDOWN /////////////////////////////////////////////////////////////////////////////// Setup(ctx => { // Executed BEFORE the first task. Information("Running tasks..."); }); Teardown(ctx => { // Executed AFTER the last task.
read morePosts
Cake - Build with MSBuild
要使用 Cake 透過 MSBuild 建置方案,可以參閱 Cake 內使用 MSBuild 的方式。
調用上就是帶入方案檔即可,如有需要設定再帶入設定值而已。
所以建置的腳本寫起來會像下面這樣,先帶入方案檔的位置找到對應的方案檔,遍尋方案檔調用 MSBuild,如有需要則加帶設定,像是是否要將緊告示為錯誤、或是設定是要建置 Debug 或是 Release 等。
var solutions = GetFiles("../**/*.sln"); ... Task("Build") .Does(() => { foreach(var solution in solutions) { ... MSBuild(solution, settings => settings.SetPlatformTarget(PlatformTarget.MSIL) .WithProperty("TreatWarningsAsErrors","true") .WithTarget("Build") .SetConfiguration(configuration)); } }); ... Cake 任務運行後。
輸出目錄就會看到建置出來的檔案。
最後附上完整的 Cake 腳本。
var solutions = GetFiles("../**/*.sln"); /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS /////////////////////////////////////////////////////////////////////////////// var target = Argument("target", "Default"); var configuration = Argument("configuration", "Release"); /////////////////////////////////////////////////////////////////////////////// // SETUP / TEARDOWN /////////////////////////////////////////////////////////////////////////////// Setup(ctx => { // Executed BEFORE the first task.
read morePosts
Cake - Visual Studio Code Cake extension
要在 Visual Studio Code 使用 Cake,可以為 Visual Studio 加裝 Cake 擴充套件。
安裝完可開啟 Command Palette。
使用 Cake: Install a boostrapper 為專案加入 boostrapper。
使用 Cake: Install a configuration file 為專案加入 Cake 設定檔。
使用 Cake: Install sample build file 為專案加入 Cake 腳本的範本。
如果一次要加入多個項目,可直接使用 Cake: Install to workspace。
要除錯的話可加入 launch.json,直接透過 Visual Studio Code 除錯。
如果要直接運行腳本的任務,可點選 [ Tasks | Run Task… ] 主選單選項。
選取要運行的腳本任務即可。
Link
read morePosts
Cake - Global .NET CLI tool
Cake 0.30.0 後開始支援 Global .NET CLI tool,可透過 dotnet tool 安裝。
dotnet tool install -g Cake.Tool 安裝完就可以直接透過 dotnet 命令運行 Cake。
dotnet cake <CakeFile> Link [Cake - Cake v0.30.0 released] (https://cakebuild.net/blog/2018/08/cake-v0.30.0-released)
read morePosts
Cake - Cake.Portable
Cake.Portable 是 Cake script runner,可直接透過 chocolatey 安裝。
choco install cake.portable 安裝完可以直接調用 Cake 命令測試看看,像是查閱 Cake 命令的使用方式。
cake --help 在使用上也就不需要再透過 bootstrapper 下載,可以直接運行 cake script。
Link Chocolatey Gallery | Cake.Portable 0.30.0
read morePosts
Cake - Cake for Visual Studio
Cake for Visual Studio 擴充套件可讓 Visual Studio 支援 Cake 的使用,可直接開啟 Extensions and Updates 功能…
搜尋並安裝。
安裝好後在 Build 主選單選項下會多 Cake Build 選單選項,裡面的 Install Cake config file 可以用來加入 Cake 設定檔 (cake.config)。
裡面的 Install PowerShell bootstrapper 可加入 Cake bootstrapper 檔 (build.ps1)。
要加入 Cake 腳本檔的話,可以用 Cake Build Script 範本加入新項目。
如要運行 Cake 腳本,可以叫出 Task Runner Explorer。
透過 Task Runner Explorer 選取 Task 進行運行。
Link Cake for Visual Studio - Visual Studio Marketplace Cake - Visual Studio
read morePosts
Cake - Setting up a new project on Windows
要在新的專案中使用 Cake,首先要下載 bootstrapper。
Invoke-WebRequest https://cakebuild.net/download/bootstrapper/windows -OutFile build.ps1 然後建立 cake 腳本檔。
裡面放置腳本的內容,像是這邊就放置了一個簡單的腳本。腳本運行後會顯示 “Hello World!” 字樣。
var target = Argument("target", "Default"); Task("Default") .Does(() => { Information("Hello World!"); }); RunTarget(target); 最後只要調用 bootstrapper 運行腳本就可以了。
./build.ps1 {% asset_img 4.png%}
Link Cake - Setting Up A New Project
read moreTag: Vue.js
Posts
Termux - Vue.js in Termux
要在 Termux 內建立 Vue.js 環境,需要安裝 Vue CLI 到全域。
npm i vue-cli -g 安裝後透過 Vue CLI 初始 Vue 專案。
vue init webpack <Project> 進入初始完的專案目錄。
還原專案需要的套件。
yarn install 運行 Vue 專案。
yarn run start 訪問 http://127.0.0.1:8080 即可看到運行結果。
read morePosts
Vue.js - Event Handling
Vue.js 在事件處理上,主要是透過 v-on 去監聽事件,事件觸發後可以指定對應的動作。
像是點擊後用運算式處理對應的動作。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <button v-on:click="click += 1">Click</button> <p>{{click}}</p> </div> <script> new Vue({ el: '#app', data:{ click: 0 } }) </script> </body> </html> 或是調用對應的方法處理。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <button v-on:click="onClick">Click</button> <p>{{click}}</p> </div> <script> new Vue({ el: '#app', data:{ click: 0 }, methods: { onClick: function(event){ this.
read morePosts
Vue.js - List Rendering
Vue.js 要渲染多個元素,可使用 v-for。
像是要渲染陣列元素,就可以像下面這樣處理。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <p v-for="item in items">{{item}}</p> </div> <script> new Vue({ el: '#app', data:{ items: [ "1.Hello World", "2.Hello World", "3.Hello World", "4.Hello World", "5.Hello World" ] } }) </script> </body> </html> 若有需要索引值,v-for 也有索引值可供使用。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <p v-for="(item, index) in items">{{index + 1}}. {{item}}</p> </div> <script> new Vue({ el: '#app', data:{ items: [ "Hello World", "Hello World", "Hello World", "Hello World", "Hello World" ] } }) </script> </body> </html> 除了陣列元素外,v-for 也支援 range 的方式,可明確指定循環的次數。
read morePosts
Vue.js - Conditional Rendering
Vue.js 要使用條件渲染,像是想要當條件成立時才渲染,可以使用 v-if、 v-else-if、 v-else。
像是下面這程式,筆者使用輸入框繫結的 name 屬性去決定要顯示的文字,如果有輸入名字,則會對該名字 Hello,反之則顯示 Hello World。 <!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input v-model="name"> <h1 v-if="name != ''">Hello {{name}}</h1> <h1 v-else>Hello World</h1> </div> <script> new Vue({ el: '#app', data:{ name: "" } }) </script> </body> </html> 條件渲染在使用上,Vue.js 為了效能考量會用最有效率的方式渲染,所以當我們程式像下面這樣時,運行上可能就會不如我們所預期。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input type="radio" value="SignIn" v-model="option">SignIn<br/> <input type="radio" value="ForgetPassword" v-model="option">Forget password<br/> {{option}} <br/><br/> <input v-if="option == 'SignIn'" placeholder="UserName"> <input v-if="option == 'ForgetPassword'" placeholder="EMail"> </div> <script> new Vue({ el: '#app', data:{ option: "SignIn" } }) </script> </body> </html> 像是運行起來在輸入框中輸入名字。
read morePosts
Vue.js - Watch
Vue.js 的 watch 可以設定監控特定的屬性,當屬性值變動時做對應的處理。
使用上只要在建構 Vue 建立時設定 watch 物件,裡面放置屬性值變化時要做的處理即可。
<div id = "app"> ... <input v-model = "<PropertyName>"> ... </div> <script> new Vue({ el : '#app' , data :{ ... }, watch: { <PropertyName>: function (val) { ... } } }) </script> 像是下面這樣的程式,設定了 message 變動時將訊息寫入 console 內。
<!DOCTYPE html> <html> <head> <title> Vue - Hello World </title> <script src = "https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id = "app"> <input v-model = "message"> <p> {{message}} </p> </div> <script> new Vue({ el : '#app' , data :{ message : "" }, watch: { message: function (val) { console.
read morePosts
Vue.js - Computed properties
Vue.js 的計算屬性(Computed properties)可以設定經過運算而來的屬性,有點類似其它程式語言的屬性(Property),而一般的 Vue.js 屬性則是類似其它程式語言的欄位(Field)。
使用上只要在建構 Vue 建立時設定 computed 物件,裡面放置計算屬性的方法,這樣在使用計算屬性時就會去調用計算屬性定義的方法去運算。
<div id="app"> ... {{<PropertyName>}} ... </div> ... <script> new Vue({ el: '#app', data:{ ... }, computed: { <PropertyName>: function () { ... } } }) </script> 像是下面這樣的程式,設定了 firstName 與 lastName 兩個屬性,並設定了名為 fullName 的計算屬性,其值為 firstName 與 lastName 用空格串接。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input v-model="firstName"> <input v-model="lastName"> <p>{{fullName}}</p> </div> <script> new Vue({ el: '#app', data:{ firstName: "Larry", lastName:"Nung" }, computed: { fullName: function () { return this.
read morePosts
Vue.js - .trim modifier
Vue.js 的 .trim modifier 可以將繫結的屬性值去除多餘的空格。
以下面這段程式為例,若不使用 .trim modifer,輸入的資料如果有空格,繫結的屬性值也會含有空格。
<!DOCTYPE html> <html> <head> <title> Vue - Hello World </title> <script src = "https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id = "app"> <input v-model = "message"> <p> {{message.length}} </p> </div> <script> new Vue({ el : '#app' , data :{ message : "Hello World" } }) </script> </body> </html> 這時候需要使用 .trim modifier 來解決這樣的問題,將繫結的屬性值去除多餘的空格。
<!DOCTYPE html> <html> <head> <title> Vue - Hello World </title> <script src = "https://unpkg.
read morePosts
Vue.js - .number modifier
Vue.js 的 .number modifier 可以讓繫結的屬性值轉換成數值型態。
以下面這段程式為例,若不使用 .number modifer,輸入的資料會被視為字串,如果要拿繫結的屬性值去做數值的處理就會不如我們的預期。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input v-model="value" type="number"> <p>{{value + 1}}</p> </div> <script> new Vue({ el: '#app', data:{ value: 0 } }) </script> </body> </html> 這時候需要使用 .number modifier 來解決這樣的問題,將繫結的屬性值轉換成數值型態,後續的數值處理才會正常。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input v-model.number="value" type="number"> <p>{{value + 1}}</p> </div> <script> new Vue({ el: '#app', data:{ value: 0 } }) </script> </body> </html>
read morePosts
Vue.js - .lazy modifier
Vue.js 的 .lazy modifier 可以讓繫結的資料在資料改變後才進行同步,而非在輸入的同時就進行同步。
像是下面這樣的程式:
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input v-model.lazy="message"> <p>{{message}}</p> </div> <script> new Vue({ el: '#app', data:{ message: "Hello World" } }) </script> </body> </html> 運行起來會像下面這樣,資料在輸入時並不會被同步。
當輸入完畢焦點移開或是按下 Enter 按鈕,資料被視為變更,才會進行資料的同步。
read morePosts
Vue.js - Select binding
Select 的繫結一樣是在 Vue 建立時連帶設定要用來繫結的屬性,然後在 Select 元素這邊透過 value 指定被選取的值,並用 v-model 指定所要繫結的屬性,設定完後資料屬性與控制項之間即會連動。
如果要支援多選,只要在 Select 元素上加上 multiple,並用陣列去設定繫結用的 Vue 屬性即可。
像是下面這樣的程式:
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <select v-model="option"> <option>option1</option> <option>option2</option> <option>option3</option> </select> {{ option }} <br/><br/> <select v-model="options" multiple> <option>option1</option> <option>option2</option> <option>option3</option> </select> <br/> {{ options }} </div> <script> new Vue({ el: '#app', data:{ option: "option1", options: [] } }) </script> </body> </html> 運行起來就會像下面這樣:
read morePosts
Vue.js - Radio binding
Radio 的繫結一樣是在 Vue 建立時連帶設定要用來繫結的屬性,然後在 Radio 元素這邊透過 value 指定被選取的值,並用 v-model 指定所要繫結的屬性,設定完後資料屬性與控制項之間即會連動。
像是下面這樣的程式:
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input type="radio" value="Male" v-model="sex">Male<br/> <input type="radio" value="Female" v-model="sex">Female<br/> {{ sex }} </div> <script> new Vue({ el: '#app', data:{ sex: "Male" } }) </script> </body> </html> 其運行結果如下:
read morePosts
Vue.js - Checkbox binding
Checkbox 的繫結一樣是在 Vue 建立時連帶設定要用來繫結的屬性,然後在 Checkbox 元素這邊透過 v-model 指定所要繫結的屬性,設定完後資料屬性與控制項之間即會連動。
如果有多個 Checkbox 要做繫結,方法大同小異,只要將繫結的屬性宣告成陣列,Checkbox 這邊使用 v-model 指定繫結至相同的屬性,並在 Checkbox 指定選取時的 value 即可。
像是下面這樣的程式:
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input type="checkbox" v-model="checked"> {{ checked }} <br/><br/> <input type="checkbox" value="option1" v-model="options">option1<br/> <input type="checkbox" value="option2" v-model="options">option2<br/> <input type="checkbox" value="option3" v-model="options">option3<br/> <br/> {{ options }} </div> <script> new Vue({ el: '#app', data:{ checked: false, options: ["option2"] } }) </script> </body> </html> 其運行結果如下:
read morePosts
Vue.js - Input text binding
要用 Vue.js 將資料與輸入框做繫結,我們可在 vue 建立的同時設定用來繫結的屬性,然後在 HTML 的輸入框元素中使用 v-model 設定所要繫結的屬性,這樣設定後輸入框的資料就會被寫入指定的屬性中,而指定屬性其值的變化也會呈現在輸入框中。
像是下面這樣的程式:
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input v-model="message"> <p>{{message}}</p> </div> <script> new Vue({ el: '#app', data:{ message: "Hello World" } }) </script> </body> </html> 其運行結果如下,在輸入框中輸入什麼,下方就會顯示什麼。
read morePosts
Vue.js - Components
Vue.js Component 可讓我們將畫面與程式封裝程可重用的元件。
可在建立 Vue 時透過 components 宣告,進行局部註冊。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <Hello></Hello> </div> <script> new Vue({ el: '#app', components: { 'Hello' : { template : '<h1>Hello World</h1>' } } }) </script> </body> </html> 也可以使用 Vue.component 宣告,進行全域註冊。
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <Hello></Hello> </div> <script> Vue.component( 'Hello' , { template : '<h1>Hello World</h1>' }) new Vue({ el: '#app' }) </script> </body> </html> 像是這邊筆者就註冊了名為 Hello 的 Component,該 Component 會顯示出 Hello World 的字樣,Component 註冊完後可以在 HTML 中使用 Hello 這個 Component 的 Element。
read morePosts
Vue.js - Getting started
要使用 Vue.js 我們要將 Vue.js 載入,可以手動加入、用 npm 安裝套件、用 vue-cli、用 bower…等。
這邊筆者用 vue-cli 做個簡單的範例,用 simple 範本建立專案。
vue init simple <ProjectName> simple 範本建立出來的專案就只有一個 index.html 檔,裡面已經幫我們加入了 vue.js 套件。
這邊筆者將檔案修改成下面這樣:
<!DOCTYPE html> <html> <head> <title>Vue - Hello World</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <h1>{{message}}</h1> </div> <script> new Vue({ el: '#app', data: { message: 'Hello World', } }) </script> </body> </html> 可以看到 script 這邊建立了一個 vue 物件,裡面設定了 el 為 #app,指向上方 id 為 app 的 div 為其作用範圍。接著設定 data,裡面有個 message 值為 ‘Hello World’,會被綁定到上方的 {{message}}。
read moreTag: Hexo
Posts
Termux - Setup Hexo blog
在 Termux 使用 Hexo 並沒什麼特別之處。
一樣是要先將 Hexo CLI 安裝到全域。
npm install hexo-cli -g 接著初始化 Blog。
hexo init <Folder> 進入剛初始化產出的目錄
運行 Hexo 服務。
hexo s 訪問 http://127.0.0.1:4000 即可看到 Blog 運行的結果。
read morePosts
vscode-hexo - VSCode extension to manage hexo commands
vscode-hexo 是 VSCode 的擴充套件,能讓我們在 VSCode 內簡易的調用 Hexo 命令。
按下熱鍵 Ctrl-Shift-P / Cmd-Shift-P 開啟 command palette,輸入 Extensions:Install Extensions,輸入 hexo 找到 vscode-hexo 擴充套件進行安裝。
安裝完後重啟 VSCode。
點選 [File | Open…] 將 Hexo 部落格目錄開啟。
按下熱鍵 Ctrl-Shift-P / Cmd-Shift-P,輸入 Hexo 即可看到可用的 Hexo 命令。
- hexo init # Initializes a website - hexo new # Creates a new article - hexo generate # Generates static files - hexo publish # Publishes a draft - hexo server # Starts a local server - hexo stop # stop a local server(Ctrl-C) - hexo deploy # Deploys your website - hexo clean # Cleans the cache file (db.
read morePosts
Hexo - Optimize with hexo-console-optimize
hexo-console-optimize 是 Hexo 的套件,可讓 Hexo 對 HTML、CSS、JS、Image 進行壓縮優化。
可透過 npm 進行安裝。
npm install hexo-console-optimize --save 要使用時調用 Hexo 的 Optimize 命令,即會對 HTML、CSS、JS、Image 檔案進行壓縮優化。
hexo optimize hexo o 如有需要,也可加帶 -d 參數在壓縮優化後直接進行佈署。
hexo o -d Link FlashSoft/hexo-console-optimize: Hexo输出内容优化 hexo-console-optimize
read morePosts
Hexo - Speed up with InstantClick
要用 InstantClick 加速 Hexo 部落格,可先下載 InstantClick 放至 source\js 下。
然後開啟 _config.yml 設定檔,加入 skip_render 設定,將 js 檔排除 render。
接著修改 Hexo 的 theme 讓 InstantClick 得以啟動。以 next theme 為例,可開啟 next theme 的 layout_layout.swig,將 InstantClick 啟動的程式插入即可。
<script type="text/javascript" src= "js/instantclick.js" data-no-instant></script> <script data-no-instant>InstantClick.init();</script> 設定完可開啟部落格網站,打開開發人員工具,切換到 Network 頁籤,然後將滑鼠移至連結,就可以看到當滑鼠移至連結時就已經在進行預載的動作了。
最後提醒一下,InstantClick 的預載行為可能會造成其它套件的異常,可能要自行視情況修正將問題排除。
Link InstantClick — JS library to make your website instant
read morePosts
Hexo - Auto deploy with Travis CI
要使用 Travis CI 自動幫我們發佈 Hexo 部落格,先參閱筆者 Travis CI - Free Hosted Continuous Integration Platform for the Open Source Community | Level Up 這篇,登入 Travis CI ,給予授權,並為 Repository 啟用 Travis CI。
接著要準備一組 Personal access token 給 Travis CI。先將 GitHub 的 Settings 開啟。
切到 Personal access tokens 頁面。
按下 Generate new token 按鈕建立一組 token。
為這組 Token 設定一個名稱,並給予它 repo 的權限。
Token 產生後複製留存以供後續使用。
再來要準備 Travis CI 的設定檔 .travis.yml,放置於 Repository 的根目錄,內容大概像這樣 (branches 位置、使用者名稱、與電子郵件位置請自行替換):
language: node_js node_js: - '0.
read morePosts
Hexo - Title SEO
要為 Hexo 部落格做 Title SEO,可以將主題的 index layout 檔開啟做些調整。
themes/[Theme]/layout/index.swig 在 Title 的區塊這邊除了 title 外,我們還可以將部落格的描述之類的額外資訊附加上去。
read morePosts
Hexo - Setup robots.txt
要為 Hexo 部落格加上 robots.txt,我們可以安裝 hexo-generator-robotstxt 套件。
npm install hexo-generator-robotstxt --save 安裝完後開啟站台設定檔,設定啟用 hexo-generator-robotstxt plugins。
然後加入 robots.txt 的設定。
設定完後存擋,接著產生靜態檔案,就可以看到 robots.txt 會順帶被產生出來。
Link GitHub - leecrossley/hexo-generator-robotstxt: Basic robots.txt generator plugin for Hexo
read morePosts
Hexo - Post asset folder
要使用 Asset folder,我們可以開啟 Hexo 的設定檔,將 post_asset_folder 設定設為 true。
當使用 Hexo 建立一篇文章時。
就會連帶幫我們建一個與文章同名的 Asset folder。
我們可以將文章以外所有的檔案放置在這目錄下,然後使用下列語法將之引用。
{% asset_path slug %} {% asset_img slug [title] %} {% asset_link slug [title] %} 像是這邊筆者將圖片放置在 Asset folder 內。
在文章中使用就會像下面這樣:
Link 資產資料夾 | Hexo
read morePosts
Hexo - Disable NexT theme's motion
Hexo 的 NexT 主題預設會有些動畫過場,如果這些動畫不是覺得那麼必要,想將之關閉以提升顯示上的速度,可以開啟 Theme 的設定檔將 use_motion 的設定設為 false。
read morePosts
Hexo - Change NexT theme's scheme
NexT 支援三種不同的 Scheme,可開啟 Theme 的設定檔設定。
Muse scheme…
Mist scheme…
Pisces scheme…
read morePosts
Hexo - Set social link with NexT theme
要設定 NexT 主題的 Social Link,只要開啟 Theme 的設定檔,設定 social link 的位置以及 social icon 即可。
read morePosts
Hexo - Set avatar with NexT theme
要設定 NexT 主題的 avatar,我們可以開啟 Theme 的設定檔,設定 avatar 檔案的位置。
然後將 avatar 的圖檔放置設定的位置就可以了。
read morePosts
Hexo - Add tag page
要為 Hexo 部落格建立標籤頁面,首先要建立 tag 的頁面。
hexo n page tags 開啟剛產生的標籤頁面,設定 type 為 tags。如果不希望能在標籤頁面上留言的話,這邊也可以順便將 comments 為 false。
再來開啟 Hexo 的設定檔,確定 tag_map 設定是否需要更動。
如果 theme 有支援設定,這邊也要確認是否有需要更動,像是是否要加選單之類的。
並在文章上方設定 tags,指定文章的分類。
將服務運行起來就可以在 /tags 看到標籤頁面了。
read morePosts
Hexo - Generate sitemap
要為 Hexo 部落格放置 Sitemap 檔,可以安裝 hexo-generator-sitemap 套件。
npm install hexo-generator-sitemap --save 開啟 Hexo 設定檔,設定 sitemap 檔案。
sitemap: path: sitemap.xml 當建立靜態檔案就會產生指定的 sitemap 檔案。
Link
read morePosts
Hexo - Migrate from octopress
要將 Octopress 部落格移至 Hexo 部落格,首先要將 Octopress source/_posts 下的文章移至 Hexo source/_posts 下。若有圖檔也依樣移過去,像是如果 Octopress 的圖檔放置在 source/images 目錄下,這邊就將它移至 source/images 下。
再來因為 Octopress 的文章的副檔名是 markdown,所以要將它取代為 md 副檔名。
然後使用 RenameRegex 將檔名前面的日期部分拔除。
rr *.md "(\d+-\d+-\d+-)(.*)" "$2" 最後因為 Octopress 文章內的時間資料只顯示到分,所以要用 Regular Expression Search and Replace Command Line Tool 將日期部分修正到秒。
rxrepl -D "C:\Users\larry.nunglog\source\_posts" -I *.md -a --no-backup --no-bom -e utf8 --output-encoding utf8 -s "(\d+-\d+-\d+\s+\d+:\d+)" -r "\1:00" 將服務跑起來看看,如果 Octopress 文章內沒用太特別的符號,這時應該已經可以看到文章了。
如果有 Error 發生,那就是要自己想辦法把出問題的文章抓出來了。
Link
read morePosts
Hexo - Add category page
要為 Hexo 部落格建立分類頁面,首先要建立 categories 的頁面。
hexo n page categories 開啟剛產生的分類頁面,設定 type 為 categories。如果不希望能在分類頁面上留言的話,這邊也可以順便將 comments 為 false。
再來開啟 Hexo 的設定檔,確定 default_category/category_map 設定是否需要更動。
並在文章上方設定 categories,指定文章的分類。
將服務運行起來就可以在 /categories 看到分類頁面了。
Link
read morePosts
Hexo - Local search support
要為 Hexo 架設的部落格加上搜尋,但卻不想依賴外部服務,可以為 Hexo 部落格加裝 hexo-generator-search 套件。
npm install hexo-generator-search --save 套件安裝完需開啟 Hexo 的設定檔,加上 search 的設定。path 的部分指到的是該套件產生的索引檔案,也就是 search.xml,field 則是指定搜尋的範圍,可帶入 post/page/all。
search: path: search.xml field: post 如果使用的主題支援的話,設完後將服務跑起就可以開始使用搜尋的功能。
Link
read morePosts
Hexo - RSS support
要為部落格加入 RSS,我們需先安裝 hexo-generator-feed。
npm install hexo-generator-feed --save 然後開啟 Hexo 的設定檔做些設定,像是 RSS feed 的數量等。
feed: type: atom path: atom.xml limit: 20 hub: 這樣在產生靜態檔案時就會一併產生出 RSS 的 xml 檔。
部落格發佈上去 RSS 就可以使用了。
這邊要注意的是,有的主題也支援 RSS 的整合,像是筆者用的 Next 主題就有支援,設定方式要參閱主題的使用文件,像是 Next 這邊的設定方式就是將主題設定黨內的 rss 設定留空。
主題就會在預期的地方顯示 RSS 訂閱的連結。
Link
read morePosts
Hexo - Apply blog themes
Hexo 支援主題的更換,Themes | Hexo 網站上也提供許多不同的主題可供我們選用,看到有興趣的主題可以直接點擊主題的圖片開啟 Demo Site 瀏覽。
若確定選用該主題,可以點選圖片下方主題的名字連結到下載頁面。
以筆者用的 Next 主題為例,我們可以直接用 GitHub 下載 Zip 檔,或是用 Git Clone 將主題下載下來。這邊只要將下載下來的主題放置在 themes 目錄下就可以了。
接著開啟 Hexo 的設定檔,將 theme 設定指到剛下載的主題目錄。
主題套用就完成了。
Link
read morePosts
Hexo - Deploy blog post
要發佈文章至遠端 repository,第一次使用之前,需要先安裝 Hexo 的 Deployer 套件。Hexo 支援多種 Deployer,這邊可視需要安裝。
像是筆者用的是 GitHub page 去 host 部落格,因此安裝的是 hexo-deployer-git。
npm install hexo-deployer-git --save Deployer 套件安裝完後,要開啟部落格的設定檔設定 Deploy 的參數,像是 Deployer 的型態以及 repository 的位置等。
設定完後我們就可以開始進行發佈的動作。
先產生發佈需要的靜態檔案。
hexo generate hexo g 再用 hexo deploy 進行發佈即可。
hexo deploy hexo d 這兩個命令可以合併起來一次叫用。
hexo g -d 如果發佈後網站無正常更新,可以嘗試清除快取後再次產生靜態檔案發佈。
hexo clean hexo g hexo d Link
read morePosts
Hexo - Write a blog post
使用 Hexo 撰寫 blog 文章,可以先用 hexo new 建立一個 post。
hexo new <title> hexo n <title> 這個指令會幫我們建立一個 post 的 md 檔,開啟該檔用 markdown 撰寫 blog 文章。
撰寫完後存檔,用 hexo server 將 Hexo 服務跑起來。
hexo server hexo s 跑起來後開啟瀏覽器瀏覽 http://localhost:4000 即可看到剛撰寫的部落格文章。
Link
read morePosts
Hexo - Restore blog envirement from remote repository
要從遠端 repository 還原 blog 撰寫的環境,我們需先確定 Hexo 需要的環境是否已經準備妥當(是否有安裝 git?是否有安裝 Node.js?是否有安裝 hexo-cli?)。
Hexo 需要的環境準備好後,可將 repository 的資料 clone 下來。
git clone [repository url] [folder] 接著進到 clone 下來的目錄。
cd [folder] 切換 branch 至 source 放置的 branch。
git checkout [branch] 再還原 npm 的套件即可。
npm install 後續如果有需要,都可從 remote repository 更新 source。
git pull origin [branch]
read morePosts
Hexo - Upload blog source
Hexo 架設完畢後,我們除了要將 blog deploy 上去外,source 的部分也要記得放到版控上面。
首先需進到部落格的目錄,初始 git。
git init 接著設定遠端的 git 位置,這邊如果是用 GitHub,位置的部分就是 GitHub page 的 repository 位置。
git remote add origin [repository url] 接著開啟一個新的 branch 去放置 source。
git checkout -b [branch] 如果需要,這邊可以放置 .gitignore 檔在部落格目錄,用以告知 git 要忽略版控的檔案與目錄。檔案內容如下:
.DS_Store Thumbs.db db.json *.log node_modules/ public/ .deploy*/ 再來要將未版控的檔案加入版控。
git add . commit 這次修改。
git commit -a -m "[comments]" 最後將部落格的 source 送到遠端 repository 即可。
git push origin [branch] 後續每次加文章時,記得也都要將 source 上到遠端 repository。
git add .
read morePosts
Hexo - Getting started
要使用 Hexo,我們需先確定已有安裝 Git & Node.js。
接著安裝 Hexo 的命令列程式。
npm install hexo-cli -g 與初始化部落格。
hexo init [Folder] 初始的動作會產生對應的目錄,並下載需要的檔案。
整個目錄結構會像下面這樣。_config.yml 是 Hexo 站台的設定檔,package.json 是 Node.js 的套件設定檔,scaffoids 目錄內存放的是部落格會用到的樣板,source 目錄內存放的是部落格文章等未經加工建立的來源擋,themes 目錄內放置的是部落格的主題。
再來要開啟 _config.yml 設定部落格。
設定完後存擋。
進到部落格目錄,還原 npm 套件,即可將之運行起來。
cd [Folder] npm install hexo server 運行起來後,用瀏覽器瀏覽 http://localhost:4000 即可看到部落格運行起來的樣子。
Link
read moreTag: Nginx
Posts
Termux - nginx
要在 Termux 內使用 nginx,首先要透過套件管理工具安裝 nginx 套件。
nginx install nginx 安裝完輸入命令啟動。
nginx 啟動後服務會在背景運行,可以用查詢看看 process 是否有起來。
ps | grep nginx 服務有正常起來到話訪問 http://127.0.0.1:8080 就可以看到 nginx 的歡迎頁面。
如果要關閉 nginx 服務,可調用…
fuser -k 8080/tcp
read moreTag: LogDevice
Posts
LogDevice - Edit range using ldshell
要使用 ldshell 變更 LogDevice 的 Log range,可以使用 -c 參數指定使用 Interactive Mode,帶入 LogDevice 的設定檔,帶入 logs set range,帶入 Log range,以及 Log name。
ldshell -c <Config> logs set range --from <Start> --to <End> <Log> 像是這邊筆者就將 test_logs 的 Range 變更為 50 到 100,查閱 Log 也確實做了改變。
Link Log configuration · LogDevice
read morePosts
LogDevice - Rename log using ldshell
要使用 ldshell 將 LogDevice 的 Log 更名,可以使用 -c 參數指定使用 Interactive Mode,帶入 LogDevice 的設定檔,帶入 logs rename 以及新舊 Log name 即可。
ldshell -c <Config> logs rename <OldLogName> <NewLogName> Link Log configuration · LogDevice
read morePosts
LogDevice - Removing log using ldshell
要使用 ldshell 刪除 LogDevice 的 Log,可以使用 -c 參數指定使用 Interactive Mode,帶入 LogDevice 的設定檔,帶入 logs remove 及指定要刪除的 Log 即可。
ldshell -c <Config> logs remove <Log> Link
read morePosts
LogDevice - Show log tree using ldshell
要查看 LogDevice 的 Log tree,可以調用 ldshell 命令使用 -c 參數指定使用 Interactive Mode,帶入 LogDevice 的設定檔,帶入 logs show 指定要查閱 Log tree 即可。
ldshell -c <Config> logs show 一開始的 log tree 應該是空的,只有根目錄。
log 增刪後可以用這方法在 log tree 中查閱對應的變化,
Link Log configuration · LogDevice
read morePosts
LogDevice - Read data from a log
要讀取 LogDevice 內的資料,可以調用 ldtail 命令,帶入設定檔位置以及要讀取的位置。
ldtail <Config> <Sequence> 像是筆者就將 hello 寫入了 LogDevice 內的第一個位置,可像下面這樣將之讀出。
Link Creating your first cluster · LogDevice
read morePosts
LogDevice - Write data into a log
要將 Log 寫入 LogDevice,需要用 echo 輸出要寫入的 data,用 Pipline 將之帶入 ldwrite,並指定設定檔位置,以及要寫入的位置即可。
echo <Data> | ldwrite <Config> <Sequence> 像這邊筆者就將 hello 這樣的資料寫到了 LogDevice 的第一個位置。
Link Creating your first cluster · LogDevice
read morePosts
LogDevice - Create log ranges using ldshell
LogDevce cluster 啟用後,首先需要先建立 Log range。
調用 ldshell 命令使用 -c 參數指定 LogDevice 的設定檔,後面帶著 logs create 指定 LogDevice 建立 log、使用 –from 與 –to 指定 log 的 range、–replicate-across 指定資料要抄寫到幾個 Cluster 節點、最後指定 Log range 的名字即可。
ldshell -c <Config> logs create --from <Start> --to <End> --replicate-across "<ReplicateAccross>" <LogName> Link Creating your first cluster · LogDevice
read morePosts
LogDevice - Running a local cluster
LogDevice 安裝完後,可以啟動 Local cluster 試試。
調用 ld-dev-cluster 命令即可啟動 Local cluster。
./_build/bin/ld-dev-cluster Local cluster 會建立暫存的目錄、啟動五個節點。
啟動時會顯示如下畫面,提示我們可以使用的命令,及怎樣操作。
... Cluster running. ^C or type "quit" or "q" to stop. Commands: replace <nid> Replace a node (kill the old node, wipe the existing data, start a replacement). Do not wait for rebuilding. start <nid> Start a node if it is not already started. stop <nid> Pause logdeviced by sending SIGSTOP. Waits for the process to stop accepting connections.
read morePosts
LogDevice - Installation
LogDevice 目前只支援在 Ubuntu 18 LTS “Bionic Beaver” 安裝。
且只支援由 Source 建置安裝,所以我們需先下載 LogDevice 的 Source Code。
git clone --recurse-submodules git://github.com/facebookincubator/LogDevice 安裝 LogDevice 依賴的套件。
sudo apt-get install -y $(cat LogDevice/logdevice/build_tools/ubuntu.deps) 然後建立目錄用來做建置。
mkdir -p LogDevice/_build 進到建立的建置目錄。
cd LogDevice/_build 使用 cmake 設定建置。
cmake ../logdevice/ 運行 make 建置。
make -j $(nproc) 如果要將建置的檔案安裝至系統中,可調用下列命令:
sudo make install Link Installation · LogDevice
read moreTag: Event Store
Posts
Event Store - Scavenging events
當刪除 Event 或是 Stream 時, Event Store 不會立即刪除,硬碟空間也並未被回收,若要讓 Event Store 立即做刪除的處理,可以使用 Event Store 的 Scavenge。
像是筆者這邊將大量的 Event 寫入 Event Store,並將 Event 設為一秒後自動刪除。
當 Event 被刪除後,雖然 Event Store 看不到這些 Event,但是 Event Store 其實必為真的將之刪除。
這時我們可以打 Event Store 的 Scavenge API。
curl -i -d {} -X POST http://localhost:2113/admin/scavenge -u "admin:changeit" 或是透過 Web interface Admin 頁面的 Scavenge 按鈕觸發 Scavenge。
處理完後點選 Scavenge 紀錄查看。
可以看到 Scavenge 處理的細部資訊,像是節省了多少硬碟空間等。
Link Scavenging events | Event Store
read morePosts
Event Store - Max age
要設定 Event Store 的 Stream 內 Event 的存活時間,可以設定 Stream 的 Max age。
透過 StreamMetadata 的 maxAge 指定 Stream 內 Event 的存活時間,然後透過 Connection.SetStreamMetadataAsync,帶入 Stream 的名稱、ExpectedVersion、以及剛設定好的 StreamMetadata。
... var streamMetaData = StreamMetadata.Create(maxAge: TimeSpan.FromSeconds(maxAge)); conn.SetStreamMetadataAsync(streamName, ExpectedVersion.StreamExists, streamMetaData).Wait(); 像是筆者這邊設定了 Stream 內 Event 的存活時間。
using EventStore.ClientAPI; ... using (var conn = EventStoreConnection.Create(connectionString, connectionName)) { conn.ConnectAsync().Wait(); var streamName = "MyStream"; var streamMetaData = StreamMetadata.Create(maxAge: TimeSpan.FromSeconds(10)); conn.SetStreamMetadataAsync(streamName, ExpectedVersion.StreamExists, streamMetaData).Wait(); } Stream 內的 Event 在指定的存活時間過後就會自動被清除。
Link Deleting streams and events | Event Store
read morePosts
Event Store - Max count
要設定 Event Store 的 Stream 只存放指定個數的 Event,可以設定 Stream 的 Max count。
透過 StreamMetadata 的 MaxCount 指定 Stream 最大存放的 Event 數,然後透過 Connection.SetStreamMetadataAsync,帶入 Stream 的名稱、ExpectedVersion、以及剛設定好的 StreamMetadata。
... var streamMetaData = StreamMetadata.Create(maxCount: maxCount); conn.SetStreamMetadataAsync(streamName, ExpectedVersion.StreamExists, streamMetaData).Wait(); 像是筆者這邊設定了 Stream 的 Metadata,指定 Stream 只存放指定個數的 Event,然後接著嘗試塞入超過指定個數的 Event。
using EventStore.ClientAPI; ... using (var conn = EventStoreConnection.Create(connectionString, connectionName)) { conn.ConnectAsync().Wait(); var streamName = "MyStream"; var typeName = "MyType"; var streamMetaData = StreamMetadata.Create(maxCount: 10); conn.SetStreamMetadataAsync(streamName, ExpectedVersion.StreamExists, streamMetaData).Wait(); var data = new { Msg = "Hello world!
read morePosts
Event Store - Truncate before
要使用 Event Store 的 Truncate before 刪除指定 Event 編號以前的 Event,可以設定 StreamMetadata。
透過 StreamMetadata 的 truncateBefore 指定編號多少以前的 Event 要被刪除,然後透過 Connection.SetStreamMetadataAsync,帶入 Stream 的名稱、ExpectedVersion、以及剛設定好的 StreamMetadata。
... var streamMetaData = StreamMetadata.Create(truncateBefore: eventID); conn.SetStreamMetadataAsync(streamName, ExpectedVersion.StreamExists, streamMetaData).Wait(); 像是筆者這邊準備了一個內含 100 筆 Event 的 Stream。
設定 Stream 的 truncateBefore metadata 為 85。
using EventStore.ClientAPI; ... using (var conn = EventStoreConnection.Create(connectionString, connectionName)) { conn.ConnectAsync().Wait(); var streamName = "MyStream"; var streamMetaData = StreamMetadata.Create(truncateBefore: 85); conn.SetStreamMetadataAsync(streamName, ExpectedVersion.StreamExists, streamMetaData).Wait(); } 運行後重整, Number 85 以下的 Event 就會被刪除。
read morePosts
Event Store - Setting up a Cluster using only Database Nodes (OSS)
要啟用 Event Store 的 Cluster 功能,可以開啟 Event Store,設定 IP、Port、與 gossip-seed。
像是下面這邊就在本機起了三個 Event Store 服務,服務的 Log、IP、Post 都錯開,並互設 gossip-seed。
start EventStore.ClusterNode.exe --mem-db --log .\logs\log1 --int-ip 127.0.0.1 --ext-ip 127.0.0.1 --int-tcp-port=1111 --ext-tcp-port=1112 --int-http-port=1113 --ext-http-port=1114 --cluster-size=3 --discover-via-dns=false --gossip-seed=127.0.0.1:2113,127.0.0.1:3113 start EventStore.ClusterNode.exe --mem-db --log .\logs\log2 --int-ip 127.0.0.1 --ext-ip 127.0.0.1 --int-tcp-port=2111 --ext-tcp-port=2112 --int-http-port=2113 --ext-http-port=2114 --cluster-size=3 --discover-via-dns=false --gossip-seed=127.0.0.1:1113,127.0.0.1:3113 start EventStore.ClusterNode.exe --mem-db --log .\logs\log3 --int-ip 127.0.0.1 --ext-ip 127.0.0.1 --int-tcp-port=3111 --ext-tcp-port=3112 --int-http-port=3113 --ext-http-port=3114 --cluster-size=3 --discover-via-dns=false --gossip-seed=127.0.0.1:1113,127.0.0.1:2113 服務啟用後,因為 Cluster 會互相抄寫,所以可在 Web interface 的 Dashboard 頁面下面看到來自其它 Event Store 服務的連線。
read morePosts
Event Store - Subscribing to Receive Stream Updates with .NET API
要使用 Event Store .NET API 訂閱並監聽 Stream 的變化,可以使用 PersistentSubscriptionSettings.Create 設定訂閱,然後調用 Connection.CreatePersistentSubscriptionAsync 方法建立 Persistent Subscriptions。
... var settings = PersistentSubscriptionSettings.Create() .DoNotResolveLinkTos() .StartFromCurrent(); ... conn.CreatePersistentSubscriptionAsync(streamName, groupName, settings, credentials).Wait(); ... 建立後可在 Web interface 看到對應的 Persistent Subscriptions。
接著透過 Connection.ConnectToPersistentSubscription 訂閱 Persistent Subscriptions,指定 Stream 的名稱、Group 的名稱、收到訂閱要做的處理…等即可。
conn.ConnectToPersistentSubscription(streamName, groupName, (_, x) => { ... }, (sub, reason, ex) => { }, credentials); ... 像是下面這邊筆者建立了一個名為 MyGroup 的訂閱,訂閱的來源來自 MyStream,建立訂閱後連結訂閱,然後將收到的訂閱訊息顯示出來。
using EventStore.ClientAPI; using EventStore.ClientAPI.SystemData; ... using (var conn = EventStoreConnection.
read morePosts
Event Store - Read a Single Event with .NET API
要使用 Event Store .NET API 讀取 Event Store 特定 Stream 內特定的 Event,可以帶入 Stream 的名稱、Event 的編號,調用 Connection.ReadEventAsync 方法。
... var readResult = conn.ReadEventAsync(streamName, 0, true).Result; ... 然後再去讀取需要的 Event 資料即可。
... Console.WriteLine("{0} {1}", readResult.EventNumber, Encoding.UTF8.GetString(readResult.Event.Value.Event.Data)); ... 像是筆者這邊有個 Event 如下:
就可以像下面這樣讀取指定的 Event。
using EventStore.ClientAPI; ... using (var conn = EventStoreConnection.Create(connectionString, connectionName)) { conn.ConnectAsync().Wait(); var streamName = "MyStream"; var readResult = conn.ReadEventAsync(streamName, 0, true).Result; Console.WriteLine("{0} {1}", readResult.EventNumber, Encoding.UTF8.GetString(readResult.Event.Value.Event.Data)); } ... Link Step 2 - Read events from a stream and subscribe to changes | Event Store
read morePosts
Event Store - Read a Stream of Events with .NET API
要使用 Event Store .NET API 讀取 Event Store 特定 Stream 內的 Event,可以帶入 Stream 的名稱、起始的 Event 編號、以及預計要讀取的 Event 數,去調用 Connetction.ReadStreamEventsForwardAsync 方法。
... var readEvents = conn.ReadStreamEventsForwardAsync(streamName, start, count, true).Result; ... 然後再去讀取需要的 Event 資料即可。
... foreach (var evt in readEvents.Events) Console.WriteLine("{0} {1}", evt.Event.EventNumber, Encoding.UTF8.GetString(evt.Event.Data)); ... 像是這邊筆者有個 Stream 內含有 100 個相同資料的 Event。
就可以像下面這樣讀取特定範圍的 Event。
using EventStore.ClientAPI; ... using (var conn = EventStoreConnection.Create(connectionString, connectionName)) { conn.ConnectAsync().Wait(); var streamName = "MyStream"; var readEvents = conn.ReadStreamEventsForwardAsync(streamName, 10, 10, true).
read morePosts
Event Store - Appending to a stream in a single write with .NET API
要使用 Event Store .NET API 發送 Event 給 Event Store,可以先進行 Event Store 的連線。
連線後設定 EventData。
... var typeName = "MyType"; var data = new { Msg="Hello world!" }; var jsonData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); var eventData = new EventData(Guid.NewGuid(), typeName, true, jsonData, null); ... 呼叫 Connection.AppendToStreamAsync 將 EventData 送入 Event Store 指定的 Stream (ExpectedVersion 可用來決定是否要判斷 Stream 是否存在)。
... conn.AppendToStreamAsync(streamName, ExpectedVersion.Any, eventData); ... 程式寫起來會像下面這樣:
using EventStore.ClientAPI; using Newtonsoft.Json; using System; using System.Text; ... var connectionName = "MyConsole"; var connectionString = "ConnectTo=tcp://admin:changeit@localhost:1113; HeartBeatTimeout=500"; using (var conn = EventStoreConnection.
read morePosts
Event Store - Connect with .NET API
要使用 Event Store .NET API 連接 Event Store,先要安裝 EventStore.Client 套件。
加入 EventStore.ClientAPI 命名空間。
using EventStore.ClientAPI; 接著調用 EventStoreConnection.Create 取得 Connection 物件。
... using (var conn = EventStoreConnection.Create(...)) { ... } 調用 Connection 物件的 ConnectAsync 方法建立與 EventStore 的連線。
... conn.ConnectAsync(); ... 像是下面這樣,指定 Connection name 與 uri 建立出對應的連線物件,然後進行連線。
var connectionName = "MyConsole"; var uri = new Uri("tcp://admin:changeit@localhost:1113"); using (var conn = EventStoreConnection.Create(uri, connectionName)) { conn.ConnectAsync().Wait(); Console.ReadKey(); } 連線的建立可從 Web interface 的 Dashboard 頁面查閱,像是這邊 Connections 下就有剛所建立的 MyConsole connection。
read morePosts
Event Store - Subscribing to Receive Stream Updates with web interface
要透過 Web interface 去訂閱事件,可切換至 Persistent Subscriptions 頁面,點選 New Subscription 按鈕。
填寫 Group、 Stream…等資訊建立 Subscription。
切回到 Stream Browser 頁面發送 Event, Stream ID 需符合 Subscription 的 Stream 。
再回到 Persistent Subscriptions 頁面,可從 Subscription 的狀態因收到了 Event 而有所變動。
Link Step 2 - Read events from a stream and subscribe to changes | Event Store
read morePosts
Event Store - Streams projection
$streams 是 Event Store 預設提供的 Projection,可以將 Event Link 到一個集中的 Stream。
使用前需先將 $streams projection 開啟。
開啟後切到 Stream Browser 頁面,點選 Add Event 按鈕發送 Event。
這邊可一次發送了多個 Event 做個測試。
發送完切回 Stream Browser 頁面,會看到 $streams projection 會幫我們產生 $streams 這樣的 Stream。
點進去會看到剛所發送的 Event 都被 Link 在這個 Stream 內。
Link System Projections | Event Store
read morePosts
Event Store - By event type projection
$by_event_type 是 Event Store 預設提供的 Projection,可以將 Event 依 Event Type 拆分成到對應的 Stream。
使用前需先將 $by_event_type projection 開啟。
開啟後切到 Stream Browser 頁面,點選 Add Event 按鈕發送 Event。
這邊可一次發送了多個 Event 做個測試。
發送完切回 Stream Browser 頁面,會看到 $by_event_type projection 會幫我們產生 $et-[EventType] 這樣的 Stream。
Link
read morePosts
Event Store - By category projection
$by_category 是 Event Store 預設提供的 Projection,可以將 Event 依 Stream ID 去拆分成不同 Category 的 Stream。
使用前需先將 $by_category projection 開啟。
開啟後切到 Stream Browser 頁面,點選 Add Event 按鈕發送 Event。
Event 的 Stream ID 可依 [Category]-[ID] 這樣的格式下去定義。
這邊可一次發送了多個 Event 做個測試。
發送完切回 Stream Browser 頁面,會看到 $by_category projection 會幫我們產生 $ce-[Category] 這樣的 Stream。
裡面都是相同 Category 的 Event 。
$by_category projection 若有需要也可以做些調動,只要點選 Edit 按鈕。
對 Source 部份做些調動,Source 中的 first 是指第一個分隔符號,- 是指用來分隔的符號,這邊可以試著把 first 改為 last。
按下 Save 按鈕儲存。
$by_category project 就會依最後一個分隔符號下去切割 Category。
read morePosts
Event Store - Read a Stream of Events with HTTP API
要透過 HTTP API 去讀取 Stream 下的所有 Event,可以像下面這樣向 Event Store 查詢。
http://<URL>/streams/<STREAM_ID> Accept 可以指定回傳的格式是 JSON。
application/vnd.eventstore.atom+json 或是 XML。
application/atom+xml 像是如果要讀取 newstream Stream 下的所有 Event,就可以像下面這樣透過 CURL 發送請求給 Event Store。
curl -i -H "Accept:application/vnd.eventstore.atom+json" "http://127.0.0.1:2113/streams/newstream" Link Step 2 - Read events from a stream and subscribe to changes | Event Store
read morePosts
Event Store - Writing events with HTTP API
要透過 HTTP API 去發送 event,可以朝以下位置發送 Post。
http://<URL>/streams/<STREAM_ID> MediaType 可以是 JSON。
application/vnd.eventstore.events+json 也可以是 XML。
application/vnd.eventstore.events+xml Post 的內容需包含 eventId、eventType、data。
像是如果要發送個 Event 給 Event Store,就可以像下面這樣準備要發送的 Event 內容。
[ { "eventId": "fbf4a1a1-b4a3-4dfe-a01f-ec52c34e16e4", "eventType": "event-type", "data": { "a": "1" } } ] 然後使用 CURL 發送給 Event Store。
curl -i -d "@event.json" "http://127.0.0.1:2113/streams/newstream" -H "Content-Type:application/vnd.eventstore.events+json" Event Store 就會接收到剛發送的 Event。
read morePosts
Event Store - Install with docker
要透過 Docker 使用 Event Store,可以調用下列命令:
docker run --name eventstore-node -it -p 2113:2113 -p 1113:1113 eventstore/eventstore Docker 會下載 eventstore-node image。
然後會運行 Event Store 服務。
訪問 http://127.0.0.1:2113 即可看到 Event Store 的 Web 介面,若要登入可用帳號 admin 密碼 changeit 登入。
Link eventstore/eventstore - Docker Hub Step 1 - Install, run, and write your first event | Event Store
read morePosts
Event Store - Writing events with web interface
要透過 Web interface 去發送 event,可以將 Web interface 切換至 Stream Browser 頁面。
點擊 Add Event 按鈕。
填入要發送的 Event 資訊。
按下 Add 按鈕發送設定的 Event。
發送完回到 Stream Broser 頁面,可以看到剛剛所發送的 Event,點選即可查閱。
要查閱更為細部的資訊可點選 Event 後方的 JSON 字樣。
即可看到更為細部的資訊。
也可以透過點選 Event name 字樣。
一樣可看到更為細部的資訊。
read morePosts
Event Store - Install on Windows
要在 Windows 下使用 Event Store,首先需確定環境已安裝:
NET Framework 4.0+ Windows platform SDK with compilers (v7.1) or Visual C++ installed (Only required for a full build) 若環境已備妥,我們可選擇透過 Chocolatey 安裝 eventstore-oss 套件。
choco install eventstore-oss 或是至下載頁下載壓縮檔。
將之解壓縮也可以。
安裝完可調用下列命令將 Event Store 服務啟動。
EventStore.ClusterNode.exe --db ./db --log ./logs 服務啟動後訪問 http://127.0.0.1:2113,沒意外的話可以看到 Event Store 的 Web 介面,若要登入可用帳號 admin 密碼 changeit 登入。
透過這 Web 介面可以觀察到服務的狀況、發送 Event、管理帳號…等。
Link Event Store
read moreTag: Kafka
Posts
Kafka - Start consumer
要啟用 Consumer 去接收 Topic 的訊息,可調用 kafka-console-consumer.sh,帶入參數 –bootstrap-server 指定 Bootstrap server 位置、–topic 參數指定 Topic。
bin/kafka-console-consumer.sh --bootstrap-server [BootstrapServer] --topic [Topic] --from-beginning Link Apache Kafka
read morePosts
Kafka - Send messages
要使用 Kafka 發送訊息到指定的 Topic,可以調用 kafka-console-producer.sh,帶入參數 –broker-list 指定 broker 的位置、–topic 參數指定 topic。
bin/kafka-console-producer.sh --broker-list [Broker] --topic [Topic] Link Apache Kafka
read morePosts
Kafka - List topic
要列出 Kafka 的 Topic,可以調用 kafka-topics.sh,帶入參數 –list 指示要列出 topic、–zookeeper 參數指定 ZooKeeper 位置。
bin/kafka-topics.sh --list --zookeeper [ZooKeeper] Link
read morePosts
Kafka - Create topic
要建立 Kafka 的 Topic,可以調用 kafka-topics.sh,帶入 –create 參數指定創建 topic、–zookeeper 參數指定 zookeeper 位置、–topic 參數指定要創建的 topic。
bin/kafka-topics.sh --create --zookeeper [ZooKeeper] --replication-factor [ReplicationFactor] --partitions [Partitions] --topic [Topic] Link Apache Kafka
read morePosts
Kafka - Download and start kafka server
要使用 Kafka 首先須確定環境中有安裝 Java。
若沒有的話需先進行安裝。
接著下載 Kafka 程式。
wget http://ftp.mirror.tw/pub/apache/kafka/2.0.0/kafka_2.11-2.0.0.tgz 將下載下來的 Kafka 程式解壓縮。
tar -xzf kafka_2.11-2.0.0.tgz 進入解壓縮後的 Kafka 目錄。
cd kafka_2.11-2.0.0 啟動 ZooKeeper。
bin/zookeeper-server-start.sh config/zookeeper.properties 啟動 Kafka。
bin/kafka-server-start.sh config/server.properties Link Apache Kafka
read moreTag: Visual Studio Code
Posts
>-
使用 Visual Studio Code 撰寫 JavaScript,如果要加上 jsdoc comment,可以考慮為 Visual Studio Code 加裝 Add jsdoc comments 套件。
按下熱鍵 Ctrl-Shift-P / Cmd-Shift-P 開啟 command palette,輸入 Extensions:Install Extensions,輸入 Add jsdoc comments 找到擴充套件進行安裝。
安裝後重啟 Visual Studio Code。
在要加上 jsdoc comment 的程式碼上按下熱鍵 Ctrl-Shift-P / Cmd-Shift-P,或是透過滑鼠右鍵快顯選單開啟 command palette。
選取 Add Doc Comments。
jsdoc comment 即會被加到程式碼上,再視需要做些調整就可以了。
Link Add jsdoc comments - Visual Studio Marketplace
read morePosts
Visual Studio Code - Using .NET Core in Visual Studio Code
要用 Visual Studio Code 開發 .NET Core,需先安裝 .NET Core SDK。
然後安裝 Visual Studio Code 的 C# Extension。
C# Extension 安裝後進行重啟。
將 Visual Studio Code 切至專案目錄,透過 Terminal 視窗建立專案。
dotnet new [ProjectTemplate] 還原套件。
dotnet restore 運行結果。
dotnet run 若要除錯的話,需先建立 launch.json 檔。
將 program 位置設為專案輸出檔的位置,以筆者這邊的例子來說就是 “${workspaceRoot}/bin/BPC/Debug/netcoreapp1.1/Test.dll”。
再來建立 task.json 檔。
最後設斷點啟動除錯即可。
Link C# programming with Visual Studio Code .NET Core and Visual Studio Code Get started with C# and Visual Studio Code - C# Guide | Microsoft Docs
read morePosts
Visual Studio Code - Markdown preview
Visual Studio Code 要預覽 Markdown,可以按下熱鍵 Ctrl + Shift + P / Cmd + Shift + P 開啟 command palette,選取 Markdown:Open Preview。
或是使用熱鍵 Ctrl + Shift + V,即可切換至 Markdown 的預覽。
若是想要在預覽的同時做編輯,可以按下熱鍵 Ctrl + Shift + P / Cmd + Shift + P 開啟 command palette,選取 Markdown:Open Preview to the Side。
或是透過編輯區右上角的 Open Preview to the Side 按鈕。
抑或是按下熱鍵 Ctrl + K V / Cmd + K V,Markdown 預覽即會開在新的水平分割視窗,且在預覽畫面上滾動捲軸,編輯視窗的捲軸會跟著同步滾動。
read morePosts
vscode-icons - Icons for Visual Studio Code
vscode-icons 是 Visual Studio Code 的套件,能讓 Visual Studio Code 的 Explorer 對 Icon 的支援更好。
未安裝 vscode-icons 套件前 Visual Studio Code 的 Explorer 在檔案與目錄的顯示上缺少 Icon,檔案格式的識別或是目錄與檔案的識別都不容易。
按下熱鍵 Ctrl-Shift-P / Cmd-Shift-P 開啟 command palette,輸入 Extensions:Install Extensions,輸入 vscode-icons 找到 vscode-icons 擴充套件進行安裝。
安裝後重啟 Visual Studio Code。
重啟後啟用 vscode-icons 套件。
切到 Visual Studio Code 的 Explorer,即可看到 Visual Studio Code 的 Explorer 在檔案與目錄上都顯示了對應的 Icon。
Link vscode-icons - Visual Studio Marketplace File and Folder Icons in Visual Studio Code
read morePosts
vscode-hexo - VSCode extension to manage hexo commands
vscode-hexo 是 VSCode 的擴充套件,能讓我們在 VSCode 內簡易的調用 Hexo 命令。
按下熱鍵 Ctrl-Shift-P / Cmd-Shift-P 開啟 command palette,輸入 Extensions:Install Extensions,輸入 hexo 找到 vscode-hexo 擴充套件進行安裝。
安裝完後重啟 VSCode。
點選 [File | Open…] 將 Hexo 部落格目錄開啟。
按下熱鍵 Ctrl-Shift-P / Cmd-Shift-P,輸入 Hexo 即可看到可用的 Hexo 命令。
- hexo init # Initializes a website - hexo new # Creates a new article - hexo generate # Generates static files - hexo publish # Publishes a draft - hexo server # Starts a local server - hexo stop # stop a local server(Ctrl-C) - hexo deploy # Deploys your website - hexo clean # Cleans the cache file (db.
read morePosts
>-
在使用 Visual Studio Code 建置時如果看到 No build task defined. Mark a task with 'isBuildCommand' in the tasks.json file. 這樣的訊息,可能是因為 tasks.json 沒做設定導致。
可直接按下 Configure Build Task 按鈕。
選取 Task Runner。
調整 tasks.json 設定。
除了 tasks.json 沒設定外,還有個可能是因為 Visual Studio Code 沒載入設定導致,將 Visual Studio Code 重啟即可。
read morePosts
Visual Studio Code - Launch files in browser
要設定 Visual Studio Code 用瀏覽器開啟運行檔案,可開啟 Command palette (MAC 下使用 ‘CMD + Shift + P’,Windows 下使用 ‘Ctrl + Shift + P’) 選取 ‘Configure Task Runner’ 為專案加入 task.json。
MAC 下 task.json 可設定如下:
{ "version": "0.1.0", "command": "Chrome", "osx": { "command": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" }, "args": ["${file}"] } Windows 下設定如下:
{ "version": "0.1.0", "command": "Chrome", "windows": { "command": "C:\Program Files (x86)\Google\Chrome\Application
read morePosts
Visual Studio Code - Analyze Python with Pylint
要在 Visual Studio Code 中開發 Python 並使用 Pylint 進行程式碼的分析,Visual Studio Code 要先安裝 Python 的套件,完成 Python 開發環境的設定。
然後安裝 Pylint,不同環境有不同的安裝方式,因為筆者用的是 Mac,所以是用 pip 安裝。
沒有 pip 的話要先進行安裝。
開啟 Visual Studio Code 運行 Python 程式,Visual Studio Code 偵測到 Pylint 沒安裝的話會彈出通知,並提供安裝的按鈕。
點選安裝的按鈕,安裝命令會帶到 TERMINAL 視窗調用。
如果有權限問題的話,還是需要自己調整命令後再調用。
安裝好後就可以支援 Python 的分析。
Link Pylint - code analysis for Python | www.pylint.org
read morePosts
Visual Studio Code - Debug with Visual Studio Code
要用 Visual Studio Code 進行程式碼的除錯,可透過 Visual Studio Code 左側的工具列切換至除錯畫面。
接著在程式碼欲中斷的程式碼位置前方用滑鼠點擊設置中斷點。
再按下 Debug 按鈕即可開始進行程式碼的除錯。
在程式碼進行除錯時,Visual Studio Code 會帶出變數資訊、呼叫堆疊、中斷點的控制設定及工具列等。
如有自己想要查看的變數,可按下滑鼠右鍵,選取 Debug: Add to Watch 選單選項。
變數即會被加入 WATCH 視窗,便於後續查看。
read morePosts
Visual Studio Code - Install extensions
要安裝 Visual Studio Cdoe 的外掛套件,可按下熱鍵打開 Command Palette (Windows 為 Ctrl+ Shift + P, OS X 為 CMD + SHIFT + P),搜尋並運行 Extensions:Install Extensions。
或是直接透過左邊的工具列按鈕開啟 Extensions:Install Extensions。
接著搜尋欲安裝的外掛套件後按下 Install 按鈕。
選取的外掛套件即會開始進行安裝。
安裝完後按下 Reload 按鈕讓安裝的外掛套件生效。
再次按下 Reload Window 按鈕確認 Reload 即可。
read morePosts
Visual Studio Code - Python on Visual Studio Code
要在 Visual Studio Code 使用 Python,可安裝 Visual Studio Code 的 Python 套件。
套件安裝完按下熱鍵打開 Command Palette (Windows 為 Ctrl+ Shift + P, OS X 為CMD + SHIFT + P),搜尋並運行 Tasks: Configure Task Runner。
接著選取 TypeScript - tsconfig.json。
修改 tasks.json 設定,command 設為 python、args 設為 ${file}、showOutput 設為 always。
設定修改完存檔,按下熱鍵運行 Tasks: Run Build Task (Windows 為 Ctrl+ Shift + B, OS X 為CMD + SHIFT + B),即可運行 Python 程式。
Link Python with Visual Studio Code [Python] 使用 Visual Studio Code 作為開發環境
read morePosts
Visual Studio Code - Check for updates
要更新 Visual Studio Code,可點選 [Code | Check For Updates…] 選單選項。
Visual Studio Code 會開始檢查是否有可用的更新。
然後開始安裝更新。
更新安裝後 Visual Studio Code 會出現提示 Visual Studio Code will be updated after it restarts.,告知我們可以套用更新,這邊可以按下 Update Now 按鈕立即套用更新,或是按下 Later 按鈕暫緩套用,抑或是按下 Release Notes 按鈕查閱這次的更新有什麼變更。
這邊按下 Update Now 按鈕繼續。
Visual Studio Code 重啟後更新就套用上去了。
read moreTag: Oracle SQL Developer
Posts
Oracle SQL Developer - Import data modeler from DDL file
在維護 Data Modeler 時,若已有現成的 DDL File,可以點選 [File | Data Modeler | Import | DDL File] 主選單選項。
將要匯入的 DDL File 加入,按下 OK 按鈕。
選取資料庫類型,按下 OK 按鈕繼續。
這邊會帶出匯入的資訊,按下 Close 按鈕關閉。
然後會帶出 Compare Models 視窗。
透過該視窗可以清楚知道有什麼會被匯入,我們也可以視需要調整要匯入的東西,匯入前可以按下 DDL Preview 按鈕確認一下會做的調動,若無問題則按下 Merge 按鈕進行匯入。
匯入完成就可以在 Data Modeler 上看到匯入的東西。
read morePosts
Oracle SQL Developer - Formatting PL/SQL code
要使用 Oracle SQL Developer,可點選 [Tools | Preferences…] 主選單選項。
將開啟的 Preferences 視窗切至 [SQL Formatter | Oracle Formatting] 頁面,選取 Profile 後按下後方的 Edit 按鈕。
依個人喜好調整設定。
設定調整好後可在程式碼上按下滑鼠右鍵,點選 Format 選單選項觸發整理程式碼。
read morePosts
Oracle SQL Developer - SQL code editor templates
Oracle SQL Developer 可透過 [Tools | Preferences…] 主選單選項開啟 Preferences 視窗。
切換至 [Debug | SQL Editor Code Templates]。
已內建一些 Template 可供使用,像是 #time#。
可用以帶入當前的時間。
#date# 可用以帶入當前的日期。
若有需要也可以自行增加 Template 使用。
read morePosts
Oracle SQL Developer - Change GUI language
要變更 Oracle SQL Develop 界面的語言,可先開啟 idein\ide.boot 檔。
查閱 oracle.translated.locates 設定中可支援的語言有哪些。
再來開啟 sqldeveloperin\sqldeveloper.conf 檔。
將 AddVMOption -Duser.language 設定值設為欲使用的語言,然後重啟 Oracle SQL Developer。
Oracle SQL Developer 就會變成指定的語言界面。
read morePosts
Oracle SQL Developer - Source code control with subversion
Oracle SQL Developer 要使用 Subversion 進行程式碼的版本控制,首先要建立連線。
可以透過 [Team | Subversion | Create Connection…] 選單選項進行連線的建立。
選取 Manually Create a Subversion Connection 後按下 OK 按鈕。
輸入 Subversion Repository 位置、連線名稱、帳號、密碼建立連線。
連線建立完成即可在 Versions 看到剛所建立的連線。
連線建立後要透過 Check Out… 滑鼠右鍵選單選項進行檔案的 Check Out。
設定 Check Out 下來的位置。
若有需要也可以指定 Check Out 的版本。
設定好按下 OK 按鈕繼續。
Check Out 下來後透過 Files 視窗瀏覽檔案可看到檔案的版控狀態。
後續也可以直接透過 Oracle SQL Developer 進行 Commit 之類的版控動作。
read morePosts
Oracle SQL Developer - Look and Feel
Oracle SQL Developer 可以支援 Look 與 Feel 的調整,所謂的 Look 指的是 Widgets 畫面的外觀,Feel 指的是 Widgets 的行為。
透過 Look and Feel 的設定調整,可以讓 Oracle SQL Developer 的外觀與操作更類似於我們習慣的環境,操作上會更為順手。
要設定 Look and Feel,首先必須要點選 [Tools | Perferences…] 主選單選項。
點選切換至 Environment 頁籤,即可對 Look and Feel 進行設定。
像是如果對 Windows 應用程式的操作比較熟悉的話就可將之切換至 Windows 設定。
設定完 Oracle SQL Developer 會需要進行重啟。
重啟後 Oracle SQL Developer 的外觀與操作就會接近一般的 Windows 應用程式。
read morePosts
Oracle SQL Developer - Unit testing
要用 Oracle SQL Developer 撰寫單元測試,可點選 [View | Unit Test] 主選單選項。
將 Unit Test 視窗開啟。
點選 [Tools| | Unit Test | Select Current Repository…]。
選取 Connection。
如果 Connection 未建立過 Unit Test 的 Repository,Oracle SQL Developer 可直接幫我們建立。
連到 Repository 後,Unit Test 視窗就會多出 Library、Lookups、Reports、Suites、Tests 這些目錄。
我們可以直接在 SP 上或是 Unit Test 視窗上按下滑鼠右鍵,點選 Create Test… 滑鼠右鍵快顯選單,開始建立 Unit Test。
選取要撰寫 Unit Test 的 SP。
設定 Unit Test 的名稱。
設定 Unit Test 前要做的前置動作。
設定 SP 運行時所需要的參數。
設定 Unit Test 的驗證部分。
read morePosts
Oracle SQL Developer - Snippets
要使用 Oracle SQL Developer 的 Snippets 功能,我們可以點選 [ View | Snippets ] 主選單選項。
將 Snippets 視窗帶出後,可以看到 Oracle SQL Developer 已經內建了許多的 Category。
每個 Category 都有對應的 Snippets。
若內建的 Category 不敷使用,這邊也可以自己建造 Snippet。
像是這邊筆者建立了一個新的 Snippet 在新的 Category,建立完就可以馬上看到建立出來的 Category。
以及建立的 Snippet。
Snippet 的使用只要將之拖曳至 SQL 視窗。
Snippet 就會被帶到 SQL 視窗
自定義的 Snippet 會設定在 %appdata%\SQL Developer\UserSnippets.xml,有需要匯入匯出可從這邊下手。
read morePosts
Oracle SQL Developer - Custom date time format
Oracle SQL Developer 預設 Date Format 設定為 DD-MON-RR,顯示上是不含時間的部分。
{% img /images/posts/OracleSQLDeveloperCustomDateFormat/1.png %}
若要顯示時間的部分,我們需點選 [Tools | Preference] 主選單選項,將開啟的 Preferences 對話框切至 [Database | NLS] 頁面,在 Date Format 這邊將時間的部分設定上去。
{% img /images/posts/OracleSQLDeveloperCustomDateFormat/2.png %}
像是這邊筆者是將之設定成 YYYY-MM-DD HH24:MI:SS 這樣。
Link How can I set a custom date time format in Oracle SQL Developer? - Stack Overflow
read morePosts
Oracle SQL Developer - PL/SQL Syntax Colors
Oracle SQL Developer 預設的的 Syntax Color 若不習慣,我們可以開啟 Perferences 對話框,在 [Code Editor | PL/SQL Syntax Colors] 下做些修改,將之調成我們習慣的樣式。
不太會調整的也可以直接換用 Scheme。
{% img /images/posts/OracleSQLDeveloperSyntaxColors/1.png %}
要注意的是,若這邊換用的是 Twilight Scheme,由於底色太暗,會看不到當前輸入的游標,因此要在切到 [Code Editor | Caret Behavior] 下設定 Caret Color,將輸入游標調成淺色系。
{% img /images/posts/OracleSQLDeveloperSyntaxColors/2.png %}
read morePosts
Oracle SQL Developer - Show query result in new tabs
Oracle SQL Developer 預設 Query 出來的結果會在同一個 Query Result 視窗,若要讓每次 Query 都在個別的視窗,我們可以開啟 Perferences 對話框,在 [Database | Worksheet] 下勾選 Show query results in new tabs 選項。
{% img /images/posts/OracleSQLDeveloperQueryResultInNewTabs/1.png %}
這樣每次 Query 結果就會在獨立的 Query Result 視窗中。
{% img /images/posts/OracleSQLDeveloperQueryResultInNewTabs/2.png %}
read morePosts
Oracle SQL Developer - Drop sequence
要使用 Oracle SQL Developer 將指定的 Sequence 移除,可以找到指定的 Sequence,在其上按下滑鼠右鍵,點選 [Drop…] 滑鼠右鍵選單選項。
{% img /images/posts/DropSequenceWithOracleSqlDeveloper/1.jpg %}
在彈出的 Drop 對話框中會顯示所要移除的 Sequence,確定無誤後按下 Apply 按鈕套用。
{% img /images/posts/DropSequenceWithOracleSqlDeveloper/2.jpg %}
完成後當彈出 Confirmation 對話框告知。
{% img /images/posts/DropSequenceWithOracleSqlDeveloper/3.jpg %}
read morePosts
Oracle SQL Developer - Drop table column
要使用 Oracle SQL Developer 將指定的表單欄位移除,可以將表單開啟,在 Columns 頁面按下滑鼠右鍵,點選 [Column | Drop…] 滑鼠右鍵選單選項。
{% img /images/posts/DropColumnWithOracleSqlDeveloper/1.jpg %}
在彈出的 Drop 對話框中下拉選取所要移除的表單欄位。
{% img /images/posts/DropColumnWithOracleSqlDeveloper/2.jpg %}
選取完後按下 Apply 按鈕套用。
{% img /images/posts/DropColumnWithOracleSqlDeveloper/3.jpg %}
按下後 Oracle SQL Developer 會開始進行指定表單欄位的移除動作。
{% img /images/posts/DropColumnWithOracleSqlDeveloper/4.jpg %}
完成後當彈出 Confirmation 對話框告知。
{% img /images/posts/DropColumnWithOracleSqlDeveloper/5.jpg %}
read moreTag: SonarQube
Posts
SonarCloud - Project badges
要使用 SonarCloud 的 Project badges,可以到 SonarCloud 的 Project 頁面,點選右下角的 Get project badges 按鈕。
選取要使用的 Project badges 與 Metric。
按下 Copy 按鈕複製 Project badges 的位置。
在要放置 Project badges 的位置上將之視為圖檔放置。
放置完後續我們就可以透過該 Project badges 知道目前專案的狀況。
read morePosts
SonarCloud - Use SonarQube as a Service
SonarQube 除了自行架設外,也提供了線上的版本可供使用,開源專案可以免費使用。
透過點擊 SonarQube 網站上的 USE ONLINE 按鈕可直接連結過去。
選擇要使用的登入帳號。
登入後會看到 SonarQube 的介面,點選 Analyze new project 開啟一個新的專案。
選取專案所屬的組織。
產生後續認證要用的 Token 或是直接使用已經存在的 Token。
選取專案的主要開發語言。
選取所使用的作業系統。
設定專案的 Project key。
右側會帶出 Sonar scanner 的下載位置以及所屬作業系統下的指令下法,這邊可以按下 Copy 按鈕先將指令複製下來。
點選 Finish this tutorial 結束設定。
設定完會看到對應的專案已被建立在 SonarQube 上。
在專案程式目錄下實際調用剛剛所複製的命令,SonarQuber Scanner 即會開始分析專案程式,並將分析的結果送至 SonarQube。
分析完就可以在 SonarQube 的專案頁面看到分析的結果。
Link Continuous Inspection | SonarQube
read morePosts
sonar-tsql-plugin - Repository for T-SQL language plugin for Sonar
sonar-tsql-plugin 是用來分析 T-SQL 的 SonarQube 套件,支援 14 的微軟內建的 analysis rules,以及 120 個 SQL Code Guard analysis rule。
套件可在 GitHub - gretard/sonar-tsql-plugin: Repository for T-SQL language plugin for Sonar 這邊下載,並透過手動的方式安裝套件。
套件安裝完後因為該套件無實作設定頁面,因此要到 Rules 頁面確認套件的安裝狀態,安裝成功的話應該可以在左側看到 T-SQL。Rule 預設是未啟用的,這邊也可以順帶啟用。
除了 Rule 的設定外,因為該套件只是簡單的將他跟 Visual Studio 的資料庫專案與 SQL Code Guard 整合,所以用 MSBuild建置時需加帶 /p:RunSqlCodeAnalysis=true 參數,且在 SonarQube 設定檔中加設定 sonar.tsql.cg.path,將該設定值指到 SQL Code Guard 運行檔的位置。
最後一提,如同上面所述,該套件並未實作設定頁面,所以一切設定都設在設定檔,要查閱該套件可做的設定的話,可參閱Configuration · gretard/sonar-tsql-plugin Wiki · GitHub這邊。
Link GitHub - gretard/sonar-tsql-plugin: Repository for T-SQL language plugin for Sonar
read morePosts
SonarQube - Integrate with GitLab
要將 SonarQube 與 GitLab 整合,讓 GitLab 簽入或是發送 MergeRequest 時可透過 SonqrQube 進行分析,即早發現程式的問題,SonarQube 需先透過 Update Center 安裝 GitLab 套件。
SonarQube 的 GitLab 套件安裝好後進行 SonarQube 的重啟。
重啟完後進入 Administration 的 General Settings 頁面,切至 GitLab 頁籤進行相關的設定。
最主要的設定有兩個,一個是 GitLab url,需填入 GitLab 服務的位置。
另外一個是 GitLab User Token,讓 SonarQube 可以存取 GitLab 用。這樣當 GitLab 觸發 SonarQube 分析完,SonarQube 才可以將分析的結果放至 GitLab 上。
這邊輸入的 GitLab User Token 是 GitLab 的 Access Token,可在 GitLab 的 [UserSettings | Access Tokens] 取得。
SonarQube 的 GitLab 套件安裝並設定好後,接著要進行 GitLab CI 的設定。只要在 GitLab CI 的設定檔中像下面這樣調用 SonarScanner 觸發 SonarQube 分析即可。
read morePosts
>-
運行 SonarQubeAnalyze 後如果看到 ERROR: JAVA_HOME exists but does not point to a valid java home folder 這樣的錯誤訊息。
我們可能會查閱系統中的 JAVA_HOME 環境變數,且查驗該環境變量所指定的位置是否存在,及是否指到正確的目錄。。。等。
查驗過後你可能會發現一切都是正常的卻運行不起來。這是因為在 SonarQubeAnalyze 檔中有去設定 JAVA_HOME 的位置,該位置並非環境變量所指定的位置,而是指到 sonar-scanner 下的 jre 目錄。
所以問題發生的話,可以檢查一下 sonar-scanner 下的 jre 目錄看看。像是筆者碰到的狀況就是因為沒將檔案加入並上傳到 git,從 git 拉下來的 jre 目錄在有少檔的狀況下就無法正常的運作。
read morePosts
SonarQube - Downgrade database
若 SonarQube DB 升級過後想要使用回舊版本的 SonarQube,會發現資料庫已經不相容於舊版本的 SonarQube DB。
這時將 SonarQube DB 刪除後重建。
DROP DATABASE sonar; CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci; 舊版本的 SonarQube 服務就可以正常運作了。
read morePosts
SonarQube - Analyzing with SonarQube Scanner
要使用 SonarQube 進行程式碼分析,並將分析結果送至 SonarQube Server,最簡單的就是使用 SonarQube Scanner。
先至官網將 SonarQube Scanner 下載下來。
下載下來後直接解壓即可使用,其命令使用方式如下:
usage: sonar-scanner [options] Options: -D,--define <arg> Define property -e,--errors Produce execution error messages -h,--help Display help information -v,--version Display version information -X,--debug Produce execution debug output 其中比較常用的就是參數 -D,–define,可用來定義 SonarQube 分析所需要的屬性,像是 sonar.host.url 屬性用來指定 SonarQube 的位置、sonar.projectName 用來指定 SonarQube 的 Project name、sonar.projectVersion 用來指定 SonqrQube 的 Project version、sonar.projectKey 用來指定 Sonarqube 的 Project key、sonar.log.level 用來指定分析運行時的 log 層級…等。
除了透過 -D,–define 將這些屬性用參數帶入設定外,也可以使用設定檔,只要將屬性的設定寫在名為 sonar-project.properties 檔案。
這樣運行分析時也只需要直接調用 sonar-scanner。
read morePosts
SonarQube - System upgrades
要進行 SonarQube 的系統升級,目前 Update Center 只支援查閱更新以及告知升級的步驟,尚未支援自動升級,需要自行手動升級。
可以先下載新版的 SonarQube 程式。
將舊的 SonarQube 服務停止。
停止後將舊的服務移除。
將舊的 SonarQube 設定與套件放到新的 SonarQube。
再將新的 SonarQube 服務安裝。
將安裝好的服務啟動。
即完成 SonarQube 的系統升級。
read morePosts
SonarQube - Project management
要將程式送到 SonarQube 進行分析,首先必須要在 SonarQube 建立 Project。
可點擊 [Administration | Projects | Management] 選單選項開啟 Project management 頁面。
點選 Project management 頁面右上方的 Create Project 按鈕。
設定 Project 的 Name 與 Key 後按下 Create 按鈕。
Project 即建立完成。
接著點選 Project 名稱進入 Project 管理頁面,這邊的 Administration 下有些設定可適需要做些調整。
像是可能要調整要分析的副檔名,就可以到 General Settings 頁面做對應的設定。
要指定專案所使用的 Quality Profile,可到 Quality Profiles 頁面設定。
要指定專案所使用的 Quality Gate,可到 Quality Gate 頁面設定。
read morePosts
SonarQube - Quality Gates
Quality Gate 是產品要上到正式環境所要滿足的條件,可在 SonarQube 的 Quality Gates 頁面管理,可以點選 Create 按鈕新增,或是點選 Quality Gate 的名稱進一步的管理。
點選 Quality Gate 名稱後,可以在導到的頁面調整 Quality Gate 所要滿足的條件。可以設定新的程式碼要小於多少分才後會是 Warning 或是 Error。
若有需要該頁面也可以針對 Quality Gate 的名稱進行修改,或是 Quality Gate 的複製、設定/取消預設使用、以及 Quality Gate 的刪除。
read morePosts
SonarQube - Quality Profiles
SonarQube 的 Quality Profiles 頁面提供我們查詢可供分析的 Profile。
Profile 為分析 Rule 的集合,多半會造著語言或是套件下去區分。透過 Quality Profiles 頁面我們可以新增 Profile、查看 Profile 的 Rule 數、查看上次使用的時間…等。
點選 Profile 的名稱可進一步進入 Profile 管理頁面。在這頁面我們可以看到 Profile 所使用的 Rule、與設定 Profile 的繼承關係。
在進行程式碼分析之前可先透過該頁面確認 Profile 的 Rule 啟用狀態,因為有時套件安裝的 Profile 其 Rule 預設是未啟用的狀態,或是某些想要分析的 Rule 並未被啟用,這時可以按下 Active More 按鈕切到 Rules 頁面,透過 Rules 頁面將之啟用。
read morePosts
SonarQube - Rules
SonarQube 的 Rules 頁面提供我們查詢可供分析的 Rule。
可以依照語言、類行、Repository…等條件下去過濾 Rule。
可透過該頁面啟用/停用 Rule、查閱 Rule 的細部說明、以及查看程式中是否有相關的 Issue。
read morePosts
Jenkins - Quality Gates Plugin
Jenkins 安裝 SonarQube Plugin 後,雖然能用 Jenkins 分析程式並將分析結果送至 SonarQube,但是不論分析的結果是否有通過 SonarQube Quality Gate, Jenkins 的 job 都是會過。
若要讓 Jenkins job 依照 SonarQube Quality Gate 通過與否去決定建置的成功狀態,可以為 Jenkins 安裝 Quality Gate Plugin。
安裝完後進入 Jenkins 的 設定系統 頁面。
在 Quality Gates 這邊按下 ADD SONAR INSTANCE。
設定 SonarQube 的名稱與位置。
接著到 Job 組態這邊設定建置後動作,使用 Quality Gates 套件,帶入 Project Key。
這樣 Job 在運行時最後就會開始運行 Quality Gates 套件。
Job 的建置狀態就會依 Quality Gates 通過與否去決定。
read morePosts
Jenkins - SonarQube Plugin
如果要將 SonarQube 整合 Jenkins,讓 Jenkins 幫我們運行並將分析送到 SonarQube,可以使用 Jenkins 的 SonarQube Plugin。
先將 Jenkins 安裝 SonarQube Plugin。
安裝完後開啟 Jenkins 的組態設定,設定 SonarQube Server 的資訊。
接著開啟 Jenkins 的 Global Tool Configuration,讓 Jenkins 進行 SonarQube Scanner 的安裝。
安裝與設定都好了後,就可以在 job 的建置這邊使用 Execute SonarQube Scanner 做 SonarQube 分析的設定,語法可參閱 SonarQube Scanner 的設定方式(主要的設定就是 projectKey、projectName、與 sources)。
read morePosts
SonarQube - Manual setup plugins
SonarQube 有些套件未放置在 Update Center,無法透過 Update Center 進行安裝,必須自行手動安裝。
這邊以 PL/SQL Cop 的 SonarQube 套件為例做個示範,先將套件下載下來。
將下載的套件放置於 extensions\plugins 下(不用解壓縮)。
接著將 SonarQube 的服務重啟。
重啟後安裝的套件即會生效。因為多半的套件會有設定頁面,像是這邊示範的 PL/SQL Cop 套件就有,所以可以先從設定頁面這邊做個初步的確認。
read morePosts
SonarQube - Setup/update/remove plugins with Update Center
SonarQube 提供 Update Center 可以讓我們很容易的控管 SonarQube 外掛套件。要使用 Update Center,可點選 [Administrator | System | Update Center]。
Update Center 中的 Installed 頁面會列出所有已安裝的套件,Updates Only 頁面會列出所有可更新的套件,Available 頁面會列出所有可安裝的套件。
套件列表後方的按鈕可供我們安裝、更新、或是移除套件。
按下後會將對應的動作 Queue 起來等待運行,當確定要運行時可按下上方的 Restart 按鈕。
再次按下 Restart 按鈕確認。
就會開始運行對應的動作並將服務重啟。
重啟後對應的設定即會生效。
read morePosts
SonarQube - Setup MySQL database
要讓 SonarQube 使用 MySQL 資料庫,需先在伺服器中安裝 MySQL 資料庫。
接著要設定 MySQL 資料庫,可先將下列 SQL 語法存放至副檔名為 SQL 的檔案 (這邊筆者選用 create_database.sql)。
CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE USER sonar@localhost IDENTIFIED BY 'password'; CREATE USER sonar@'%' IDENTIFIED BY 'password'; GRANT ALL ON sonar.* TO sonar@localhost; GRANT ALL ON sonar.* TO sonar@'%'; 接著使用 mysql -u -root -p < create_database.sql 將 SQL 送到 MySQL 運行。
然後要設定 SonarQube 的設定檔 sonar.properties,sonar.jdbc.username 與 sonar.jdbc.password 這邊要設定 MySQL 的帳密,sonar.jdbc.url 設定這邊要將註解拿掉。
read morePosts
SonarQube - Failed to start SonarQube windows service
在啟動 SonarQube windows service 食,有可能會看到像下面這樣的畫面:
如果是透過 Services 視窗啟動的畫,會看到像下面這樣的畫面:
這時可以檢查任務管理員是否有殘留的 java.exe 與 conhost.exe,有的話將之刪除,再次啟動應該就可以了。
read morePosts
SonarQube - Setup SonarQube windows service
要設定 SonarQube Windows 服務,只要運行 InstallNTService.bat 檔即可。
運行完,SonarQube 的 Service 就安裝設定完畢了。
接著要將剛安裝的服務啟動,這邊看是要透過運行 StartNTService.bat 檔,或是透過 Services 視窗將服務啟動都可以。
到這邊服務已經安裝並運行起來了,沒意外的話 SonarQube 已經可以正常使用了。
後續如果要停止或是移除 SonarQube 服務,這邊也都有對應的 bat 檔可供直接叫用。
read morePosts
SonarQube - Failed to create an empty directory
SonarQube 運行 Pre-processing 時,可能會拋出 Failed to create an empty directory 這樣的錯誤訊息。
這錯誤是因為 SonarQube 運行時會需要建立一個 .sonarqube 的目錄,該目錄如果因位檔案佔住無法刪除就會發生這樣的錯誤。
這問題發生時可以查看任務管理員,看看是否有殘留的 MSBuild 在背後運行,如果有將之刪除即可。
read morePosts
SonarQube - Unsupported major.minor version 52.0
SonarQube 如果出現 Unsupported major.minor version 52.0 這樣的錯誤。
代表 JRE 與 JDK 版本對不起來,可以安裝對應的版本,然後用 Java -version 與 Javac -version 確認看看。
確認版本是對的後再次運行 SonarQube,應該就可以了。
read morePosts
SonarQube - Remote access
SonarQube 裝完後若未做任何修改,只能透過本地存取服務。
如果要開放遠端存取服務,可開啟 conf\sonar.properties 設定檔進行設定。像是將 sonar.web.host 設為 0.0.0.0,或是透過設定 sonar.web.port 改變 port 號。
read morePosts
SonarQube - Analyzing with SonarQube scanner for MSBuild from the command line
要使用 SonarQube scanner for MSBuild 在命令列下進行程式碼的掃描,需先確保 .NET Framework 有到 4.5.2 以上的版本,以及 jre 有到 7u75 以上的版本。
接著下載 SonarQube scanner for MSBuild 後將其解壓縮。
再來要開啟 SonarQube.Analysis.xml 設定 SonarQube 的位置以及認證的資訊。
設定完後運行 MSBuild.SonarQube.Runner.exe begin 開始分析。
MSBuild.SonarQube.Runner.exe begin /k:"sonarqube_project_key" /n:"sonarqube_project_name" /v:"sonarqube_project_version" 接著用 MSBuild 建置要分析的專案。
最後運行 MSBuild.SonarQube.Runner.exe end 停止分析。
MSBuild.SonarQube.Runner.exe end 分析完的結果就會送到 SonarQube 上。
Link
read morePosts
SonarQube - Getting started
要試用 SonarQube 我們只需將 SonarQube distribution 下載下來解壓縮,並運行 StartSonar.bat。
這樣服務就運行起來了。
接著用瀏覽器瀏覽 http://localhost:9000 即可開始體驗 SonarQube。
如果需要進一步管理 SonarQube,可以用 admin/admin 登入。
Link SonarQube™ » Download Get Started in Two Minutes - SonarQube Documentation - SonarQube
read moreTag: Rest
Posts
Rest - Safe/Idempotent method
Rest API 的方法依其性質可以被劃分為 Safe method 或是 Idempotent method。
Safe method 也就是安全的方法,表示該方法不會對資源進行任何的修改,且其結果可以被快取。GET 與 HEAD 屬於這類方法。
Idempotent method 也就是冪等方法,表示該方法重複調用的結果都是相同的, GET、PUT、DELETE、HEAD、OPTIONS 屬於這類方法。
POST、PATCH 則兩類方法都不是。
了解 HTTP Method 屬於 Safe method 還是 Idempotent method,可讓我們清楚識別 API 應該使用哪種 HTTP method,也可以了解 HTTP method 在實作上所應該做的處理。
最後附上對應總表:
Method Safe Indempotent GET Y Y POST N N PUT N Y DELETE N Y PATCH N N HEAD Y Y OPTIONS Y Y Link 程式設計 - 簡明RESTful API設計要點 - Twincl 哪些是冪等或/且安全的方法? - RESTful 手冊 RFC 7231 - Hypertext Transfer Protocol (HTTP/1.
read moreTag: Machine Learning
Posts
One-Hot Encoding
One-Hot Encoding 是一編碼方式,使用 N 位狀態寄存器來對 N 個狀態進行編碼,常被用於機器學習中的資料前處理,特別是無序的類別資料。
像是性別資料 Male 與 Female,雖然可以用數值編碼將之編成 0 與 1 之類的數值。
Male => 0 Female => 1 但是這樣當我們以座標空間來表示這些資料時,這些無序資料距離原點的距離就會有所差異,不利於機器學習。
如果改用 One-Hot Encoding,將每個類別資料都給予一個維度來存放狀態值 (第一個 Bit 用以存放 Male 的狀態,第二個 Bit 用以存放 Female 的狀態),那這些無序資料距離原點的距離就都會一樣,無大小之分。
Male => 01 Female => 10 Link 特徵提取方法: one-hot 和 IF-IDF - 掃文資訊 One-hot - Wikipedia Why One-Hot Encode Data in Machine Learning? [資料分析&機器學習] 第2.4講:資料前處理(Msssing data, One-hot encoding, Feature Scaling)
read moreTag: TensorFlow
Posts
TensorFlow - placeholder
TensonrFlow 的 placeholder 方法可用來指定後續運行才會帶入的值,其函式原型如下:
tf.placeholder( dtype, shape=None, name=None ) 其中 dtype 是值的型態,shape 是常數的維度。
可以直接調用 placeholder 方法並帶入指定的型態。
... a = tf.placeholder(tf.float32) ... 也可以帶入 shape 限定維度。
... b = tf.placeholder(tf.float32, shape=(2, 3)) ... 然後使用 placeholder 構成運算。
... a2 = a * a ... bPlus = b + 1 ... 最後用 feed_dict 帶入 placeholder 的值去運行即可。
... print(sess.run(a2, feed_dict={a: 2})) print(sess.run(a2, feed_dict={a: [[1, 2, 3], [4, 5, 6]]})) print(sess.run(bPlus, feed_dict={b: [[1, 2, 3], [4, 5, 6]]})) .
read morePosts
TensorFlow - Variable
TensorFlow 可以直接調用 Variable 方法並將變數值帶入以建立對應的變數。
... a = tf.Variable(2) ... 變數值也可以是一為陣列。
... b = tf.Variable([1, 2, 3, 4, 5, 6, 7]) ... 或是多維陣列。
... c = tf.Variable([[1, 2, 3], [4, 5, 6]]) ... 最重要的是要記得變數在使用時需要做初始才可使用。
... tf.initialize_all_variables().run(session = sess) ... 最後附上完整的範例程式:
import tensorflow as tf a = tf.Variable(2) b = tf.Variable([1, 2, 3, 4, 5, 6, 7]) c = tf.Variable([[1, 2, 3], [4, 5, 6]]) sess = tf.Session() tf.initialize_all_variables().run(session = sess) sess.run(a) sess.
read morePosts
TensorFlow - Constant
TensonrFlow 的 constant 方法可用來建置 TensorFlow 的常數,其函式原型如下:
tf.constant( value, dtype=None, shape=None, name='Const', verify_shape=False ) 其中 value 表示常數的值,dtype 是值的型態,shape 是常數的維度。
可以直接調用 constant 方法並將常數值帶入以建立對應的常數。
... a = tf.constant(2) ... 常數值也可以是一為陣列。
... b = tf.constant([1, 2, 3, 4, 5, 6, 7]) ... 或是多維陣列。
... c = tf.constant([[1, 2, 3], [4, 5, 6]]) ... 數值的型態 constant 方法會自動識別,但若有需要也可以直接透過 dtype 指定。多維陣列元素若是相同值,可以使用 shape 輔助設定,設定特定維度且特定常數值的常數。
... d = tf.constant(-1, shape = [2, 3], dtype = tf.float32) ... 最後附上完整的範例程式:
import tensorflow as tf a = tf.
read morePosts
TensorFlow - Getting started
安裝完 TensorFlow 後,可以試著撰寫個簡單的 Hello World 程式。
首先我們需將 tensorflow 匯入。
import tensorflow as tf ... 設定一個常數其內容為 “Hello World!"。
... hello = tf.constant("Hello World!") ... 再來要取得 TensorFlow 的 Session,可以把 Session 想成運行 TensorFlow 的環境。
... sess = tf.Session() ... 將要運行的部分送至 Session 中運行。
... print(sess.run(hello)) 最後記得要將 Session 關閉。
... sess.close() 完整的程式會像下面這樣:
import tensorflow as tf hello = tf.constant("Hello World!") sess = tf.Session() print(sess.run(hello)) sess.close() 運行結果如下:
也可以搭配使用 with as 寫法,這樣就不需要明確的調用 session.close()。
import tensorflow as tf hello = tf.
read morePosts
TensorFlow - Install TensorFlow on MAC
要在 MAC 下安裝 TensorFlow,可以直接透過 pip 安裝,也可以透過 Virtualenv 等方法安裝。
這邊筆者使用 Virtualenv,所以要先安裝 Virtualenv。
sudo pip install 00upgrade virtualenv 創建一個沙盒。
virtualenv --system-site-packages ~/tensorflow 啟動沙盒環境。
source ~/tensorflow/bin/activate 最後透過 pip 將 TensorFlow 安裝起來即可。
pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.11.0rc0-py2-none-any.whl 安裝完後可以使用 python 測試一下 TensorFlow 是否已可正常使用,輸入 python 命令進入交互模式,引用 tensorflow 套件,調用 version 查閱 TensorFlow 的版本。
import tensorflow as tf tf.__version__ Link 在Mac OS X上安装TensorFlow - 纯净的天空
read morePosts
TensorFlow - Installing TensorFlow on Ubuntu
要在 Ubuntu 下安裝 TensorFlow,可先用 apt-get 更新一下。
sudo apt-get update 更新完後使用 apt-get 安裝 python 與 pip。
sudo apt-get install python-pip python-dev 最後透過 pip 將 TensorFlow 安裝起來即可。
sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl 安裝完後可以使用 python 測試一下 TensorFlow 是否已可正常使用,輸入 python 命令進入交互模式,引用 tensorflow 套件,調用 version 查閱 TensorFlow 的版本。
import tensorflow as tf tf.__version__ 如果可以正常看到 TensorFlow 版本的話代表 TensorFlow 已被正常安裝完成。
Link 真正從零開始,TensorFlow安裝入門教程!(圖文版) | 香港矽谷
read moreTag: Flutter
Posts
Flutter - Drawer class
Flutter 的 Drawer widget 需搭配 Scaffold 使用,可用以設定 Scaffold 左側的選單。
其建構子如下:
Drawer({Key key, double elevation: 16.0, Widget child, String semanticLabel }) 屬性如下:
Name Type Description child Widget The widget below this widget in the tree. elevation double The z-coordinate at which to place this drawer. This controls the size of the shadow below the drawer. semanticLabel String The semantic label of the dialog used by accessibility frameworks to announce screen transitions when the drawer is opened and closed.
read morePosts
Flutter - BottomNavigationBar class
Flutter 的 BottomNavigationBar widget 需搭配 Scaffold 使用,可用以設定 Scaffold 下方的巡覽列。 其建構子如下:
BottomNavigationBar({Key key, @required List<BottomNavigationBarItem> items, ValueChanged<int> onTap, int currentIndex: 0, BottomNavigationBarType type, Color fixedColor, double iconSize: 24.0 }) 屬性如下:
Name Type Description currentIndex int The index into items of the current active item. fixedColor Color The color of the selected item when bottom navigation bar is BottomNavigationBarType.fixed. iconSize double The size of all of the BottomNavigationBarItem icons. items List The interactive items laid out within the bottom navigation bar.
read morePosts
Flutter - AppBar class
Flutter 的 AppBar widget 需搭配 Scaffold 使用。
其建構子如下:
AppBar({Key key, Widget leading, bool automaticallyImplyLeading: true, Widget title, List<Widget> actions, Widget flexibleSpace, PreferredSizeWidget bottom, double elevation: 4.0, Color backgroundColor, Brightness brightness, IconThemeData iconTheme, TextTheme textTheme, bool primary: true, bool centerTitle, double titleSpacing: NavigationToolbar.kMiddleSpacing, double toolbarOpacity: 1.0, double bottomOpacity: 1.0 }) 屬性如下:
Name Type Description actions List Widgets to display after the title widget. automaticallyImplyLeading bool Controls whether we should try to imply the leading widget if null.
read morePosts
Flutter - Scaffold class
Flutter 的 Scaffold widget 可用來實現基本的 material design layout。
其建構子如下:
Scaffold({Key key, PreferredSizeWidget appBar, Widget body, Widget floatingActionButton, FloatingActionButtonLocation floatingActionButtonLocation, FloatingActionButtonAnimator floatingActionButtonAnimator, List<Widget> persistentFooterButtons, Widget drawer, Widget endDrawer, Widget bottomNavigationBar, Color backgroundColor, bool resizeToAvoidBottomPadding: true, bool primary: true }) 屬性如下:
Name Type Description appBar PreferredSizeWidget An app bar to display at the top of the scaffold. backgroundColor Color The color of the Material widget that underlies the entire Scaffold. body Widget The primary content of the scaffold.
read morePosts
Flutter - ListView class
Flutter 的 ListView 元件是一具備捲軸的元件且能用來顯示多筆內容的元件。
其建構子如下:
ListView({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, double itemExtent, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, List<Widget> children: const [] }) ListView.builder({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, double itemExtent, @required IndexedWidgetBuilder itemBuilder, int itemCount, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true }) ListView.
read morePosts
Flutter - Card class
Flutter 的 Card class 提供類似卡片的效果,該元件的四個角落為圓角,並具備有陰影的效果。
其建構子如下:
Card({Key key, Color color, double elevation: 2.0, Widget child }) 屬性如下:
Name Type Description child Widget The widget below this widget in the tree. color Color The color of material used for this card. elevation double The z-coordinate at which to place this card. This controls the size of the shadow below the card. hashCode int The hash code for this object. key Key Controls how one widget replaces another widget in the tree.
read morePosts
Flutter - ButtonBar class
Flutter 的 ButtonBar widget 可以用來做按鈕的水平排列。
其建構子如下:
ButtonBar({Key key, MainAxisAlignment alignment: MainAxisAlignment.end, MainAxisSize mainAxisSize: MainAxisSize.max, List<Widget> children: const [] }) 屬性如下:
Name Type Description alignment MainAxisAlignment How the children should be placed along the horizontal axis. children List The buttons to arrange horizontally. mainAxisSize MainAxisSize How much horizontal space is available. See Row.mainAxisSize. hashCode int The hash code for this object. key Key Controls how one widget replaces another widget in the tree.
read morePosts
Flutter - Stateless Widgets
Flutter 的 Stateless widget 指的是無狀態的 widget。
使用時會建立一個繼承自 StatelessWidget 的子類別,然後複寫處理 build 方法,在該方法描述要怎樣建立該 widget。
... class MyWidget extends StatelessWidget { ... @override Widget build(BuildContext context) { ... } } ... 像是下面這邊筆者就試著建立了一個簡單的 widget,用 Container widget 與 Icon widget 搭配,簡單的做了類似於 Button 的效果,並允許由 widget 外部注入去決定要呈現的 icon。
import 'package:flutter/material.dart'; void main() { runApp( new MaterialApp( home: new Center ( child: new MyWidget(icon: Icons.add) ) ) ); } class MyWidget extends StatelessWidget { MyWidget({this.icon}); final IconData icon; @override Widget build(BuildContext context) { return new Container( width: 200.
read morePosts
Flutter - FloatingActionButton class
Flutter 的 FloatingActionButton widget 可以用來做按鈕的呈現,一般會搭配 Scaffold一起使用。
其建構子如下:
FloatingActionButton({Key key, Widget child, String tooltip, Color backgroundColor, Object heroTag: const _DefaultHeroTag(), double elevation: 6.0, double highlightElevation: 12.0, @required VoidCallback onPressed, bool mini: false, double notchMargin: 4.0 }) 屬性如下:
Name Type Description backgroundColor Color The color to use when filling the button. child Widget The widget below this widget in the tree. elevation double The z-coordinate at which to place this button. This controls the size of the shadow below the floating action button.
read morePosts
Flutter - RaisedButton class
Flutter 的 RaisedButton widget 可以用來做按鈕的呈現。
其建構子如下:
RaisedButton({Key key, @required VoidCallback onPressed, ValueChanged<bool> onHighlightChanged, ButtonTextTheme textTheme, Color textColor, Color disabledTextColor, Color color, Color disabledColor, Color highlightColor, Color splashColor, Brightness colorBrightness, double elevation: 2.0, double highlightElevation: 8.0, double disabledElevation: 0.0, EdgeInsetsGeometry padding, ShapeBorder shape, Duration animationDuration: kThemeChangeDuration, Widget child }) 屬性如下:
Name Type Description animationDuration Duration Defines the duration of animated changes for shape and elevation. child Widget The button’s label. color Color The button’s fill color, displayed by its Material, while it is in its default (unpressed, enabled) state.
read morePosts
Flutter - Icon class
Flutter 的 Icon widget 可用來顯示 icon。
其建構子如下:
Icon(IconData icon, { Key key, double size, Color color, String semanticLabel, TextDirection textDirection }) 屬性如下:
Name Type Description color Color The color to use when drawing the icon. icon IconData The icon to display. The available icons are described in Icons. semanticLabel String Semantic label for the icon. size double The size of the icon in logical pixels. textDirection TextDirection The text direction to use for rendering the icon.
read morePosts
Flutter - FlutterLogo class
Flutter 的 FlutterLogo widget 可用來顯示 Flutter 的 Logo。
其建構子如下:
FlutterLogo({Key key, double size, MaterialColor colors, Color textColor: const Color(0xFF616161), FlutterLogoStyle style: FlutterLogoStyle.markOnly, Duration duration: const Duration(milliseconds: 750), Curve curve: Curves.fastOutSlowIn }) 屬性如下:
Name Type Description colors MaterialColor The color swatch to use to paint the logo, Colors.blue by default. curve Curve The curve for the logo animation if the style, colors, or textColor change. duration Duration The length of time for the animation if the style, colors, or textColor properties are changed.
read morePosts
Flutter - Install app with flutter CLI
要將 Flutter app 安裝至連接的裝置,可以調用下列命令。
Flutter install 命令調用後 Flutter app 會被安裝至連接的裝置,直接點擊開啟即可使用。
read morePosts
Flutter - Placeholder class
Flutter 的 Placeholder widget 主要用來標示後續會被其它 Widget 取代的地方。
其建構子如下:
Placeholder({Key key, Color color: const Color(0xFF455A64), double strokeWidth: 2.0, double fallbackWidth: 400.0, double fallbackHeight: 400.0 }) 屬性如下:
Name Type Description color Color The color to draw the placeholder box. fallbackHeight double The height to use when the placeholder is in a situation with an unbounded height. fallbackWidth double The width to use when the placeholder is in a situation with an unbounded width.
read morePosts
Flutter - Column class
Flutter 的 Column widget 可用來將子元件垂直放置。
其建構子如下:
Column({Key key, MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start, MainAxisSize mainAxisSize: MainAxisSize.max, CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection: VerticalDirection.down, TextBaseline textBaseline, List<Widget> children: const [] }) 屬性如下:
Name Type Description children List The widgets below this widget in the tree. crossAxisAlignment CrossAxisAlignment How the children should be placed along the cross axis. direction Axis The direction to use as the main axis. hashCode int The hash code for this object.
read morePosts
Flutter - Container class
Flutter 的 Container widget 是能用來繪製、設定位置/尺寸的容器 widget。
其建構子如下:
Container({Key key, AlignmentGeometry alignment, EdgeInsetsGeometry padding, Color color, Decoration decoration, Decoration foregroundDecoration, double width, double height, BoxConstraints constraints, EdgeInsetsGeometry margin, Matrix4 transform, Widget child }) 屬性如下:
Name Type Description alignment AlignmentGeometry Align the child within the container. child Widget The child contained by the container. constraints BoxConstraints Additional constraints to apply to the child. decoration Decoration The decoration to paint behind the child. foregroundDecoration Decoration The decoration to paint in front of the child.
read morePosts
Flutter - Center widget
Flutter 的 Center widget 可用來做置中的呈現。
其建構子如下:
Center({Key key, double widthFactor, double heightFactor, Widget child }) 屬性如下:
Name Type Description alignment AlignmentGeometry How to align the child. child Widget The widget below this widget in the tree. hashCode int The hash code for this object. heightFactor double If non-null, sets its height to the child’s height multiplied by this factor. key Key Controls how one widget replaces another widget in the tree.
read morePosts
Flutter - List all connected devices with flutter CLI
要使用 Flutter CLI 列出所有連接的裝置,可以調用下列命令。
Flutter devices 命令調用後會顯示所有連接的裝置。
這命令可用來確認裝置的連接狀態,如果同時有多個裝置連接,我們也可以用這命令確認裝置的識別碼,用以指定運行到特定的裝置。
read morePosts
Flutter - Run flutter app with flutter CLI
要使用 Flutter CLI 運行 Flutter app,可以調用下列命令。
Flutter run 命令調用後會顯示運行時可供使用的功能。
且 Flutter app 會被運行起來。
Flutter app 運行的當中我們可以開啟 http://127.0.0.1:8101,進行 Flutter app 的 profiling。
如果開發中要進行 app 的重載,可以使用 r 進行 hot reload,或是按下 R 進行 app 的重載。
像是這邊筆者將正在運行中的程式做個簡單的修改。
按下 R 將 app 重載,Flutter 只花了 748 ms 就完成了重載的動作。
如果要查看更多支援的操作,可以按下 h,會將更進階操作功能顯示出來。
像是按下 w 可以看到 app 的 widget 的階層架構。
按下 t 可以看到 app 的 rendering tree。
按下 L 可以查看 app 的 layout。
按下 p 可以顯示 construction lines。
按下 s 可以擷取畫面。
read morePosts
Flutter - Text widget
Flutter 的 Text widget 可以用來做簡易的文字顯示。
其建構子如下:
Text(String data, { Key key, TextStyle style, TextAlign textAlign, TextDirection textDirection, bool softWrap, TextOverflow overflow, double textScaleFactor, int maxLines }) 屬性如下:
Name Type Description data String The text to display. maxLines int An optional maximum number of lines for the text to span, wrapping if necessary. If the text exceeds the given number of lines, it will be truncated according to overflow. overflow TextOverflow How visual overflow should be handled.
read morePosts
Flutter - Hello world
Flutter 專案建立後可以先撰寫個簡單的 Hello world 程式,lib/main.dart 為 Flutter 程式的主要進入點,將之開啟後撰寫如下程式。
import 'package:flutter/material.dart'; void main() { runApp( new Center( child: new Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); } 可以看到 Flutter 程式撰寫上主要有幾個要注意的部分,首先需引用 flutter/material.dart 套件。
import 'package:flutter/material.dart'; 再來就是要在 main 這個處函式內調用 runApp 方法,runApp 方法調用時要帶入構成畫面的 widget。
void main() { runApp(...); } 像是這邊的範例就帶入了一個 Center 的 Widget,Center 的 Widget 內又放置了一個 Text Widget,所以 Text Widget 設定的字串會在程式的正中央顯示。
read morePosts
Flutter - Getting started with VS Code
要在 VS Code 運行 Flutter,需先安裝 Dart Code 套件。
安裝完後重啟 VS Code。
使用 Command Palette 調用 Flutter: New Project。
輸入 Flutter 專案名稱(專案的名稱必須要全小寫)後按下 Enter 建繼續。
選取專案要放置的位置。
Flutter 專案即會被建立在指定的位置。
接著進行除錯上的設定。
點選 Open launch.json,VS Code 會幫我們自動產生對應的 launch.json 檔。
點選 Start Debugging 按鈕。
即會進入 Flutter 專案的除錯。
Link Get Started: Configure Editor - Flutter Get Started: Test Drive - Flutter
read morePosts
Flutter - Examples
Flutter 安裝目錄下的 examples 目錄附有一些 Flutter 的範例程式,學習時可先從這邊下手。
可先調用命令將範例運行起來操作看看,再對照看程式是怎麼撰寫的。
flutter run 若是將 hello_world 範例運行起來,會看到…
運行 platform_view…
運行 catalog…
運行 stocks…
運行 flutter_gallery…
運行 platform_channel…
運行 flutter_view…
read morePosts
Flutter - Install on macOS
要在 Mac 中使用 Flutter,首先要先用 Git 將 Flutter 抓取下來。
git clone -b beta https://github.com/flutter/flutter.git 然後設定 Flutter 路徑參考,可以在 Terminal 直接輸入設定。
export PATH=[PATH_TO_FLUTTER_GIT_DIRECTORY]/flutter/bin:$PATH 也可以開啟 HOME/.bash_profile 修改,加入上述設定,然後調用下面命令重新讀取設定值。
source $HOME/.bash_profile 設定好後調用下面命令,檢驗環境中所缺少的依賴。
flutter doctor 運行完可以看到缺少的依賴有哪些,且會很詳細的顯示該怎麼處理,接著只要照著指示反覆將缺少的依賴修正即可。
Link Get Started: Install on macOS - Flutter
read moreTag: Trello
Posts
Trellodoro - Trello + Pomodoro = Personal Kanban Bliss
Trellodoro 是一整合 Trello 與蕃茄鐘的工具,使用時需連結 Trello。
授與存取權限。
選取要使用的 Trello board 及要進行的 Task。
調整蕃茄鐘的時間設定,最後點選 Launch Time 按鈕。
蕃茄鐘就會開始倒數。
當蕃茄吃完,它會更改對應的 Trello card 讓你知道吃了幾顆蕃茄。
Link Home - Trellodoro
read morePosts
Trello - Calendar power-up
要啟動 Trello Calendar 功能,我們可以開啟 Trello 的右側 Menu,點選 Power-Ups 選項。
{% img /images/posts/TrelloCalendar/1.png %}
Power-Ups 這邊有三個進階的功能可供開啟,這邊我們只要開啟 Calendar 功能,因此點選 Calendar 就好。
{% img /images/posts/TrelloCalendar/2.png %}
這邊 Trello 會跟你介紹一下 Calendar 功能,直接按下 Enable 按鈕啟用即可。
{% img /images/posts/TrelloCalendar/3.png %}
注意到這邊,啟用下方的設定頁面可供我們決定是否啟用 iCalendar Feed,若想將 Trello 的卡標示在我們慣用的日曆像是 Google Calendar,這邊可以將之啟用,並將下方的 Feed 位置加入慣用的日曆。
{% img /images/posts/TrelloCalendar/4.png %}
Trello Calendar 啟用後,Trello 的右上方會多一個 Calendar 連結,點選可進入 Trello Calendar。
它有提供週日曆…
{% img /images/posts/TrelloCalendar/5.png %}
及月日曆兩種呈現方式,我們可依需求下去切換。
{% img /images/posts/TrelloCalendar/6.png %}
有壓上 Due Date 的 Trello 卡都會在日曆上呈現,有需要也可以在 Trello Calendar 指定的日期上直接加上 Trello 卡,或是將 Trello 卡拖曳進行 Due Date 的調整。
read moreTag: Vagrant
Posts
Vagrant - Install VirtualBox Guest Additions
OS Kernal 更新,可能會造成 Vagrant 無法正常使用,像是筆者切換了不同 Domain 的 AD帳號後,嘗試使用 Vagrant 就會出錯。
這時我們可以嘗試重新安裝 VirtualBox Guest Additions。
vagrant plugin install vagrant-vbguest 重新安裝完 Vagrant 就可以正常使用了。
read morePosts
Vagrant - Global Status
Vagrant box 一多,常常會 Vagrant up 後就忘 Vagrant halt,虛擬機就在背後持續運行。
這時我們可以呼叫 global-status 命令查詢當前使用者所有 Vagrant 虛擬機的使用狀況。
Vagrant globl-status {% img /images/posts/VagrantGlobalStatus/1.png %}
會顯示 id、name、provider、status、directory 這些資訊,藉此我們可以找到正在運行的 Vagrant box 所在目錄,切換過去將之關閉.
Link vagrant global-status - Command-Line Interface - Vagrant Documentation
read morePosts
Vagrant - File Provisioning
File Provisioning 可以讓我們自動在 Vagrant 啟動時將檔案傳遞至虛擬機中。
使用上主要是透過 Vagrantfile 將 config.vm.provision 設為 file,並利用支援的參數與方法做些對應的設定。
支援的參數有 source、 destination。source 參數指定的是本機上的來源檔案位置,destination 參數指定的是虛擬機上的目標檔案位置。
像是這邊,若要將本地的 shell script 帶入到虛擬機中。
{% img /images/posts/VagrantFileProvisioning/1.png %}
Provisioning 運行後虛擬機就會將指定的檔案帶到指定的位置。
{% img /images/posts/VagrantFileProvisioning/2.png %}
Link File Uploads - Provisioning - Vagrant Documentation
read morePosts
Vagrant - Docker Provisioning
Docker Provisioning 可以自動在 Vagrant 啟動時幫我們進行 Docker 的安裝,容器的下載,與容器的設定。
使用上主要是透過 Vagrantfile 將 config.vm.provision 設為 docker,並利用支援的參數與方法做些對應的設定。
支援的參數有 images、version。images 用以指定所要拉下來的 Docker 映像檔,跟 pull_images 方法類似。version 則是指定要裝的 docker 版本,若未指定預設是使用最新版本。
支援的方法有 build_image、pull_images、run。build_images 方法可以讓我們把 dockerfile 建立成映像檔。pull_images 方法可以將指定容器下載下來。run 方法可以啟動指定容器。
像是下面這個例子,筆者使用 boot2docker 的 vagrant box,結合 docker provision 拉下 oracle-xe-11g 容器,以守護容器方式啟動,將 1521 port 導出,並掛上 data volume。
Vagrant.configure(2) do |config| config.vm.box = "blinkreaction/boot2docker" config.vm.box_check_update = false config.vm.synced_folder "Data", "/home/docker/data", create: true config.vm.network "forwarded_port", guest: 1521, host: 1521 config.vm.provision "docker", images:["wnameless/oracle-xe-11g:latest"] do |d| d.
read morePosts
Vagrant - Shell Provisioning
要讓 Vagrant 在第一次啟動時透過 Shell Script 去做些設定,我們可以透過 Vagrant 的 Shell Provisioning。
若想在 Vagrantfile 內直接設定,可以使用 Inline 的方式撰寫。像是下面這樣設定 config.vm.provision 為 shell,並在 inline 參數這邊直接將 Script 帶在後面。
Vagrant.configure("2") do |config| ... config.vm.provision "shell", inline: "echo Hello, World" ... end 也可以先抽成方法後指給 inline 參數。
$script = <<SCRIPT echo I am provisioning... date > /etc/vagrant_provisioned_at SCRIPT Vagrant.configure("2") do |config| ... config.vm.provision "shell", inline: $script ... end 若想將 Script 獨立於 Vagrantfile 外,這邊也可以透過 path 參數指定 Script 檔。
Vagrant.configure("2") do |config| .
read morePosts
Vagrant - Vagrantfile inheritance
Vagrantfile 的設定跟很多軟體一樣是有繼承關係的。
{% img /images/posts/VagrantfileInheritance/1.png %}
首先他會去看 Vagrant Box 的 Vagrantfile。通常會是在 %HOMEPATH%\.vagrant.doxs 下,若有設定 VAGRANT_HOME 則是在 %VAGRANT_HOME%\.vagrant.doxs 下。
{% img /images/posts/VagrantfileInheritance/2.png %}
接著會看 %HOMEPATH%\.vagrant.d 或是 %VAGRANT_HOME%\.vagrant.d\ 下的 Vagrantfile。
{% img /images/posts/VagrantfileInheritance/3.png %}
最後才會看專案目錄下的 Vagrantfile。
通常我們跟著專案跑的設定會設在專案下的 Vagrantfile,若是一些通用的設定或是跟主機環境比較相關的設定,我們會在 .vagrant.d 下的 Vagrantfile 設定,像是 Proxy 的設定等。
Link Vagrantfile inheritance | Michael Maclean
read morePosts
Vagrant - Configures the virtual machine to use proxies
要讓 Vagrant 走 Proxy,我們可以借助 vagrant-proxyconf 套件。
用 vagrant plugin install 帶入套件名稱 vagrant-proxyconf 進行套件的安裝。
vagrant plugin install vagrant-proxyconf {% img /images/posts/ConfigVagrantProxy/1.png %}
套件安裝完畢後,我們可以修改 Vagrantfile 做 proxy 的設定。像是下面這樣:
... if Vagrant.has_plugin?("vagrant-proxyconf") config.proxy.http = "http://proxy.xuenn.com:3128/" config.proxy.https = "https://proxy.xuenn.com:3128/" config.proxy.no_proxy = "localhost,127.0.0.1" end ... if Vagrant.has_plugin?(“vagrant-proxyconf”) 用以判斷 vagrant-proxyconf 套件是否有安裝,config.proxy.http 用以設定 http 的 proxy,config.proxy.https 用以設定 https 的 proxy,config.proxy.no_proxy 用以設定不走 proxy 的 domain。
若是 Proxy 需經過認證,設定時要將帳密一併帶入:
... if Vagrant.has_plugin?("vagrant-proxyconf") deblock %} config.proxy.http = "http://username:password@proxy.xuenn.com:3128/" config.proxy.https = "https://username:password@proxy.
read morePosts
Vagrant - VBox Snapshot
要透過 Vagrant 去操作 Snapshot,我們可以借助 Vagrant 的 vagrant-vbox-snapshot 套件。
用 vagrant plugin install 帶入套件名稱 vagrant-vbox-snapshot 進行套件的安裝。
vagrant plugin install vagrant-vbox-snapshot 這邊若有需要可能會連帶要求安裝套件 vagrant-winnfsd。
vagrant plugin install vagrant-winnfsd {% img /images/posts/VagrantSnapshot/1.png %}
套件安裝完畢後,我們就可以視需要調用命令進行 Snapshot 的操作。
套件的使用方式如下:
Usage vagrant snapshot <command> [<args>] Sub Commands back vagrant snapshot back [vm-name] delete vagrant snapshot delete [vm-name] <SNAPSHOT_NAME> go vagrant snapshot go [vm-name] <SNAPSHOT_NAME> list vagrant snapshot list take vagrant snapshot take [vm-name] <SNAPSHOT_NAME> 使用上會像這樣:
Vagrant snapshot take “init” Vagrant snapshot list Vagrant snapshot go “init” Vagrant snapshot delete “init” 像是 vagrant snapshot take 後面接 Snapshot 的名稱下去調用即可進行 Snapshot 的建立。vagrant snapshot list 可查驗有哪些 Snapshot 可用。
read morePosts
Vagrant - Creating a new box from an existing VM
要將已經存在的 VM 匯出成 Vagrant Box,我們可以透過 Vagrant package 命令的 --base 參數。
參數使用方式官方的說明如下:
--base NAME - Instead of packaging a VirtualBox machine that Vagrant manages, this will package a VirtualBox machine that VirtualBox manages. NAME should be the name or UUID of the machine from the VirtualBox GUI. 簡單的說就是以直接在 --base 參數後帶入欲匯出的虛擬機的名稱即可。以匯出筆者電腦的 Win7 VM 為例,就是帶入 Win7,這邊另帶 --output 參數指定匯出後的 box 檔。
{% img /images/posts/CreateVagrantBoxFromExistingVM/1.png %}
輸入完我們就會看到指定的 box 產出。
我們可以將 box 加入。
{% img /images/posts/CreateVagrantBoxFromExistingVM/2.png %}
read morePosts
Vagrant - SSH in windows
要在 Windows 下使用 SSH 連進 Vagrant 作些設定,我們有幾種方式可以使用。
一種是透過 SSH 連線軟體連進 Vagrant,像是 PuTTY。
輸入 IP 與 Port 進行連線。
{% img /images/posts/VagrantSSHInWindow/1.png %}
連進去後輸入 Vagrant Box 的帳密即可,如果不知道帳密的話,通常這邊的帳密會是 vagrant,可以試試看。
{% img /images/posts/VagrantSSHInWindow/2.png %}
另外一種方式則是直接透過命令提示字元叫用 Vagrant SSH 連進 Vagrant。使用前需先安裝 Git,並將 Bin 的路徑設上,都完成後即可直接叫用Vagrant SSH 連進 Vagrant。
{% img /images/posts/VagrantSSHInWindow/3.png %}
路徑的設定可以直接在系統的環境變數中設定,叫用上會比較方便。但若有需要也可以直接在命令提示字元中加入。
set PATH=%PATH%;C:\Program Files (x86)\Gitin 此外也可以直接叫用 SSH 連進去,比較麻煩一點就是了。
{% img /images/posts/VagrantSSHInWindow/4.png %}
read moreTag: Firebase
Posts
Firebase - Getting Started with Cloud Functions
要使用 Firebase 的 Functions,可先切至 Firebase 下的 Functions 頁面。
點選開始使用。
這邊會提示使用 Firebase Functions 的步驟,首先要有 Firebase 指令列工具。
接著要使用 Firebase 指令列工具初始專案,撰寫專案後再次透過 Firebase 指令列工具部屬專案即可。
這邊跟著提示簡單的操作一次,先用 Firebase 指令列初始專案。
firebase init 選取使用 Functions 設定。
選取要使用的 Firebase 專案。
選取要使用的程式語言。
初始完後開啟專案進行修改,撰寫 Firebase Functions。
撰寫完使用 Firebase 指令列工具進行專案的部屬。
firebase deploy 部屬完成 Firebase 的 Functions 資訊主頁會看到我們發布上去的 Firebase Functions。
訪問 Firebase Functions 對應的網址,可看到 Firebase Functions 正確的運作。
Link 使用Firebase Functions前的環境準備與開發工具安裝,Serverless真的來了 - 綠豆湯 firebase/functions-samples: Collection of sample apps showcasing popular use cases using Cloud Functions for Firebase 使用Firebase Functions的HTTP Triggers設計簡易的Android網路登入驗證功能,連PHP、ASP、Servlet都不用了 - 綠豆湯 Getting Started with Cloud Functions for Firebase - Firecasts - YouTube
read morePosts
Firebase - Append a list of data to realtime database on the web
要將資料附加到 Firebase 的 List 內,需先進行 Firebase 與應用程式的連結,然後透過呼叫 Firebase 的 database 方法取得資料庫物件,調用 ref 方法取得資料物件的參考,再調用 push 方法取得新資料的參考,透過參考調用 set 方法將資料寫入即可。
Link Work with Lists of Data on the Web | Firebase Realtime Database | Firebase
read morePosts
Firebase - Listen for value events from realtime database on the web
要監聽資料並自 Firebase 將資料讀取出來,需先進行 Firebase 與應用程式的連結,然後透過呼叫 Firebase 的 database 方法取得資料庫物件,調用 ref 方法取得資料物件的參考,最後調用 on 方法,指定監聽 value 事件,並帶入一個委派,在委派內取用數值即可。
像是本來 Firebase Realtime Database 內的資料如下:
將應用程式運行起來,可以看到應用程式正常取得了資料。
這時回到 Firebase Realtime Database 的資料頁面,將資料值做個修改。
可以看到應用程式監聽到了資料的改變,並做出了對應的動作。
Link Read and Write Data on the Web | Firebase Realtime Database | Firebase
read morePosts
Firebase - Read data once from realtime database on the web
要將資料自 Firebase 讀取出來,需先進行 Firebase 與應用程式的連結,然後透過呼叫 Firebase 的 database 方法取得資料庫物件,調用 ref 方法取得資料物件的參考,最後調用 once 與 then 方法,在 then 方法中帶入一個委派,在委派內取用數值即可。
假設 Firebase Realtime Database 內的資料如下:
運行起來可以看到會從 Firebase 取得正確的數值。
Link Read and Write Data on the Web | Firebase Realtime Database | Firebase
read morePosts
Firebase - Set data to realtime database on the web
建立完 Firebase 專案且調完資料庫的安全性規則設定,可以開始嘗試進行 Firebase Realtime Database 的寫入動作,因為這邊是用 Web 專案開發,所以點選 “將 Firebase 加入您的網路應用程式”。進行應用程式的連結。
這邊會給予一段連結應用程式用的 JavaScript 程式,按下複製按鈕複製下來,貼至應用程式中。完成應用程式的連結。
接著進行撰寫寫入的部分,透過呼叫 Firebase 的 database 方法取得資料庫物件,調用 ref 方法取得資料物件的參考,最後調用 set 方法將要設定的資料值帶入即可。
將撰寫的應用程式運行起來。
回到 Firebase Realtime Database 的資料頁面,可以看到資料已被正確的寫入。
Link Read and Write Data on the Web | Firebase Realtime Database | Firebase
read morePosts
Firebase - Realtime database rules
Firebase 專案建立後,若要使用 Realtime Database 功能可點選左側 DEVELOP 下的 Database。
點選 Realtime Database 下的開始使用按鈕。
在開始使用 Realtime Database 之前,我們需先切至規則頁面,調整 Realtime Database 的的安全性規則設定。
預設的安全性規則設定為讀寫都需先經過認證。
我們可以開啟模擬工具簡單的測試一下,嘗試讀取 Realtime Database。
因為沒通過認證,所以讀取的動作會被拒絕。
如果我們將設定調整如下,直接開放讀取與寫入,讓讀取與寫入的動作不需要經過認證。
同樣的透過模擬工具簡單的測試一下。
會發現讀寫的動作都會不會被拒絕了。
Link Understand Firebase Realtime Database Rules | Firebase Realtime Database | Firebase
read morePosts
Firebase - Create project
Firebase 在使用前需先進入控制台。
新增一個對應的專案。
設定專案的名稱、ID、及服務想放置的地區。按下建立專案按鈕。
Firebase 即會建立專案並導到專案頁面,我們即可將連結應用程式做進一步的開發,或是使用該頁面針對 Firebase 所提供的服務進行操作。
read moreTag: Mailgun
Posts
Mailgun - Authorized Recipients
Mailgun 使用 Sandbox subdomain 時,預設只能發送訊息給自己的信箱,除非加上自己的 Domain 或是設定 Authorized recipients。
要設定 Autorized recipients,點選網頁右上角的帳號名稱,點選 Account Settings 選單選項。
接著切至 Autorized recipients 頁面。
點選 Invite New Recipient 按鈕。
將要加入的 Recipient mail 位置填入,按下 Invite Recipient 按鈕。
Recipient 就會被加到列表中,此時還是 Unverified 的狀態。
Recipient 會收到來自 Mailgun 的驗證信件,按下 Aggree 按鈕進行驗證的動作。
再次按下 Yes 按鈕確認。
驗證的動作就完成了。
此時 Mailgun 的 Authorized Recipients 內的狀態會變為 Verified。
Mailgun 就可以正常的發送信件給 Recipient 了。
read morePosts
Mailgun - Getting started
要使用 Mailgun 發送 Email,先要有 Mailgun 會員帳號。
註冊成為 Mailgun 會員後,會被導到 https://app.mailgun.com/app/account/setup 頁面,該頁面會簡單的展示 Curl、Ruby、Python、PHP、Java、與 C# 等不同的使用方式。
這邊可以簡單的用 Curl 測試一下,下完 Curl 命令後可從 API 的回應看到訊息已發送至 Mailgun 且被 Queue 起來供後續處理。
處理的紀錄可在 Mailgun 的 Logs 頁面查閱。
若有需要也可以進一步展開查閱更為細節的部分。
Link Transactional Email API Service For Developers | Mailgun
read moreTag: Cmder
Posts
Cmder - Force as default terminal for console application
若要強制讓所有非由 Cmder 直接開啟的 Terminal 視窗都由 Cmder 開啟,可開啟 Cmder 的設定頁面。
切到 [Integration | Default term] 頁面,勾選 Force ConEmu as default terminal for console applications 後存檔離開。
這樣當我們開啟 MS-DOS 或是 PowerShell 時就會強制使用 Cmder 開啟。
read moreTag: Parcel
Posts
Parcel - TypeScript transform
Parcel 支援 TypeScript 的轉換。
像是下面這邊筆者創建了個簡單的範例,建立了個 index.html,裡面引用了 index.ts。
<html> <body> <script src="./index.ts"></script> </body> </html> index.ts 內引用 message.ts,並將 message.ts 傳回的訊息輸出到主控台。
import message from "./message"; console.log(message); message.ts 則是將要顯示的訊息輸出。
export default "Hello, world"; 範例準備好後調用 Parcel 命令建置並啟用服務,Parcel 會自行下載 TypeScript 套件編譯 TypeScript。
Parcel 解析網站後會將需要的檔案處理後移至輸出目錄。
連至啟動的服務網址,可看到網站正確的被運行。
Link 🐠 轉換(Transforms)
read morePosts
Parcel - CSS asset
Parcel 支援 CSS 文件的處理,可在 CSS 中透過 @import 載入另一個 CSS。
... @import './background.css'; ... 也可以透過 url 函式引用圖片、字型。
... background-image: url('../images/Profile.jpg'); ... 像是下面這邊筆者創建了個簡單的範例,建立了個 index.html,裡面引用了 index.css。
<html> <head> <link rel="stylesheet" href="./style/index.css"> </head> <body> </body> </html> index.css 內透過 @import 引用了 background.css 檔,用 url 方法使用指定圖片設定背景圖片。
@import './background.css'; body { background-image: url('../images/Profile.jpg'); background-repeat:no-repeat; background-position: center; } background.css 設定背景為指定顏色。
body {background-color: coral;} 範例準備好後調用 Parcel 命令建置並啟用服務。
Parcel 解析網站後會將需要的檔案處理後移至輸出目錄。
連至啟動的服務網址,可看到網站正確的被運行。
Link 📦 資源(Assets)
read morePosts
Parcel - HTML asset
除了 JavaScript 文件外,Parcel 也支援 HTML 文件的處理。
像是下面這邊筆者創建了個簡單的範例,建立了個 index.html,裡面載入了 profile.jpg 且連結了 hello.html 頁面。
<html> <body> <img src="./images/profile.jpg"> <a href="./hello.html">Say Hello</a> </body> </html> profile.jpg 是很單純的大頭照。
hello.html 內引用了 hello.js 並輸出 Hello World 字樣。
<html> <body> <script src="./scripts/hello.js"></script> Hello World </body> </html> hello.js 內則是很簡單的利用 Console 輸出 hello world 字樣。
console.log("hello world"); 調用 Parcel 命令建置並啟用服務。
Parcel 解析網站後會將需要的檔案處理後移至輸出目錄。
連至啟動的服務網址,可看到網站正確的被運行。
Link 📦 資源(Assets)
read morePosts
Parcel - JavaScript asset
要使用 Parcel 在 JavaScript 中載入 JavaScript 模塊可用 CommonJS 的寫法。
const module = require(modulePath); 或是 ES6 的寫法。
import module from modulePath; 除了 JavaScript 的模塊外,也能引用 CSS 文件。
import cssPath; 以及引用圖片。
import imageUrl from imagePath; 像是下面這邊筆者創建了個簡單的範例,建立了個 index.html,裡面引用了 index.js。
<html> <body> <script src="./scripts/index.js"></script> </body> </html> index.js 內引用了不同類型的檔案。
//const hello = require('./hello'); import hello from './hello'; import '../style/index.css'; import profileImageUrl from '../images/profile.jpg'; console.log(profileImageUrl); 像是 js 檔(hello.js)。
console.log("hello world"); CSS 檔(index.css)。
body {background-color: coral;} 以及圖檔。
範例準備好後調用 Parcel 命令建置並啟用服務。
read morePosts
'Parcel - SyntaxError: Unexpected token function'
使用 Parcel 時若發生 SyntaxError: Unexpected token function 錯誤。
這是因為 Parcel 用到了 Node.js 8.x 的語法,確認 Node.js 是否已更新到指定版本,更新完後即可正常運行。
Link 🐛 about SyntaxError: Unexpected token function · Issue #244 · parcel-bundler/parcel · GitHub parcel 錯誤:SyntaxError: Unexpected token function - JJC 前端進階- SegmentFault
read morePosts
Parcel - Getting started
Parcel 使用前需先安裝套件。
可以透過 yarn。
yarn global add parcel-bundler 或是透過 npm 安裝。
npm install -g parcel-bundler 安裝完準備要進行打包的程式。
Index.html 檔案內容為:
<html> <body> <script src="./index.js"></script> </body> </html> Index.js 檔案內容為:
console.log("hello world"); 調用 Parcel 命令進行編譯並運行網站服務。
parcel [WebFile] 編譯後的檔案會產生在 dist 目錄下。
連至網站可看到打包後運行起來的樣子。
要退出網站服務的話,按下熱鍵 Ctrl + C,鍵入 Y 後 Enter 即可。
read morePosts
Parcel - Blazing fast, zero configuration web application bundler
Parcel 是一極速零配置的 Web 應用打包工具,不需額外的配置設定就能快速的將 Web 應用程式進行打包。
該工具具有以下幾個特點:
Blazing fast bundle times Bundle all your assets Automatic transforms Zero config code splitting Hot module replacement Friendly error logging 也就是說 Parcel 的打包速度極快、支援 JS/CSS/HTML 文件、可以自動轉換程式、不用額外的配置、可以動態更新、錯誤訊息比較好看。
其中速度極快是因為 Parcel 使用多核進行編譯,且會將編譯過的文件進行快取,所以編譯速度極快。
Parcel 的作者有在 4 CPU 的 2016 MacBook Pro 上將 1726 的模塊,6.5 M 大小的 Web 應用程式進行壓縮,可以看到 Parcel 在打包上的確花了較少的時間。
Tool Time browserify 22.98s webpack 20.71s parcel 9.98s parcel - with cache 2.64s Link 📦 Parcel
read moreTag: LiteDB
Posts
LiteDB - FileStorage
為了控制記憶體的使用量,LiteDB 限制資料的存放量為 1 MB,1 MB 對於一般的資料而言是已經足夠了,但是對於二進制檔案來說就不怎麼足夠,所以 LiteDB 提供 FileStorage 用以存放二進制檔案。
FileStorage 支援以下方法:
Method Description Upload Send file or stream to database. Can be used with file or Stream. If file already exists, file content is overwritten. Download Get your file from database and copy to Stream parameter Delete Delete a file reference and all data chunks Find Find one or many files in _files collection. Returns LiteFileInfo class, that can be download data after.
read morePosts
LiteDB - Query data
要取得 LiteDB 內的資料,首先需先將 LiteDB 開啟,取得對應的 Collection,調用 Collecion.FindAll 即可取得 Collection 內所有的資料。
... using (var db = new LiteDatabase(dbFile)) { var collection = db.GetCollection<T>(collectionName); ... var collectionItems = collection.FindAll(); ... } using System; namespace LiteDB.Demo8 { class Program { static void Main(string[] args) { using (var db = new LiteDatabase("Person.db")) { var persons = db.GetCollection<Person>("persons"); foreach (var person in persons.FindAll()) { Console.WriteLine(person.NickName); } } } } public class Person { public int ID { get; set; } public String Name { get; set; } public String NickName { get; set; } } } 要找尋滿足特定條件的資料的話,可以調用 Collection.
read morePosts
LiteDB - Update data
要將 LiteDB 內的資料更新,需先將 LiteDB 開啟,取得 Collection,取得 Collection 內的元素,更新元素的屬性值後,再用 Collection.Update 將資料更新回 LiteDB 即可。
… using (var db = new LiteDatabase(dbFile)) { var collection = db.GetCollection<T>(collectionName); ... collectionItem.Property = newValue; collection.Update(collectionItem); } 像是下面這個範例就會將資料寫入,將塞入的資料做個變更。
using System; namespace LiteDB.Demo2 { class Program { static void Main(string[] args) { using (var db = new LiteDatabase("Person.db")) { var persons = db.GetCollection<Person>("persons"); var firstPerson = collection.FindById(1); firstPerson.Name = "Larry Nung"; firstPerson.NickName = "Larry"; persons.Update(firstPerson); } } } public class Person { public int ID { get; set; } public String Name { get; set; } public String NickName { get; set; } } } 若是要更新為全新的資料,也可以建立個資料物件指定 ID 將之替換。
read morePosts
LiteDB - Insert data
要將資料塞入 LiteDB,需先準備一個用來存放資料的 Model,該 Model 跟一般的 Model 沒什麼太大的不同,不需要特別加掛 Attribute,只需要為 Model 加上一個 ID 的數值屬性,讓 LiteDB 用以識別資料。
public class MyModel { public int ID { get; set; } ... } 再來準備要塞入的資料,ID 值不用填,LiteDB 會自行填入。
var collectionItem = new T() { ... }; 最後將 LiteDB 開啟,取得對應的 Collection,用 Collection.Insert 將資料塞入即可。
… using (var db = new LiteDatabase(dbFile)) { var collection = db.GetCollection<T>(collectionName); ... collection.Insert(collectionItem); } 程式撰寫起來會像下面這樣:
using System; namespace LiteDB.Demo1 { class Program { static void Main(string[] args) { using (var db = new LiteDatabase("Person.
read morePosts
LiteDB - Create and open DB
LiteDB 使用上跟一般資料庫一樣需要先建立資料庫操作物件,帶入指定的資料庫檔案位置建立出 LiteDatabase 物件實體即可。
… using (var db = new LiteDatabase(dbFile)) { ... } LiteDatabase 物件實體建立後,即可針對 LiteDatabase 物件實體進行資料庫的操作,資料庫的連線 LiteDB 會幫我們開啟,不需自行開啟。若指定的資料庫檔案位置不存在資料庫檔案,LiteDB 會自動建立指定的資料庫檔案。
除了檔案形式的資料庫外,LiteDB 也允許我們使用記憶體形式的資料庫,只要建立 MemoryStream 帶入建立 LiteDatabase 的物件實體即可。
… using (var ms = new MemoryStream(buffer)) using (var db = new LiteDatabase(ms)) { ... } 這樣資料庫就會存在於記憶體中。在需要存放些資料在記憶體中的某些情境下,就可以評估使用 In-Memory 的 LiteDB。
read morePosts
LiteDB - A .NET NoSQL Document Store in a single data file
LiteDB 是一用 C# 寫的 .NET NoSQL 免費開源資料庫。
具備有以下特點:
Lightweight Fast Thread safe Process safe Portable UWP and Xamarin iOS/Android ACID transaction Recovery data in writing failure (journal mode) Map your POCO class to BsonDocument Fluent API for custom mapping Cross collections references (DbRef) Store files and stream data (like GridFS in MongoDB) LINQ support FREE for everyone - including commercial use Shell command line Datafile encryption using DES (AES) cryptography LiteDB 有點像是 MongoDB 與 SQLite 的混合體,操作與使用上跟 MongoDB 相似,但又跟 SQLite 一樣是 Standalone 的資料庫,不像 MongoDB 需要架設服務,只需引用 250 KB 左右的組件即可直接使用。
read moreTag: PL/SQL & SQL CODING GUIDELINE
Posts
>-
條款五十九,嘗試使用 RETURNING INTO,而非使用 Using OUT 綁定輸出參數。
像是下面這段程式使用了 Using OUT 語法去綁定輸出參數就不被建議。
CREATE OR REPLACE PACKAGE BODY employee_api IS PROCEDURE upd_salary (in_employee_id IN employees.employee_id%TYPE ,in_increase_pct IN types_up.percentage ,out_new_salary OUT employees.salary%TYPE) IS co_sql_stmt CONSTANT types_up.big_string_type := ' UPDATE employees SET salary = salary + (salary / 100 * :1) WHERE employee_id = :2 RETURNING salary INTO :3'; BEGIN EXECUTE IMMEDIATE co_sql_stmt USING in_increase_pct, in_employee_id, OUT out_new_salary; END upd_salary; END employee_api; / 建議的做法是用 RETURNING INTO 語法去綁定輸出參數。
read moreTag: Sonar
Posts
sonar - Formatters
sonar 的 formatter 可用來設定 sonar 分析結果的格式,目前提供 summery、json、stylish、codeframe 這幾個 formatter,可透過 sonar 設定檔指定使用。
像是指定 summary formatter 的話,sonar 分析完就只會摘要出各個 rule 的 warning 與 error 數。
使用 json formatter 的話,sonar 分析結果會用 json 格式呈現。
使用 stylish formatter 的話,sonar 分析結果會依 resource 告知哪一列哪一行及違反的 rule。
使用 codeframe formatter 的話,sonar 分析結果會顯示違反的 rule 以及出問題的程式碼。
Link List of official formatters | sonar documentation
read morePosts
sonar - Solve permission issue
在用 npm 進行 sonar 的安裝時,有可能會碰到 permission denied 的錯誤。
這時可以修改 npm 的預設目錄,再次用 npm 運行 sonar 的安裝即可。
Link User guide | sonar documentation
read morePosts
sonar - Getting started
要使用 sonar CLI,需先要有 Node.js v8.x 以上的版本。
再透過 npm 安裝 sonar 到全域。
npm install -g --engine-strict @sonarwhal/sonar 安裝完可查詢 sonar 版本確認安裝的狀態。
sonar -v 若安裝無誤可用 sonar 命令產生 sonar 的設定檔。
sonar --init 設定完 sonar 的設定檔 (.sonarrc) 就會產生在當前目錄。
若有需要可將設定檔開啟修改。
最後調用 sonar 命令並帶上要分析的網址,即可使用 sonar 分析指定的網站。
sonar [URL] Link User guide | sonar documentation
read morePosts
sonar - Analyze website with online sonar scanner
要使用 sonar 網站針對網站進行分析,可切到 online scanner 頁面。
輸入要分析的網站後按下 Enter 或是後方的 RUN SCAN 按鈕進行網站的分析。
sonar 會給一個 PERMALINK,點選該連結進到網站分析頁面。
等待網站分析完成。
分析完成該分析頁面會顯示分析的網站、Warning 數、Error 數、分析的時間、分析的位置、不同分類下的 Warning 與 Error 數…等。
點選感興趣的分類即可跳至該分類下查看對應的 Warning 與 Error。
若要查看 Warning 與 Error 的細節,可點選後方的 + OPEN DETAILS 按鈕。
若還是不理解 Warning 與 Error 為何要檢測或是要如何修正,可點選後方的按鈕查閱對應的 sonar Rule 說明。
Link sonar, a linting tool for the web
read moreTag: Npm
Posts
npm - Change default directory
要設定 npm 的預設目錄,只要透過 npm config 命令設定 prefix 為指定的位置即可。
npm config set prefix [Path] Link 03 - Fixing npm permissions | npm Documentation
read morePosts
npm - Update npm with powershell
npm 的版本如果過舊要更新版本,除了用 npm install 去安裝更新版本的 npm,也可以用 powershell 去進行更新.
先用 npm 安裝 npm-windows-upgrade。
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force npm install -g npm-windows-upgrade 再呼叫 npm-windows-upgrade,選取要安裝的 npm 版本,然後等待更新完成即可。
read morePosts
npm - Update npm
npm 的版本如果過舊要更新版本,可以使用 npm install 去安裝更新版本的 npm,就像下面這樣:
npm install -g npm
read moreTag: Calibre Web
Posts
Calibre Web - Update Calibre Web
要進行 Calibre Web 的更新,可點擊頁面右上角的 Admin 按鈕進到 Admin 功能。
移到頁面最下方,點選 Check for update 按鈕。
如果有檢測到新的版本,會顯示出新版本發出的時間。若確定要更新,可點選 Perform Update 按鈕進行更新。
更新完按下 Ok 按鈕後重整頁面。
即可看到 Calibre Web 已被更新成新的版本。
read morePosts
Calibre Web - Upload book
要上傳電子書到 Calibre Web,可在登入後點選右上角的 Upload 按鈕。
選取要上傳的電子書。
上傳後 Calibre Web 會嘗試從電子書擷取封面、名稱、作者、描述。。。等資訊。
不過因為能從電子書中擷取的資訊有限,這邊可以點選最下方的 Get metadata 按鈕。
Calibre Web 會嘗試使用電子書的名稱到 Google 與 Douban 搜尋書籍的資訊,如果有符合的書籍,可在這邊直接選取。
Calibre Web 就會將選取的書籍資訊帶進來。
書籍資訊填妥後,最後按下 Submit 按鈕即可。
read morePosts
Calibre Web - Install on windows
要在 Windows 安裝 Calibre Web,可先在 Windows 安裝 Python 與 Pip。
然後將 Calibre Web 下載下來。
git clone https://github.com/janeczku/calibre-web.git 將 KindleGen 放至 Calibre Web 下的 vendor 目錄。
使用 pip 安裝 dependencies。
sudo pip install --target vendor -r requirements.txt 將 Calibre Web 服務運行起來。
python cps.py 訪問 http://localhost:8083,指定 Calibre database 位置,這邊的 Calibre 資料庫指的是 Calibre 桌機版的 Calibre library 目錄下的 metadata.db,可以直接指到同一個檔案,或是將之複製一份放置在欲放置的位置。
設定完導回 http://localhost:8083 首頁,輸入帳密 admin/admin123 登入。
即可開始使用 Calibre Web。
read morePosts
Calibre Web - Run Calibre Web with Kitematic
要使用 Kitematic 運行 Calibre Web,可在 Kitematic 搜尋 Calibre Web 的容器,點選 CREATE 按鈕將容器拉回啟用。
容器啟用後開啟瀏覽器訪問對應的位置,即可看到 Calibre Web 運行起來的畫面。
在 Location of Calibre database 填入 Docker 的 Data Vokumes 設定 /books,然後依需求調整其他設定,像是 Port 號、每頁放置的書本數量、是否支援上傳…等,設定完按下 Submit 按鈕送出。
導回首頁,輸入帳密 admin/admin123 登入即可開始使用。
Link technosoft2000/calibre-web - Docker Hub
read morePosts
Calibre Web - Install on ubuntu 12.04
要在 ubuntu 12.04 安裝 Calibre Web,可先將 apt-get 更新。
sudo apt-get update 因為會用到 pip 與 git,所以用 apt-get 安裝 python-setuptools 與 git。
sudo apt-get install python-setuptools git -y 使用 easy_install 安裝 pip。
sudo easy_install pip 將 Calibre Web 下載下來。
git clone https://github.com/janeczku/calibre-web.git 下載 KindleGen。
wget http://kindlegen.s3.amazonaws.com/kindlegen_linux_2.6_i386_v2_9.tar.gz 將 KindleGen 放至 Calibre Web 下的 vendor 目錄。
sudo mkdir calibre-web/vendor sudo tar -C calibre-web/vendor -xzvf kindlegen_linux_2.6_i386_v2_9.tar.gz 使用 pip 安裝 dependencies。
sudo pip install --target calibre-web/vendor -r calibre-web/requirements.
read moreTag: ProGet
Posts
MyInedo - Request trial/free license
要申請 Inedo 產品的試用或免費帳號,可到 MyInedo 註冊登入。
登入後按下 Request Trial/Free License 按鈕。
選取要申請的 Inedo 產品 License。
按下 Request License 按鈕。
即可取得申請的 License。
Link Log-in
read morePosts
ProGet - Licensing Activation
Licensing & Activation 頁面可設定 ProGet 的授權,像是使用 Docker 來跑 ProGet 的話,因為少了安裝的步驟,所以就需要自行到該頁面設定授權。
要設定授權的話可以點選 License key 後方的 change 連結。
輸入授權碼後按下 Save 按鈕。
然後需按下 Activation status 後方的 activate 連結啟用授權。
按下 Close 按鈕。
授權即會啟用。
read morePosts
ProGet - Upload VSIX Package
要從本地上傳 VSIX 套件到 ProGet 的 VSIX feed,可在 ProGet 的 VSIX feed 頁面按下 Add Package 按鈕。
點選 Upload Package。
按下 Choose File 按鈕。
選取要上傳的 VSIX 套件。
按下 Upload 按鈕。
選取的套件即會上傳到 ProGet 的 VSIX feed。
read morePosts
ProGet - Push via NuGet command line utility
要透過 NuGet 命令上傳 NuGet 套件到 ProGet 的 NuGet feed,可在 ProGet 的 NuGet feed 頁面按下 Add Package 按鈕。
點選 Push via NuGet Command Line Utility。
這邊會告知怎樣使用 NuGet 命令上傳 NuGet 套件。
參照說明使用 NuGet 命令上傳指定 NuGet 套件。
nuget push [Package] [APIKey] -source [FeedUrl] 若未設定 API key,可用 [UserName]:[Password] 替代。
命令調用完選取的套件即會上傳到 ProGet 的 feed。
read morePosts
ProGet - Getting Started with ProGet for Linux
要在 Linux 架設 ProGet,目前只有 Docker 的 Solution。
建立 Docker 容器的網路連結。
docker network create proget 建立 Postgres 資料庫容器供 ProGet 使用。
docker run -d -v /etc/localtime:/etc/localtime:ro -v /var/proget/db:/var/lib/postgresql/data --net=proget --name=proget-postgres --restart=unless-stopped postgres:9.5 建立 ProGet 容器。
docker run -d -v /etc/localtime:/etc/localtime:ro -v /var/proget/packages:/var/proget/packages -v /var/proget/extensions:/var/proget/extensions -p 80:80 --net=proget --name=proget --restart=unless-stopped inedo/proget:latest ProGet 即可正常運作。
若要停止服務,可用 docker stop 停止 proget 與 proget-postgres 容器。
docker stop proget proget-postgres 若要啟動服務,可用 docker start 啟動 proget 與 proget-postgres 容器。
read morePosts
ProGet - Manage users tasks
要管理 ProGet 的使用者,可先用具備管理權限的帳號進行登入。
如果還未設定過帳號,可用預設障密 Admin / Admin 登入。
登入後進到設定頁面。
選取 Manage User & Tasks 切到 Security 頁面。
Users 頁籤可以用來管理使用者,要建立使用者的話可按下 Create User 按鈕。
填入使用者資訊,像是使用者名稱、使用者密碼、用來顯示的名稱、電子郵件位置、使用者群組…等,按下 Save 按鈕。
指定的使用者即會被建立。
若要修改使用者資訊,可在該頁籤點選要修改資訊的使用者。
修改使用者資訊後按下 Save 按鈕即可。
若是要刪除使用者的話,可在該頁籤點選使用者資料列後方的 x。
Groups 頁籤可用來管理使用者群組,像是要建立使用者群組,可按下 Create Group 按鈕。
設定群組的名稱、群組內的成員,再按下 Save 按鈕。
指定的使用者群組即被會建立,若要修改使用者群組,可在該頁籤點選要修改的使用者群組。
修改使用者群組的資訊後按下 Save 按鈕即可。
要刪除指定使用者群組的話,點選使用者群組列後方的 x。
再按下 Yes,Delete Group 按鈕即可參除指定的使用者群組。
Tasks 頁籤可用來管理 Task,我們可點選 Customize Tasks 按鈕。
再點選 Add Task 按鈕進行 Task 的新增動作。
Task 新增時要填入 Task 的名字、描述、以及可以使用的權限,設定完按下 Create Task 按鈕。
Task 即會被建立,若要修改 Task 可點選要修改的 Task,進行 Task 的修改動作。
read morePosts
ProGet - Connectors
ProGet Connector 允許 ProGet feed 取得其它來源的套件。
可從 Feed 管理頁面建立加入 Connector。
也可以在 Connectors 頁面建立 Connector。
然後在 Feed 管理頁面加入 Connector。
Feed 加入 Connector 後即可查閱到 Connector 來源內的套件。
Link Connectors - ProGet Documentation | Inedo
read morePosts
ProGet - Bulk nuget package import
要將大量的 NuGet 套件匯入到 ProGet 的 NuGet feed,可在 ProGet 的 NuGet feed 頁面按下 Add Package 按鈕。
點選 Bulk Package Import/File Copy。
這功能需要設定 drop path,若 drop path 未被設定,會看到如下警示畫面,可點選 Go to the feed administration page 連結設定 drop path。
若是 drop path 有設定的話,則會顯示 drop path 設定。
接著只要將 NuGet 套件放置 drop path。
套件即會被匯入。
read morePosts
ProGet - Pull NuGet package from another repository
要拉外部 repository 的 NuGet 套件到 ProGet 的 NuGet feed,可在 ProGet 的 NuGet feed 頁面按下 Add Package 按鈕。
點選 Pull From Another Repository。
填入外部 Feed 位置、套件 ID、套件版本,按下 Install Package 按鈕。
即會從指定的 Repository 位置拉指定版本的套件到 ProGet 的 NuGet feed。
read morePosts
ProGet - Upload NuGet package from disk
要從本地上傳 NuGet 套件到 ProGet 的 NuGet feed,可在 ProGet 的 NuGet feed 頁面按下 Add Package 按鈕。
點選 Upload from Disk。
按下 Choose File 按鈕。
選取要上傳的 NuGet 套件。
按下 Upload 按鈕。
選取的套件即會上傳到 ProGet 的 NuGet feed。
read morePosts
ProGet - Push npm package via npm command line
要透過 npm 命令上傳 npm 套件到 ProGet 的 npm feed,可在 ProGet 的 npm feed 頁面按下 Add Package 按鈕。
點選 Push via npm (Command line)。
這邊會告知怎樣使用 npm publish 命令上傳 npm 套件,使用前需點選 configured npm,參閱該連結做些設定。
像是設定 npm 的 registry 位置。
npm set registry <RegistryUrl> 設定 npm registry 使用者帳號,這邊直接使用 ProGet 帳號轉小寫後輸入、輸入密碼。
npm adduser 再使用 npm publish 將指定的 npm 套件發佈上 Registry。
npm publish <NpmPackage> 選取的套件即會上傳到 ProGet 的 npm feed。
read morePosts
ProGet - Upload npm package
要上傳 npm 套件到 ProGet 的 npm feed,可在 ProGet 的 npm feed 頁面按下 Add Package 按鈕。
點選 Upload npm Package。
選取要上傳的套件檔案並設定 Tags,按下 Upload File 按鈕繼續。
選取的套件即會上傳到 ProGet 的 npm feed。
read morePosts
ProGet - Pull npm package from external registry
要拉外部 registry 的 npm 套件到 ProGet 的 npm feed,可在 ProGet 的 npm feed 頁面按下 Add Package 按鈕。
點選 Pull from External Registry。
填入 Registry 位置、套件名稱、套件版本,按下 Pull Package 按鈕。
即會從指定的 Registry 位置拉指定版本的套件到 ProGet 的 npm feed。
read morePosts
ProGet - Create feed
ProGet 要建立 Feed,可在帳號登入後切至 Feeds 頁面。
點選 Create New Feed 按鈕。
選取要建立的 Feed 類型,看是 npm、NuGet、Bower…
設定要建立的 Feed 的名稱,按下 Create Feed 按鈕。
指定的 Feed 就會被建立,並帶到 Manage Feed 的頁面,若有需要可透過該頁面做細部設定的調整。
切回 Feeds 頁面就會看到剛建立的 Feed。
read morePosts
ProGet - Installation
要安裝 ProGet,可到 ProGet 官網,切換到下載頁面下載安裝程式。
安裝程式下載下來後點擊安裝,
一開始是授權頁面,沒問題的話按下 I Agree 按鈕接受授權繼續。
設定要使用的 ProGet 版本,看是要使用免費版、企業版的 45 天試用、還是要輸入序號使用。
設定要註冊用的電子郵件與使用者名稱。
設定安裝的路徑。
設定 ProGet 要用的 SQL Server。若已有 SQL Server,可勾選 Existing SQL Server Instance,設定 SQL Server 的連線。若是沒有現成的 SQL Server,可勾選 New Instance of SQL Express,讓安裝程式安裝 SQL Express 給 ProGet 使用。
設定 ProGet 的 Host 方式。勾選 Integrated Web Server,ProGet 會 Host 成 Windows 服務。勾選 IIS,ProGet 會 Host 在 IIS 站台上。
設定要給 ProGet 運行用的帳號。
如果設定都正確,按下 Install 按鈕進行安裝即可。
安裝完按下 Launch ProGet 按鈕。
read moreTag: SQLiteStudio
Posts
SQLiteStudio - Create SQLite database
要透過 SQLiteStudio 建立 SQLite 資料庫,可點選 [Database | Add a database] 主選單選項,或是按下熱鍵 Ctrl + O。
在開啟的對話框中,點選 File 後面的 Add 按鈕。
設定要建立的 SQLite 資料庫存放的位置與檔名,按下 Save 按鈕。
指定的 SQLite 資料庫檔即會被建立。
read moreTag: Gitea
Posts
Gitea - Install from binary
要透過二進制黨進行 Gitea 的安裝,可將 Gitea 二進制黨拉下來。
wget -O gitea https://dl.gitea.io/gitea/1.0.0/gitea-1.0.0-linux-amd64 調整權限。
chmod +x gitea 啟用 Gitea 服務即可。
./gitea web Link 從二進制安裝- Docs
read morePosts
Gitea - Install with docker
透過 Docker 使用 Gitea,可用 docker pull 將 Gitea 容器拉回。
docker pull gitea/gitea:latest 然後建立一個目錄用以存放資料。
使用 docker run 啟動 Gitea 容器,將剛建立的目錄掛載為資料卷。
docker run -d --name=gitea -p 10022:22 -p 80:3000 -v /gitea:/data gitea/gitea:latest 即可使用 Gitea 服務。
Link Docker 安裝 - Docs
read moreTag: GitKraken
Posts
GitKraken - Create branch
使用 GitKraken 建立分支,可在 Tag、Repository、commit 上按下滑鼠右鍵,點選 Create branch here 選單選項。
或是按下上方工具列的 Branch 按鈕,按下後會要求輸入新分支的名稱。
輸入心分支的名稱後按下 Enter。
GitKraken 即會建立並切換至指定的分支。
read morePosts
GitKraken - Clone git repository
要使用 GitKraken 將 Repository clone 下來,可點選 GitKraken 左上方的資料夾圖示。
切到 Clone 頁籤,選取 Clone with URL,帶入 Repository url 與要 Clone 到的位置,點選 Clone the repo! 按鈕。
輸入 Repository 帳密後按下 Log In 按鈕。
GitKraken 即會開始 Clone repository 到指定的位置。
Clone 完可點選 Open Now 按鈕直接開啟。
read moreTag: Visual Studio
Posts
BuiltinCmd - Integrate windows cmd terminal into Visual Studio
BuiltinCmd 是 Visual Studio 的擴充套件,能整合命令列視窗至 Visual Studio。
透過 Extension Manager 安裝套件。
將 Visual Studio 重啟。
點選 [View | Other Windows | Toggle BuiltinCmd] 主選單選項,或是按下熱鍵 Ctrl + Shift + T 即可開啟 BuiltinCmd 視窗。
Link BuiltinCmd - Visual Studio Marketplace
read morePosts
>-
Exception Breaker 是 Visual Studio 的套件,能更方便快速的切換 CLR Exception 是否要中斷。
在開發時為了補獲 First chance exception 並中斷,時常要對 CLR Exception 的 Exception Setting 設定做切換,每次都要開啟 Exception Setting 去切換/還原設定十分的麻煩。該套件提供了工具列按鈕與熱鍵,讓切換上更為方便快速。
該套件可透過 Extension Manager 安裝。
套件安裝完需要重啟 Visual Studio。
Visual Studio 重啟後進入除錯模式,即可看到 Exception Breaker 套件的按鈕,按下工具列按鈕或是熱鍵 Ctrl + E, Ctrl + B 即可進行 CLR Exception 中斷設定的切換。
Link Exception Breaker - Visual Studio Marketplace
read morePosts
Visual Studio 2017 - Live unit testing
要啟動 Visual Studio 2017 Live Unit Testing 功能,可點選 [Test | Live Unit Testing | Start] 主選單選項。
啟動後單元測試會持續在背景運行。
可在開發程式時即時看到測試的狀況與覆蓋情形。
需注意的是這功能需要 MSTest V2 才能啟用,舊測試專案需要移除 Microsoft.VisualStudio.QualityTools.UnitTestFramework 的參考。
加入 MSTest.TestFramework 套件。
加入 TestAdapter 套件。
最後調整命名空間即可。
read morePosts
Visual Studio 2017 - Improved Code Navigation
Visual Studio 2017 對程式碼的巡覽做了些強化,[Edit | Go To] 主選單選項內有著所有的巡覽功能。
像是 Go To All... (熱鍵 Ctrl+T)
Go To Line... (熱鍵 Ctrl+G)
Go To File... (熱鍵 Ctrl+1, Ctrl+F)
Go To Type... (熱鍵 Ctrl+1, Ctrl+T)
Go To Symbol... (熱鍵 Ctrl+1, Ctrl+S)
Go To Member... (熱鍵 Ctrl+1, Ctrl+M)
也可以記住搜尋框認的關鍵字,像是 Go To Line... 是用 :、Go To File... 是用 f、Go To Type... 是用 t、Go To Symbol... 是用 #、Go To Member... 是用 m,這樣會更方便使用。
read morePosts
Visual Studio 2017 - Find all references
Visual Studio 2017 針對 Find all references 視窗做了些強化,在要查詢 Reference 的地方按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中點選 Find All References 選單選項,將 Find all references 視窗開啟。
開啟後會看到該視窗跟 Visual Studio 2017 以前有些許不同,上方工具列有些差異,結果也改以群組的方式呈現。
上方工具列有下拉式選單可供我們選擇是找尋整個方案、開啟的文件、當前專案、當前文件。
也提供向前巡覽 reference (也可用熱鍵 Shift + F8 觸發)。
向後巡覽 reference (也可用熱鍵 F8 觸發)。
也有下拉選單可以改變群組的方式,像是預設的 Project then Definition 群組,會先以專案再以程式碼的定義去群組:
Definition Only 會以程式碼的定義去群組:
Definition then Project 會先以程式碼定義再以專案去群組:
Definition then Path 會先以程式碼定義再以專案路徑去群組:
Definition, Project then Path 會先以程式碼定義再以專案最後以專案路徑去群組:
不同的群組方式適用於不同的使用情境,可視需求調整使用。
若有需要進一步篩選,可利用上方的搜尋框。
若要保留搜尋結果供後續使用,可按下 Keep Result 按鈕。
這樣再次搜尋 Reference 時就不會重用本來的視窗。
而會使用新的視窗。
read morePosts
Visual Studio 2017 - Roaming Extension Manager
Visual Studio 2017 以前安裝的 Extension 無法同步,所以在不同電腦間 Extension 都需要自行安裝。
Visual Studio 2017 以後新增了 Roaming Extension Manager,可用來設定要同步的 Extension。只要開啟 Extensions and Updates 視窗,切到 Roaming Extension Manager 頁面,在想要同步的 Extension 後面按下 Start Roaming 按鈕,指定的 Extension 即可同步到不同電腦。
read morePosts
Visual Studio 2017 - Modify extensions in bulk
Visual Studio 2017 以後使用 Extensions and Updates 視窗進行 Extension 的修改。
修改的 Extension 會被加入排程,排程的 Extension 可以在 Extensions and Updates 視窗的右下角看到,若有需要也可以將排程刪除。
接著將 Visual Studio 關閉。
排程的 Extension 即會開始運行對應的動作。
read morePosts
Visual Studio 2017 - Reattach to process
Visual Studio 2017 以前如果要重新附加到相同的處理序,我們需要自行用 Attach to Process 對話框再次附加相同的處理序,或是透過 Visual Studio 2017 的外掛直接重新附加處理序。
Visual Studio 2017 以後新增 Reattach to process 功能,只要之前附加過處理序,[Debug | Reattach to Process…] 主選單選項即會浮現,若有需要則可點選該主選單選項,或是用熱鍵 Shift+Alt+P,進行處理序的重新附加。
read morePosts
Visual Studio 2017 - Match highlighting
Visual Studio 2017 以前在使用 IntelliSense 時,有時我們會搞不清楚出來的成員是因為匹配到什麼才會顯示出來。
Visual Studio 2017 以後支援 Match highlighting,當使用 IntelliSense 時匹配到的字元會被 Highlight,可以清楚知道為什麼 IntelliSense 會將該成員列出。
read morePosts
Visual Studio 2017 - IntelliSense filtering
Visual Studio 2017 以前 IntelliSense 是不具備 Filtering 功能的,必須從眾多成員中挑選出所要選用的,當成員過多時這問題會更加嚴重。
Visaul Studio 2017 加入 IntelliSense filtering,在 IntelliSense 對話框的下半部增加了過濾的按鈕,能針對成員類型進行過濾。
像是可以設定只顯示屬性。
可以設定只顯示方法。
可以設定只顯示擴充方法…等等。
read morePosts
Visual Studio 2017 - Run to click
Visual Studio 2017 以前,在除錯時若要讓斷點繼續向下運行至指定位置,我們需要在指定位置設定斷點後讓他向下運行,或是直接在指定位置上按下滑鼠右鍵,點選 Run to cursor 滑鼠右鍵選單也可以。
在 Visual Studio 2017 以後新增了 Run to click 的功能,提供我們另一個選擇。使用上要先設定個斷點進入除錯模式,讓它中斷在設定的斷點上。
接著將滑鼠移到指定位置上,指定位置的前方會浮現個小圖示,滑鼠點擊該圖示即可運行至指定位置後中斷。
read morePosts
Visual Studio 2017 - Structure visualizer
Visual Studio 2017 以前,在編寫程式時有時我們會需要找一下程式碼中的刮號,確定我們在改的區塊是否正確。Visual Studio 2017 新增 Structure visualizer 功能,能讓我們更容易知道所修改的區塊是哪。
該功能預設應該是開啟的,若未開啟可開啟 Options 視窗,切到 [Text Editor | General] 頁面,將 Show structure guide lines 選項勾選。
在程式碼這邊應該就會看到對應的括號之間出現了 Structure Guide Lines。接著只要將滑鼠移至 Structure Guide Lines 上,Structure visualizer 即會浮現,我們可以清楚的了解到所在修改的區塊位置。
read morePosts
Visual Studio 2017 - Lightweight solution load
Visual Studio 2017 新增 Lightweight Solution load 功能,能 OnDemand 進行專案的載入,特別適用於大型專案的開發。
該功能預設是關閉的,要啟用可開啟選項對話框,切到 [Projects and Solutions | General] 頁籤,勾選 Lightweight Solution load 選項。
將專案載入,乍看起來好像沒什麼太大的變化。
但仔細看方案總管這邊,會發現方案名稱後面多了個 lightweight 字樣。
將方案總管的專案展開,會看到其實專案還沒被載入,展開的同時才開始進行載入。
稍待一下即可載入完成。
read morePosts
Visual Studio 2017 - Attach to Process Filter
在 Visual Studio 2017 以前要在 Attach to Process 對話框中找到要附加的處理序,需要在一堆處理序中挑選。
Visual Studio 2017 針對 Attach to Process 對話框做了強化,新增過濾的功能,便於使用者快速挑選要附加的處理序。
滑鼠點選 [Debug|Attac to Process…] 主選單選項,或是按下熱鍵 Ctrl+Alt+P,叫出 Attach to Process 對話框。
會看到在 Attach to Process 對話框中處理序列表的上方多出了一個搜尋框,將要過濾的字樣填入,下方的處理序列表即會列出過濾後的處理序。
Link Visual Studio 2017 Release Notes
read morePosts
Web Deploy - Publish with Visual Studio
要直接用 Visual Studio 使用 Web Deploy 去做佈署,首先在方案總管的專案上按下滑鼠右鍵,點選 Publish... 滑鼠右鍵選單選項。
在 Publish Web 視窗中選取 Cuetom Profile。
設定 Profile 的名稱。
接著 Publish method 選定 Web Deploy,設定要佈署的 Server 及帳號資訊。
再來選定要建置的 Configuration。
若想在發佈前查看一下會做哪些更動,可透過預覽的功能查看。
沒問題就可以進行發佈的動作。
read morePosts
Visual Studio - Exception of type 'Phx.FatalError' was thrown
如果 Visual Studio 出現 “Exception of type ‘Phx.FatalError’ was thrown” 這樣的錯誤。
可以重新註冊 dll 來修復這問題,不同版本的 Visual Studio 需要註冊不同的 dll。
Visaul Studio Command Visual Studio 2010 regsvr32 “%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\msdia100.dll” Visual Studio 2012 regsvr32 “%ProgramFiles(x86)%\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\msdia110.dll” Visual Studio 2013 regsvr32 “%ProgramFiles(x86)%\Microsoft Visual Studio 12.0\Common7\Packages\Debugger\msdia120.dll” Visual Studio 2015 regsvr32 “%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\Common7\Packages\Debugger\msdia140.dll” 像是筆者出問題的是 Visual Studio 2015,所以要像下面這樣註冊。
註冊完問題就排除了。
Link Error in FxCop Phoenix analysis engine - Stack Overflow FxCop error CA0001 on build server – Altug Sahin’s Blog
read morePosts
Visual Studio - Clone git repository
使用 Visual Studio clone git repository,先將 Team Explorer 視窗開啟。
在 本機 Git 儲存機制 這邊點選 複製 按鈕。
再來要設定欲 clone 的 git repository 位置,以及 clone 下來存放的位置。
填完按下 複製 按鈕開始進行 Clone。
Clone 完成會在 Team Explorer 直接列出該 Repository。
透過滑鼠右鍵快顯選單我們可以用命令提示字元或是檔案總管開啟 Clone 下來的 Repository。
read morePosts
Visual Studio - Move obj folder
Visual Studio 的專案在建置 .NET 專案時會自動建立 Obj 目錄放置中繼檔案,該目錄位置並無直接的設定方式。
如果想要調整該目錄位置,可設定 Project 檔案,在欲生效的 PropertyGroup 中加入 BaseIntermediateOutputPath 元素去指定位置。
... <PropertyGroup> ... <BaseIntermediateOutputPath>..\..\Obj</BaseIntermediateOutputPath> </PropertyGroup> ...  <br/> Link
read morePosts
Visual Studio 15 Preview - Enabling C# 7 Features
Visual Studio 15 Preview 開始支援部分 C# 7.0 的功能,由於尚未完全定案,故並未直接開放,需要做些特別的設定才可將之開啟。
若要啟用需切打開專案的屬性頁,切至建置頁面,在條件式編譯的符號那邊設定 __DEMO__,__DEMO_EXPERIMENTAL__ 即可。
{% img /images/posts/VS15PreviewEnableCSharp7/1.png %}
Link Enabling C# 7 Features in Visual Studio “15” Preview | StrathWeb. A free flowing web tech monologue.
read morePosts
Visual Studio 15 Preview - Exception Helper
Visual Studio 15 Preview 以前,託管的程式會透過 Exception Assistant 提供錯誤資訊。
{% img /images/posts/VS15PreviewExceptionHelper/1.png %}
非託管的程式或是將 Exception Assistant 關閉的話,則是透過 Exception Dialog 提供錯誤資訊。
{% img /images/posts/VS15PreviewExceptionHelper/2.png %}
在 Visual Studio 15 Preview 以後,開發人員可以選擇使用 Exception Helper 來提供除錯資訊,只要開啟選項對話框,切換到偵錯頁面,啟用 Exception Helper。
{% img /images/posts/VS15PreviewExceptionHelper/3.png %}
當例外發生時,錯誤資訊就會改用 Exception Helper,可以看到新的 Exception Helper 訊息精簡許多。
{% img /images/posts/VS15PreviewExceptionHelper/4.png %}
新的 Exception Helper 不會像以往一樣直接蓋在程式碼上面,而且可釘選,查閱程式錯誤時不再那麼綁手綁腳。
{% img /images/posts/VS15PreviewExceptionHelper/5.png %}
如果有 Inner exception,也可以很直接就看到 Inner exception 的訊息,不用特別追進 Detail 查閱。
{% img /images/posts/VS15PreviewExceptionHelper/6.png %}
當然若有需要也是可以查閱到 Detail 的部分。
read morePosts
Visual Studio 15 Preview - Code style enhancement
Visual Studio 15 Preview 針對 Code Style 做了些強化。
在 Visual Studio 2015 Update 2 中,Code Style 只有少少的幾個項目可供設定:
{% img /images/posts/VS15PreviewCodeStyleEnhancement/1.png %}
在 Visual Studio 15 Preview 中這功能完整了許多,添加許多的設定項目,相似的設定會被群組在一起,而且改用下拉清單取代本來的勾選框,設定上也更為清楚直覺。
{% img /images/posts/VS15PreviewCodeStyleEnhancement/2.png %}
{% img /images/posts/VS15PreviewCodeStyleEnhancement/3.png %}
有些設定還可套上嚴重程度,這邊視個人需要下去調整即可,看覺得是 None,Info,Warning,Error 哪個層級都可。
{% img /images/posts/VS15PreviewCodeStyleEnhancement/4.png %}
read morePosts
Visual Studio 15 Preview - Open folder
Visual Studio 15 Preview 開始支援用目錄的方式開啟。
使用上只要點選 [File | Open | Folder…] 主選單選項,選取要載入的目錄即可。
{% img /images/posts/VS15PreviewOpenFolder/1.png %}
{% img /images/posts/VS15PreviewOpenFolder/2.png %}
read morePosts
Visual Studio 15 Preview - Naming style
Visual Studio 15 Preview 開始支援命名規則的檢查。
使用時可開啟選項視窗,切換到 [Text Editor | C# | Code Style | Naming] 頁面,點選右側頁面的 “+” 按鈕,加入新的命名規則。
{% img /images/posts/VS15PreviewNamingStyle/1.png %}
在彈出的命名規則對話框中,我們要先為這個命名規則取個名字,接著點選符號規格後的 “+” 按鈕,設定命名規則要套的範圍。
{% img /images/posts/VS15PreviewNamingStyle/2.png %}
符號規格對話框這邊,我們一樣要給符號規格命名,然後決定命名規則套用的範圍。像是這邊筆者想要對所有方法生效,在符號種類這邊就要選取 method,存取範圍則全部選取。
{% img /images/posts/VS15PreviewNamingStyle/3.png %}
符號規則訂定後,接著要訂定命名樣式,命名樣式這邊一樣要為它命名,然後設定他的前置詞,後置詞,分隔字元,大小寫。像是這邊筆者想要讓所有的方法都用 Pascal 命名,所以這邊將設定調為 Pascal 大小寫名稱。
{% img /images/posts/VS15PreviewNamingStyle/4.png %}
最後要設定的是命名規則的嚴重程度,這邊視個人需要下去調整即可,看覺得是 None,Info,Warning,Error 哪個層級都可。
{% img /images/posts/VS15PreviewNamingStyle/5.png %}
設定好後在撰寫程式時 Visual Studio 就會依照制定的命名規則下去檢查。
{% img /images/posts/VS15PreviewNamingStyle/6.png %}
read morePosts
Visual Studio 2015 - Diagnostic Tools
Diagnostic Tools 是 Visual Studio 2015 的新功能,能幫助開發人員快速的找出效能上的問題。
該功能預設除錯時會自動帶出,畫面會像下面這樣。
{% img /images/posts/DiagnosticTools/1.png %}
一邊運行,一邊就會將 CPU、記憶體、與 Event 的狀態帶出。有效能問題開發人員可以即早發現。像這邊的記憶體曲線看起來雖然是平的,但是可以看到有很多次的 GC 出現,這就是需要進行調整的。
{% img /images/posts/DiagnosticTools/2.png %}
記憶體這邊的診斷上我們可以用快照比對分析。只要簡單的進行快照,Diagnostic Tools 就會將兩個快照間的差異清楚的呈現。像是這邊就可以看到物件數跟 Heap 大小有上升的趨勢。進一步點擊,我們可以查看是被哪些物件佔用的,增加的又是哪些物件。
{% img /images/posts/DiagnosticTools/3.png %}
Link Performance and Diagnostic Tools in Visual Studio 2015 - Microsoft Application Lifecycle Management - Site Home - MSDN Blogs Visual Studio 2015 Diagnostics Investments - The Visual Studio Blog - Site Home - MSDN Blogs
read morePosts
Visual Studio 2015 - New Exception Settings Window
在使用 Visual Studio 對 .NET 程式進行除錯時,有時候我們會需要對 Exception Setting 進行些調整,以便快速的找出問題發生的點。
但是以往的 Exception Setting 是以對話框形式呈現,開關設定十分的不便,且不具搜尋過濾的功能,要找到指定的設定很不容易。
這樣的問題在 Visual Studio 2015 獲得了改善,Exception Setting 改以 Window 方式呈現能方便我們隨時進行調動,也新噌了搜尋與過濾的功能便於快速找到指定的設定。
舉個例子來說,今天我們的程式碰到了個不如預期的問題,我們的程式會被導到例外被攔截的位置。
{% img /images/posts/ExceptionSettingWindowInVS2015/1.png %}
但例外被攔截的位置並非我們所關注的地方,此時我們會調整 Exception Setting 讓 Common Language Runtime Exceptions 設定被勾選,這樣因為可以攔截到 First chance exception,所以程式會改停在錯誤實際發生的位置。
{% img /images/posts/ExceptionSettingWindowInVS2015/2.png %}
若要細部指定特定的例外,像是 NullReferenceException,可以直接透過搜尋找到對應的設定。
{% img /images/posts/ExceptionSettingWindowInVS2015/3.png %}
針對非系統提供的例外,這邊也允許自行加入設定。
{% img /images/posts/ExceptionSettingWindowInVS2015/4.png %}
Link The New Exception Settings Window in Visual Studio 2015 - Microsoft Application Lifecycle Management - Site Home - MSDN Blogs Understanding Exceptions while debugging with Visual Studio - Microsoft Application Lifecycle Management - Site Home - MSDN Blogs
read morePosts
Code Cracker
Code Cracker 是 Roslyn analyzer 的 Library,有點類似 FxCop 的 Rule,依不同的範疇實做了很多相關的檢查,可以看到有 Design、Globalization、Maintainability、Naming、Performance、Portabili、Security …等。雖然還未完全實作完畢,但目前已經相當多的檢查 Rule 了。
{% img /images/posts/CodeCracker/1.png %}
安裝上一樣是提供 VSIX 或是 NuGet Package 兩種,若是要套到所有專案,可直接透過 Extension and Updates 安裝。
{% img /images/posts/CodeCracker/2.png %}
若是只要套用到單一專案,可直接透過 NuGet 安裝。不論是要用 NuGet 的 GUI 介面。
{% img /images/posts/CodeCracker/3.png %}
或是直接透過 NuGet 命令都可以。
Install-Package CodeCracker.CSharp -IncludePrerelease Install-Package CodeCracker.VisualBasic -IncludePrerelease 用 NuGet 安裝的話,Analyzer 會出現在方案總管的 References\Analyzers 節點下。
{% img /images/posts/CodeCracker/4.png %}
展開 Analyzer 節點可進一步看到支援的 Rule。
{% img /images/posts/CodeCracker/5.png %}
read morePosts
Visual Studio 2015 - New Breakpoint Configuration Experience
Visual Studio 2015 在除錯功能上做了一些改進,其中一項就是 New Breakpoint Configuration Experience。
以往在設定中斷點時,中斷點的設定視窗是彈跳出來的,設定時要參考程式碼不易,且各個設定雖然可以合併使用但卻是分開的設定視窗。Visual Studio 2015 將之做了個調整,使用類似 Peek Definition 的作法,並將設定整合,讓設定可在一個地方一次設完且一目了然。
使用上只要將滑鼠移至斷點之上,按下浮現的設定按鈕。
{% img /images/posts/NewBreakpointExperienceInVS2015/1.png %}
類似 Peek Definition 的設定視窗會跑出來,可看到之前的設定都在這邊可以一次設完,像是 Hit Condition 與 Count Condition。
{% img /images/posts/NewBreakpointExperienceInVS2015/2.png %}
追蹤點的設定也不例外。
{% img /images/posts/NewBreakpointExperienceInVS2015/3.png %}
因為是用嵌入的方式去做設定,所以設定完在除錯時若有需要,檢視上也比較容易。
{% img /images/posts/NewBreakpointExperienceInVS2015/4.png %}
Link Debugging Improvements in Visual Studio 2015 | Visual Studio Toolbox | Channel 9 New Breakpoint Configuration Experience in Visual Studio 2015 - Microsoft Application Lifecycle Management - Site Home - MSDN Blogs
read morePosts
Visual Studio 2015 - Support for debugging lambda expressions
Visual Studio 2015 以前,無論是透過監看視窗還是快速監看視窗,在除錯時都無法針對 Lambda 語法進行偵錯,除錯上很不方便。
{% img /images/posts/VS2015DebugLambda/1.png %}
{% img /images/posts/VS2015DebugLambda/2.png %}
在 Visual Studio 2015 以後,這問題獲得了改善,針對 Lambda 語法的除錯進行了支援。不僅解決了除錯上的困擾,要在除錯時用 Linq 拉些額外的資料來看也更為方便了。
{% img /images/posts/VS2015DebugLambda/3.png %}
{% img /images/posts/VS2015DebugLambda/4.png %}
read morePosts
.NET Portability Analyzer Extension
.NET Portability Analyzer Extension 是微軟出的 Visual Studio 擴充套件,能偵測程式是否具備 Portability,並針對不具 Portability 的地方提供對應的修改建議,讓開發人員在做跨平臺的開發上更加的便利。
{% img /images/posts/PortabilityAnalyzerExtension/1.png %}
Channel9 這邊有相關的介紹影片,建議可以稍微瀏覽一下,可以幫助我們快速上手。
使用前記得先將擴充套件裝上。
裝好後需先至 Options 這邊設定所要分析的平臺。
{% img /images/posts/PortabilityAnalyzerExtension/2.png %}
在使用上,該擴充套件有兩種不同的使用方式。一種是對選取的組件進行分析,透過 [Analyze/Analyze Assembly Portability…] 主選單選項去觸發。
{% img /images/posts/PortabilityAnalyzerExtension/3.png %}
{% img /images/posts/PortabilityAnalyzerExtension/4.png %}
產生的報表能顯示出程式在各平台的支援程度,及細部的支援比較。
{% img /images/posts/PortabilityAnalyzerExtension/5.png %}
另一種則是對選取的專案進行分析,透過方案總管的滑鼠右鍵選單選項觸發。
{% img /images/posts/PortabilityAnalyzerExtension/6.png %}
一樣會產生類似的報表,但是因為透過專案的方式觸發有程式原碼,所以報表還會進一步的給予我們對應的修改建議,Error List 工具視窗這邊也會顯示出對應的訊息。
{% img /images/posts/PortabilityAnalyzerExtension/7.png %}
Link .NET Portability Analyzer extension Leveraging existing code across .NET platforms - .NET Blog - Site Home - MSDN Blogs
read morePosts
Clr C# Heap Allocation Analyzer
Clr C# Heap Allocation Analyzer 是 Diagnostic Analyzers 的套件,功能上有點類似 ReSharper - Heap Allocation Viewer Extension,能對 Heap 的操作部分做些 Highlight。
這邊可先參閱一下影片的介紹:
該套件提供兩種安裝方式,一種是選擇安裝 VSIX,用 Extension Manager 搜尋安裝或是自 NuGet Gallery | Clr C# Heap Allocation Analyzer 1.0.0.5 下載安裝,好處是可以將效果套用至所有專案。
{% img /images/posts/HeapAllocationAnalyzer/1.png %}
一種則是用 NuGet By 專案安裝,好處是可以只套用至特定的專案。
{% img /images/posts/HeapAllocationAnalyzer/2.png %}
安裝完後,在程式編輯時即會呈現進行對應的分析,像是筆者這邊的程式即被偵測出有 Boxing 的動作。
{% img /images/posts/HeapAllocationAnalyzer/3.png %}
Link NuGet Gallery | Clr C# Heap Allocation Analyzer 1.0.0.5 Clr Heap Allocation Analyzer extension
read morePosts
Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers
Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers 是一個 Diagnostic Analyzer 套件,是 FxCop 部分檢查規則的 Analyzer 實作。
{% img /images/posts/FxCopAnalyzers/1.png %}
因為目前仍是 Preview 版本,所以這邊在使用時需先叫出 Package Manager Console,然後叫用命令安裝:
Install-Package Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers -Pre {% img /images/posts/FxCopAnalyzers/2.png %}
安裝完後,我們可以看到方案總管的 Analyzers 節點下多了兩個 Analyzer。
{% img /images/posts/FxCopAnalyzers/3.png %}
展開節點可以看到該 Analyzer 所 Support 的分析。
{% img /images/posts/FxCopAnalyzers/4.png %}
回到程式編輯這邊,可以看到當我們程式撰寫不符合 Analyzer 的規定時,編譯器就會提出對應的警告,像這邊就告知我們要實作 IDisposible 介面,也提供了對應的修正。
{% img /images/posts/FxCopAnalyzers/5.png %}
read morePosts
Roslyn Syntax Visualizers
在使用 Roslyn 做開發時,常免不了會要去處理語法的解析,這時我們會需要輔助工具將語法解析轉換為語法樹,以視覺的方式呈現,讓 Roslyn 的開發上更為便利。
所以開發前我們要到 .NET Compiler Platform Syntax Visualizer extension 這邊下載 Roslyn Syntax Visualizer。
{% img /images/posts/RoslynSyntaxVisualizer/1.png %}
下載完後進行安裝。
{% img /images/posts/RoslynSyntaxVisualizer/2.png %}
{% img /images/posts/RoslynSyntaxVisualizer/3.png %}
安裝完我們可以透過 Visual Studio 的主選單選項(View\Other Windows\Roslyn Syntax Visualizer)將 Roslyn Syntax Visualizer Tool Window 叫出。
{% img /images/posts/RoslynSyntaxVisualizer/4.png %}
叫出後 Roslyn Syntax Visualizer 後,它會偵測目前所編輯的程式碼,將之解析成語法樹。且會偵測編輯區的選取,反映在語法樹上。
{% img /images/posts/RoslynSyntaxVisualizer/5.png %}
反之亦然。
{% img /images/posts/RoslynSyntaxVisualizer/6.png %}
語法樹上的節點有做顏色的區分,可以透過上方的 Legend 按鈕查閱各顏色所代表的意義。
{% img /images/posts/RoslynSyntaxVisualizer/7.png %}
語法樹上節點的滑鼠右鍵快顯選單也有提供一些功能,像是可以用更直覺的圖形方式呈現。
{% img /images/posts/RoslynSyntaxVisualizer/8.
read morePosts
Visual Studio 14 CTP 3 - PerfTips in the Debugger
PerfTips 是 Visual Studio 14 (CTP3 以後釋出)的新功能,能讓開發人員在除錯的同時了解程式的耗時與 CPU 的耗用。
以往我們為了觀測程式的耗時我們需要做程式碼的修改,用 Stopwatch 去監測。在 Visual Studio 14 CTP3 後,我們不需要修改程式就可以很輕易的監測程式的效能,只要透過 PerfTips 功能就可以了。
PerfTips 使用上很簡單,只要設定斷點進行除錯,看你是要 Step Into、Step Over、Step Out、或是直接 F5 跳到下一個斷點,PerfTips 都會自動在後面跳出上一步到這一步之間的耗時。
{% img /images/posts/PerfTips/1.png %}
預設這邊只有開啟耗時的部份,若要查閱 CPU 的耗費,我們可以將滑鼠移至 PerfTips 上面,彈出的 ToolTip 會有這方面的資訊。
{% img /images/posts/PerfTips/2.png %}
或者也可以點擊 PerfTips 叫出對應的選項設定。
{% img /images/posts/PerfTips/3.png %}
將 CPU 耗費的顯示給開啟,或是設定 PerfTips 要大於等於多少才顯示。
{% img /images/posts/PerfTips/4.png %}
{% img /images/posts/PerfTips/5.png %}
Link Visual Studio “14” CTP 3 Released - The Visual Studio Blog - Site Home - MSDN Blogs PerfTips: Performance Information at-a-glance while Debugging with Visual Studio - Microsoft Application Lifecycle Management - Site Home - MSDN Blogs
read morePosts
Visual Studio 14 CTP 2 - Light Bulb Editor Adornment
Light Bulb Editor Adornment 是Visual Studio 14 的新功能,能讓開發人員快速識別及修正程式的錯誤。
當程式錯誤時,Visual Studio 會在編輯區前方,或是在錯誤列的下方出現發亮的燈泡,用以提示程式有錯誤發生。
{% img /images/posts/LightBulbEditorAdornment/1.png %}
{% img /images/posts/LightBulbEditorAdornment/2.png %}
點擊燈泡展開選單,選單會嘗試提供對應的修正。
{% img /images/posts/LightBulbEditorAdornment/3.png %}
{% img /images/posts/LightBulbEditorAdornment/4.png %}
該功能相信很多人都很熟悉,很多知名外掛都有類似的功能。只是 Visual Studio 將之整併成內建的功能,並提供擴充的彈性,允許開發人員撰寫擴充套件自行擴充。
read morePosts
ReSharper - Heap Allocation Viewer Extension
Heap Allocation Viewer 是 Reshaper 的擴充套件,能將 Heap 相關的操作 (像是 Local object allocation、Boxing、Delegate creation、Closure creation ) 進行 Highlight。
使用前需先開啟 ReSharper 的 Extension Manager。
{% img /images/posts/HeapAllocationViewer/1.png %}
搜尋框輸入 heapview 關鍵字,下載並安裝 Heap Allocation Viewer 套件 (若搜尋不到,可能是因為 ReSharper 太舊,需更新為 8.1 以後的版本)。
{% img /images/posts/HeapAllocationViewer/2.png %}
{% img /images/posts/HeapAllocationViewer/3.png %}
{% img /images/posts/HeapAllocationViewer/4.png %}
安裝好後,Visual Studio 即會將 Heap 相關的操作 Highlight。
{% img /images/posts/HeapAllocationViewer/5.png %}
{% img /images/posts/HeapAllocationViewer/6.png %}
以筆者來說,加裝該套件的主要原因是它可以幫我們 Highlight 程式中 Boxing 問題,而且在開發時當 Boxing 問題發生可以很容易的意識到。
read morePosts
Visual Studio 14 CTP 2 - Save and Apply Custom IDE Layouts
Save and Apply Custom IDE Layouts 是 Visual Studio 14 所釋出的新功能,能讓開發人員儲存並套用 IDE 的版面配置。藉此開發人員可依不同的開發情境或是需求下去設置適合的版面配置。像是要專注於程式碼的撰寫時,我們可以配置一個以程式碼編輯區為主較不被打擾的版面配置;要撰寫單元測試,可配置一個嵌有測試結果視窗的版面配置。
使用上只要將 IDE 的版面配置好,接著點擊 [Window/Save Window Layout] 主選單選項將當前的版面配置儲存。
{% img /images/posts/VS14SaveAndApplyLayout/1.png %}
{% img /images/posts/VS14SaveAndApplyLayout/2.png %}
{% img /images/posts/VS14SaveAndApplyLayout/3.png %}
當需要時可透過點擊 [Window/Apply Window Layout] 主選單選項,或是透過觸發熱鍵 Ctrl + Alt +1~9 快速的進行版面配置的切換。
{% img /images/posts/VS14SaveAndApplyLayout/4.png %}
這邊的 Layout 擺放順序跟儲存的順序有關,若有需要隨時可透過點擊 [Window/Manage Window Layouts] 主選單選項,將 Manage Window Layouts 視窗叫出來調整。
{% img /images/posts/VS14SaveAndApplyLayout/5.png %}
{% img /images/posts/VS14SaveAndApplyLayout/6.png %}
read morePosts
Visual Studio - Use 64 Bit IISExpress
雖然 .Net 程式支援位元適應性,Visual Studio 也允許我們做 64 位元的網站開發,但 Visual Studio 預設啟用的 IISExpress 是 32位元的。
{% img /images/posts/x64IISExpress/1.png %}
所以當在做 64 位元的網站開發時,在本地端測試我們會發現網站會跑不起來,因為 64 位元的網站無法跑在 32 位元的 IISExpress 上。
這時要馬要改用 IIS 去跑,要馬就是要像像下面這樣輸入命令修改登錄檔,將 Visual Studio 設定為使用 64 位元的 IISExpress:
reg add HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\WebProjects /v Use64BitIISExpress /t REG_DWORD /d 1 注意到這邊,登錄檔位置依 Visual Studio 版本不同會有所差異,可參閱 Microsoft Visual Studio - Wikipedia, the free encyclopedia 內的 Internal version 部分下去調整。
{% img /images/posts/x64IISExpress/2.png %}
設定完後重起 Visual Studio,再次運行跑起來的就會是 64 位元的 IIS Express。
read morePosts
Visual Studio 2013 - 64-bit Edit and Continue for .NET Framework code
Visual Studio 的 Edit And Continue 功能可以允許開發人員在除錯的同時進行程式的修改,Visual Studio 會自動套用變更的程式碼,不需中斷除錯或是重新編譯,能有效的節省時間,增加除錯與開發上的效率。
不過在舊版的 Visual Studio 只支援 32 Bit 的程式使用 Edit And Continue 功能,若是開發 64 Bit 程式則不能啟用。
{% img /images/posts/VSEditAndContinue64/1.png %}
Visual Studio 2013 後解除了這項限制,開始支援在 64 Bit 程式上使用。
{% img /images/posts/VSEditAndContinue64/2.png %}
Link Debugging support for 64-bit Edit and Continue in Visual Studio 2013 - Microsoft Application Lifecycle Management - Site Home - MSDN Blogs What’s New in Visual Studio 2013 Edit and Continue
read morePosts
Devart T4 Editor - VS add-in for editing T4 templates
Visual Studio 內建的 T4 Template Editor 很陽春,不僅無法 Syntax Highlighting,也無法 Intellisense,在除錯時查看變數也非常不便,更無法靜態程式碼分析及 Format 程式碼,造成開發 T4 Template 的效率大幅降低。
Devart T4 Template 是ㄧ Visual Studio 的擴充套件,能解決這些煩人的問題,提升 T4 Template 的開發速度。
套件可至 Download Devart T4 Editor 這邊下載安裝。
{% img /images/posts/DevartT4Editor/1.png %}
{% img /images/posts/DevartT4Editor/2.png %}
{% img /images/posts/DevartT4Editor/3.png %}
{% img /images/posts/DevartT4Editor/4.png %}
{% img /images/posts/DevartT4Editor/5.png %}
{% img /images/posts/DevartT4Editor/6.png %}
安裝完重啟 Visual Studio,開啟 T4 Template 檔案,可以看到 Syntax Highlighting 已被支援。
{% img /images/posts/DevartT4Editor/7.png %}
Intrllisense 支援。
read morePosts
Visual Studio - Extension Manger Cannot Connect From Behind a Firewall
筆者工作環境的電腦,Visual Studio 內的 Extension Manager 無法正常的運作,查了一下才知道這是因為防火牆擋住了 100-Continue 的訊息發送所導致。
{% img /images/posts/VSExpect100Continue/1.png %}
因此要將 Common7\IDE 下的 devenv.exe.config 開啟調整,將 100-Continue 這個 Feature 關閉才可正常運作。
{% img /images/posts/VSExpect100Continue/2.png %}
檔案開啟後,在 system.net 的節點內加入 <servicePointManager expect100Continue="false"/>,將 100-Continue 這個 Feature 給關閉就可以了。
{% img /images/posts/VSExpect100Continue/3.png %}
Link visual studio 2010 - Cannot connect to any online resource - Stack Overflow ServicePointManager.Expect100Continue 屬性 (System.Net) Visual Studio Extension Manger Cannot Connect From Behind a Firewall Expect:100-continue | 風雪之隅
read morePosts
Code Compare - File and Folder Merge Tool
Code Compare 是ㄧ用來對檔案、目錄做比對與合併的程式,能輕易整合開發人員的開發環境。
使用前請至 Visual Studio Gallery 下載。
{% img /images/posts/CodeCompare/1.png %}
下載後點擊安裝…
{% img /images/posts/CodeCompare/2.png %}
{% img /images/posts/CodeCompare/3.png %}
{% img /images/posts/CodeCompare/4.png %}
安裝這邊會提供一些設定選項,可供使用者決定有哪些環境需要整合。
{% img /images/posts/CodeCompare/5.png %}
{% img /images/posts/CodeCompare/6.png %}
安裝完成就可以透過被整合的環境下去觸發使用。
像是筆者這邊在安裝時有勾選與 Visual Studio 整合,就可以在 Visual Studio 的方案總管中直接選取兩個檔案做比對。
{% img /images/posts/CodeCompare/7.png %}
{% img /images/posts/CodeCompare/8.png %}
Link Code Compare extension Code Compare - File Diff & File Merge Tool, Folder Compare Tool
read morePosts
Visual Studio - JSON Debugger Visualizer in Visual Studio 2013
以往我們在做 JSON 資料的除錯時,若是不加裝外掛, 在 Visual Studio 上只能透過純文字模式下去檢視。不易查閱與驗證,若資料是非 Format 過的,則更是麻煩。
Visual Studio 2013 Update 2 CTP 後 Visual Studio 加入了 JSON Debugger Visualizer 功能。透過這個功能,能有效的解決這樣的困擾。
它提供了較為友善的除錯界面,將 JSON 資料展開用樹狀結構呈現。不管是否是 Format 過的資料,都是一樣的呈現方式。
{% img /images/posts/JSONDebugVisualizer/1.png %}
{% img /images/posts/JSONDebugVisualizer/2.png %}
透過樹狀結構的呈現方式, JSON Debugger Visualizer 清楚的表達了 JSON 資料的階層性與其值。
若是 JSON 內資料多到不易找尋,它也提供了搜尋的功能,能輔助我們快速的從 JSON 資料中找出感興趣的部分…
{% img /images/posts/JSONDebugVisualizer/3.png %}
找到感興趣的資料後,若有需要我們可以在上面按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中有提供一些複製的功能,像是複製該資料的路徑、Key、Value、或是 Key 跟 Value 一起複製。
{% img /images/posts/JSONDebugVisualizer/4.png %}
最後一提,要是這邊所查閱的資料是非 JSON 格式的,或是格式有誤。 JSON Debugger Visualizer 會改以純文字的方式呈現,並告知我們該資料不是 JSON 格式。
read morePosts
Code Digger - Analyzes possible execution paths through your .NET code
Code Digger 是精簡版的 Pex,其內部還是使用 Pex 的程式碼分析引擎,能將有意義的參數的抓出,幫助我們更了解程式,並找到可能的淺在問題。目前該擴充套件支援 Visual Studio 2010 以後的版本 (Visual Studio 2012、 Visual Studio 2013),Visual Studio 2010 以前我們可以改使用功能更為強大的 Pex。
Code Digger 在設立之初只支援 Protable Class Library ,故非 Protable Class Library 的專案在使用時會看到像下面這樣的訊息框。
{% img /images/posts/CodeDigger/1.png %}
Code Digger 的功能也無法使用。
但在某一版後,Code Digger 能在 Options 那邊將這限制關閉。只要開啟 Options 對話框,切換至 Pex/General 頁籤,將 Code Digger 群組下的 DisableCodeDiggerPortableClassLibraryRestriction 設定為 True 就可以了。
{% img /images/posts/CodeDigger/2.png %}
使用時,我們只要在要分析的方法中按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中選取 Generate Inputs / Outputs Table 選單選項。
{% img /images/posts/CodeDigger/3.png %}
接著會彈出 Code Digger Analytics 對話框,詢問是否同意 Code Digger 收集使用的資訊,這邊請視個人需求下去勾選就好,若有需要後續都可以至 Options 內做修改。
read morePosts
[C++]使用nsiqcppstyle輔助檢查C/C++的Coding Style
[Example] nsiqcppstyle . nsiqcppstyle targetdir nsiqcppstyle -f filefilterpath targetfilepath
[Options] -h Show this help -v Show detail ouput(verbose mode) -r Show rule list -o path Set the output path. It’s only applied when the output is csv or xml. -f path Set the filefilter path. If not provided, it uses the default fi lterpath (target/filefilter.txt) If you provide the file path(not folder path) for the target, -f option should be provided.
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: lambda
auto result = lambda(1,2);
auto result = lambda(1,2);
auto lambda = = -> int { return val1 + val2; };
result = lambda();
lambda(1,2);
lambda(1,2);
auto lambda = =, &result { result = val1 + val2; };
lambda();
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: nullptr
void Test(int value) { cout << “void Test(int value)”; }
int _tmain(int argc, _TCHAR* argv[]) { Test(NULL); return 0; }
#include “stdafx.h” #include <iostream>
using namespace std;
void Test(int* value) { cout << “void Test(int* value) “; }
void Test(int value) { cout << “void Test(int value) “; }
int _tmain(int argc, _TCHAR* argv[]) { Test(NULL); Test((int*)NULL); Test(nullptr); return 0; }
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: auto
#include “stdafx.h” #include <string> #include <list> #include <map>
using namespace std;
int _tmain(int argc, _TCHAR* argv[]) { auto x = 1, *y = &x, **z = &y; // Resolves to int. auto a(2.01), *b (&a); // Resolves to double. auto c = ‘a’, *d(&c); // Resolves to char. auto m = 1, &n = m; // Resolves to int.
map<int,list<string>> mapObj; map<int,list<string>>::iterator i1 = mapObj.begin(); auto i2 = mapObj.begin(); auto lambda = []()->int { return 0; }; return 0; }
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: static_assert
#include “stdafx.h”
#define DEFAULT_VALUE 0 #define MAX_VALUE 100
const int VALUE = 10;
struct MyStruct { char data[1024]; };
template < class T, int Size > class Vector { static_assert(Size > 0, “Vector size must be bigger than zero!”);
T m_values[Size]; };
int _tmain(int argc, _TCHAR* argv[]) { static_assert( sizeof(void ) == 4, “64-bit code generation is not supported.”); static_assert( MAX_VALUE > DEFAULT_VALUE, “DEFAULT_VALUE must be smaller than MAX_VALUE” ); static_assert( MAX_VALUE > VALUE, “VALUE must be smaller than MAX_VALUE” ); static_assert( sizeof( MyStruct ) < 10241024, “The structure size exceeds stack size” ); Vector<int, 10> intArray; return 0; }
read morePosts
[C++][Visual Studio]Natived C++使用Visual Studio做單元測試
//Act actual = myObj.Add(x, y); //Assert Assert::AreEqual(actual, expected); }; }; }
read morePosts
[VS 2010]Generate From Usage
namespace Generate_From_Usage { class Person { } } Generate Property當物件的屬性不存在時,我們可透過Generate From Usage的Generate Property來替我們產生。 使用後,會幫我們產生對應的屬性 using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace Generate_From_Usage { class Person { public string Name { get; set; } } } 若要產生靜態的屬性,我們可以透過"類別.屬性名稱"來作Generate Property 使用後,靜態的屬性就產生了 using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace Generate_From_Usage { class Person { public string Name { get; set; } public static string StaticProperty { get; set; } } } Generate Field當物件的欄位不存在時,我們可透過Generate From Usage的Generate Field來替我們產生。 使用後,會幫我們產生對應的欄位 using System; using System.
read moreTag: Visual Studio 2017
Posts
BuiltinCmd - Integrate windows cmd terminal into Visual Studio
BuiltinCmd 是 Visual Studio 的擴充套件,能整合命令列視窗至 Visual Studio。
透過 Extension Manager 安裝套件。
將 Visual Studio 重啟。
點選 [View | Other Windows | Toggle BuiltinCmd] 主選單選項,或是按下熱鍵 Ctrl + Shift + T 即可開啟 BuiltinCmd 視窗。
Link BuiltinCmd - Visual Studio Marketplace
read morePosts
Visual Studio 2017 - Live unit testing
要啟動 Visual Studio 2017 Live Unit Testing 功能,可點選 [Test | Live Unit Testing | Start] 主選單選項。
啟動後單元測試會持續在背景運行。
可在開發程式時即時看到測試的狀況與覆蓋情形。
需注意的是這功能需要 MSTest V2 才能啟用,舊測試專案需要移除 Microsoft.VisualStudio.QualityTools.UnitTestFramework 的參考。
加入 MSTest.TestFramework 套件。
加入 TestAdapter 套件。
最後調整命名空間即可。
read morePosts
Visual Studio 2017 - Improved Code Navigation
Visual Studio 2017 對程式碼的巡覽做了些強化,[Edit | Go To] 主選單選項內有著所有的巡覽功能。
像是 Go To All... (熱鍵 Ctrl+T)
Go To Line... (熱鍵 Ctrl+G)
Go To File... (熱鍵 Ctrl+1, Ctrl+F)
Go To Type... (熱鍵 Ctrl+1, Ctrl+T)
Go To Symbol... (熱鍵 Ctrl+1, Ctrl+S)
Go To Member... (熱鍵 Ctrl+1, Ctrl+M)
也可以記住搜尋框認的關鍵字,像是 Go To Line... 是用 :、Go To File... 是用 f、Go To Type... 是用 t、Go To Symbol... 是用 #、Go To Member... 是用 m,這樣會更方便使用。
read morePosts
Visual Studio 2017 - Find all references
Visual Studio 2017 針對 Find all references 視窗做了些強化,在要查詢 Reference 的地方按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中點選 Find All References 選單選項,將 Find all references 視窗開啟。
開啟後會看到該視窗跟 Visual Studio 2017 以前有些許不同,上方工具列有些差異,結果也改以群組的方式呈現。
上方工具列有下拉式選單可供我們選擇是找尋整個方案、開啟的文件、當前專案、當前文件。
也提供向前巡覽 reference (也可用熱鍵 Shift + F8 觸發)。
向後巡覽 reference (也可用熱鍵 F8 觸發)。
也有下拉選單可以改變群組的方式,像是預設的 Project then Definition 群組,會先以專案再以程式碼的定義去群組:
Definition Only 會以程式碼的定義去群組:
Definition then Project 會先以程式碼定義再以專案去群組:
Definition then Path 會先以程式碼定義再以專案路徑去群組:
Definition, Project then Path 會先以程式碼定義再以專案最後以專案路徑去群組:
不同的群組方式適用於不同的使用情境,可視需求調整使用。
若有需要進一步篩選,可利用上方的搜尋框。
若要保留搜尋結果供後續使用,可按下 Keep Result 按鈕。
這樣再次搜尋 Reference 時就不會重用本來的視窗。
而會使用新的視窗。
read morePosts
Visual Studio 2017 - Roaming Extension Manager
Visual Studio 2017 以前安裝的 Extension 無法同步,所以在不同電腦間 Extension 都需要自行安裝。
Visual Studio 2017 以後新增了 Roaming Extension Manager,可用來設定要同步的 Extension。只要開啟 Extensions and Updates 視窗,切到 Roaming Extension Manager 頁面,在想要同步的 Extension 後面按下 Start Roaming 按鈕,指定的 Extension 即可同步到不同電腦。
read morePosts
Visual Studio 2017 - Modify extensions in bulk
Visual Studio 2017 以後使用 Extensions and Updates 視窗進行 Extension 的修改。
修改的 Extension 會被加入排程,排程的 Extension 可以在 Extensions and Updates 視窗的右下角看到,若有需要也可以將排程刪除。
接著將 Visual Studio 關閉。
排程的 Extension 即會開始運行對應的動作。
read morePosts
Visual Studio 2017 - Reattach to process
Visual Studio 2017 以前如果要重新附加到相同的處理序,我們需要自行用 Attach to Process 對話框再次附加相同的處理序,或是透過 Visual Studio 2017 的外掛直接重新附加處理序。
Visual Studio 2017 以後新增 Reattach to process 功能,只要之前附加過處理序,[Debug | Reattach to Process…] 主選單選項即會浮現,若有需要則可點選該主選單選項,或是用熱鍵 Shift+Alt+P,進行處理序的重新附加。
read morePosts
Visual Studio 2017 - Match highlighting
Visual Studio 2017 以前在使用 IntelliSense 時,有時我們會搞不清楚出來的成員是因為匹配到什麼才會顯示出來。
Visual Studio 2017 以後支援 Match highlighting,當使用 IntelliSense 時匹配到的字元會被 Highlight,可以清楚知道為什麼 IntelliSense 會將該成員列出。
read morePosts
Visual Studio 2017 - IntelliSense filtering
Visual Studio 2017 以前 IntelliSense 是不具備 Filtering 功能的,必須從眾多成員中挑選出所要選用的,當成員過多時這問題會更加嚴重。
Visaul Studio 2017 加入 IntelliSense filtering,在 IntelliSense 對話框的下半部增加了過濾的按鈕,能針對成員類型進行過濾。
像是可以設定只顯示屬性。
可以設定只顯示方法。
可以設定只顯示擴充方法…等等。
read morePosts
Visual Studio 2017 - Run to click
Visual Studio 2017 以前,在除錯時若要讓斷點繼續向下運行至指定位置,我們需要在指定位置設定斷點後讓他向下運行,或是直接在指定位置上按下滑鼠右鍵,點選 Run to cursor 滑鼠右鍵選單也可以。
在 Visual Studio 2017 以後新增了 Run to click 的功能,提供我們另一個選擇。使用上要先設定個斷點進入除錯模式,讓它中斷在設定的斷點上。
接著將滑鼠移到指定位置上,指定位置的前方會浮現個小圖示,滑鼠點擊該圖示即可運行至指定位置後中斷。
read morePosts
Visual Studio 2017 - Structure visualizer
Visual Studio 2017 以前,在編寫程式時有時我們會需要找一下程式碼中的刮號,確定我們在改的區塊是否正確。Visual Studio 2017 新增 Structure visualizer 功能,能讓我們更容易知道所修改的區塊是哪。
該功能預設應該是開啟的,若未開啟可開啟 Options 視窗,切到 [Text Editor | General] 頁面,將 Show structure guide lines 選項勾選。
在程式碼這邊應該就會看到對應的括號之間出現了 Structure Guide Lines。接著只要將滑鼠移至 Structure Guide Lines 上,Structure visualizer 即會浮現,我們可以清楚的了解到所在修改的區塊位置。
read morePosts
Visual Studio 2017 - Lightweight solution load
Visual Studio 2017 新增 Lightweight Solution load 功能,能 OnDemand 進行專案的載入,特別適用於大型專案的開發。
該功能預設是關閉的,要啟用可開啟選項對話框,切到 [Projects and Solutions | General] 頁籤,勾選 Lightweight Solution load 選項。
將專案載入,乍看起來好像沒什麼太大的變化。
但仔細看方案總管這邊,會發現方案名稱後面多了個 lightweight 字樣。
將方案總管的專案展開,會看到其實專案還沒被載入,展開的同時才開始進行載入。
稍待一下即可載入完成。
read morePosts
Visual Studio 2017 - Attach to Process Filter
在 Visual Studio 2017 以前要在 Attach to Process 對話框中找到要附加的處理序,需要在一堆處理序中挑選。
Visual Studio 2017 針對 Attach to Process 對話框做了強化,新增過濾的功能,便於使用者快速挑選要附加的處理序。
滑鼠點選 [Debug|Attac to Process…] 主選單選項,或是按下熱鍵 Ctrl+Alt+P,叫出 Attach to Process 對話框。
會看到在 Attach to Process 對話框中處理序列表的上方多出了一個搜尋框,將要過濾的字樣填入,下方的處理序列表即會列出過濾後的處理序。
Link Visual Studio 2017 Release Notes
read moreTag: Swagger
Posts
Swagger Editor - Setup with http-server module
要使用 http-server 自行架設 Swagger Editor,可透過 npm 進行 http-server 的安裝,
npm install -g http-server 然後至 Swagger Editor 的 GitHub 上下載 Swagger Editor 的壓縮包。
解開壓縮包。
用 http-server 啟用 Swagger Editor 服務。
即可使用啟用的 Swagger Editor 服務。
Link Swagger Editor - Swagger
read moreTag: P4Merge
Posts
P4Merge - Use P4Merge as git mergetool
要將 P4Merge 與 Git 整合,使用 P4Merge 去做 Merge,可以加入 Merge tool 設定。
git config --global merge.tool p4merge 設定 P4Merge 檔案的位置。
git config --global mergetool.p4merge.path [P4MergeFileLocation] 或是直接開啟 global configuration file 編輯也可以。
[merge] tool = p4merge [mergetool "p4merge"] path = C:\Program Files\Perforce\p4merge.exe 設定好後就可以使用 P4Merge 在 git 做 Merge。
git mergetool Link Setup p4merge as difftool and mergetool on Windows Git for Windows tip: Use P4Merge as mergetool – danlimerick
read moreTag: Mmock
Posts
mmock - Configuration
使用 mmock 去 Mock API,會需要放置 mock 的設定。
設定檔可以是 json 格式…
{ "request": { "method": "GET", "path": "/hello/*" }, "response": { "statusCode": 200, "headers": { "Content-Type":["application/json"] }, "body": "{\"hello\": \"{{request.query.name}}, my name is {{fake.FirstName}}\"}" } } 也可以是 yml 格式…
--- request: method: GET path: "/hello/*" response: statusCode: 200 headers: Content-Type: - application/json body: '{"hello": "{{request.query.name}}, my name is {{fake.FirstName}}"}' 設定檔格式定義如下:
{ "description": "Some text that describes the intended usage of the current configuration", "request": { "host": "example.
read morePosts
mmock - Getting started
要使用 mmock 除了將 mmock 服務啟用外。
還要在放置 mock 設定在放置設定檔的目錄,mmock 會去放置設定檔的目錄找尋並載入設定。
放置好後透過 mmock 的 http 或是 https 位置訪問 mock 出來的 API 位置即可,像是筆者的 mmock http 位置為 192.168.99.100:3281,而設定檔內設定的是 http 這個 path,所以訪問 http://192.168.100:3281/hello 就會依設定檔內的設定去回應。
如果有開啟 mmock 的 console 頁面,當 request 進來時 console 頁面會立即收到請求,可在主控台查閱發送的請求。
點選展開可看到更為詳細的資訊,像是回應的內容…等。
切到 Mapping 頁面,可看到 mmock 載入進去的設定檔,設定檔檔名、設定的 Method、與 Path,點選後面的 View 按鈕。
可看到設定檔的內容。
如果需要調動設定,可點選後方的 Edit 按鈕。
調動設定檔後存檔。
Link jmartin82/mmock: Mmock is an HTTP mocking application for testing and fast prototyping
read morePosts
mmock - Run with mmock command
要使用 mmock,可先安裝 go 語言,透過 go get 下載 mmock command。
go get github.com/jmartin82/mmock 下載下來後可簡單的測試一下,順便查閱 mmock 的使用方式。
mmock -h Usage of ./mmock: -cconsole-port int Console server Port (default 8082) -config-path string Mocks definition folder (default "execution_path/config") -console Console enabled (true/false) (default true) -console-ip string Console Server IP (default "public_ip") -server-ip string Mock server IP (default "public_ip") -server-port int Mock server Port (default 8083) -server-tls-port int Mock HTTPS server Port (default 8084) -tls-path TLS config folder (It will load any crt/key combination, for example server.
read morePosts
mmock - Run mmock with Kitematic
要透過 Kitematic 使用 mmock,可在 Kitematic 搜尋 mmock 的容器,點選 CREATE 按鈕將容器拉回啟用。
容器啟用後在 CONTAINER LOGS 這邊會看到 mmock 服務啟用的畫面,上面會帶有 http、https、console 服務的資訊。
IP & PORTS 這邊會顯示容器與主機的 Port 號對應。
點選 VOLUMES 可開啟對應的目錄位置。
將 mmock 的設定放至這個位置。
mmock 即可依照設定 mock API。
Link jmartin82/mmock: Mmock is an HTTP mocking application for testing and fast prototyping
read moreTag: Kubectl
Posts
kubectl - Install with Chocolatey on Windows
要在 Windows 使用 kubectl,透過 Chocolatey 進行安裝即可。
choco install kubernetes-cli 安裝完可運行 kubectl 命令查閱 kubectl 版本,確認命令可以正確運行。
kubectl version Link Install and Set Up kubectl - Kubernetes
read morePosts
kubectl - Install kubectl binary via curl on Linux
要在 Linux 安裝 kubectl,可以透過 curl 下載 kubectl。
如果要使用最新的版本的可調用下列命令。
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl 如果要使用指定版本,可像下面這樣調用。
curl -LO https://storage.googleapis.com/kubernetes-release/release/[Version]/bin/linux/amd64/kubectl 像是要使用 1.7.0 版,可調用下列命令。
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.7.0/bin/linux/amd64/kubectl 下載下來後修改 kubectl 執行檔權限,設上執行權限。
chmod +x ./kubectl 然後搬移 kubectl 到 /usr/local/bin/kubectl 下。
sudo mv ./kubectl /usr/local/bin/kubectl 運行 kubectl 命令查閱 kubectl 版本,確認命令可以正確運行。
kubectl version Link Install and Set Up kubectl - Kubernetes
read moreTag: JFrog
Posts
JFrog - Install JFrog Artifactory open source on Windows
要在 Windows 安裝 JFrog Artifactory open source,可先到 JFrog Artifactory open source 的下載頁面。
下載 Windows 用的壓縮檔。
解壓縮下載下來的壓縮檔。
切到 bin 目錄用 Administrator 運行 artifactory.bat。
即會運行 JFrog Artifactory 服務。
瀏覽器訪問 http://localhost:8081 即可看到 JFrog Artifactory 頁面。
如果要將 JFrog Artifactory 註冊成 Windows 服務,可用 Administrator 運行命令提示字元,在命令提示字元中運行 installService.bat 註冊 Windows 服務。
註冊好後可以看到增加的 Artifactory Windows 服務。
如果要將 JFrog Artifactory 的 Windows 服務移除,一樣用 Administrator 運行命令提示字元,在命令提示字元中運行 uninstallService.bat 取消註冊 Windows 服務。
Link JFrog - Managing Binaries for Maven Repository, Docker, npm, Ruby and More
read moreTag: Drone
Posts
Drone - Integrate with GitHub
要將 GitHub 與 GitHub 整合,需要先在 GitHub 建立 Application。
切到 GitHub 設定頁面。
切到 [Developer settings | OAuth Apps]。
創建新的 Applcation。
填寫 Application 的名稱、Drone 的位置、Application 的描述、Drone 的認證位置 (http://[DroneUrl]/api/auth/github.com),按下 Register application 按鈕繼續。
指定的 Application 即會建立。
開啟 Drone 的配置文件,設定連接 GitHub Application 需要的 client 與 secret。
vi /etc/drone/drone.toml 重啟 Drone 服務再次瀏覽 Drone 服務頁面即可。
Link How to Setup Drone on Ubuntu/Debian - FoxuTech 如何在 linux 上配置持續集成服務 - Drone - 壹讀
read morePosts
Drone - Setup Drone on Linux
要安裝 Drone,首先需要安裝 Docker。
接著下載 Drone 的 deb 檔。
wget downloads.drone.io/master/drone.deb 透過 dpkg 安裝 Drone。
dpkg -i drone.deb 若有需要可開啟 Drone 配置文件配置 Port 以及資料庫連線,配置後將服務重啟。
vi /etc/drone/drone.toml 即可用瀏覽器訪問架設好的 Drone 網站。
Link How to Setup Drone on Ubuntu/Debian - FoxuTech
read moreTag: GitHub
Posts
Drone - Integrate with GitHub
要將 GitHub 與 GitHub 整合,需要先在 GitHub 建立 Application。
切到 GitHub 設定頁面。
切到 [Developer settings | OAuth Apps]。
創建新的 Applcation。
填寫 Application 的名稱、Drone 的位置、Application 的描述、Drone 的認證位置 (http://[DroneUrl]/api/auth/github.com),按下 Register application 按鈕繼續。
指定的 Application 即會建立。
開啟 Drone 的配置文件,設定連接 GitHub Application 需要的 client 與 secret。
vi /etc/drone/drone.toml 重啟 Drone 服務再次瀏覽 Drone 服務頁面即可。
Link How to Setup Drone on Ubuntu/Debian - FoxuTech 如何在 linux 上配置持續集成服務 - Drone - 壹讀
read morePosts
gist-it - Embed files from a github repository like a gist
筆者在寫部落格時,有時候會將範例程式碼整理放至 GitHub 上。而文章中又會針對程式做細部的拆解與解說,以往筆者會將程式碼片段複製在部落格的文章內,或是貼至 gist 然後將之內嵌。雖然都可以達到相同的結果,但這樣的作法總是會覺得有些不對勁,因為我的程式就在 GitHub 上,卻還是要將程式碼片段重複貼至部落格或是 gist 上。
也因如此順手找了一下相關的解決方案,發現了 gist-it 這個服務…
gist-it 使用上十分的簡單,只要在文章中內嵌一段 JavaScript,像是:
<script src="http://gist-it.appspot.com/github/robertkrimen/gist-it-example/blob/master/example.js"/> Script 的位置前綴為 http://gist-it.appspot.com/github/ ,也就是 gist-it 的服務位置,後面緊接著帶入要內嵌的檔案在 GitHub 上的位置。
像是下面這樣,筆者想要嵌入 larrynung/RDPDemo 這個 Repository 下的 Source/RDPDemo/Form1.cs 檔案,我們要帶到 gist-it 服務位置後的位置就是 larrynung/blob/master/Source/RDPDemo/Form1.cs 。
{% img /images/posts/GistIt/1.png %}
所以內嵌的 JavaScript 會是
<script src="http://gist-it.appspot.com/github/larrynung/blob/master/Source/RDPDemo/Form1.cs"/> 這樣放在部落格中就能將指定的檔案內容整個內嵌進去,很簡單吧?不過筆者不建議像這樣使用,因為以這個例子來說,內嵌到的會是最新的檔案,隨著 Commit 檔案的內容可能會有增減或是刪除,所以比較保險應該是由特定 Commit 的檔案去作內嵌。
像是下面這樣:
<script src="http://gist-it.appspot.com/http://github.com/larrynung/RDPDemo/blob/bdc43c40e50305f2e12f29c5ff7e8b376b73d90b/Source/RDPDemo/Form1.cs"> 此外, gist-it 服務也提供一些參數可接在 Script 位置後面供細部調整。
像是 slice 參數可設定檔案所要內嵌的部份,可帶入指定的行數或是行數區間。(使用時可一邊開啟 GitHub 確定要做內嵌的部份,但要注意到這邊指定的行數是以 0 為基底)
所以要指定內嵌 Form1.cs 的第 31 行,可以像下面這樣撰寫
read morePostsread more
GitHub Pages
GitHub Pages服務可讓使用者免費Hosting網頁在GitHub上,享用GitHub不受限的儲存空間與網路流量。依用途不同可分為User/Organization Pages與Project Pages兩種。
Tag: Lua
Posts
Lua - Assignment
Lua 的賦值語法如下:
variable1[, variable2 ...] = value1[, value2 ...] 簡單說就是先寫要被賦值的變數,接著帶上賦值運算子 =,然後再帶入要賦予的值即可。像是下面這樣:
local a = 1 local b = 2 print(a) print(b) 若要一次賦予多個變數,可用逗號隔開帶上數個要被賦值的變數與要賦予的值。要賦予的值會依序賦予給要被賦予的變數,如果賦予的值少於要被賦予的變數,那多餘的變數不會做賦值的動作,其值為 nil。如果賦予的值多餘要被賦予的變數,那多餘的賦予值會被忽略不處理。
local a, b = 1, 2 print(a) print(b) 賦值語法也可以拿來做數值的交換。
variable1, variable2 = value2, value1 像是下面這樣:
local a, b = 1, 2 a, b = b, a print(a) print(b) Link Programming in Lua : 4.1
read morePosts
Lua - String concatenation operator
Lua 的字串要作串接的話,可以使用 .. 運算子。該運算子能將前後的字串相加,若是運算子的前後為數值的話,則會轉成字串後再做相加。
程式寫起來會像下面這樣:
print("Hello " .. "World") print(0 .. 1) Link Programming in Lua : 3.4
read morePosts
Lua - If then else
Lua 的 if 寫法如下,if 後接進入的條件,then … end 區塊內帶入要運行的動作即可。
if condition then ... end 如果有多個分支條件,可以用 elseif 區塊帶上另外的分支條件,或是用 else 區塊指定所有分支條件條件都不滿足時要運行的動作。
if condition then ... elseif condition then ... else ... end 像是要寫個簡易的程式能讓使用者輸入來決定要運行的動作,就可以像下面這樣撰寫:
local input repeat input = io.read() if input == "y" then print("y") elseif input == "n" then print("n") else print("unknow") end until input == "exit" Link
read morePosts
Lua - Repeat until loop
Lua 的 repeat until 寫法如下,repeat until 區塊內帶入要運行的動作,until 後帶上要跳脫迴圈的條件即可。
repeat ... until condition 像是要簡單的跑迴圈五次,然後印出 1 到 5 的數值,就可以像下面這樣撰寫:
local idx = 1 local count = 5 repeat print(idx) idx = idx + 1 until idx > count Link Programming in Lua : 4.3.3
read morePosts
Lua - While loop
Lua 的 while 寫法如下,while 後面帶上要進入迴圈的條件,然後用 do…end 設定迴圈的區塊,在迴圈的區塊內帶入要運行的動作即可。
while condition do ... end 像是要簡單的跑迴圈五次,然後印出 1 到 5 的數值,就可以像下面這樣撰寫:
local idx = 1 local count = 5 while idx <= count do print(idx) idx = idx + 1 end Link Programming in Lua : 4.3.2
read morePosts
Lua - pairs and ipairs
Lua 內的 ipairs 可用來遍巡處理陣列,如果遍巡到非陣列元素,或是空值的話,遍巡動作即會中止。
所以像下面這樣的程式就不會將所有元素印出。
local data = {} data[1] = "Value1" data[2] = "Value2" data[4] = "Value4" data.Key1 = "Value4" for x, y in ipairs(data) do print("( " .. x .. ", " .. y .." )") end 若是使用 pairs,則可遍巡所有元素。
local data = {} data[1] = "Value1" data[2] = "Value2" data[4] = "Value4" data.Key1 = "Value4" for x, y in pairs(data) do print("( " .. x .. ", " .
read morePosts
Lua - Generic for
Lua generic for 語法要遍巡處理陣列的話,語法如下:
for idx[, value] in ipairs(array) do ... end 像是要遍巡陣列然後將陣列索引與陣列元素顯示出來,就可以像下面這樣撰寫:
local array = {} array[1] = "Value1" array[2] = "Value2" for idx, value in ipairs(array) do print(idx .. "." .. value) end 如果是要遍巡字典,語法會像下面這樣:
for key[, value] in pairs(dict) do ... end 像是要遍巡字典然後將字典內元素的鍵值與元素值顯示出來,就可以像下面這樣撰寫:
local data = {} data.Key1 = "Value1" data.Key2 = "Value2" for key, value in pairs(data) do print(key .. " = " .. value) end Link
read morePosts
Lua - Numeric for
Lua numeric for 的語法如下,for 後面設定迴圈內要使用的變數,變數後面用等號帶上數值的起點、終點、遞增/減值 設定值間用逗號隔開,然後用 do…end 設定迴圈的區塊,在迴圈的區塊內帶入要運行的動作即可。
for var=from,to[,step] do ... end 像是要簡單的跑迴圈五次,然後印出 1 到 5 的數值,就可以像下面這樣撰寫:
for i=1,5 do print(i) end 若是要跑迴圈印出 1、3、5,可像下面這樣調整遞增條件:
for i=1,5,2 do print(i) end Link Programming in Lua : 4.3.4
read morePosts
Lua - Arithmetic operators
Lua 的 Arithmetic operators 有 +、-、*、/、%、>=,這些運算符可用來做數值的運算。
Operator Description + 用來將前後數值相加 - 用來將前後數值相減 * 用來將前後數值相乘 / 用來將前後數值相除 % 用來將前後數值相除取模 ^ 用來將數值乘冪 - 用來將數值正負反轉 使用起來就像下面這樣:
print(1 + 2) print(1 - 2) print(1 * 2) print(1 / 2) print(7 % 4) print(2 ^ 2) print(-1) Link Lua 5.1 Reference Manual
read morePosts
Lua - Relational Operators
Lua 的 Relational operators 有 ==、~=、<、>、<=、>=,這些運算符可用來處理兩者間的關係,看是相等、不等、小於、大於、小於等於、還是大於等於,其運算結果都為布林值,不是 true 就是 false。
Operator Description == 用來判斷前者與後者是否相等 ~= 用來判斷前者與後者是否不相等 < 用來判斷前者是否小於後者 > 用來判斷前者是否大於後者 <= 用來判斷前者是否小於等於後者 >= 用來判斷前者是否大於等於後者 使用起來就像下面這樣:
print(1 == 2) print(1 ~= 2) print(1 < 2) print(1 > 2) print(1 <= 2) print(1 >= 2) Link Lua 5.1 Reference Manual
read morePosts
Lua - Logical operators
Lua 的邏輯運算會將 false 與 nil 視為 false,其它值視為 true。
所以 and、or 運算寫起來就會像下面這樣。
print(10 or 20) print(true or false) print(nil or "a") print(nil and 10 ) print(true and false) print(false and nil) print(false or nil) print(10 and 20) and、or 運算也可以用作三元運算處理,最前面是條件值,然後用 and 運算接條件成立時要回傳的值,再 or 運算接條件不成立時要回傳的值即可。
print(true and 1 or 2) print(false and 1 or 2) 至於 not 運算就是把 true、false 反轉。
print(not true) print(not false) print(not nil) print(not 1) Link [Lua] 邏輯運算 « Huli’s Blog Lua 5.
read morePosts
redis-lua - A Lua client library for the redis key value storage system
redis-lua 是 Lua 的 Redis client 套件,能讓 Lua 具備存取 Redis 的能力。
因為相依於 LuaSocket 套件,所以必須先用 LuaRocks 安裝 LuaSocket 套件。
luarocks install luasocket 相依套件安裝好,就可以進行 redis-lua 套件的安裝。
luarocks install redis-lua 都安裝好了就可以開始在程式中使用 redis-lua 對 Redis 進行存取。
使用上需先加入 redis-lua 套件。
local redis = require 'redis' 然後進行對 redis 的連線。
local client = redis.connect(ip, port) 如果 redis 有設定認證,可調用 auth 命令並帶入對應的密碼。
client:auth(password) 接著就可以視需要調用其它 Redis 的命令。
Link nrk/redis-lua: A Lua client library for the redis key value storage system.
read morePosts
LuaRocks - The Lua package manager
LuaRocks 是 Lua 的套件管理程式,可在官網找到下載頁面。
點選下載所要使用的版本。
安裝包下載下來後,解壓縮即可進行安裝,但是安裝前需先確定是否已裝有 Lua binary,如果 Lua binary 已經備妥,可以運行 ‘install.bat’ 進行 LuaRocks 的安裝。
因為 LuaRocks 需要 C compiler,MinGW 或是 Microsoft compiler 都可以,所以這邊筆者直接使用 Visual Studio 內建的命令列模式來操作。
設定 LuaRocks 的路徑。
就可以用 LuaRocks install 安裝指定的 Lua 套件。
LuaRocks install <LuaPackage> Link LuaRocks - The Lua package manager
read morePosts
Lua for Windows - A 'batteries included environment' for the Lua scripting language on Windows
在 Winwodw 下要使用 Lua binary,可下載 Lua for Windows。
下載後點擊安裝即可。
Link rjpcomputing/luaforwindows: Lua for Windows is a ‘batteries included environment’ for the Lua scripting language on Windows.
read moreTag: Sass
Posts
Sass - Install Sass
Sass 依賴於 Ruby,Sass 安裝前需先安裝 Ruby。
Ruby 安裝完後再用 RubyGems 安裝 sass 套件即可。
gem install sass 安裝完後可查詢 Sass 版本做個確認,沒意外的話應該可以看到 Sass 命令正常運作,會顯示當前 Sass 版本。
sass -v Link Sass: Install Sass
read moreTag: Ruby
Posts
RubyInstaller for Windows - The easy way to install Ruby on Windows
要在 Windows 內使用 Ruby,可下載 RubyInstaller for Windows。
下載完後點擊安裝。
安裝完即可使用 Ruby。
Link RubyInstaller for Windows
read moreTag: InstantClick
Posts
Hexo - Speed up with InstantClick
要用 InstantClick 加速 Hexo 部落格,可先下載 InstantClick 放至 source\js 下。
然後開啟 _config.yml 設定檔,加入 skip_render 設定,將 js 檔排除 render。
接著修改 Hexo 的 theme 讓 InstantClick 得以啟動。以 next theme 為例,可開啟 next theme 的 layout_layout.swig,將 InstantClick 啟動的程式插入即可。
<script type="text/javascript" src= "js/instantclick.js" data-no-instant></script> <script data-no-instant>InstantClick.init();</script> 設定完可開啟部落格網站,打開開發人員工具,切換到 Network 頁籤,然後將滑鼠移至連結,就可以看到當滑鼠移至連結時就已經在進行預載的動作了。
最後提醒一下,InstantClick 的預載行為可能會造成其它套件的異常,可能要自行視情況修正將問題排除。
Link InstantClick — JS library to make your website instant
read morePosts
InstantClick - JS library to make your website instant
InstantClick 是一 JS 套件,能讓在 MouseHover 時就預先進行站台的載入,這樣在 MouseDown 後切換頁面就會只需要較少的載入時間,加速網站的載入速度。
InstantClick 這邊也提供了個簡易的測試站台,可用來測試 MouseHover 與 MouseDown 之間的時間間隔,也就是 InstantClick 會拿來預載網頁的時間間隔。
測試上只要先把滑鼠從連結上移開,然後將滑鼠移上連結,按下滑鼠按鈕即可。通常測試下來大概可以看到可用來預載的時間間隔約為 200 ~ 300 ms。
想要看一下 InstantClick 的運作的話,可以在 InstantClick 網站開啟開發人員工具,切換到 Network 頁籤,然後將滑鼠移至連結,就可以看到當滑鼠移至連結時就已經在進行預載的動作了。
InstantClick 支援的瀏覽器版本如下:
若是要使用可在下載頁面將要使用的 js 檔下載。
或是透過 bower 之類的套件管理工具下載。
bower install instantclick 下載下來後放置專案中像下面這樣調用即可。
<script type="text/javascript" src= "js/instantclick.js" data-no-instant></script> <script data-no-instant>InstantClick.init();</script> 最後提醒一下,InstantClick 的預載行為可能會造成其它套件的異常,可能要自行視情況修正將問題排除。
Link InstantClick — JS library to make your website instant
read moreTag: ReSharper
Posts
'ReSharper - Finding, Exploring, and Installing NuGet Packages'
ReSharper 的 NuGet browser 提供 NuGet 套件的搜尋、瀏覽、與安裝的功能。
若有需要可以直接開啟 NuGet browser 自行搜尋使用,也可以透過程式碼讓 ReSharper 幫我們帶出 NuGet browser 找尋遺失的 NuGet 套件。
NuGet browser 找尋到 NuGet 套件後,後面會有三個按鈕,若不確定套件是否是要使找尋的,可透過最後一個按鈕將套件的詳細說明展開。
若有查閱類別與成員的需要,這邊也可以透過第一個按鈕查閱。
若都確認無誤要安裝的話,可按下第二個按鈕進行套件的安裝。
Link Finding, Exploring, and Installing NuGet Packages - Help | ReSharper
read morePosts
ReSharper - Heap Allocation Viewer Extension
Heap Allocation Viewer 是 Reshaper 的擴充套件,能將 Heap 相關的操作 (像是 Local object allocation、Boxing、Delegate creation、Closure creation ) 進行 Highlight。
使用前需先開啟 ReSharper 的 Extension Manager。
{% img /images/posts/HeapAllocationViewer/1.png %}
搜尋框輸入 heapview 關鍵字,下載並安裝 Heap Allocation Viewer 套件 (若搜尋不到,可能是因為 ReSharper 太舊,需更新為 8.1 以後的版本)。
{% img /images/posts/HeapAllocationViewer/2.png %}
{% img /images/posts/HeapAllocationViewer/3.png %}
{% img /images/posts/HeapAllocationViewer/4.png %}
安裝好後,Visual Studio 即會將 Heap 相關的操作 Highlight。
{% img /images/posts/HeapAllocationViewer/5.png %}
{% img /images/posts/HeapAllocationViewer/6.png %}
以筆者來說,加裝該套件的主要原因是它可以幫我們 Highlight 程式中 Boxing 問題,而且在開發時當 Boxing 問題發生可以很容易的意識到。
read moreTag: PL/SQL and SQL Coding Guidelines
Posts
>-
條款五十八,總是使用字串變數去執行 Dynamic SQL。
像是下面這段程式直接將要執行的字串帶入執行 Dynamic SQL 就不被建議。
DECLARE l_empno emp.empno%TYPE := 4711; BEGIN EXECUTE IMMEDIATE 'DELETE FROM emp WHERE epno = :p_empno' USING l_empno; END; 建議的做法是用字串變數儲存要執行的 Dynamic SQL 語法,在將字串變數帶入動態運行。這樣的做法在串接複雜語句時會比較容易,在例外處理上若有需要也可以直接將變數拿來使用。
DECLARE l_empno emp.empno%TYPE := 4711; l_sql VARCHAR2(32767); BEGIN l_sql := 'DELETE FROM emp WHERE epno = :p_empno'; EXECUTE IMMEDIATE l_sql USING l_empno; EXCEPTION WHEN others THEN DBMS_OUTPUT.PUT_LINE(l_sql); END;
read morePosts
PL/SQL SQL CODING GUIDELINE 57 - Avoid using Oracle’s predefined exceptions
條款五十七,避免使用 Oracle 預先定義好的例外。
像是下面這段程式,在程式中主動拋出了 Oracle 預先定義好的例外就不是建議的做法。
BEGIN RAISE NO_DATA_FOUND; END; 應該要避免直接使用 Oracle 預先定義好的例外。
DECLARE my_exception EXCEPTION; BEGIN RAISE my_exception; END;
read morePosts
PL/SQL SQL CODING GUIDELINE 56 - Avoid unhandled exceptions
條款五十六,避免未處理的例外。
像是下面這段程式,當沒資料或是資料過多時 Select into 就會丟出例外。
CREATE OR REPLACE PACKAGE BODY department_api IS FUNCTION name_by_id (in_id IN departments.department_id%TYPE) RETURN departments.department_name%TYPE IS l_department_name departments.department_name%TYPE; BEGIN SELECT department_name INTO l_department_name FROM departments WHERE department_id = in_id; RETURN l_department_name; END name_by_id; END department_api; 建議是要確保程式不會有未處理的例外,像是上面這樣的程式就要加處理 NO_DATA_FOUND 與 TOO_MANY_ROWS。
CREATE OR REPLACE PACKAGE BODY department_api IS FUNCTION name_by_id (in_id IN departments.department_id%TYPE) RETURN departments.department_name%TYPE IS l_department_name departments.department_name%TYPE; BEGIN SELECT department_name INTO l_department_name FROM departments WHERE department_id = in_id; RETURN l_department_name; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN NULL; WHEN TOO_MANY_ROWS THEN RAISE; END name_by_id; END department_api;
read morePosts
>-
條款五十五,避免直接使用 RAISE_APPLICATION_ERROR hard code 帶入 error number 與 error message 拋出錯誤。
像是下面這樣的程式,程式中直接使用 RAISE_APPLICATION_ERROR hard code 帶入 error number 與 error message 拋出錯誤,這樣 error number 與 error message 會散在許多地方,且會有重複撰寫的可能性,並不是建議採用。
BEGIN raise_application_error(-20501,'Invalid employee_id'); END; 建議將之封裝,集中撰寫,不僅修改方便,維護起來也方便。
BEGIN err_up.raise(in_error => err.co_invalid_employee_id); END;
read morePosts
>-
條款五十三,避免單獨使用 WHEN OTHERS 去處理例外。
像是下面這樣的程式,使用 WHEN OTHERS 搭配 IF 條件式與 SQLCODE 去處理例外,就是不建議的作法。
... EXCEPTION WHEN OTHERS THEN IF SQLCODE = -1 THEN update_instead (...); ELSE err.log; RAISE; END IF; ... 如果明確使用例外的名稱去處理例外,可以免去不必要的 IF 判斷,及 SQLCODE 的使用。
... EXCEPTION WHEN DUP_VAL_ON_INDEX THEN update_instead (...); WHEN OTHERS THEN err.log; RAISE; ...
read morePosts
>-
條款五十二,不要使用自定義錯誤去重新定義 Oracle 預先定義的錯誤。
像是下面這樣的程式,使用自定義錯誤重新定義了 no_data_found 錯誤,就是不建議的作法。
DECLARE no_data_found EXCEPTION; … BEGIN ... EXCEPTION WHEN no_data_found THEN sys.dbms_output.put_line(co_no_data_found); END; 比較好的作法應該是反思是否需要重新定義 Oracle 預先定義的錯誤、是否應該定義的是不同的錯誤。
DECLARE empty_value EXCEPTION; ... BEGIN ... EXCEPTION WHEN empty_value THEN sys.dbms_output.put_line(co_empty_value); WHEN no_data_found THEN sys.dbms_output.put_line(co_no_data_found); END;
read morePosts
>-
條款五十一,不要使用 Error Number 去處理 Unnamed Exceptions。
像是下面這樣的程式,直接使用 Error Number -2291 去處理 Unnamed Exception 就不是建議的作法。
BEGIN ... EXCEPTION WHEN OTHERS THEN IF SQLCODE = -2291 THEN ... END IF; END; 比較好的作法是透過 pragma exception_init 將未命名的內部錯誤做個命名,然後直接用這個命名去攔截對應的錯誤做對應的處理。
DECLARE e_parent_missing EXCEPTION; PRAGMA EXCEPTION_INIT(e_parent_missing,-2291); ... BEGIN ... EXCEPTION WHEN e_parent_missing THEN ... END;
read morePosts
>-
條款五十,避免 hard-codeed FOR loop 的上下邊界值。
像是下面這段程式 hard-coded 了 FOR loop 的上下邊界值,這樣的撰寫預期上下邊界值是不會被變動的,且後續再看這段程式可能也會不理解為何上下邊界值會帶這樣的值,程式的維護性上會比較差。
BEGIN <<for_loop>> FOR i IN 1..5 LOOP sys.dbms_output.put_line(i); END LOOP for_loop; END; 比較好的做法是不要將上下邊界值 hard-coded,可能用常數設定其值,並給予較具意義的常數名稱,讓程式的可讀性與可維護性更好。
DECLARE co_lower_bound CONSTANT SIMPLE_INTEGER := 1; co_upper_bound CONSTANT SIMPLE_INTEGER := 5; BEGIN <<for_loop>> FOR i IN co_lower_bound..co_upper_bound LOOP sys.dbms_output.put_line(i); END LOOP for_loop; END;
read morePosts
PL/SQL SQL CODING GUIDELINE 49 - Avoid use of unreferenced FOR loop indexes
條款四十九,避免未使用的 FOR loop 索引。
像是下面這樣的程式使用了 numeric FOR loop,卻未使用 FOR loop 的索引,導致程式碼變得更為複雜沒有效率。
DECLARE ... BEGIN l_row := co_lower_bound; l_value := co_first_value; <<for_loop>> FOR i IN co_lower_bound .. co_upper_bound LOOP sys.dbms_output.put_line(l_row || co_delimiter || l_value); l_row := l_row + co_row_incr; l_value := l_value + co_value_incr; END LOOP for_loop; END; 比較好的作法是要看看是否能透過索引撰寫出更適合的程式,如果不行則要反思這邊使用 numeric FOR loop 是否合適。
DECLARE ... BEGIN <<for_loop>> FOR i IN co_lower_bound .. co_upper_bound LOOP sys.dbms_output.put_line(i || co_delimiter || to_char(co_first_value + i * co_value_incr)); END LOOP for_loop; END;
read morePosts
>-
條款四十八,不要遍巡 CURSOR 去確認是否含有資料。
像是下面這段程式片巡走訪 CURSOR 以確認是否含有資料,這樣並不是很好的寫法。
DECLARE l_employee_found BOOLEAN := FALSE; … BEGIN <<check_employees>> FOR r_employee IN c_employee LOOP l_employee_found := TRUE; END LOOP check_employees; END; 比較好的作法應該像是下面這段程式這樣,將 CURSOR 開啟,嘗試 Fetch 一筆資料,利用 CURSOR 的 %FOUND 去判斷是否含有資料,最後將 CURSOR 關閉。
DECLARE l_employee_found BOOLEAN := FALSE; … BEGIN OPEN c_employee; FETCH c_employee INTO r_employee; l_employee_found := c_employee%FOUND; CLOSE c_emplyoee; END;
read morePosts
PL/SQL SQL CODING GUIDELINE 47 - Try to label your EXIT WHEN statements
條款四十七,嘗試將 EXIT WHEN 搭配 label 使用。
像是下面這樣的程式,雖然使用了 EXIT WHEN 跳離迴圈,但是未搭配 label 使用,因此在巢狀迴圈下得一層一層的跳離。
BEGIN ... <<outerloop>> LOOP ... <<innerloop>> LOOP ... EXIT WHEN l_innerlp = co_exit_value; END LOOP innerloop; EXIT WHEN l_innerlp = co_exit_value; END LOOP outerloop; END; 如果將 EXIT WHEN 搭配 label 使用可以直接在巢狀迴圈下跳離,這樣程式會比較簡短、清晰、且易於維護。
BEGIN ... <<outerloop>> LOOP ... <<innerloop>> LOOP ... EXIT outerloop WHEN l_innerlp = 3; END LOOP innerloop; END LOOP outerloop; END;
read morePosts
>-
條款四十六,總是使用 EXIT WHILE loop 去跳離迴圈,不要使用 IF…EXIT。
像是下面這樣的程式使用 IF 判斷要跳離迴圈的條件是否成立,成立的話使用 EXIT 跳離迴圈。如果 IF 判斷只是單純的用來處裡跳離迴圈的條件判斷,那這樣的撰寫方式就不是那麼洽當,程式碼變得比較冗餘,且不好維護。
BEGIN <<process_employees>> LOOP ... IF ... THEN EXIT process_employees; END IF; ... END LOOP process_employees; END; 比較好的做法是用 EXIT WHEN,將跳離迴圈的判斷直接寫在 EXIT WHEN 後面,這樣程式會比較簡短、清晰、且易於維護。
BEGIN <<process_employees>> LOOP ... EXIT process_employees WHEN (...); END LOOP process_employees; END;
read morePosts
>-
條款四十五,避免使用 EXIT 去跳離迴圈,除非使用的是 basic loop。
像是下面這樣的程式,使用了 EXIT 去跳離迴圈,但是非 basic loop 都有迴圈的邊界條件可以設定,可以做到一樣的事情,所以這樣的寫法並不是很好。
... i := co_min_value; <<while_loop>> WHILE (i <= co_max_value) LOOP i := i + co_increment; EXIT while_loop WHEN i > co_max_value; END LOOP while_loop; <<for_loop>> FOR i IN co_min_value..co_max_value LOOP ... EXIT for_loop WHEN i = co_max_value; END LOOP for_loop; <<process_employees>> FOR r_employee IN (SELECT last_name FROM employees) LOOP ... EXIT process_employees; END LOOP process_employees; ... 若使用非 basic loop,建議使用邊界條件來跳離迴圈。而 basic loop 因為沒有邊界條件的設定,因此也只能使用 EXIT 來跳離迴圈。
read morePosts
>-
條款四十四,總是使用 WHILE loop 去處理 loose array。
像是下面這樣的程式用 FOR loop 去遍巡處理 loose array,這不是被建議使用的寫法,雖然大部分的狀況下可以正常運行,但是當 loose array 的內容被刪除時,這樣的處理會因為 null 元素而運行錯誤。
DECLARE ... l_index PLS_INTEGER; BEGIN ... IF t_employees IS NOT NULL THEN <<process_employees>> FOR i IN 1..t_employees.COUNT() LOOP ... END LOOP process_employees; END IF; END; 建議使用 WHILE loop 遍巡處理 loose array,才不會因為 Null 元素導致錯誤。
DECLARE ... l_index PLS_INTEGER; BEGIN l_index := t_employees.FIRST(); <<process_employees>> WHILE l_index IS NOT NULL LOOP ... l_index := t_employees.NEXT(l_index); END LOOP process_employees; END;
read morePosts
>-
條款四十三,遍巡 dense array 時,建議使用 1 當做 lower boundary,使用 COUNT() 當做 upper boundary。
像是下面這樣的程式,使用了 FIRST() 與 LAST() 做為遍巡走訪的條件,dense array 不為空時可以正常運作,但當 dense array 為空時則會發生錯誤。
DECLARE t_employees t_employee_type := t_employee_type(); BEGIN <<process_employees>> FOR i IN t_employees.FIRST()..t_employees.LAST() LOOP … END LOOP process_employees; END; 簡單的解決方式可以加判斷 dense array 是否為空。
DECLARE t_employees t_employee_type := t_employee_type(); BEGIN <<process_employees>> IF t_employees IS NOT EMPTY THEN FOR i IN t_employees.FIRST()..t_employees.LAST() LOOP … END LOOP process_employees; END IF; END; 但建議的方式是改以 1 與 COUNT() 做為遍巡走訪的條件。
read morePosts
>-
條款四十二,總是使用 NUMERIC FOR loop 去處理 dense array。
像是下面這樣的程式:
... BEGIN <<process_employees>> LOOP EXIT process_employees WHEN i > t_employees.COUNT(); … i := i + 1; END LOOP process_employees; END; 可以像下面這樣改寫,程式碼的維護性會比較好。
... BEGIN <<process_employees>> FOR i IN 1..t_employees.COUNT() LOOP … END LOOP process_employees; END;
read morePosts
>-
條款四十一,總是使用 CURSOR for loop,除非使用 Bulk operations。
像是下面這樣的程式:
... BEGIN <<read_employees>> LOOP FETCH c_employees INTO r_employee; EXIT read_employees WHEN c_employees%NOTFOUND; … END LOOP read_employees; CLOSE c_employees; END; 可以像下面這樣改寫,程式碼的維護性會比較好。
... BEGIN <<read_employees>> FOR r_employee IN c_employee LOOP … END LOOP read_employees; END;
read morePosts
PL/SQL SQL CODING GUIDELINE 40 - Always label your loops
條款四十,如果程式中有 loop,嘗試使用 label 讓他的區塊範圍更為清楚。
像是下面這樣的程式:
BEGIN FOR r_employee IN (SELECT * FROM emp) LOOP … END LOOP; END; 可以像下面這樣改寫,在 loop 的前面加上 Label,然後在 End 後加上 Label Name。
BEGIN <<process_employees>> FOR r_employee IN (SELECT * FROM emp) LOOP … END LOOP process_employees; END; 這樣程式碼的區塊範圍清楚許多。
read morePosts
>-
條款三十八,如果 NVL 第二或第三個參數是 function 呼叫或是 select 語句,使用 CASE 取代 NVL2。
這是因為 NVL2 會先把每個可能的結果都先取出,儘管是根本不會出的結果,所以這樣會有不必要的 overhead。
SELECT NVL2(dummy, function_call(), function_call()) FROM dual; 建議的做法是用 CASE 取代 NVL2,以避開這樣的問題。
SELECT CASE WHEN dummy IS NULL THEN function_call() ELSE function_call() END FROM dual;
read morePosts
PL/SQL SQL CODING GUIDELINE 36 - Try to use CASE rather than DECODE
條款三十六,嘗試使用 CASE 而不要用 DECODE。
用 DECODE 的可讀性較低,不易閱讀。
BEGIN SELECT DECODE(dummy, 'A', 1 , 'B', 2 , 'C', 3 , 'D', 4 , 'E', 5 , 'F', 6 , 7) INTO l_result FROM dual; ... 改用 CASE 撰寫雖然程式變多,但閱讀起來相對會比較清楚。
BEGIN l_result := CASE dummy WHEN 'A' THEN 1 WHEN 'B' THEN 2 WHEN 'C' THEN 3 WHEN 'D' THEN 4 WHEN 'E' THEN 5 WHEN 'F' THEN 6 ELSE 7 END; ...
read morePosts
>-
條款三十四,避免在 SQL 語句運行與 implicit cursor 中間使用 procedure 或是 function。
像是下面的例子,這邊先刪除了一些資料,後續要用 SQL%ROWCOUNT 去判斷刪除的筆數,但中間卻調用了其它 function,以致於 SQL%ROWCOUNT 的值不如我們的預期。
CREATE PROCEDURE remove_emp_and_process (in_id IN emp.empno%TYPE) AS BEGIN DELETE FROM emp WHERE empno = in_id RETURNING deptno INTO l_deptno; process_department (...); IF SQL%ROWCOUNT > 1 THEN -- Too many rows deleted! Rollback and recover... ROLLBACK; END IF; END remove_emp_and_process; 所以我們必須避免在 SQL 語句運行與 implicit cursor 中間使用 procedure 或是 function。
read morePosts
PL/SQL SQL CODING GUIDELINE 33 - Always close locally opened cursors
條款三十三,總是關閉開啟的游標。
像是下面這樣將游標開啟後並未揪游標關閉,使用的資源不會自動釋放。
CREATE PROCEDURE not_close_cursor (out_count OUT INTEGER) AS CURSOR c1 IS SELECT COUNT (*) FROM all_users; BEGIN out_count := 0; OPEN c1; FETCH c1 INTO out_count; END not_close_cursor; ... 應該要自己將游標在適當的時機點關閉,使用的資源才會被釋放。
CREATE PROCEDURE close_cursor (out_count OUT INTEGER) AS CURSOR c1 IS SELECT COUNT (*) FROM all_users; BEGIN out_count := 0; OPEN c1; FETCH c1 INTO out_count; CLOSE c1 END close_cursor;
read morePosts
>-
條款三十二,當使用 BULK 與 LIMIT 操作時,避免直接在後面用 %NOTFOUND 判斷是否有資料處理,應改用 COUNT() 判斷。
像是下面這樣的撰寫方式,迴圈內每次會處理 5 筆資料,假設今天總資料量為 14,那第三次處理時因為剩餘的筆數 4 小於 LIMIT 設定的筆數 5,%NOTFOUND 會為 true 跳離,剩餘的資料就都沒有跑到。
-- This example will only show 10 of 14 employees DECLARE TYPE t_employee_type IS TABLE OF emp%ROWTYPE; t_employees t_employee_type; CURSOR c_emp IS SELECT * FROM emp ORDER BY empno; BEGIN OPEN c_emp; <<process_emp>> LOOP FETCH c_emp BULK COLLECT INTO t_employees LIMIT 5; EXIT process_emp WHEN c_emp%NOTFOUND; <<display_emp>> FOR i IN 1.
read morePosts
>-
條款三十一,Always use %NOTFOUND instead of NOT %FOUND to check whether a cursor was successful。
不要用 Not %FOUND 去撰寫判斷邏輯。
LOOP FETCH c_employees INTO r_employee; EXIT WHEN NOT c_employees%FOUND; ... END LOOP; 取而代之的是要用 %NOTFOUND 去撰寫判斷邏輯。
LOOP FETCH c_employees INTO r_employee; EXIT WHEN c_employees%NOTFOUND; ... END LOOP; 這樣可讀性會比較好。
read morePosts
>-
條款二十九,Try to use anchored records as targets for your cursors。
像是下面這邊的程式就宣告了幾個變數,開啟 Cursor 後遍巡,將資料塞到變數後再進一步處理。
DECLARE CURSOR c_user IS SELECT user_id, firstname, lastname FROM user; l_user_id user.user_id%TYPE; l_firstname user.firstname%TYPE; l_lastname user.lastname%TYPE; BEGIN OPEN c_user; FETCH c_user INTO l_user_id, l_firstname, l_lastname; WHILE c_user%FOUND LOOP FETCH c_user INTO l_user_id, l_firstname, l_lastname; END LOOP; CLOSE c_user; END; 如果改用 cursor-anchored records 去實作,就可以省去一些不必要的變數宣告。
DECLARE CURSOR c_user IS SELECT user_id, firstname, lastname FROM user; r_user c_user%ROWTYPE; BEGIN OPEN c_user; FETCH c_user INTO r_user; <<process_user>> WHILE c_user%FOUND LOOP FETCH c_user INTO r_user; END LOOP process_user; CLOSE c_user; END;
read morePosts
>-
條款二十六,運行插入命令時總是指定塞入的欄位。
像是下面這樣不指定要塞入欄位的寫法,塞入的動作會對資料表欄位的順序有所依賴,當欄位順序一有變動就會產生不如預期的結果,而且問題發生時不是很容易可以被偵測出來。
INSERT INTO messages VALUES (l_mess_no ,l_mess_typ ,l_mess_text ); 如果在塞入時明確的指定塞入的欄位,就能避開這樣的問題。
INSERT INTO messages (mess_no ,mess_typ ,mess_text ) VALUES (l_mess_no ,l_mess_typ ,l_mess_text );
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 25 - Avoid using the LONG and LONG RAW data types
條款二十五,避免使用 LONG 與 LONG RAW 型態。
LONG 與 LONG RAW 型態已經過時,留著只是為了向前相容,不建議拿來使用,應考慮用 NCLOB、BLOB、BFILE 去替。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 24 -Try to use boolean data type for values with dual meaning
條款二十四,當值只有兩種狀態時,試著使用 Boolean 型態。
像是如果要表達的是是否為較大的數值,如果沒有特別的理由,那就不該使用數值表示,因為數值代表的意義沒有 Boolean 型態來的明確。
DECLARE v_IsBigger number(1) := 1; BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_IsBigger = 1 THEN 'True' ELSE 'False' END); END; 若用 Boolean 型態表達會比較清楚。
DECLARE v_IsBigger BOOLEAN := true; BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_IsBigger THEN 'True' ELSE 'False' END); END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 23 - Always define your VARCHAR2 variables using CHAR SEMANTIC
條款二十三,使用 Varchar2 時總是定義 Char Semantic。
預設未定義時有可能指定的是 Byte,也有可能是 Char,端看 NLS_LENGTH_SEMANTICS 參數的設定,預設是 Byte。
DECLARE v_str varchar(200); BEGIN ... END; 但通常我們指定字串應該看的是字元數,建議是將其指定用 Char。
DECLARE v_str varchar(200 char); BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 22 - Never use zero-length strings to substitute NULL
條款二十二,不要用空字串去代替 Null 值。
在 Oracle 這邊不論是對的 Varchar 或是 Varchar2 型態賦予空字串,Oracle 都會將其視為 Null,所以這邊不建議將其設為空字串。
DECLARE v_str varchar2(4000) := ''; BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_str is null THEN 'null' ELSE 'not null' END); END; 而是應該像下面,沒特別塞值時預設就是 Null。
DECLARE v_str varchar2(4000); BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_str is null THEN 'null' ELSE 'not null' END); END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 21 - Avoid using VARCHAR data type
條款二十一,避免使用 Varchar 型態。
Varchar 型態在工業標準上是可以儲存空字串的,但在 Oracle 這邊並未遵循這樣的標準,當將空字串存放至 Varchar 型態,Oracle 這邊會將空字串變為 null 值,就跟 Varchar2 型態是一樣的,但難保哪天會改回遵循工業標準。
DECLARE v_str varchar(4000); BEGIN … END; 因此在 Oracle 這邊建議不要使用 Varchar 型態,建議使用 Varchar2 型態。
DECLARE v_str varchar2(4000); BEGIN … END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 20 - Avoid using CHAR data type
條款二十,避免使用 Char。
Oracle 的 Char 型態在宣告時需指定大小,宣告多大就佔多大。像是下面這邊筆者宣告了 4000 的 char,則該變數即佔了 4000,儘管這邊只賦予了短短的幾個字元進去。
DECLARE v_str char(4000) := 'test'; BEGIN DBMS_OUTPUT.PUT_LINE(Length(v_str)); END; 取而代之的是應該改用 varchar2 型態。
DECLARE v_str varchar2(4000) := 'test'; BEGIN DBMS_OUTPUT.PUT_LINE(Length(v_str)); END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 19 - Try to use PLS_INTEGER instead of NUMBER for arithmetic operations with integer values (no decimal point)
條款十九,用 PLS_INTEGER 去表示整數。
如果要宣告整數,不要用 Number 型態去宣告。
DECLARE v_number number(38, 0); BEGIN ... END; 建議使用 PLS_INTEGER,因為使用 PLS_INTEGER 型態使用的記憶體會比較少,且效能上會快上三倍。
DECLARE v_number PLS_INTEGER; BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 18 - Avoid declaring NUMBER variables or subtypes with no precision
條款十八,避免在宣告 Number 型態的變數或是 SubType 時未設定整數位數。
像是下面這樣,變數宣告時未指定整數位數,預設精確度為 38 位。
DECLARE v_number number; BEGIN ... END; 如果使用上已經知道明確位數,那建議在宣告時還是明確的指定。
DECLARE v_number number(9, 2); BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 15 - Never use quoted identifiers
條款十五是說在變數宣告時,變數的名稱不要加上雙引號。
像是下面這樣,宣告的變數加上雙引號是合法的。
DECLARE "v_str" VARCHAR2(30) ; BEGIN … END main; 但不建議這樣宣告,建議還是不要加上雙引號。
DECLARE v_str VARCHAR2(30) ; BEGIN … END main;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 14 - Never overload data structure usages
條款十四是說不要去覆寫變數。
像是下面這樣外層與內層宣告了一樣名稱的變數,是不建議的寫法。
<<main>> DECLARE v_str VARCHAR2(30); BEGIN <<sub>> DECLARE v_str VARCHAR2(4000) ; BEGIN … END sub; END main; 建議使用上還是應該要將變數名稱錯開。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 13 - Avoid initializing variables using functions in the declaration section
條款十三是說要避免在變數宣告的同時呼叫 function 去初始變數。
DECLARE l_company_name VARCHAR2(30) := util_pck.get_company_name(in_id => 47); BEGIN … END; 因為在變數宣告的地方呼叫 function 去初始變數,function 發生例外時是無法攔截處理的。
因此要像下面這樣將宣告與初始拆開處理。
DECLARE v_str VARCHAR2(30); BEGIN <<init>> BEGIN v_str := util_pck.get_company_name(inId => 47); EXCEPTION WHEN VALUE_ERROR THEN ... END init; END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 12 - Avoid comparisons with null value
條款十二是在說當判斷變數是否為 null 時,不要像下面這樣使用 = 去判斷。
DECLARE v_str VARCHAR2(30); BEGIN if v_str = null then … end if; END; 因為 null 不等於任何東西,即使是 null 也不等於 null。
{% img /images/posts/PLSQLCopRule12/1.png %}
正確的方式應該是用 is 或 is not 去做判斷。
DECLARE v_str VARCHAR2(30); BEGIN if v_str is null then … end if; END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 11 - Never initialize variables with NULL
條款十一是說不要將變數初始為 NULL。
DECLARE v_str VARCHAR2(30) := null; BEGIN ... END; 因為預設就是初始為 Null。
DECLARE v_str VARCHAR2(30); BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 10 - Try to use subtypes for constructs used often in your application
條款十是在說如果有些常用的型態使用,建議將它設成 SubType,像是下面這邊 VARCHAR2(4000) 程式中如果常用的話,就可以將它設成 SubType。
DECLARE v_str VARCHAR2(4000); BEGIN … END; 這邊將它設成名為 STRING_MAX 的 SubType,後續可直接拿來宣告使用。
CREATE OR REPLACE PACKAGE PKG_SUBTYPE AS SUBTYPE STRING_MAX IS VARCHAR2(4000); END PKG_SUBTYPE; DECLARE v_str PKG_SUBTYPE.STRING_MAX; BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 9 - Try to have a single location to define your types
條款九主要是在描述型態的定義要集中一處放置,以 Oracle 來說型態的定義可以放置在 DB 的 Types 下。
{% img /images/posts/PLSQLCopRule9/1.png %}
也可以建造個 Package 集中放置,這邊建議是挑選一個地方放置即可,避免有些型態的宣告放置在 Types 下,而有的在 Package 下。
選用上要注意 Oracle 內的型態有的只能在 Database 下使用,無法在 Package 下使用,像是 Object 型態。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 8 - Try to use anchored declarations for variables
條款八,使用 anchored declarations。
像是下面這樣的程式:
DECLARE v_empName VARCHAR2(10); BEGIN … END; 預期要帶入的是 emp table 的 ename,這在 emp table 的 schema 中是其實是已經定義好的。如果像上面這樣另行宣告可能會不小心設錯,或是 schema 修改時會很麻煩。
若是使用 anchored declarations,型態會直接參照 schema 的定義,免去像這樣的困擾。
DECLARE v_empName emp.ename%TYPE; BEGIN … END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 5 - Avoid using literals in your code
條款五,避免在程式中直接使用字串。
像是下面這樣的程式:
SET SERVEROUTPUT ON Begin DBMS_OUTPUT.put_line('Root Account:' || 'Admin'); End; 可以像下面這樣改寫,建立一個 Package 統一存放常數字串,呼叫端改透過 Package 叫用。
SET SERVEROUTPUT ON CREATE OR REPLACE PACKAGE CONST IS ROOT_ACCOUNT CONSTANT varchar(50) := 'Admin'; END CONST; / Begin DBMS_OUTPUT.put_line('Root Account:' || CONST.ROOT_ACCOUNT); End; 這樣常數字串的宣告會集中在 Package 內,修改上也比較方便。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 2 - Always have a matching loop or block label
條款二,如果程式中有迴圈區塊,為其加上 label 讓他的區塊範圍更為清楚。
像是下面這樣的程式:
SET SERVEROUTPUT ON DECLARE i PLS_INTEGER; Begin FOR i IN 1..10 LOOP DBMS_OUTPUT.put_line('i =' || i); End LOOP; End; 可以像下面這樣改寫,在 For…Loop 前面加上 Label,然後在 End 後加上 Label Name。
SET SERVEROUTPUT ON DECLARE i PLS_INTEGER; Begin <<Print1To10>> FOR i IN 1..10 LOOP DBMS_OUTPUT.put_line('i =' || i); End LOOP Print1To10; End; 改完程式碼的區塊範圍清楚了許多。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 1 - Try to label your sub blocks
條款一,如果程式中有子 block,嘗試使用 label 讓他的區塊範圍更為清楚。
像是下面這樣的程式:
SET SERVEROUTPUT ON Begin DBMS_OUTPUT.put_line('Start'); Begin DBMS_OUTPUT.put_line('Processing...'); End; DBMS_OUTPUT.put_line('End'); End; 可以像下面這樣改寫,在子 Block 的 Begin 前面加上 Label,然後在 End 後加上 Label Name。
SET SERVEROUTPUT ON Begin DBMS_OUTPUT.put_line('Start'); <<Processing>> Begin DBMS_OUTPUT.put_line('Processing...'); End Processing; DBMS_OUTPUT.put_line('End'); End; 改完程式碼的區塊範圍清楚了許多。
read moreTag: Puppet
Posts
Puppet - Install puppet server via apt
要透過 apt 安裝 Pupper server,需要開啟 package repository。
首先要先依作業系統的版本下載 puppetlabs-release。
Ubuntu 12.04
curl -O https://apt.puppetlabs.com/puppetlabs-release-precise.deb Ubuntu 14.04
curl -O https://apt.puppetlabs.com/puppetlabs-release-trusty.deb 下載完用 dpkg 安裝下載的套件。
dpkg -i <PACKAGE NAME> 安裝完更新 apt 套件的清單。
sudo apt-get update 最後用 apt 安裝 puppetserver 即可。
sudo apt-get install puppetserver Link Installing Puppet: Debian and Ubuntu — Documentation — Puppet
read moreTag: Yarn
Posts
Yarn - Yarn global
Yarn global 命令可用來進行全域套件的管理。
像是可以使用 Yarn global add 將套件安裝到全域。
yarn global add <PackageName> 或是在套件名稱後用小老鼠串接套件的版本,指定安裝指定的套件版本。
yarn global add <PackageName>@<PackageVersion> 安裝完可用 Yarn global list 查閱安裝的套件。
yarn global list 若要更新全域套件,可使用 yarn global upgrade,帶上要更新的套件名稱即可。
yarn global upgrade <PackageName> 若要移除全域套件,可使用 yarn global remove,後面帶上要移除的套件。
yarn global remove <PackageName> Link yarn global | Yarn
read morePosts
Yarn - Yarn upgrade
Yarn upgrade 命令可用來更新套件版本。
假設今天使用的是舊版的套件。
就可以使用 Yarn upgrade 帶上套件的名稱進行套件版本的更新。
yarn upgrade <PackageName> 或是在套件名稱後用小老鼠串接套件的版本,指定套件更新到特定的版本。
yarn upgrade <PackageName>@<PackageVersion> 命令調用後套件即更新完成,若有需要,可以從設定檔內依賴的套件版本做個確認。
Link yarn upgrade | Yarn
read morePosts
Yarn - Yarn why
Yarn why 命令可用來查閱套件安裝的原因。
使用上只要用 yarn why 帶上套件的名稱即可。
yarn why <PackageName> 像是這邊安裝了 gulp 套件。
用 yarn why 查驗,就會看到是因為在 dependencies 設定的關係。
如果查驗 gulp 以外的套件,就會看到是因為被 gulp 套件依賴或是間接依賴才會被安裝進去。
Link yarn why | Yarn
read morePosts
Yarn - Install Yarn via npm
透過 npm 安裝 Yarn 是最簡易的 Yarn 安裝方式,只要調用 npm install 命令並帶上 Yarn 套件名稱及 -g 參數,將 Yarn 安裝到全域即可。
npm install -g yarn
read morePosts
Yarn - Yarn info
Yarn info 命令可用來查閱套件的資訊。
可以直接用 yarn info 帶上指定的套件名稱查閱指定套件的資訊。
yarn info <PackageName> 若要查閱指定版本的套件資訊,也可以在套件名稱後面用小老鼠加帶套件版本。
yarn info <PackageName>@<PackageVersion> 要查閱指定的套件資訊的話,可以再多帶上套件資訊的名稱。
yarn info <PackageName> <InfoName> 像是可以查閱套件的名稱。
yarn info <PackageName> name 查閱套件的描述。
yarn info <PackageName> description 查閱套件的依賴。
yarn info <PackageName> dependencies 查閱套件的建立與修改時間。
yarn info <PackageName> time 查閱套件的說明文件。
yarn info <PackageName> readme 若是要用程式去擷取套件的資訊,也可以加帶 –json 改用 JSON 格式顯示。
yarn info <PackageName> --json Link pyarn info | Yarn](https://yarnpkg.com/en/docs/cli/info)
read morePosts
Yarn - Yarn cache
yarn cache 命令可以針對 yarn 的快取做些相關的控制。
像是調用 yarn cache ls 可查閱現在有備快取的套件。
yarn cache dir 可查閱套件快取的位置。
yarn 快取的套件都會存放在設定的套件快取位置下。
yarn cache clean 命令可以清除 yarn 的快取。
清除完用 yarn cache ls 查看就會看到快取已被清除。
設定的套件快取位置下所快取的檔案也會一併移除。
read morePosts
Yarn - Yarn outdated
yarn outdated 命令可用來檢查是否有使用到過時的套件。
調用命令 yarn outdated 後會列出像下面這樣的資訊,有套件的名稱、目前使用的版本、預期的版本、最新的版本等資訊。
yarn outdated 若資訊過多也可以在調用時加帶套件的名稱,這樣就會只檢查指定的套件。
yarn outdated [package...] Link yarn outdated | Yarn
read morePosts
Yarn - Yarn install
yarn install 命令可用來還原套件。
若是在 package.json 中設定的套件並未在本地被載入,可調用 yarn install 命令將之還原。
yarn install 除了調用 yarn install 還原外,直接調用 yarn 也有相同的效果。
yarn 若有需要,也可以加帶參數 –force 強制運行套件還原,所有已載入的套件都會被重新進行載入。
yarn install --force Link yarn install | Yarn
read morePosts
Yarn - Yarn remove
yarn remove 命令可以用來移除載入的套件。
若是本來已有載入的套件。
就可以調用 yarn remove 命令,帶入套件名稱,將指定的套件移除。
yarn remove <PackageName> Link yarn remove | Yarn
read morePosts
Yarn - Yarn add
yarn add 命令可以用來載入要使用的套件。
調用 yarn add,帶入套件名稱,即可將指定的套件載入。
yarn add <PackageName> 若要指定版本,可在套件名稱後面加上套件的版本號。
yarn add <PackageName>@<PackageVersion> 套件載入的同時會寫入 package.json 的 dependencies。
如果要將套件載入的同時寫入 package.json 的 devDependencies,可帶入參數 –dev 或是 -D。
yarn add <PackageName> --dev yarn add <PackageName> -D 要在套件載入的同時寫入 package.json 的 peerDependencies,可帶入參數 –peer 或 -P。
yarn add <PackageName> --peer yarn add <PackageName> -P 要在套件載入的同時寫入 package.json 的 optionalDependencies,可帶入參數 –optional 或 -O。
yarn add <PackageName> --optional yarn add <PackageName> -O Link yarn add | Yarn
read morePosts
Yarn - Yarn init
yarn init 命令可以用來建立 package.json 檔案。
調用 yarn init,依序填入 package.json 檔需要的資訊。
即可建立 package.json。
如果要直接用預設值建立 package.json,可在調用 yarn init 時帶入 -y 參數。
yarn init -y 就不用使用互動的方式建立,然後一直按 Enter 套預設值。
Link yarn init | Yarn
read morePosts
Yarn - Install Yarn via apt
要透過 APT 安裝 Yarn,需要先設定 Repository。
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list Repository 設定完後,更新 apt-get,更新完即可進行 Yarn 的安裝。
sudo apt-get update && sudo apt-get install yarn Link Installation | Yarn
read moreTag: Grok
Posts
Grok Debugger
要測試 Grok pattern,可以借助一些線上工具,像是 Grok Debugger。
使用上只要在 Input 部份帶入要被 Grok 處理的資料,Pattern 部份帶入要用來處理資料的 Grok pattern 即可。
像是要處理 IP 資料,就可以在 Input 部份帶入要處理的 IP,在 Pattern 部份帶入 %{IP:ip} 這樣的 Grok pattern,下方即會顯現經由 Grok pattern 處理完的結果,也就是 Logstash 的 field,以及其對應的資料。
處理完的結果如果資訊太多不易閱讀,可勾選 Named Captures Only 選項。
若要增加自定義的 Grok pattern,這邊也可勾選 Add custom patterns 選項進行設定。
除了 Grok pattern 的測試外,Grok Debugger 也提供一些定義好的 Grok pattern 可供參考,點選上方的連接切換至 Patterns 頁面即可。
Link Grok Debugger
read morePosts
Grok patterns
使用 Logstash 免不了會用到 Grok patterns,Grok patterns 其實也就只是用預先定義好的正規表示式來設定怎麼匹配,以及匹配成功後的 Group name,讓設定變得更為簡易、直覺。
Grok patterns 的語法為…
%{SYNTAX:SEMANTIC} SYNTAX 就是預先定義好的正規表示式,SEMANTIC 就是正規表示式匹配後的 Group name,等同於使用下面這樣的正規表示式語法。
(?<<GroupName>><RegexPattern>) SYNTAX 的設定可參閱 logstash/grok-patterns at v1.4.2 · elastic/logstash,參閱設定可更加了解要怎樣使用 SYNTAX,以及有助了解設定的 SYNTAX 為何會無法正確的匹配。
USERNAME [a-zA-Z0-9._-]+ USER %{USERNAME} INT (?:[+-]?(?:[0-9]+)) BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))) NUMBER (?:%{BASE10NUM}) BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+)) BASE16FLOAT (?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+))) POSINT (?:[1-9][0-9]*) NONNEGINT (?:[0-9]+) WORD \w+ NOTSPACE \S+ SPACE \s* DATA .*? GREEDYDATA .* QUOTEDSTRING (?>(?<!\)(?>"(?>\.|[^\"]+)+"|""|(?>'(?>\.|[^\']+)+')|''|(?>`(?>\.|[^\`]+)+`)|``)) UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12} # Networking MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC}) CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4}) WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2}) COMMONMAC (?
read moreTag: MessagePack
Posts
MsgPack.Cli - MessagePack implementation for Common Language Infrastructure
MsgPack.Cli 是 MessagePack 在 CLI 下的實作,如果要在 .NET 程式裡面使用 MessagePack,可以直接透過 NuGet 安裝使用。
Install-Package MsgPack.Cli 使用時先引用 MsgPack.Serialization 命名空間,然後透過 SerializationContext.Default.GetSerializer 取得 Serializer,用取得的 Serializer 帶入 stream 與要序列化的物件去調用 Pack 方法即可將物件序列化。
using MsgPack.Serialization; ... public static byte[] Serialize<T>(T thisObj) { var serializer = SerializationContext.Default.GetSerializer<T>(); using (var ms = new MemoryStream()) { serializer.Pack(ms, thisObj); return ms.ToArray(); } } ... 要解序列化則是透過取得的 Serializer 將 Stream 帶入調用 Unpack 方法。
... public static T Deserialize<T>(byte[] bytes) { var serializer = SerializationContext.Default.GetSerializer<T>(); using (var byteStream = new MemoryStream(bytes)) { return serializer.
read morePosts
MessagePack - An efficient binary serialization format
MessagePack 是一個有效率的二進制序列化格式,傳遞的資料內容有點像是 JSON,但是因為是二進制的序列化格式,所以資料量更快且更小。
像是下面這張官網的圖,可以看到 {“compact”:true,“schema”:0} 這樣的 JSON 資料換由 MessagePack 來處理,資料量會從 27 bytes 降到 18 bytes,減少了 67%。
不過官網這張圖只是簡單的示意,實際上 compact 與 schema 這兩個字串得替換為 ascii,所以實際傳送的資料會變為 82 a7 63 6f 6d 70 61 63 74 c3 a6 73 63 68 65 6d 61 00。
若想要讀懂 MessagePack 格式的資料,必需先了解 MessagePack 的 format,其定義如下:
format name first byte (in binary) first byte (in hex) positive fixint 0xxxxxxx 0x00 - 0x7f fixmap 1000xxxx 0x80 - 0x8f fixarray 1001xxxx 0x90 - 0x9f fixstr 101xxxxx 0xa0 - 0xbf nil 11000000 0xc0 (never used) 11000001 0xc1 false 11000010 0xc2 true 11000011 0xc3 bin 8 11000100 0xc4 bin 16 11000101 0xc5 bin 32 11000110 0xc6 ext 8 11000111 0xc7 ext 16 11001000 0xc8 ext 32 11001001 0xc9 float 32 11001010 0xca float 64 11001011 0xcb uint 8 11001100 0xcc uint 16 11001101 0xcd uint 32 11001110 0xce uint 64 11001111 0xcf int 8 11010000 0xd0 int 16 11010001 0xd1 int 32 11010010 0xd2 int 64 11010011 0xd3 fixext 1 11010100 0xd4 fixext 2 11010101 0xd5 fixext 4 11010110 0xd6 fixext 8 11010111 0xd7 fixext 16 11011000 0xd8 str 8 11011001 0xd9 str 16 11011010 0xda str 32 11011011 0xdb array 16 11011100 0xdc array 32 11011101 0xdd map 16 11011110 0xde map 32 11011111 0xdf negative fixint 111xxxxx 0xe0 - 0xff 這邊舉幾個簡單的例子來看。
read moreTag: Logstash
Posts
Logstash - grok filter
grok filter 能讓我們使用 Grok 語法簡易的切割 Logstash field。
其可使用的設定如下:
Setting Type Required Default Description add_field hash No {} If this filter is successful, add any arbitrary fields to this event. add_tag array No [] If this filter is successful, add arbitrary tags to the event. break_on_match boolean No true Break on first match. The first successful match by grok will result in the filter being finished. If you want grok to try all patterns (maybe you are parsing different things), then set this to false.
read morePosts
Logstash - Getting started
Logstash 安裝好後,可以用 Logstash 的 -e 參數帶入 Logstash 設定快速的體驗一下。
logstash -e <Setting> 像是下面這樣帶入簡單的設定,將標準輸入串流輸入的資料導到標準輸出串流。
logstash -e 'input { stdin{} } output { stdout{} }' 將資料輸入。
資料就會被輸出到標準輸出串流。
不再使用時按下熱鍵 Ctrl + D 即可退出。
除了 Input & Output 外,也可以試著設定 Filter,像是要用 Filter 去將訊息內的 IP 切成 client field,可以像下面這樣調用。
logstash -e 'input { stdin{} } filter { grok { match => { "message" => "%{IP:client}" } } } output { stdout { codec => rubydebug } }'
read morePosts
Logstash - Install Logstash via apt
安裝 Logstash 前,需先確認已有安裝 Java 8。
可輸入指令查看 Java 版本。
java -version 若版本不對,可先進行 Java 8 的安裝。
apt-get install python-software-properties 加入 PPA。
add-apt-repository -y ppa:webupd8team/java 進行 apt-get 的更新。
apt-get update 透過 APT 安裝 Java 8。
apt-get -y install oracle-java8-installer Java 環境準備好後,開始進行 Logstash 的安裝。
設定 repository definition。
echo "deb http://packages.elastic.co/logstash/2.1/debian stable main" | sudo tee -a /etc/apt/sources.list.d/logstash-2.x.list 透過 APT 安裝 Logstash。
apt-get install logstash Link Installing Logstash | Logstash Reference [5.4] | Elastic
read moreTag: Winlogbeat
Posts
Winlogbeat - Install Winlogbeat on Windows
要在 Windows 下使用 Winlogbeat,可先至官網下載下來解壓縮。
裡面比較會要用到的檔案有 winlogbeat.exe、install-service-winlogbeat.psl、uninstall-service-winlogbeat.psl 與 winlogbeat.yml。
winlogbeat.yml 是 Winlogbeat 的設定檔,設定完後直接點擊 winlogbeat.exe 就會開始作用。
也可以執行 install-service-winlogbeat.psl 註冊成 Windows 服務,讓 Winlogbeat 在背景服務。
Windows 服務註冊完後記得將服務啟動才有效果。
做到這邊 Winlogbeat 就能依照設定正常的傳送 Windows Event Logs。
若有需要後續也可執行 uninstall-service-winlogbeat.psl 將 Winlogbeat 的 Windows 服務移除。
Link Download Winlogbeat • Ship Windows Event Logs | Elastic
read moreTag: Ansible
Posts
Ansible - Copy module
Ansible 的 Copy module 可以用來處理檔案的複製。
可用的參數如下:
parameter required default choices comments attributes no None Attributes the file or directory should have. To get supported flags look at the man page for chattr on the target system. This string should contain the attributes in the same order as the one displayed by lsattr. backup no no yes/no Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly.
read morePosts
Ansible - APT module
Ansible 的 APT module 可以用來管理 APT 套件。
可用的參數如下:
parameter required default choices comments allow_unauthenticated no no yes/no Ignore if packages cannot be authenticated. This is useful for bootstrapping environments that manage their own apt-key setup. autoremove no yes/no If yes, remove unused dependency packages for all module states except build-dep. It can also be used as the only option. cache_valid_time no Update the apt cache if its older than the cache_valid_time.
read morePosts
Ansible - Shell module
Ansible 的 Shell module 可以用來執行命令。
可用的參數如下:
parameter required default choices comments chdir no cd into this directory before running the command creates no a filename, when it already exists, this step will not be run. executable no change the shell used to execute the command. Should be an absolute path to the executable. free_form yes The shell module takes a free form command to run, as a string. There’s not an actual option named “free form”.
read morePosts
Ansible - Command module
Ansible 的 Command module 可以用來執行命令。
可用的參數如下:
parameter required default choices comments chdir no cd into this directory before running the command creates no a filename or (since 2.0) glob pattern, when it already exists, this step will not be run. executable no change the shell used to execute the command. Should be an absolute path to the executable. free_form yes the command module takes a free form command to run. There is no parameter actually named ‘free form’.
read morePosts
Ansible - Offline docs with ansible-doc
Ansible 有許多模組,每麼模組有不同的用途、不同的參數、不同的使用方式,要查閱模組的使用方式除了透過網路查詢外,也可以用 ansible-doc 離線查詢。
ansible-doc 的使用方式如下:
Usage: ansible-doc [options] [module...] Options: -h, --help show this help message and exit -l, --list List available modules -M MODULE_PATH, --module-path=MODULE_PATH specify path(s) to module library (default=['./library/']) -s, --snippet Show playbook snippet for specified module(s) -v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging) --version show program's version number and exit 要查詢上面顯示的使用方式可以直接輸入 ansible-doc,或是帶入 -h,抑或是帶入 –help 參數。
ansible-doc ansible-doc -h ansible-doc --help 要查閱 ansible-doc 的版本,可使用 -v 或是 –version 參數。
read morePosts
Ansible - Inventory
Ansible 的 Inventory 是 Ansible 的主機清單,紀錄著要被管理的主機資訊。
最簡單的設置方式就是直接將要被管理的主機 IP 逐一寫入。
Ansible 就可以透過 Inventory 找到要控制的機器做對應的操控。
若有多台相近 IP 或相近網址的主機,Inventory 也可以用中括號來設定範圍值,便於設定與後續的管理。
在比較複雜的環境下,為了佈署上的方便,我們也可以在 Inventory 中將機器做群組。
這樣可針對不同群組套用不同的佈署策略。
此外, Inventory 也支援一些可以設定的參數,可參閱下表。
Parameter Description ansible_connection Connection type to the host. This can be the name of any of ansible’s connection plugins. SSH protocol types are smart, ssh or paramiko. The default is smart. Non-SSH based types are described in the next section. ansible_host The name of the host to connect to, if different from the alias you wish to give to it.
read morePosts
Ansible - Ansible CLI
Ansible 安裝完且 SSH 環境準備好後就可以開始使用 Ansible CLI 去使用 Ansible。
Ansible CLI 的使用方式如下:
Usage: ansible <host-pattern> [options] Options: -a MODULE_ARGS, --args=MODULE_ARGS module arguments -k, --ask-pass ask for SSH password -K, --ask-sudo-pass ask for sudo password -B SECONDS, --background=SECONDS run asynchronously, failing after X seconds (default=N/A) -C, --check don't make any changes; instead, try to predict some of the changes that may occur -c CONNECTION, --connection=CONNECTION connection type to use (default=smart) -f FORKS, --forks=FORKS specify number of parallel processes to use (default=5) -h, --help show this help message and exit -i INVENTORY, --inventory-file=INVENTORY specify inventory host file (default=/etc/ansible/hosts) -l SUBSET, --limit=SUBSET further limit selected hosts to an additional pattern --list-hosts outputs a list of matching hosts; does not execute anything else -m MODULE_NAME, --module-name=MODULE_NAME module name to execute (default=command) -M MODULE_PATH, --module-path=MODULE_PATH specify path(s) to module library (default=/usr/share/ansible) -o, --one-line condense output -P POLL_INTERVAL, --poll=POLL_INTERVAL set the poll interval if using -B (default=15) --private-key=PRIVATE_KEY_FILE use this file to authenticate the connection -s, --sudo run operations with sudo (nopasswd) -U SUDO_USER, --sudo-user=SUDO_USER desired sudo user (default=root) -T TIMEOUT, --timeout=TIMEOUT override the SSH timeout in seconds (default=10) -t TREE, --tree=TREE log output to this directory -u REMOTE_USER, --user=REMOTE_USER connect as this user (default=vagrant) -v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging) --version show program's version number and exit 比較常用的參數有 -i、-m、-a、-s,-i 用來指定 inventory file 或是管理機的位置,-m 用來指定要使用的模組,-a 用來指定模組所需要的參數,-s 用來指定需要用 sudo 運行。
read morePosts
Ansible - Install Ansible via apt
要在 Ubuntu 下使用 apt 安裝 Ansible。
可先用 apt-get 安裝 software-properties-common。
sudo apt-get install software-properties-common 然後進行 apt-get 的更新,避免後面的 apt-add-repository 命令找不到。
sudo apt-get update 接著用 apt-add-repository 新增套件庫。
sudo apt-add-repository ppa:ansible/ansible 套件庫新增時可能會出現 Cannot add PPA: ‘ppa:ansible/ansible’. Please check the PPA name or format is correct. 錯誤。
可以運行下列命令。
sudo apt-get install --reinstall ca-certificates 再次調用 apt-add-repository 新增套件庫。
套件庫加完後再次運行 apt-get 更新。
sudo apt-get update 就可以用 apt-get 安裝 ansible 了。
sudo apt-get install ansible 安裝完後最後輸入 ansible 確認安裝無誤。
read moreTag: PL/SQL
Posts
>-
條款四十四,總是使用 WHILE loop 去處理 loose array。
像是下面這樣的程式用 FOR loop 去遍巡處理 loose array,這不是被建議使用的寫法,雖然大部分的狀況下可以正常運行,但是當 loose array 的內容被刪除時,這樣的處理會因為 null 元素而運行錯誤。
DECLARE ... l_index PLS_INTEGER; BEGIN ... IF t_employees IS NOT NULL THEN <<process_employees>> FOR i IN 1..t_employees.COUNT() LOOP ... END LOOP process_employees; END IF; END; 建議使用 WHILE loop 遍巡處理 loose array,才不會因為 Null 元素導致錯誤。
DECLARE ... l_index PLS_INTEGER; BEGIN l_index := t_employees.FIRST(); <<process_employees>> WHILE l_index IS NOT NULL LOOP ... l_index := t_employees.NEXT(l_index); END LOOP process_employees; END;
read morePosts
>-
條款四十三,遍巡 dense array 時,建議使用 1 當做 lower boundary,使用 COUNT() 當做 upper boundary。
像是下面這樣的程式,使用了 FIRST() 與 LAST() 做為遍巡走訪的條件,dense array 不為空時可以正常運作,但當 dense array 為空時則會發生錯誤。
DECLARE t_employees t_employee_type := t_employee_type(); BEGIN <<process_employees>> FOR i IN t_employees.FIRST()..t_employees.LAST() LOOP … END LOOP process_employees; END; 簡單的解決方式可以加判斷 dense array 是否為空。
DECLARE t_employees t_employee_type := t_employee_type(); BEGIN <<process_employees>> IF t_employees IS NOT EMPTY THEN FOR i IN t_employees.FIRST()..t_employees.LAST() LOOP … END LOOP process_employees; END IF; END; 但建議的方式是改以 1 與 COUNT() 做為遍巡走訪的條件。
read morePosts
>-
條款四十二,總是使用 NUMERIC FOR loop 去處理 dense array。
像是下面這樣的程式:
... BEGIN <<process_employees>> LOOP EXIT process_employees WHEN i > t_employees.COUNT(); … i := i + 1; END LOOP process_employees; END; 可以像下面這樣改寫,程式碼的維護性會比較好。
... BEGIN <<process_employees>> FOR i IN 1..t_employees.COUNT() LOOP … END LOOP process_employees; END;
read morePosts
PL/SQL SQL CODING GUIDELINE 39 - Never use GOTO statements in your code
條款三十九,從不使用 GOTO 語句。
像是下面這樣的程式。
... BEGIN ... <<check_digit>> FOR i IN co_lower_bound .. l_len_array LOOP <<check_pw_char>> FOR j IN co_lower_bound .. l_len_pw LOOP IF SUBSTR(in_password, j, 1) = SUBSTR(co_digitarray, i, 1) THEN l_isdigit := TRUE; GOTO check_other_things; END IF; END LOOP check_pw_char; END LOOP check_digit; <<check_other_things>> NULL; IF NOT l_isdigit THEN raise_application_error(co_errno, co_errmsg); END IF; END password_check; ... 可考慮使用 exit 搭配 label 從迴圈內跳離。
... BEGIN ... <<check_digit>> FOR i IN co_lower_bound .
read morePosts
>-
條款四十一,總是使用 CURSOR for loop,除非使用 Bulk operations。
像是下面這樣的程式:
... BEGIN <<read_employees>> LOOP FETCH c_employees INTO r_employee; EXIT read_employees WHEN c_employees%NOTFOUND; … END LOOP read_employees; CLOSE c_employees; END; 可以像下面這樣改寫,程式碼的維護性會比較好。
... BEGIN <<read_employees>> FOR r_employee IN c_employee LOOP … END LOOP read_employees; END;
read morePosts
PL/SQL SQL CODING GUIDELINE 40 - Always label your loops
條款四十,如果程式中有 loop,嘗試使用 label 讓他的區塊範圍更為清楚。
像是下面這樣的程式:
BEGIN FOR r_employee IN (SELECT * FROM emp) LOOP … END LOOP; END; 可以像下面這樣改寫,在 loop 的前面加上 Label,然後在 End 後加上 Label Name。
BEGIN <<process_employees>> FOR r_employee IN (SELECT * FROM emp) LOOP … END LOOP process_employees; END; 這樣程式碼的區塊範圍清楚許多。
read morePosts
>-
條款三十八,如果 NVL 第二或第三個參數是 function 呼叫或是 select 語句,使用 CASE 取代 NVL2。
這是因為 NVL2 會先把每個可能的結果都先取出,儘管是根本不會出的結果,所以這樣會有不必要的 overhead。
SELECT NVL2(dummy, function_call(), function_call()) FROM dual; 建議的做法是用 CASE 取代 NVL2,以避開這樣的問題。
SELECT CASE WHEN dummy IS NULL THEN function_call() ELSE function_call() END FROM dual;
read morePosts
PL/SQL SQL CODING GUIDELINE 36 - Try to use CASE rather than DECODE
條款三十六,嘗試使用 CASE 而不要用 DECODE。
用 DECODE 的可讀性較低,不易閱讀。
BEGIN SELECT DECODE(dummy, 'A', 1 , 'B', 2 , 'C', 3 , 'D', 4 , 'E', 5 , 'F', 6 , 7) INTO l_result FROM dual; ... 改用 CASE 撰寫雖然程式變多,但閱讀起來相對會比較清楚。
BEGIN l_result := CASE dummy WHEN 'A' THEN 1 WHEN 'B' THEN 2 WHEN 'C' THEN 3 WHEN 'D' THEN 4 WHEN 'E' THEN 5 WHEN 'F' THEN 6 ELSE 7 END; ...
read morePosts
>-
條款三十四,避免在 SQL 語句運行與 implicit cursor 中間使用 procedure 或是 function。
像是下面的例子,這邊先刪除了一些資料,後續要用 SQL%ROWCOUNT 去判斷刪除的筆數,但中間卻調用了其它 function,以致於 SQL%ROWCOUNT 的值不如我們的預期。
CREATE PROCEDURE remove_emp_and_process (in_id IN emp.empno%TYPE) AS BEGIN DELETE FROM emp WHERE empno = in_id RETURNING deptno INTO l_deptno; process_department (...); IF SQL%ROWCOUNT > 1 THEN -- Too many rows deleted! Rollback and recover... ROLLBACK; END IF; END remove_emp_and_process; 所以我們必須避免在 SQL 語句運行與 implicit cursor 中間使用 procedure 或是 function。
read morePosts
PL/SQL SQL CODING GUIDELINE 33 - Always close locally opened cursors
條款三十三,總是關閉開啟的游標。
像是下面這樣將游標開啟後並未揪游標關閉,使用的資源不會自動釋放。
CREATE PROCEDURE not_close_cursor (out_count OUT INTEGER) AS CURSOR c1 IS SELECT COUNT (*) FROM all_users; BEGIN out_count := 0; OPEN c1; FETCH c1 INTO out_count; END not_close_cursor; ... 應該要自己將游標在適當的時機點關閉,使用的資源才會被釋放。
CREATE PROCEDURE close_cursor (out_count OUT INTEGER) AS CURSOR c1 IS SELECT COUNT (*) FROM all_users; BEGIN out_count := 0; OPEN c1; FETCH c1 INTO out_count; CLOSE c1 END close_cursor;
read morePosts
>-
條款三十二,當使用 BULK 與 LIMIT 操作時,避免直接在後面用 %NOTFOUND 判斷是否有資料處理,應改用 COUNT() 判斷。
像是下面這樣的撰寫方式,迴圈內每次會處理 5 筆資料,假設今天總資料量為 14,那第三次處理時因為剩餘的筆數 4 小於 LIMIT 設定的筆數 5,%NOTFOUND 會為 true 跳離,剩餘的資料就都沒有跑到。
-- This example will only show 10 of 14 employees DECLARE TYPE t_employee_type IS TABLE OF emp%ROWTYPE; t_employees t_employee_type; CURSOR c_emp IS SELECT * FROM emp ORDER BY empno; BEGIN OPEN c_emp; <<process_emp>> LOOP FETCH c_emp BULK COLLECT INTO t_employees LIMIT 5; EXIT process_emp WHEN c_emp%NOTFOUND; <<display_emp>> FOR i IN 1.
read morePosts
>-
條款三十一,Always use %NOTFOUND instead of NOT %FOUND to check whether a cursor was successful。
不要用 Not %FOUND 去撰寫判斷邏輯。
LOOP FETCH c_employees INTO r_employee; EXIT WHEN NOT c_employees%FOUND; ... END LOOP; 取而代之的是要用 %NOTFOUND 去撰寫判斷邏輯。
LOOP FETCH c_employees INTO r_employee; EXIT WHEN c_employees%NOTFOUND; ... END LOOP; 這樣可讀性會比較好。
read morePosts
>-
條款二十九,Try to use anchored records as targets for your cursors。
像是下面這邊的程式就宣告了幾個變數,開啟 Cursor 後遍巡,將資料塞到變數後再進一步處理。
DECLARE CURSOR c_user IS SELECT user_id, firstname, lastname FROM user; l_user_id user.user_id%TYPE; l_firstname user.firstname%TYPE; l_lastname user.lastname%TYPE; BEGIN OPEN c_user; FETCH c_user INTO l_user_id, l_firstname, l_lastname; WHILE c_user%FOUND LOOP FETCH c_user INTO l_user_id, l_firstname, l_lastname; END LOOP; CLOSE c_user; END; 如果改用 cursor-anchored records 去實作,就可以省去一些不必要的變數宣告。
DECLARE CURSOR c_user IS SELECT user_id, firstname, lastname FROM user; r_user c_user%ROWTYPE; BEGIN OPEN c_user; FETCH c_user INTO r_user; <<process_user>> WHILE c_user%FOUND LOOP FETCH c_user INTO r_user; END LOOP process_user; CLOSE c_user; END;
read morePosts
>-
條款二十六,運行插入命令時總是指定塞入的欄位。
像是下面這樣不指定要塞入欄位的寫法,塞入的動作會對資料表欄位的順序有所依賴,當欄位順序一有變動就會產生不如預期的結果,而且問題發生時不是很容易可以被偵測出來。
INSERT INTO messages VALUES (l_mess_no ,l_mess_typ ,l_mess_text ); 如果在塞入時明確的指定塞入的欄位,就能避開這樣的問題。
INSERT INTO messages (mess_no ,mess_typ ,mess_text ) VALUES (l_mess_no ,l_mess_typ ,l_mess_text );
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 25 - Avoid using the LONG and LONG RAW data types
條款二十五,避免使用 LONG 與 LONG RAW 型態。
LONG 與 LONG RAW 型態已經過時,留著只是為了向前相容,不建議拿來使用,應考慮用 NCLOB、BLOB、BFILE 去替。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 24 -Try to use boolean data type for values with dual meaning
條款二十四,當值只有兩種狀態時,試著使用 Boolean 型態。
像是如果要表達的是是否為較大的數值,如果沒有特別的理由,那就不該使用數值表示,因為數值代表的意義沒有 Boolean 型態來的明確。
DECLARE v_IsBigger number(1) := 1; BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_IsBigger = 1 THEN 'True' ELSE 'False' END); END; 若用 Boolean 型態表達會比較清楚。
DECLARE v_IsBigger BOOLEAN := true; BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_IsBigger THEN 'True' ELSE 'False' END); END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 23 - Always define your VARCHAR2 variables using CHAR SEMANTIC
條款二十三,使用 Varchar2 時總是定義 Char Semantic。
預設未定義時有可能指定的是 Byte,也有可能是 Char,端看 NLS_LENGTH_SEMANTICS 參數的設定,預設是 Byte。
DECLARE v_str varchar(200); BEGIN ... END; 但通常我們指定字串應該看的是字元數,建議是將其指定用 Char。
DECLARE v_str varchar(200 char); BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 22 - Never use zero-length strings to substitute NULL
條款二十二,不要用空字串去代替 Null 值。
在 Oracle 這邊不論是對的 Varchar 或是 Varchar2 型態賦予空字串,Oracle 都會將其視為 Null,所以這邊不建議將其設為空字串。
DECLARE v_str varchar2(4000) := ''; BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_str is null THEN 'null' ELSE 'not null' END); END; 而是應該像下面,沒特別塞值時預設就是 Null。
DECLARE v_str varchar2(4000); BEGIN DBMS_OUTPUT.PUT_LINE(CASE WHEN v_str is null THEN 'null' ELSE 'not null' END); END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 21 - Avoid using VARCHAR data type
條款二十一,避免使用 Varchar 型態。
Varchar 型態在工業標準上是可以儲存空字串的,但在 Oracle 這邊並未遵循這樣的標準,當將空字串存放至 Varchar 型態,Oracle 這邊會將空字串變為 null 值,就跟 Varchar2 型態是一樣的,但難保哪天會改回遵循工業標準。
DECLARE v_str varchar(4000); BEGIN … END; 因此在 Oracle 這邊建議不要使用 Varchar 型態,建議使用 Varchar2 型態。
DECLARE v_str varchar2(4000); BEGIN … END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 20 - Avoid using CHAR data type
條款二十,避免使用 Char。
Oracle 的 Char 型態在宣告時需指定大小,宣告多大就佔多大。像是下面這邊筆者宣告了 4000 的 char,則該變數即佔了 4000,儘管這邊只賦予了短短的幾個字元進去。
DECLARE v_str char(4000) := 'test'; BEGIN DBMS_OUTPUT.PUT_LINE(Length(v_str)); END; 取而代之的是應該改用 varchar2 型態。
DECLARE v_str varchar2(4000) := 'test'; BEGIN DBMS_OUTPUT.PUT_LINE(Length(v_str)); END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 19 - Try to use PLS_INTEGER instead of NUMBER for arithmetic operations with integer values (no decimal point)
條款十九,用 PLS_INTEGER 去表示整數。
如果要宣告整數,不要用 Number 型態去宣告。
DECLARE v_number number(38, 0); BEGIN ... END; 建議使用 PLS_INTEGER,因為使用 PLS_INTEGER 型態使用的記憶體會比較少,且效能上會快上三倍。
DECLARE v_number PLS_INTEGER; BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 18 - Avoid declaring NUMBER variables or subtypes with no precision
條款十八,避免在宣告 Number 型態的變數或是 SubType 時未設定整數位數。
像是下面這樣,變數宣告時未指定整數位數,預設精確度為 38 位。
DECLARE v_number number; BEGIN ... END; 如果使用上已經知道明確位數,那建議在宣告時還是明確的指定。
DECLARE v_number number(9, 2); BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 15 - Never use quoted identifiers
條款十五是說在變數宣告時,變數的名稱不要加上雙引號。
像是下面這樣,宣告的變數加上雙引號是合法的。
DECLARE "v_str" VARCHAR2(30) ; BEGIN … END main; 但不建議這樣宣告,建議還是不要加上雙引號。
DECLARE v_str VARCHAR2(30) ; BEGIN … END main;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 14 - Never overload data structure usages
條款十四是說不要去覆寫變數。
像是下面這樣外層與內層宣告了一樣名稱的變數,是不建議的寫法。
<<main>> DECLARE v_str VARCHAR2(30); BEGIN <<sub>> DECLARE v_str VARCHAR2(4000) ; BEGIN … END sub; END main; 建議使用上還是應該要將變數名稱錯開。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 13 - Avoid initializing variables using functions in the declaration section
條款十三是說要避免在變數宣告的同時呼叫 function 去初始變數。
DECLARE l_company_name VARCHAR2(30) := util_pck.get_company_name(in_id => 47); BEGIN … END; 因為在變數宣告的地方呼叫 function 去初始變數,function 發生例外時是無法攔截處理的。
因此要像下面這樣將宣告與初始拆開處理。
DECLARE v_str VARCHAR2(30); BEGIN <<init>> BEGIN v_str := util_pck.get_company_name(inId => 47); EXCEPTION WHEN VALUE_ERROR THEN ... END init; END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 12 - Avoid comparisons with null value
條款十二是在說當判斷變數是否為 null 時,不要像下面這樣使用 = 去判斷。
DECLARE v_str VARCHAR2(30); BEGIN if v_str = null then … end if; END; 因為 null 不等於任何東西,即使是 null 也不等於 null。
{% img /images/posts/PLSQLCopRule12/1.png %}
正確的方式應該是用 is 或 is not 去做判斷。
DECLARE v_str VARCHAR2(30); BEGIN if v_str is null then … end if; END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 11 - Never initialize variables with NULL
條款十一是說不要將變數初始為 NULL。
DECLARE v_str VARCHAR2(30) := null; BEGIN ... END; 因為預設就是初始為 Null。
DECLARE v_str VARCHAR2(30); BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 10 - Try to use subtypes for constructs used often in your application
條款十是在說如果有些常用的型態使用,建議將它設成 SubType,像是下面這邊 VARCHAR2(4000) 程式中如果常用的話,就可以將它設成 SubType。
DECLARE v_str VARCHAR2(4000); BEGIN … END; 這邊將它設成名為 STRING_MAX 的 SubType,後續可直接拿來宣告使用。
CREATE OR REPLACE PACKAGE PKG_SUBTYPE AS SUBTYPE STRING_MAX IS VARCHAR2(4000); END PKG_SUBTYPE; DECLARE v_str PKG_SUBTYPE.STRING_MAX; BEGIN ... END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 9 - Try to have a single location to define your types
條款九主要是在描述型態的定義要集中一處放置,以 Oracle 來說型態的定義可以放置在 DB 的 Types 下。
{% img /images/posts/PLSQLCopRule9/1.png %}
也可以建造個 Package 集中放置,這邊建議是挑選一個地方放置即可,避免有些型態的宣告放置在 Types 下,而有的在 Package 下。
選用上要注意 Oracle 內的型態有的只能在 Database 下使用,無法在 Package 下使用,像是 Object 型態。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 8 - Try to use anchored declarations for variables
條款八,使用 anchored declarations。
像是下面這樣的程式:
DECLARE v_empName VARCHAR2(10); BEGIN … END; 預期要帶入的是 emp table 的 ename,這在 emp table 的 schema 中是其實是已經定義好的。如果像上面這樣另行宣告可能會不小心設錯,或是 schema 修改時會很麻煩。
若是使用 anchored declarations,型態會直接參照 schema 的定義,免去像這樣的困擾。
DECLARE v_empName emp.ename%TYPE; BEGIN … END;
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 5 - Avoid using literals in your code
條款五,避免在程式中直接使用字串。
像是下面這樣的程式:
SET SERVEROUTPUT ON Begin DBMS_OUTPUT.put_line('Root Account:' || 'Admin'); End; 可以像下面這樣改寫,建立一個 Package 統一存放常數字串,呼叫端改透過 Package 叫用。
SET SERVEROUTPUT ON CREATE OR REPLACE PACKAGE CONST IS ROOT_ACCOUNT CONSTANT varchar(50) := 'Admin'; END CONST; / Begin DBMS_OUTPUT.put_line('Root Account:' || CONST.ROOT_ACCOUNT); End; 這樣常數字串的宣告會集中在 Package 內,修改上也比較方便。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 2 - Always have a matching loop or block label
條款二,如果程式中有迴圈區塊,為其加上 label 讓他的區塊範圍更為清楚。
像是下面這樣的程式:
SET SERVEROUTPUT ON DECLARE i PLS_INTEGER; Begin FOR i IN 1..10 LOOP DBMS_OUTPUT.put_line('i =' || i); End LOOP; End; 可以像下面這樣改寫,在 For…Loop 前面加上 Label,然後在 End 後加上 Label Name。
SET SERVEROUTPUT ON DECLARE i PLS_INTEGER; Begin <<Print1To10>> FOR i IN 1..10 LOOP DBMS_OUTPUT.put_line('i =' || i); End LOOP Print1To10; End; 改完程式碼的區塊範圍清楚了許多。
read morePosts
PL/SQL amp; SQL CODING GUIDELINE 1 - Try to label your sub blocks
條款一,如果程式中有子 block,嘗試使用 label 讓他的區塊範圍更為清楚。
像是下面這樣的程式:
SET SERVEROUTPUT ON Begin DBMS_OUTPUT.put_line('Start'); Begin DBMS_OUTPUT.put_line('Processing...'); End; DBMS_OUTPUT.put_line('End'); End; 可以像下面這樣改寫,在子 Block 的 Begin 前面加上 Label,然後在 End 後加上 Label Name。
SET SERVEROUTPUT ON Begin DBMS_OUTPUT.put_line('Start'); <<Processing>> Begin DBMS_OUTPUT.put_line('Processing...'); End Processing; DBMS_OUTPUT.put_line('End'); End; 改完程式碼的區塊範圍清楚了許多。
read morePosts
PL/SQL - EXTRACT Function
EXTRACT function 可擷取日期或時間中指定部分的資料。
使用語法如下:
EXTRACT ( { YEAR | MONTH | DAY | HOUR | MINUTE | SECOND } | { TIMEZONE_HOUR | TIMEZONE_MINUTE } | { TIMEZONE_REGION | TIMEZONE_ABBR } FROM { date_value | interval_value } ) 我們可以帶入日期並指定擷取 年、月、日,或是帶入時間並指定擷取 時、分、秒。
像是要擷取現在是西元幾年,可以像下面這樣叫用:
EXTRACT(year from sysdate) 要擷取現在是幾點,可以像下面這樣叫用:
EXTRACT(hour from systimestamp) 使用上會像下面這樣:
{% img /images/posts/ExtractFunction/1.png %}
Link Oracle/PLSQL: EXTRACT Function
read morePosts
PL/SQL - MONTHS_BETWEEN Function
MONTHS_BETWEEN function 可計算兩個日期相差多少月份。
使用語法如下:
MONTHS_BETWEEN( date1, date2 ) 帶入的兩個日期,若第一個日期大過第二個日期,則回傳正值的月份差。反之則回傳負值月份差。
像是下面這樣叫用就會傳回 2:
MONTHS_BETWEEN(ADD_MONTHS(sysdate, 2), sysdate) 像下面這樣叫用就會傳回 -2:
MONTHS_BETWEEN(sysdate, ADD_MONTHS(sysdate, 2)) 使用上會像下面這樣:
{% img /images/posts/MonthsBetweenFunction/1.png %}
Link Oracle/PLSQL: MONTHS_BETWEEN Function
read morePosts
PL/SQL - LAST_DAY function
LAST_DAY function 會依帶入的日期回傳對應月份的最後一天。
使用語法如下:
LAST_DAY( date ) 其中 date 為要處理的日期,帶入即會回傳對應月份的最後一天。
像是要取得當月的最後一天,可以像下面這樣叫用:
last_day(sysdate) 使用上會像下面這樣:
{% img /images/posts/LastDayFunction/1.png %} Link Oracle/PLSQL: LAST_DAY Function
read morePosts
PL/SQL - NEXT_DAY function
NEXT_DAY function returns the first weekday that is greater than a date。
使用語法如下:
NEXT_DAY( date, weekday ) 其中 date 為基準日,weekday 指定要回傳的日期為星期幾。
weekday 可為 SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY。
像是要找尋下一個星期日,可這樣叫用:
next_day(sysdate, 'SUNDAY') 使用上會像下面這樣:
{% img /images/posts/NextDayFunction/1.png %}
Link Oracle/PLSQL: NEXT_DAY Function
read morePosts
PL/SQL - ADD_MONTHS function
ADD_MONTHS function 可將帶入的日期月份做加減處理後回傳。
使用語法如下:
ADD_MONTHS( date1, number_months ) 其中 data1 為要做處理的日期,number_months 為要加減的月份。
number_months 帶入的值為正值,表示是要加上指定的月份,反之表示要減上指定的月份。
像是要將當前的日期加三個月,可這樣叫用:
add_months(sysdate, 3) 要將當前日期減三個月,可這樣叫用:
add_months(sysdate, -3) 使用上會像下面這樣:
{% img /images/posts/AddMonthsFunction/1.png %}
Link Oracle/PLSQL: ADD_MONTHS Function
read morePosts
PL/SQL - MOD function
MOD function 可傳回兩數相除後的餘數。
使用語法如下:
MOD( m, n ) 其中 m 為被除數,n 為除數。
所以如果要取 5/2 的餘數,可以像這樣寫。
Mod(5, 2) 使用上會像下面這樣:
{% img /images/posts/ModFunction/1.png %}
Link Oracle/PLSQL: MOD Function
read morePosts
PL/SQL - FLOOR function
FLOOR function 可傳回小於或等於指定數值的最大整數值。
使用語法如下:
FLOOR( number ) 使用上會像下面這樣:
{% img /images/posts/FloorFunction/1.png %}
Link Oracle/PLSQL: FLOOR Function
read morePosts
PL/SQL - CEIL function
CEIL function 可傳回大於或等於指定數值的最小整數值。
使用語法如下:
CEIL( number ) 使用上會像下面這樣:
{% img /images/posts/CeilFunction/1.png %}
Link Oracle/PLSQL: CEIL Function
read morePosts
PL/SQL - Round function
Round function 可將帶入的值依指定的位數下去做四捨五入運算並回傳。
使用語法如下:
ROUND( number [, decimal_places] ) number 是要做四捨五入的值,decimal_places 是要做四捨五入的位數。
這邊的 decimal_places 可以是正值,也可以是負值。如果是正值表示的是小數點後的位數,如果是負值則表示小數點前的位數。
寫起來就像下面這樣:
{% img /images/posts/RoundFunction/1.png %}
{% img /images/posts/RoundFunction/2.png %}
{% img /images/posts/RoundFunction/3.png %}
{% img /images/posts/RoundFunction/4.png %}
{% img /images/posts/RoundFunction/5.png %}
Link Oracle/PLSQL: ROUND Function (with numbers)
read morePosts
PL/SQL - ABS function
ABS function 會將帶入的值取絕對值傳出。
使用語法如下:
ABS( number ) number 為要轉換的數值,如果帶入的是負值,會將其變為正值傳出,就像下面這樣:
{% img /images/posts/ABSFunction/1.png %}
{% img /images/posts/ABSFunction/2.png %}
Link Oracle/PLSQL: ABS Function
read morePosts
PL/SQL - NUMTODSINTERVAL function
NUMTODSINTERVAL function 會將帶入的值轉成特定單位的 Interval。
使用語法如下:
NUMTODSINTERVAL( number, expression ) number 這邊帶入的是要轉換的值,expression 這邊帶入的是要轉換的單位,可以是 Day、 Hour、 Minute、 Second。
使用上可搭配日期使用,對日期做些增減處理。像是下面這樣:
{% img /images/posts/NUMTODSINTERVALFunction/1.png %}
{% img /images/posts/NUMTODSINTERVALFunction/2.png %}
{% img /images/posts/NUMTODSINTERVALFunction/3.png %}
{% img /images/posts/NUMTODSINTERVALFunction/4.png %}
{% img /images/posts/NUMTODSINTERVALFunction/5.png %}
{% img /images/posts/NUMTODSINTERVALFunction/6.png %}
Link Oracle/PLSQL: NUMTODSINTERVAL Function
read morePosts
PL/SQL - Sysdate function
Sysdate function 會回傳資料庫系統當前的日期與時間。
使用語法如下:
Sysdate 直接叫用即可,不需帶入任何的參數。
像是這樣:
{% img /images/posts/SysdateFunction/1.png %}
Link Oracle/PLSQL: SYSDATE function
read morePosts
PL/SQL - Decode function
Decode function 可用於取代簡單的 If-Then-Else 陳述式。
使用語法如下:
DECODE( expression , search , result [, search , result]... [, default] ) 簡單來說如果 expression 的值等同 search 值的話,則回傳對應的 result 值。
像是要將數值帶入,依其值決定要回傳 ’true’ 或是 ‘false’,可以像下面這樣撰寫:
{% img /images/posts/DecodeFunction/1.png %}
{% img /images/posts/DecodeFunction/2.png %}
Link Oracle/PLSQL: DECODE Function
read moreTag: Postman
Posts
Newman - A command-line collection runner for Postman
Newman 是一用來運行 Postman collection 的命令列工具,當要在不開啟 Postman 的狀態下運行 Postman collection 時會需要使用。
安裝只要透過 npm 將 Newman 做全域安裝即可。
npm install newman -g 使用上只要透過 newman run 帶入匯出的 collection JSON 檔案運行 Postman collection即可。
newman run <CollectionFile> 如果要運行多次可使用 -n 參數指定所要運行的次數。
newman run <CollectionFile> -n <Times> 如果 Postman collection 有使用到環境變數的話,使用 -e 參數指定匯出的環境變數 JSON 檔。
newman run <CollectionFile> -e <EnvironmentVariableFile> 如果要設定 Report,可使用 -r 參數指定要產出的 Report 格式,可使用的 Report 格式有 html、cli、json、junit。
newman run <CollectionFile> -r html,cli,json,junit Link postmanlabs/newman: Newman is a command-line collection runner for Postman Newman - Running collections in the command line
read moreTag: R
Posts
R 語言翻轉教室 - 全中文 R 語言互動式教材
R 語言翻轉教室是一全中文互動式教材,教材的內容主要是來自 An Introduction to R。
可開啟 RGui 或是 RStudio,在 Console 視窗輸入命令開始進行安裝。
source("http://wush978.github.io/R/init-swirl.R") 決定 CRAN 鏡象位置。
設定是否使用繁體中文,以及是否讓安裝程式幫你調整語系。
安裝好後輸入 swirl() 即可進入教材。
教材使用時需要做登入,選個希望使用的登入的方式並授權即可。
安裝且登入後,會先帶一下教材必奧的操作知識,像是看到 ‘…’ 代表要按 ‘Enter’ 按鈕繼續:看到 “Selection:” 就是要輸入選擇後按 ‘Enter’ 按鈕繼續。
或是一些 swirl 提供的命令…等。
這部份帶完後才會開始進入課程,課程都放在 ‘DataScienceAndR’ 下,所以這邊要選 1 繼續。
再挑選要上的課程即可。
不過因為 RGui 在編輯器的編碼切換上會有些問題,建議還是使用 RStudio 來運行教材。
學習告一段落,將 RGui 或是 RStudio 關閉。下次要進入教材的話,只要將 swirl 套件載入,輸入 swirl() 即可再次進入教材。
教材在使用上程式碼的部分可能會有中文顯示的問題,這時點選 RStudio 的 [File | Reopen with Encoding…] 主選單選項。
設定編碼為 UTF-8。
中文顯示就會正常了。
Link R語言翻轉教室
read moreTag: AgileSlot
Posts
Filebeat - Configuring Filebeat
Filebeat 的設定檔為 filebeat.yml,可以設定資料的輸入與輸出,以及其它細項設定。
像是設定資料的輸入,可以指定要輸入的 Log 檔位置。
filebeat.prospectors: - input_type: log paths: - E:\AgileSlot\Log\*\*Full*log* 可以設定 Log 資料要怎樣切割傳送,像是若使用 Log4Net 去記錄 Log,不特別調整格式的話 Log 前面一定會有 Log 的時間,就可以以 Log 時間當作切割傳送的依據。
filebeat.prospectors: - input_type: log # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [ multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' # Defines if the pattern set under pattern should be negated or not. Default is false. multiline.negate: true # Match can be set to "after" or "before".
read moreTag: DEV
Posts
Filebeat - Configuring Filebeat
Filebeat 的設定檔為 filebeat.yml,可以設定資料的輸入與輸出,以及其它細項設定。
像是設定資料的輸入,可以指定要輸入的 Log 檔位置。
filebeat.prospectors: - input_type: log paths: - E:\AgileSlot\Log\*\*Full*log* 可以設定 Log 資料要怎樣切割傳送,像是若使用 Log4Net 去記錄 Log,不特別調整格式的話 Log 前面一定會有 Log 的時間,就可以以 Log 時間當作切割傳送的依據。
filebeat.prospectors: - input_type: log # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [ multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' # Defines if the pattern set under pattern should be negated or not. Default is false. multiline.negate: true # Match can be set to "after" or "before".
read moreTag: Filebeat CAS
Posts
Filebeat - Configuring Filebeat
Filebeat 的設定檔為 filebeat.yml,可以設定資料的輸入與輸出,以及其它細項設定。
像是設定資料的輸入,可以指定要輸入的 Log 檔位置。
filebeat.prospectors: - input_type: log paths: - E:\AgileSlot\Log\*\*Full*log* 可以設定 Log 資料要怎樣切割傳送,像是若使用 Log4Net 去記錄 Log,不特別調整格式的話 Log 前面一定會有 Log 的時間,就可以以 Log 時間當作切割傳送的依據。
filebeat.prospectors: - input_type: log # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [ multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' # Defines if the pattern set under pattern should be negated or not. Default is false. multiline.negate: true # Match can be set to "after" or "before".
read moreTag: Filebeat
Posts
Filebeat - Install Filebeat on Windows
要在 Windows 下使用 Filebeat,可先至官網下載下來解壓縮。
裡面比較會要用到的檔案有 filebeat.exe、install-service-filebeat.psl、uninstall-service-filebeat.psl 與 filebeat.yml。
filebeat.yml 是 Filebeat 的設定檔,設定完後直接點擊 filebeat.exe 就會開始作用。
也可以執行 install-service-filebeat.psl 註冊成 Windows 服務,讓 Filebeat 在背景服務。
Windows 服務註冊完後記得將服務啟動才有效果。
做到這邊 Filebeat 就能依照設定正常的傳送 Log。
若有需要後續也可執行 uninstall-service-filebeat.psl 將 Filebeat 的 Windows 服務移除。
Link Filebeat: Lightweight Log Analysis & Elasticsearch | Elastic
read moreTag: RStudio
Posts
RStudio - Installation
要安裝 RStudio 可在官網的下載頁面下載安裝程式。
點選安裝程式安裝。
安裝完就可以開始使用 RStudio。
Link RStudio – Open source and enterprise-ready professional software for R
read moreTag: Angular
Posts
Angular CLI - A command line interface for Angular
使用 Angular CLI 前,需先確認 Node.js 版本有到 6.9.0 以上,npm 有到 3 以上。
安裝用 npm 將 Angular CLI 安裝到全域。
npm install -g @angular/cli 安裝完可調用 ng 並帶入參數 -v 去查驗版本。
ng -v 用 help 命令去查閱使用語法。
ng help 用 new 命令帶入專案名稱去建立指定名稱的 Angular 專案。
ng new <ProjectName> 專案建立後會幫我們準備好基本的程式。
進入專案目錄,用 serve 命令啟動服務器。
開啟瀏覽器輸入服務器網址即可看到專案運行起來的樣子。
Link CLI tool for Angular
read moreTag: Zapier
Posts
Zapier - Share new RSS items to your LinkedIn profile
要使用 Zapier 去觀察 RSS 的變化自動在 LinkedIn 貼文,可先找到對應的 Zap。
設置要連接 RSS。
按下 ‘Fetch & Continue’ 按鈕測試 RSS 的擷取。
測試完成按下 ‘Continue’ 按鈕繼續。
RSS 設完接著要設定 LinkedIn。
按下 ‘Connect a New Account’ 連結 LinkedIn 帳號。
授予 Zapier 使用 LinkedIn 的權限。
回到 Zapier 後按下 ‘Test’ 按鈕測試連結。
連結測試無誤後,按下 ‘Save + Continue’ 按鈕。
再來要設定 LinkedIn 貼文的資訊,像是貼文的訊息格式,預設會使用 RSS 擷取到的 Title 與 Link 當作貼文的內容,若想要用更多資訊去設定貼文,可以按下後方的按鈕加入欲使用的資訊。
如果要設定貼文以外的資訊,可點選 ‘Show advanced options’。
設定好後按下 ‘Continue’ 按鈕。
接著會詢問是否要做個測試,可點選 ‘Create & Continue’ 按鈕測試由 Zapier 擷取 RSS 並在 LinkedIn 貼文。
read morePosts
Zapier - Share new RSS feed items to Facebook
要使用 Zapier 去觀察 RSS 的變化自動在 Facebook 貼文,可先找到對應的 Zap。
按下 ‘Create this Zap’ 建立 Zap。
接著要連接 RSS。
帶入 RSS 的位置後按下 ‘Continue’ 按鈕繼續。
按下 ‘Fetch & Continue’ 按鈕測試 RSS 的擷取。
測試完成按下 ‘Continue’ 按鈕繼續。
RSS 設完接著要設定 Facebook。
按下 ‘Connect a New Account’ 連結 Facebook 帳號。
授予 Zapier 使用 Facebook 的權限。
回到 Zapier 後按下 ‘Test’ 按鈕測試連結。
連結測試無誤後,按下 ‘Save + Continue’ 按鈕。
再來要設定 Facebook 貼文的資訊,像是貼文的訊息格式,預設會使用 RSS 擷取到的 Title 與 Link 當作貼文的內容,若想要用更多資訊去設定貼文,可以按下後方的按鈕。
Zapier 會列出可以使用的資訊,點選即可加入貼文格式的設定。
如果要設定貼文以外的資訊,可點選 ‘Show advanced options’。
read moreTag: RGui
Posts
RGui - Load package
要在 RGui 載入安裝的 R 語言套件,可點選 [Packages|Load package…] 主選單選項。
選取所要載入的套件。
即會載入指定的套件。
除了透過主選單選項外,也可以在 Console 使用 ‘library()’ 帶入要載入的套件名稱,輸入完一樣會載入指定的套件。
read morePosts
RGui - Install package
要安裝 R 語言的套件,可透過點選 RGui 的 [Packages|Install package(s)…] 主選單選項。
選取鏡象位置。
選取所要安裝的套件。
指定的套件就會開始進行下載並安裝。
除了透過主選單選項外,也可以在 Console 使用 ‘install.packages’ 帶入要安裝的套件名稱,輸入完一樣選取鏡象位置。
一樣會進行指定套件的下載並安裝。
read morePosts
RGui - Install R for Windows
要安裝 R for Windows,首先要至官網下載頁面。
選取下載點。
選取下載的作業系統版本。
下載安裝程式。
點擊下載下來的安裝程式進行安裝。
安裝完即可開始使用。
Link R: The R Project for Statistical Computing
read moreTag: ZeroBrane Studio
Posts
ZeroBrane Studio - CloneView Plugin
要在 ZeroBrane Studio 使用 CloneView 功能,首先要先將 CloneView Plugin 下載至 ZeroBrane Studio 的 packages 目錄下。
接著啟動 ZeroBrane Studio,在程式頁籤上按下滑鼠右鍵,可看到多了 ‘Clone Horizontally’ 與 ‘Clone Vertically’ 兩個選單選項。
點選 ‘Clone Horizontally’ 選單選項。
ZeroBrane Studio 會將當前程式視窗複製一份水平並排。
點選 ‘Clone Vertically’ 選單選項。
ZeroBrane Studio 則會將當前程式視窗複製一份垂直並排。
該套件在程式撰寫需要比對程式時特別好用。
Link ZeroBranePackage/cloneview.lua at master · pkulchenko/ZeroBranePackage
read morePosts
ZeroBrane Studio - DocumentMap Plugin
要在 ZeroBrane Studio 使用 DocumentMap 功能,首先要先將 DocumentMap Plugin 下載至 ZeroBrane Studio 的 packages 目錄下。
接著啟動 ZeroBrane Studio,可點選 [View|Document Map Window] 主選單選項開啟 DocumentMap 視窗。
透過 DocumentMap 視窗,我們可以看到整份文件的縮圖預覽,並透過滑鼠點選或拖曳移動輸入的焦點至指定的文件位置。
Link ZeroBranePackage/documentmap.lua at master · pkulchenko/ZeroBranePackage
read morePosts
ZeroBrane Studio - TODO Plugin
要在 ZeroBrane Studio 使用 TODO 功能,可將 TODO Plugin 下載下來放置在 ZeroBrane Studio 的 packages 目錄下。
啟動 ZeroBrane Studio,可以看到多出了個 TODO 視窗。
接著在程式中加入 TODO 註解,這些註解就會顯示在 TODO 視窗內。
Link ZeroBranePackage/TODO.lua at master · pkulchenko/ZeroBranePackage
read morePosts
ZeroBrane Studio - HighlightSelected Plugin
ZeroBrane Studio 預設在選取變數時並不像某些強大的編輯器一樣會將所有變數出現的地方標記,但透過安裝 HighlightSelected Plugin ZeroBrane Studio 也可以提供這樣的功能。
將 HighlightSelected Plugin 下載下來放置在 ZeroBrane Studio 的 packages 目錄下。
啟動 ZeroBrane Studio,選取變數,即會看到所有變數出現的地方會被標記。
Link ZeroBranePackage/highlightselected.lua at master · pkulchenko/ZeroBranePackage
read morePosts
ZeroBrane Studio - ZeroBrane Studio Plugin for Redis Lua Scripts
要讓 ZeroBrane Studio 支援 Redis,先要取得 redis.lua。
將其內容存檔。
儲存到 ZeroBrane Studio 的 packages 目錄下。
啟動 ZeroBrane Studio,選取 [Project|Lua Interpreter|Redis] 主選單選項,將 Lua Interpreter 切為 Redis。
切完後 ZeroBrane Studio 就可以支援 Redis 的 Lua Script,像是除錯、Intellisense…等。
載入 Redis Lua Script,按下 F5 即可開始運行,第一次運行會詢問 Redis 的位置,將 Redis 位置填入設定後即可。
設定的 Redis 位置會被存放在 ‘%appdata%\ZeroBraneStudio.ini’ 下,需要時可開啟修改。
如果 Redis Lua Script 需要帶參數運行,可以選取 [Project|Command Line Parameters…] 主選單選項。
帶上 Redis 運行 Lua Script 所需要的 KEYS 與 ARGV,KEYS 與 ARGV 用 “,” 隔開,且分隔符號前後要有空格。
設定完後運行,指定的參數即會被帶入運行。
read morePosts
ZeroBrane Studio - Changing color theme in ZeroBrane Studio
ZeroBrane Studio 內建已有不同的 color theme 可供切換使用,有需要可開啟 cfg/tomorrow.lua 查閱可供使用的 color theme。
可使用的 color theme 有 Tomorrow、TomorrowContrast、TomorrowNight、TomorrowNightEighties、TomorrowNightBlue、TomorrowNightBright、Zenburn、Monokai、Molokai、SolarizedDark、SolarizedLight、NotedPlusPlus、SciTeLuaIDE。
要套用到 ZeroBrane Studio 可點選 [Edit|Preferences|Settings:User] 主選單選項。
加上 color theme 的設定,loadfile 這邊要帶入 cfg/tomorrow.lua 檔,並指定要套用的 color theme。
styles = loadfile('cfg/tomorrow.lua')('TomorrowNightEighties') stylesoutshell = styles -- apply the same scheme to Output/Console windows styles.auxwindow = styles.text -- apply text colors to auxiliary windows styles.calltip = styles.text -- apply text colors to tooltips 重啟 ZeroBrane Studio 指定的 color theme 套用即會生效。
read morePosts
ZeroBrane Studio - Installation
要進行 ZeroBrane Studio 的安裝,可到 ZeroBrane Studio 的下載頁面下載 ZeroBrane Studio 的主程式。
除了有不同的作業系統版本外,如果是 Windows 的程式,還有安裝包與壓縮包可供選擇,可適需求下載使用。
這邊筆者以壓縮包為例,將壓縮包下載下來,解壓縮運行 ZeroBrane Studio 主程式。
即可開始使用 ZeroBrane Studio。
Link ZeroBrane Studio - Lightweight IDE for your Lua needs
read moreTag: BenchmarkDotNet
Posts
BenchmarkDotNet - Baseline
BenchmarkDotNet 如果要指定量測比較的標準,可在 BenchmarkAttribute 設定 Baseline 為 true,指定的量測方法即會被視為量測的標準,後續的量測則會跟該量測標準做比較。
像是下面這段程式:
using System.Threading; using BenchmarkDotNet.Attributes; ... public class ProgramBenchmarker { protected Program m_Program { get; set; } = new Program(); [Benchmark(Baseline = true)] public void Test1() { m_Program.Test(); Thread.Sleep(10); } [Benchmark] public void Test2() { m_Program.Test(); Thread.Sleep(20); } } 運行起來會看到設為基準的量測方法其 Scaled 值為 1,而另外一個量測方法其時間耗費大約為基準量測方法的兩倍,所以其 Scaled 值為 2。
read morePosts
BenchmarkDotNet - Params
使用 BenchmarkDotNet 時若需要設定欄位或是屬性的值,可以使用 ParamsAttribute 指定,像是下面這樣:
using BenchmarkDotNet.Attributes; ... public class ProgramBenchmarker { [Params(100, 200)] public int Parameter { get; set; } protected Program m_Program { get; set; } = new Program(); [Benchmark] public void Test() { m_Program.Test(); } } 運行時即會依序將指定的值帶入欄位或屬性下去量測。
read morePosts
BenchmarkDotNet - Exporters
Exporter 會將 benchmark 的結果輸出成不同的格式。
內建可使用的 Exporter 有:
HtmlExporter CsvExporter MarkdownExporter AsciiDocExporter CsvMeasurementsExporter PlainExporter JsonExporter 使用上只要透過 Attribue 掛上 benchmark 類別即可:
using BenchmarkDotNet.Attributes.Exporters; … [AsciiDocExporter] [CsvMeasurementsExporter] [PlainExporter] [JsonExporter] public class ProgramBenchmarker { … } 或是透過 config 的方式設定也可以。
using BenchmarkDotNet.Configs; using BenchmarkDotNet.Exporters; using BenchmarkDotNet.Exporters.Csv; using BenchmarkDotNet.Exporters.Json; … [Config(typeof(Config))] public class ProgramBenchmarker { private class Config : ManualConfig { public Config() { Add(AsciiDocExporter.Default); Add(CsvMeasurementsExporter.Default); Add(PlainExporter.Default); Add(JsonExporter.Default); } } … } HtmlExporter 的輸出會像這樣:
MarkdownExporter 的輸出會像這樣:
read morePosts
BenchmarkDotNet - Diagnosers
Diagnoser 可以附加到 benchmark 上,並獲取一些有用的資訊。像是內建的 MemoryDiagnoser 就可以幫我們獲取記憶體資訊。
使用上只要透過 Attribute 的方式加到要 benchmark 的類別即可。像是下面這樣:
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; ... [MemoryDiagnoser] public class ProgramBenchmarker { ... } 或是透過 config 的方式設定也可以。
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; ... [Config(typeof(Config))] public class ProgramBenchmarker { private class Config : ManualConfig { public Config() { Add(MemoryDiagnoser.Default); } } ... } 運行起來會看到多了 Allocated 欄位,顯示配置的記憶體量。
read morePosts
BenchmarkDotNet - Columns
BenchmarkDotNet 允許透過設定去變更 Summary Table 的 Column。
內建可使用的 Column 有:
NamespaceColumn MedianColumn MinColumn MaxColumn RankColumn 使用上只要透過 Attribue 掛上 benchmark 類別即可:
using BenchmarkDotNet.Attributes.Columns; … [NamespaceColumn] [MedianColumn] [MinColumn] [MaxColumn] [RankColumn] [RankColumn(NumeralSystem.Roman)] [OrderProvider(SummaryOrderPolicy.FastestToSlowest)] public class ProgramBenchmarker { … } 運行起來就會在 Summary Table 看到設定的欄位。
如果要加的欄位是未內建的,可透過 Config 與 TagColumn。像是這邊筆者想要加個 HashCode Column,其值為方法的 Hash 值,就可以像下面這樣撰寫:
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; … [Config(typeof(Config))] public class ProgramBenchmarker { private class Config : ManualConfig { public Config() { Add(new TagColumn("HashCode", item => item.
read morePosts
BenchmarkDotNet - Jobs
BenchmarkDotNet 的 Job 是用來描述 benchmark 是怎樣運行的。
內建的 Job 有:
DryJob ClrJob CoreJob MonoJob LegacyJitX86Job LegacyJitX64 RyuJitX64Job SimpleJob LongRunJob MediumRunJob ShortRunJob VeryLongRunJob Job 在使用上只要透過 Attribute 的方式加到要 benchmark 的類別即可。像是這邊想要跑短一點的 benchmark 就可以為 benchmark 類別加掛 ShortRunJobAttribute:
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes.Jobs; ... [ShortRunJob] public class ProgramBenchmarker { ... } 運行結果如下:
read morePosts
BenchmarkDotNet - Getting started
要使用 BenchmarkDotNet 去做 .NET 程式的 benchmark,可先透過 NuGet 安裝 BenchmarkDotNet 套件。
套件安裝好後進行 benchmark 程式的撰寫,撰寫方式只要寫個 benchmark 的方法,方法內去叫用要測的方法,最後在方法上面加上 BenchmarkAttribute 即可。
using BenchmarkDotNet.Attributes; … public class ProgramBenchmarker { protected Program m_Program { get; set; } = new Program(); [Benchmark] public void Test() { m_Program.Test(); } } … benchmark 程式寫好後撰寫 benchmark 運行的部份,只要透過 BenchmarkRunner.Run 帶入 benchmark 類別就可以了。
using BenchmarkDotNet.Running; … public class Program { static void Main(string[] args) { var summary = BenchmarkRunner.Run<ProgramBenchmarker>(); } public void Test() {… } } … } 完整的測試程式如下:
read moreTag: CSharp 7.0
Posts
'C# 7.0 - Out variables'
C# 7.0 以前使用的方法若有 Out 參數,需要事先宣告才能帶入使用。
... string data; GetData(out data); ... static void GetData(out string data) { ... } C# 7.0 以後,可以在帶入 Out 參數時直接順帶宣告。
... GetData(out string data); ... 也可以結合使用區域型別推斷。
... GetData(out var data); ... 完整的範例程式如下:
using System; namespace ConsoleApp2 { class Program { static void Main(string[] args) { GetData(out string data); //GetData(out var data); Console.WriteLine($"{data}"); } static void GetData(out string data) { data = "Level Up (http://larrynung.github.io/)"; } } } 運行結果如下:
read morePosts
'C# 7.0 - Throw expressions'
C# 7.0 開始支援 Throw expressions。
三元運算中可以視需要直接丟出 exception。
... this.FirstName = firstName == null ? throw new ArgumentNullException(nameof(firstName)) : firstName; ... ?? 運算式中也可以直接丟出 exception。
... this.LastName = lastName ?? throw new ArgumentNullException(nameof(lastName)); ... Expression bodied member 也可以丟出 exception。
... public override string ToString() => throw new NotImplementedException(); ... 最後附上完整的測試範例:
class Program { static void Main(string[] args) { var person = new Person("Larry", "Nung"); Console.WriteLine(person.ToString()); } } struct Person { public string FirstName { get; set; } public string LastName { get; set; } public Person(string firstName, string lastName) { this.
read morePosts
'C# 7.0 - More expression bodied members'
C# 7.0 擴展了 Expression bodied。
開始支援建構子。
... class Program { ... public Program() => Console.WriteLine("Program()"); ... } ... 支援解構子。
... class Program { ... ~Program() => Console.WriteLine("~Program()"); ... } ... 支援 property accessors。
... private string _myProperty; public string MyProperty { get => _myProperty; set => _myProperty = value; } ... 支援 event accessors。
... public event EventHandler MyEvent { add => _myEvent += value; remove => _myEvent -= value; } .
read morePosts
'C# 7.0 - Deconstruction'
C# 7.0 新增 Deconstruction,可將 Tuple、結構、類別的成員拆解使用。
以 Tuple 為例,若想要將 Tuple 值拆解使用,可以用小括弧宣告出多個區域變數,並將 Value Tuple 指派過去,Value Tuple 的屬性值就會依序塞入這些區域變數。
(var v1, var v2) = GetTuple(); var (v1, v2) = GetTuple(); 若是結構或是類別,則要建一個 public 的 Deconstruct 方法,方法的參數用 out 將拆解出來的值依序傳出,編譯時編譯器就會自行幫我們調用 Deconstruct 方法將值拆解。
(var v1, var v2) = new MyClass(); ... class MyClass() { ... public void Deconstruct(out string v1, out string v2) { v1 = this.V1; v2 = this.V2; } } 若有需要 Deconstruct 也支援多載。
(var v1, var v2) = new MyClass(); .
read morePosts
'C# 7.0 - Tuple'
C# 7.0 新增了 Value Type 的 Tuple,因為是 Value Type,所以對 GC 的負擔會比較少。另外增加了一些語法糖,改進了本來 Tuple 類別可讀性不佳的問題。
使用上需先加入 System.ValueTuple 套件。
若不加入該套件編譯時會看到 System.ValueTuple is not defined or imported 的錯誤。
套件加入引用後我們可以看一下該套件的內容,可以看到有一堆泛型的 ValueTuple struct,裡面的成員屬性跟以往的 Tuple 一樣都是 Item1 ~ ItemN。
使用上可以直接建立 ValueTuple,然後在建立的同時指定其型態與值,在要取值的地方用 Item1 ~ ItemN 屬性來取值。
也可以用小括弧包住屬性值直接宣告。
但這樣的宣告方式跟舊的 Tuple 類別一樣有著可讀性不佳的問題,因此在用小括弧包住屬性值宣告的同時,我們將屬性名稱也一併指定,取值時就可以用指定的屬性名稱來取值。
編譯器在編譯時會自動幫你將程式轉換成 Item1 ~ ItemN。
若想要將 Tuple 值拆解使用,可以用小括弧宣告出多個區域變數,並將 Value Tuple 指派過去,Value Tuple 的屬性值就會依序塞入這些區域變數。
這些功能即使套用在方法的回傳值上也一樣適用。
Link Tackling Tuples: Understanding the New C# 7 Value Type - Our ComponentOne C# 7.0 – Tuples – CsharpStar Tuple deconstruction in C# 7 | Thomas Levesque’s .
read morePosts
C# 7.0 - Digit separators
以前在開發 C# 時,如果數值過大,在閱讀上會十分不易。
C# 7.0 以後提供了 Digit separators 功能,允許開發人員使用 _ 將數值做些分隔,有效解決了上述問題。最普遍的用法就是將數值做千分位分隔,像是下面這樣:
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var values = new int[] { 1_000, 1_000_000, 0b1_000 }; foreach (var value in values) { Console.WriteLine(value.ToString()); } } } } {% img /images/posts/CSharp7DigitSeparators/1.png %}
Link C# 7 features preview · Anton Sizikov Exploring Visual Studio “15” Preview and Playing with C# 7 Test driving C# 7 features in Visual Studio “15” Preview » Thomas Levesque’s .
read morePosts
C# 7.0 - Binary literals
在程式開發時,有時我們會需要使用二進制的數值,像是在使用標有 FlagsAttribute 的列舉值做權限時就會用到。在 C 7.0# 前我們必需要使用十進制數值表示法,確保他是二進制的數值。
在 C# 7.0 後開始支援二進制數值表示法,使用上只需用 0b 當做前綴即可,像是 0 可以寫成 0b00、1 可以寫成 0b01、2 可以寫成 0b10、4 可以寫成 0b100,以此類推。
using System; namespace ConsoleApplication1 class Program { static void Main(string[] args) { var values = new int[] { 0b00, 0b01, 0b10, 0b100, 0b1000 }; foreach (var value in values) { Console.WriteLine(value.ToString()); } } } } {% img /images/posts/CSharp7Binaryliterals/1.png %}
Link A glance at C# vNext - CodeProject
read morePosts
C# 7.0 - Local functions
有時候我們在開發程式時,會碰到一些情境是需要建立個方法,但這個方法只有某個地方會用到,這時我們多半是用委派去做掉,但帶來的問題就是會有額外的記憶體耗費,而且無法被 inline 處理。
C# 7.0 後,我們可以改用 Local functions 功能去處理。使用方式很簡單,就是一般的方法宣告,只是是寫在方法裡面。像是:
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { void SayHello(string name) { Console.WriteLine(string.Format("Hello~{0}", name)); } SayHello("Larry"); } } } 這邊也可以搭配使用 C# 6.0 的 Expression Bodied Members,程式碼會更為精簡。
using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { void SayHello(string name) => Console.WriteLine(string.Format("Hello~{0}", name)); SayHello("Larry"); } } } 運行結果如下:
{% img /images/posts/CSharp7LocalFunctions/1.png %}
反組譯看一下:
{% img /images/posts/CSharp7LocalFunctions/2.
read moreTag: Web Deploy
Posts
Web Deploy - Delete local site content
如要使用 Web Deploy 刪除本地站台內容,可以指定 Web Deploy 使用 delete 操作,dest 使用 contentPath provider,並帶入要刪除的 content 即可。
msdeploy -verb:delete -dest:contentPath=<ContentPath>
read morePosts
Web Deploy - Delete remote app pool
如要使用 Web Deploy 刪除遠端 application pool,可以指定 Web Deploy 使用 delete 操作,dest 使用 appPoolConfig provider,並帶入要刪除的 application pool 名稱,及用 computerName provider setting 指定遠端電腦的位置。
msdeploy –verb:delete –dest: appPoolConfig ="<DestAppPool>",computerName=<DestServer>
read morePosts
Web Deploy - Delete local app pool
如要使用 Web Deploy 刪除本地 application pool,可以指定 Web Deploy 使用 delete 操作,dest 使用 appPoolConfig provider,並帶入要刪除的 application pool 名稱即可。
msdeploy –verb:delete –dest: appPoolConfig ="<DestAppPool>"
read morePosts
Web Deploy - Delete remote site
如要使用 Web Deploy 刪除遠端站台,可以指定 Web Deploy 使用 delete 操作,dest 使用 appHostConfig provider,並帶入要刪除的站台名稱,及用 computerName provider setting 指定遠端電腦的位置。
msdeploy –verb:delete –dest:apphostconfig="<DestSite>",computerName=<DestServer>
read morePosts
Web Deploy - Delete local site
如要使用 Web Deploy 刪除本地站台,可以指定 Web Deploy 使用 delete 操作,dest 使用 appHostConfig provider,並帶入要刪除的站台名稱即可。
msdeploy –verb:delete –dest:apphostconfig="<DestSite>"
read morePosts
Web Deploy - Sync local package to remote site and exclude specified file
如要使用 Web Deploy 將 Web Deploy Package 佈署到遠端站台並忽略同步指定的檔案,可以指定 Web Deploy 使用 sync 操作,source 使用 package provider,帶入 Web Deploy Package 的檔案位置,dest 這邊使用 appHostConfig,指定要佈署的本地站台,用 skip operation setting 指定 objectname 為 filePath,absolutepath 帶入要忽略同步的檔案位置。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -source:package=<Package> -dest:appHostConfig="<DestSite>",computerName=<DestServer> -skip:objectname='filePath',absolutepath='<FilePath>'
read morePosts
Web Deploy - Stop site and sync local package to remote site
如要使用 Web Deploy 將 Web Deploy Package 佈署到遠端站台,且要在佈署前停止 IIS,在佈署後啟動 IIS (Sop site => Sync local package to remote site => Start site )。可以指定 Web Deploy 使用 sync 操作,presync 指定佈署前要運行的命令 (以這邊來說就是 appcmd.exe stop apppool ),postsync 指定佈署後要運行的命令 (以這邊來說就是 appcmd.exe start apppool ),source 使用 package provider,帶入 Web Deploy Package 的檔案位置,dest 這邊使用 appHostConfig,指定要佈署的本地站台,及用 computerName provider setting 指定遠端電腦的位置即可。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -presync:runCommand="%windir%\system32\inetsrvppcmd.exe stop apppool <DestSite>",successReturnCodes=0,waitinterval=15000,computerName=<DestServer> -source:package=<Package> -dest:appHostConfig="<DestSite>",computerName=<DestServer> -postsync:runCommand="%windir%\system32\inetsrvppcmd.
read morePosts
Web Deploy - Restart remote IIS
如要使用 Web Deploy 重啟遠端 IIS,可以指定 Web Deploy 使用 sync 操作,source 使用 runcommand,dest 使用 runcommand,並帶入要運行的遠端命令(以這邊來說就是用 iisreset /restart 去重啟 IIS 的命令),及用 computerName provider setting 指定遠端電腦的位置。
msdeploy -verb:sync -source:runcommand -dest:runCommand="iisreset /restart",waitinterval=15000,computerName=<DestServer>
read morePosts
Web Deploy - Start remote IIS
如要使用 Web Deploy 啟動遠端 IIS,可以指定 Web Deploy 使用 sync 操作,source 使用 runcommand,dest 使用 runcommand,並帶入要運行的遠端命令(以這邊來說就是用 iisreset /start 去啟動 IIS 的命令),及用 computerName provider setting 指定遠端電腦的位置。
msdeploy -verb:sync -source:runcommand -dest:runCommand="iisreset /start",computerName=<DestServer>
read morePosts
Web Deploy - Stop remote IIS
如要使用 Web Deploy 停止遠端 IIS,可以指定 Web Deploy 使用 sync 操作,source 使用 runcommand,dest 使用 runcommand,並帶入要運行的遠端命令(以這邊來說就是用 iisreset /stop 去停止 IIS 的命令),及用 computerName provider setting 指定遠端電腦的位置。
msdeploy -verb:sync -source:runcommand -dest:runCommand="iisreset /stop",computerName=<DestServer>
read morePosts
Web Deploy - Start remote application
如要使用 Web Deploy 去啟動遠端 Application,可以指定 Web Deploy 使用 sync 操作,source 使用 recycleApp,dest 使用 recycleApp,並帶入要回收的 Application,且指定 recycleMode 為 StartAppPool。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",recycleMode="StartAppPool", computerName=<DestServer> 如果要透過 Web Management Service 去做遠端電腦連線的話,則 dest 這邊要使用 wmsvc provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",recycleMode="StartAppPool",wmsvc=<DestServer>,userName=<UserName>,password=<Password> -allowUntrusted
read morePosts
Web Deploy - Start local application
如要使用 Web Deploy 啟動本地 Application,可以指定 Web Deploy 使用 sync 操作,source 使用 recycleApp,dest 使用 recycleApp,並帶入要啟動的 Application,且指定 recycleMode 為 StartAppPool。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",recycleMode="StartAppPool"
read morePosts
Web Deploy - Stop remote application
如要使用 Web Deploy 停止遠端 Application,可以指定 Web Deploy 使用 sync 操作,source 使用 recycleApp,dest 使用 recycleApp,並帶入要回收的 Application,指定 recylceMode 為 StopAppPool。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",recycleMode="StopAppPool" , computerName=<DestServer> 如果要透過 Web Management Service 去做遠端電腦連線的話,則 dest 這邊要使用 wmsvc provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",recycleMode="StopAppPool",wmsvc=<DestServer>,userName=<UserName>,password=<Password> -allowUntrusted
read morePosts
Web Deploy - Stop local application
如要使用 Web Deploy 停止本地 Application,可以指定 Web Deploy 使用 sync 操作,source 使用 recycleApp,dest 使用 recycleApp,並帶入要回收的 Application,且指定 recycleMode 為 StopAppPool。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",recycleMode="StopAppPool"
read morePosts
Web Deploy - Recycle remote application
如要使用 Web Deploy 回收遠端 Application,可以指定 Web Deploy 使用 sync 操作,source 使用 recyleApp,dest 使用 recycleApp,並帶入要回收的 Application。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",computerName=<DestServer> 如果要透過 Web Management Service 去做遠端電腦連線的話,則 dest 這邊要使用 wmsvc provider setting 去指定遠端電腦的位置。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>",wmsvc=<DestServer>,userName=<UserName>,password=<Password> -allowUntrusted
read morePosts
Web Deploy - Recycle local application
如要使用 Web Deploy 回收本地 Application,可以指定 Web Deploy 使用 sync 操作,source 使用 recyleApp,dest 使用 recycleApp,並帶入要回收的 Application。
msdeploy -verb:sync -source:recycleApp -dest:recycleApp="<DestApp>"
read morePosts
Web Deploy - Restore remote site to last backup
如要使用 Web Deploy 還原遠端站台至最後的備份,可以指定 Web Deploy 使用 sync 操作,source 使用 backupManager,dest 使用 backupManager,指定要還原的站台,並用 useLatest = true 指定使用最後一次備份,及用 computerName provider setting 指定遠端電腦的位置。
msdeploy.exe -verb:sync -source:backupManager -dest:backupManager=<siteName>,useLatest=true, computerName=<DestServer>
read morePosts
Web Deploy - Restore local site to last backup
如要使用 Web Deploy 還原本地站台至最後的備份,可以指定 Web Deploy 使用 sync 操作,source 使用 backupManager,dest 使用 backupManager,指定要還原的站台,並用 useLatest = true 指定使用最後一次備份。
msdeploy.exe -verb:sync -source:backupManager -dest:backupManager=<siteName>,useLatest=true
read morePosts
Web Deploy - Restore remote site to specified backup
如要使用 Web Deploy 還原遠端站台至指定備份,可以指定 Web Deploy 使用 sync 操作,source 使用 backupManager,dest 使用 backupManager,並指定要還原的站台以及要用來還原的備份檔,及用 computerName provider setting 指定遠端電腦的位置。
msdeploy.exe -verb:sync -source:backupManager -dest:backupManager=<DestSite>/<BackupFile>, computerName=<DestServer>
read morePosts
Web Deploy - Restore local site to specified backup
如要使用 Web Deploy 還原本地站台至指定備份,可以指定 Web Deploy 使用 sync 操作,source 使用 backupManager,dest 使用 backupManager,並指定要還原的站台以及要用來還原的備份檔。
msdeploy.exe -verb:sync -source:backupManager -dest:backupManager=<DestSite>/<BackupFile>
read morePosts
Web Deploy - Backup remote site
如要使用 Web Deploy 備份本地站台,可以指定 Web Deploy 使用 sync 操作,source 使用 backupManager,dest 也使用 backupManager,並指定要備份的站台名稱。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy.exe -verb:sync -source:backupManager -dest:backupManager=<DestSite>,computerName=<DestServer> 如果要透過 Web Management Service 去做遠端電腦連線的話,則 dest 這邊要使用 wmsvc provider setting 去指定遠端電腦的位置。
msdeploy.exe -verb:sync -source:backupManager -dest:backupManager=<DestSite>,wmsvc=<DestServer>,userName=<UserName>,password=<Password> -allowUntrusted
read morePosts
Web Deploy - Backup local site
如要使用 Web Deploy 備份本地站台,可以指定 Web Deploy 使用 sync 操作,source 使用 backupManager,dest 也使用 backupManager,並指定要備份的站台名稱。
msdeploy.exe -verb:sync -source:backupManager -dest:backupManager=<DestSite>
read morePosts
Web Deploy - Sync remote site to local package
要用 Web Deploy 將遠端站台打包成 Web Deploy Package,可以指定 Web Deploy 使用 sync 操作,source 使用 appHostConfig provider,帶入要打包的站台名稱,及用 computerName provider setting 指定遠端電腦的位置,dest 使用 package provider,指定打包後的 Web Deploy Package 位置即可。
msdeploy -verb:sync -source:appHostConfig="<SourceSite>",computerName=<SourceServer> -dest: package=<Package>
read morePosts
Web Deploy - Sync local site to local package
要用 Web Deploy 將本地站台打包成 Web Deploy Package,可以指定 Web Deploy 使用 sync 操作,source 使用 appHostConfig provider,帶入要打包的站台名稱,dest 使用 package provider,指定打包後的 Web Deploy Package 位置即可。
msdeploy -verb:sync -source:appHostConfig="<SourceSite>" -dest: package=<Package>
read morePosts
Web Deploy - Sync local package to remote site
如要使用 Web Deploy 將 Web Deploy Package 佈署到遠端站台,可以指定 Web Deploy 使用 sync 操作,source 使用 package provider,帶入 Web Deploy Package 的檔案位置,dest 這邊使用 appHostConfig,指定要佈署的本地站台,及用 computerName provider setting 指定遠端電腦的位置即可。
msdeploy -verb:sync -source:package=<Package> -dest:appHostConfig="<SourceSite>",computerName=<SourceServer>
read morePosts
Web Deploy - Sync local package to local site
如要使用 Web Deploy 將 Web Deploy Package 佈署到本地站台,可以指定 Web Deploy 使用 sync 操作,source 使用 package provider,帶入 Web Deploy Package 的檔案位置,dest 這邊使用 appHostConfig,指定要佈署的本地站台即可。
msdeploy -verb:sync -source:package=<Package> -dest:appHostConfig="<DestSite>"
read morePosts
Web Deploy - Dump remote available backups
如要使用 Web Deploy 將遠端可以使用的備份資訊 dump 出來,可以指定 Web Deploy 使用 dump 操作,source 使用 backupManager,帶入要查詢的站台名稱。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy.exe -verb:dump -source:backupManager=<SourceSite>,computerName=<DestServer> 如果要透過 Web Management Service 去做遠端電腦連線的話,則 dest 這邊要使用 wmsvc provider setting 去指定遠端電腦的位置。
msdeploy.exe -verb:dump -source:backupManager=<SourceSite>,wmsvc=<DestServer>,userName=<UserName>,password=<Password> -allowUntrusted
read morePosts
Web Deploy - Dump local available backups
如要使用 Web Deploy 將本地可以使用的備份資訊 dump 出來,可以指定 Web Deploy 使用 dump 操作,source 使用 backupManager,帶入要查詢的站台名稱即可。
msdeploy.exe -verb:dump -source:backupManager=<SourceSite>
read morePosts
Web Deploy - Dump remote site
如要使用 Web Deploy 將遠端站台資訊 dump 出來,可以指定 Web Deploy 使用 dump 操作 ,因為站台的指定是用 appHostConfig provider,所以將 source 指定為 appHostConfig provider,並帶入站台的名稱。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy -verb:dump -source:appHostConfig="<SourceSite>",computerName=<SourceServer> 如果要透過 Web Management Service 去做遠端電腦連線的話,則 dest 這邊要使用 wmsvc provider setting 去指定遠端電腦的位置。
msdeploy -verb:dump -source:appHostConfig="<SourceSite>",wmsvc=<DestServer>,userName=<UserName>,password=<Password> -allowUntrusted
read morePosts
Web Deploy - Dump local site
如要使用 Web Deploy 將本地站台資訊 dump 出來,可以指定 Web Deploy 使用 dump 操作,因為站台的指定是用 appHostConfig provider,所以將 source 指定為 appHostConfig provider,並帶入站台的名稱即可。
msdeploy -verb:dump -source:appHostConfig="<SourceSite>"
read morePosts
Web Deploy - Dump remote server
如要使用 Web Deploy 將遠端 server 資訊 dump 出來,可以指定 Web Deploy 使用 dump 操作,將 source 指定為 WebServer provider。
透過 Remote Agent Service 去做遠端電腦連線的話,dest 這邊要使用 computerName provider setting 去指定遠端電腦的位置。
msdeploy -verb:dump -source:webServer,computerName=<DestServer> 如果要透過 Web Management Service 去做遠端電腦連線的話,則 dest 這邊要使用 wmsvc provider setting 去指定遠端電腦的位置。
msdeploy -verb:dump -source:webServer,wmsvc=<DestServer>,userName=<UserName>,password=<Password> -allowUntrusted
read morePosts
Web Deploy - Dump local server
如要使用 Web Deploy 將本地 server 資訊 dump 出來,可以指定 Web Deploy 使用 dump 操作,並將 source 指定為 WebServer provider 即可。
msdeploy -verb:dump -source:webServer
read morePosts
Web Deploy - Web Deploy Command Line
Web Deploy 支援命令列操作,在 Web Deploy 安裝完後,Web Deploy command line 程式會被放置於 %ProgramFiles%\IIS\Microsoft Web Deploy V3\ 下。
其 Syntax 如下:
msdeploy.exe -verb:<verbName> -source:<provider>[=<pathToProviderObject> [,<providerSetting>=<providerSettingValue>]] [-dest:<provider>[=<pathToProviderObject> [,<providerSetting>=<providerSettingValue>]] ] [-<MSDeployOperationSetting> ...] -verb 參數後面接的是 verb 的名稱,指定 Web Deploy 來源物件或是目的物件要處理的動作。可以是 dump、sync、delete、getDependencies、getSystemInfo。
-source 參數後面接的是 provider,指定來源端的資料物件。
-dest 參數後面接的是 provider,指定目的端的資料物件。
Provider 後面可以接 provider setting 針對 provider 做些設定,可以用的 provider setting 有:
authType computerName encryptPassword getCredentials ignoreErrors includeAcls password storeCredentials tempAgent userName wmsvc 比較常用的為 userName、password、computerName,當要指定遠端 provider 時會用需要設定。
命令列最後帶的參數為 operation setting,可針對整個操做作些設定,可以使用的設定有:
allowUntrusted appHostConfigDir declareParam declareParamFile disableLink disableRule disableSkipDirective enableLink enableRule enableSkipDirective postSync preSync removeParam replace retryAttempts retryInterval setParam setParamFile showSecure skip unicode useCheckSum verbose webServerDir whatif xml xpath 其中比較常用的大概就是 disableRule、enableRule、postSync、preSync、retryAttempts、retryInterval、setParam、setParamFile、useCheckSum、whatif 這幾個參數。
read morePosts
Web Deploy - Web Deploy Rules
Web Deploy 提供許多不同的 Rule,像是:
AboFilter AnonymousUser ApplicationExistsRule AppPoolIdentity AppRootNormalize BlockHarmfulDeleteOperations BlockUnsupportedDeleteOperations ClassicAppPoolProtectRule CreateApplicationRule CrossPlatformRule DependencyCheckAppPoolExists DependencyCheckFailOnError DependencyCheckFailOnWarning DependencyCheckInUse DoNotDeleteRule EnvironmentVariableNormalize IgnoreFileLastWriteTime IISConfigFrom64To32 MetakeyToIIS6 Parameterization SchemaSection SkipInvalidSource SkipNewerFilesRule SkipUNC SyncGeneral SyncXP UrlScanSkipIncompat WarnForEncryptedDataRule XpIsapis 這些 Rule 能讓我們更改 sync operation 的行為。
這些 Rule 中以 DoNotDeleteRule 較常使用,能用來決定 sync 時是否刪除多餘的檔案。
Link Web Deploy Rules
read morePosts
Web Deploy - Web Deploy Operations
Web Deploy 支援 dump、sync、delete、GetDependencies、GetSystemInfo 這幾種不同的操作。
dump 操作用於取得指定來源的資訊。
sync 操作用於將資料從來源端傳送至目的端。
delete 操作用於刪除指定目的端物件。
GetDependencies 操作用於回傳 Web Deploy 無法傳送的 Dependencies,這些 Dependencies 必須要自己手動處理。
GetSystemInfo 操作用於回傳系統資訊。
read morePosts
Web Deploy - Web Deploy Providers
Web Deploy Provider 主要是用來決定來源端或是目的端的資料要怎麼處理。
可以用的 Providers 有:
Web Deploy appHostConfig Provider Web Deploy appHostSchema Provider Web Deploy appPoolConfig Provider Web Deploy appPoolEnable32Bit Provider Web Deploy appPoolNetFx Provider Web Deploy appPoolPipeline Provider Web Deploy archiveDir Provider Web Deploy auto Provider Web Deploy cert Provider Web Deploy comObject32 Provider Web Deploy comObject64 Provider Web Deploy contentPath Provider Web Deploy createApp Provider Web Deploy dbFullSql Provider Web Deploy dbMySql Provider Web Deploy dbSqlite Provider Web Deploy dirPath Provider Web Deploy fcgiExtConfig Provider Web Deploy filePath Provider Web Deploy gacAssembly Provider Web Deploy gacInstall Provider Web Deploy iisApp Provider Web Deploy machineConfig32 Provider Web Deploy machineConfig64 Provider Web Deploy manifest Provider Web Deploy metaKey Provider Web Deploy package Provider Web Deploy recycleApp Provider Web Deploy regKey Provider Web Deploy regValue Provider Web Deploy rootWebConfig32 Provider Web Deploy rootWebConfig64 Provider Web Deploy runCommand Provider Web Deploy setAcl Provider Web Deploy urlScanConfig Provider Web Deploy webApp Provider Web Deploy webServer Provider Web Deploy webServer60 Provider 比較常用的有 appHostConfig、appPoolConfig、contentPath、createApp、dbFullSql、manifest、package、recycleApp、runCommand 這幾個 Provider。appHostConfig Provider 主要用來做站台的處理、appPoolConfig 做 Application Pool 的處理、contentPath 做站台內容的處理、createApp 做網站應用程式建立的處理、dbFullSql 做 MsSQL 的處理、manifest 做自定義內容的處理、package 做 package 的處理、recycleApp 做 Application Pool 回收的處理、runCommand 做命令執行的處理。
read morePosts
>-
Web Deploy 是一 client-server 架構的工具程式,能用來同步 IIS 內容與設定,簡化網頁應用程式或是網站的佈署。 具有以下幾個特點:
與 IIS Manager、Visual Studio 無縫整合,能建立 package 並佈署到本地或是遠端機器 整合 WebMatrix 與 Web Platform Installer 無縫整合 網頁應用程式打包 – 能夠打包網頁應用程式或是整個站台,包含關聯的資料庫 – 能夠打包 ACLs、COM、GAC 與註冊檔設定 – 支援 live 伺服器與壓縮後的 package 當成來源或是目的端 網頁應用程式佈署 – 支援非 Admin 權限的網頁應用程式佈署 – 支援參數化佈署,能在佈署時替換檔案中的字串 – 整合 IIS Web Management Service 做非 Admin 的佈署 網站伺服器同步 – 能夠同步整個網頁伺服器、網頁站台、或是網頁應用程式 – 只同步變動的資料 – 能夠在同步時偵測遺失的 dependencies – 同步時自動收集 IIS 設定、SSL certificates、與 ASP.NET 設定 變動前自動備份站台 – 管理員可以設定啟用自動備份 – 使用者可以直接還原站台 支援 CommandLine、PowerShell Cmdlets、與 API Web Deploy 在運作上如下圖所示:
read morePosts
Web Deploy - Install setup web deploy
Web Deploy 程式可至微軟網站下載。
下載完點擊安裝。
安裝類型建議選取 Custom,確認一下要安裝的元件。
這邊的元件有 IIS Manager UI 模組,安裝完會將 Web Deploy 部分功能整合在 IIS Manager。比較重要的需要確認 Management Service 與 Remote Agent Service 的安裝狀況,因為 Web Deploy 佈署時可能會走這兩條路 ,所以需要視需要將之勾選安裝。
如果剛有選取 Manager Service 或是 Remote Agent Service,安裝完就可以看到系統內會有新增對應的服務(Web Management Service 與 Web Deployment Agent Service),我們需要確保服務是正常啟用的。
除了確定服務啟動外,也可以開啟瀏覽器訪問 http://localhost/MSDEPLOYAGENTSERVICE 去驗證 Remote Agent Service 是否正常運作。
至於 Manager Service 這邊,可以開啟 IIS Manager 的 Management Service。
確定這邊的 Enable remote connections 是勾選的,以及 Port 號正確,若不修改就是走預設的 8172 Port。
如果要使用非 Admin 權限佈署,可以開啟 IIS Manager Permissions。
read morePosts
Web Deploy - Generate Web Deploy package with MsBuild
要使用 MsBuild 建置 Web Deploy package,可以在 MsBuild 建置時用 /t:package 告知要產生 Web Deploy package,並帶上 PackageLocation 參數指定產出的 Package 放置位置。
msbuild <ProjectFile|SolutionFile> /p:Configuration=<Configuration>; Platform="<Platform>"; PackageLocation="<PackageLocation>" /t:package 建置完成就可以在指定的位置看到產出的 Web Deploy package。
read morePosts
Web Deploy - Generate Web Deploy package with Visual Studio
要使用 Visual Studio 建立 Web Deploy package,首先在方案總管的專案上按下滑鼠右鍵,點選 Publish... 滑鼠右鍵選單選項。
在 Publish Web 視窗中選取 Cuetom Profile。
設定 Profile 的名稱。
接著 Publish method 選定 Web Deploy Package,設定 Package 放置的位置以及要佈署的站台名稱。
再來選定要建置的 Configuration。
進行發佈。
發佈完成就可以在指定的位置看到產出的 Web Deploy package。
read morePosts
Web Deploy - Publish with MsBuild
要使用 MsBuild 建置專案並佈署,可以在 MsBuild 建置時帶上 DeployOnBuild 參數告知 MsBuild 在建置完要做佈署,並帶上 PublishProfile 參數指定要使用的 Publish Profile。
msbuild <ProjectFile|SolutionFile> /p:Configuration=<Configuration>; Platform="<Platform>"; DeployOnBuild=true; PublishProfile=<PublishProfile> 若有需要可加帶 UserName 參數指定帳號,加帶 Password 參數指定密碼。
msbuild <ProjectFile|SolutionFile> /p:Configuration=<Configuration>; Platform="<Platform>"; DeployOnBuild=true; PublishProfile=<PublishProfile>; UserName=<UserName>; Password=<Password> 或是加帶其他參數,像是加帶 EnableMSDeployAppOffline 參數使用 AppOffline rule 做佈署,讓 Web deploy 在做發佈的同時幫你放上 App_Offline 頁面。
msbuild <ProjectFile|SolutionFile> /p:Configuration=<Configuration>; Platform="<Platform>"; DeployOnBuild=true; PublishProfile=<PublishProfile>; UserName=<UserName>; Password=<Password>; AllowUntrustedCertificate=True; EnableMSDeployAppOffline=true
read morePosts
Web Deploy - Publish with Visual Studio
要直接用 Visual Studio 使用 Web Deploy 去做佈署,首先在方案總管的專案上按下滑鼠右鍵,點選 Publish... 滑鼠右鍵選單選項。
在 Publish Web 視窗中選取 Cuetom Profile。
設定 Profile 的名稱。
接著 Publish method 選定 Web Deploy,設定要佈署的 Server 及帳號資訊。
再來選定要建置的 Configuration。
若想在發佈前查看一下會做哪些更動,可透過預覽的功能查看。
沒問題就可以進行發佈的動作。
read morePosts
Web Deploy - Synchronize IIS
若要做 IIS 之間的同步,我們可以使用 Web Deploy。
它可以做到 Local To Remote。
msdeploy -verb:sync -source:webServer -dest:webServer,computerName=Server2 Remote To Local。
msdeploy -verb:sync -source:webServer,computerName=Server2 -dest:webServer 以及 Remote To Remote。
msdeploy -verb:sync -source:webServer,computerName=Server2 -dest:webServer,computerName=Server3 簡單來說就只是用 msdeploy 帶入 sync verb,並指定 source 與 dest。source 與 dest若是針對整個 Server 同步則帶入 webServer,若是遠端電腦則要多帶入 computerName。
像是如果我要將本地的 IIS 整個同步到 192.168.0.2 的 IIS,就要像下面這樣:
msdeploy -verb:sync -source:webServer -dest:webServer,computerName=192.168.0.2 命令執行後 Web Deploy 即會將 WebSite、Application Pool、Binding、File、以及 Setting 等在指定的電腦間進行同步,十分的方便.
Link Synchronize IIS : The Official Microsoft IIS Site Web Deploy sync Operation
read morePosts
Web Deploy - Import Package
要將 Application 或 Server 的匯出檔匯入 IIS,我們可以透過 Web Deploy 的匯入功能來做。先確定 Server 有安裝 Web Deploy,安裝後在 IIS 的 Application 或是 Server 節點上按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中應該會多出 Deploy 的功能選項。這邊點選 [Deploy | Import Server Package…] 選單選項。
{% img /images/posts/ImportWebDeployPackage/1.png %}
點選後會彈出匯入對話框,選取要匯入的匯出檔。
{% img /images/posts/ImportWebDeployPackage/2.png %}
{% img /images/posts/ImportWebDeployPackage/3.png %}
{% img /images/posts/ImportWebDeployPackage/4.png %}
接著要選取要匯入的內容。確定後點選 Next 按鈕繼續。
{% img /images/posts/ImportWebDeployPackage/5.png %}
接著會彈出確認對話框,確認是否要進行匯入的動作,確定無誤則按下 OK 按鈕繼續。
{% img /images/posts/ImportWebDeployPackage/6.png %}
匯入完成會帶出 Summary 資訊,按下 Finish 按鈕即可。
{% img /images/posts/ImportWebDeployPackage/7.png %}
對話框關閉後我們可以看到網站已被正常的匯入。
{% img /images/posts/ImportWebDeployPackage/8.
read morePosts
Web Deploy - Export package
要將 IIS 網站 Application 或 Server 匯出,我們可以透過 Web Deploy 的匯出功能來做。先確定 Server 有安裝 Web Deploy,安裝後在 IIS 的 Application 或是 Server 節點上按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中應該會多出 Deploy 的功能選項。這邊點選 [Deploy | Export Server Package…] 選單選項。
{% img /images/posts/ExportWebDeployPackage/1.png %}
點選後會彈出匯出對話框,可選取要匯出的內容。確定後點選 Next 按鈕繼續。
{% img /images/posts/ExportWebDeployPackage/2.png %}
接著要設定參數的部份,設定完後一樣按下 Next 按鈕繼續。
{% img /images/posts/ExportWebDeployPackage/3.png %}
最後這邊要選取匯出的檔案位置。
{% img /images/posts/ExportWebDeployPackage/4.png %}
{% img /images/posts/ExportWebDeployPackage/5.png %}
選取完按下 Next 按鈕進行匯出。
{% img /images/posts/ExportWebDeployPackage/6.png %}
匯出完成會帶出 Summary 資訊。
{% img /images/posts/ExportWebDeployPackage/7.png %}
Link Export a Package through IIS Manager : The Official Microsoft IIS Site
read morePosts
Web Deploy - Automatic Backups
若想讓 Web Deploy 在 Deploy 時自動幫我們進行網站的備份,甚至是控管備份的數量,我們可以將 Web Deploy 的 Automatic Backups 功能啟用。
要啟用時我們需將 Server IIS 的 Configuration Editor 開啟,可以針對整台機器進行設定,或是針對 Site 進行設定,這邊視個人需求而定。
{% img /images/posts/WebDeployAutoBackup/1.png %}
Configuration Editor 開啟後,上方的 Section 記得切到 system.webServer/wdeploy/backup。接著將 enabled 與 turnedOn 設為 True,按下右側的 Apply 進行套用,即完成 Automatic Backups 功能開啟的動作。
{% img /images/posts/WebDeployAutoBackup/2.png %}
若有需要這邊我們也可以更改 backupPath 去設定備份的位置,或是更改 numberOfBackups 去設定備份保留的數量。
功能開啟後,只要透過 Web Deploy 進行佈署,Web Deploy 即會幫我們自動將 Application 備份。我們可以從 Web Deploy 的 Deploy 訊息看到該功能是否有成功的生效。
{% img /images/posts/WebDeployAutoBackup/3.png %}
若是在備份時失敗,Web Deploy 的 Deploy 訊息也會告知。
read moreTag: Sql-Cli
Posts
sql-cli - Cross platform command line interface for SQL Server
sql-cli 是一命令列的 SQL Server 工具。
透過 npm 安裝到全域即可使用。
npm install -g sql-cli 使用方式如下:
Usage: mssql [options] Options: -h, --help output usage information -V, --version output the version number -s, --server <server> Server to conect to -u, --user <user> User name to use for authentication -p, --pass <pass> Password to use for authentication -o, --port <port> Port to connect to -t, --timeout <timeout> Connection timeout in ms -d, --database <database> Database to connect to -q, --query <query> The query to execute -v, --tdsVersion <tdsVersion> Version of tds protocol to use [7_4, 7_2, 7_3_A, 7_3_B, 7_4] -e, --encrypt Enable encryption -f, --format <format> The format of output [table, csv, xml, json] -c, --config <path> Read connection information from config file 其中 -s 可用來指定 SQL Server 位置,-u 用來指定帳號,-p 用來指定密碼。像是若要連入本機的 SQL Server,其 sa 的密碼為 pass.
read moreTag: SQL Server V.Next
Posts
SQL Server v.Next - Run the SQL Server Docker image
要使用 Docker 運行 SQL Server v.Next,首先要先確定下列環境需求:
Docker Engine: 1.8+ Disk space: Minimum of 4 GB RAM: Minimum of 4 GB Docker 引擎需要在 1.8 以上的版本,硬碟空間最小要 4 GB,記憶體最小要有 4GB。
記得要調整設定讓 Docker 吃到 4 GB 的記憶體。
接著將 microsoft/mssql-server-linux 這個 Docker image 拉下來。
sudo docker pull microsoft/mssql-server-linux 拉下來後可以像下面這樣將 Container 運行起來,SA_PASSWORD 需要自行修改後帶入。
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=<YourStrong!Passw0rd>' -p 1433:1433 -d microsoft/mssql-server-linux 若是要將資料庫的資料保留下來,可以在 Container 運行時加掛資料卷。
sudo docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=<YourStrong!Passw0rd>' -p 1433:1433 -v <host directory>:/var/opt/mssql -d microsoft/mssql-server-linux 叫用命令 docker ps 查驗是否 Container 有正常運行。
read moreTag: ASP.NET Core
Posts
ASP.NET Core - Building Projects with Yeoman
要使用 Yeoman 去建立 ASP.NET Core 專案,首先需安裝 Yeoman 與 bower。
npm install -g yo bower 再來要安裝 ASP.NET generator。
npm install -g generator-aspnet ASP.NET generator 安裝完後,透過 Yeoman 叫用 ASP.NET generator。
yo aspnet 選取要使用的應用程式範本。
設定應用程式名稱,Yeoman 就會幫我們建立應用程式專案。
應用程式專案建立完整個目錄結構會像下面這樣:
到這邊就可以開啟專案來開發應用程式了,開發完成,我們可以還原會使用到的套件。
dotnet restore 然後將應用程式運行起來看看 (dotnet run 會順帶運行 dotnet build,這種情況下 dotnet build 可省略不調用)。
dotnet build dotnet run Link Building Projects with Yeoman Creating a new ASP.NET Core project using Yeoman · asp.net core from the ground up
read moreTag: SQLite
Tag: SikuliX
Posts
SikuliX - Global Settings
SikuliX 有提供一些設定值可供設定,像是 ActionLogs、InfoLogs、DebugLogs、MinSimilarity、MoveMouseDelay、DelayAfterDrag、DelayBeforeDrop、SlowMotionDelay、WaitScanRate、ObserveScanRate、ObserveMinChangedPixels 等,若有需要可以透過程式修改設定,詳細的說明可參閱這篇。
像是我們可以修改滑鼠移動的延遲、修改點擊的延遲、修改滑鼠按下前的延遲、修改鍵盤輸入的延遲、修改等待逾時的時間。
Settings.MoveMouseDelay = 0 Settings.ClickDelay = 0 Settings.DelayBeforeMouseDown = 0 Settings.TypeDelay = 0 Settings.AutoWaitTimeout = 30 * 1000 用程式設定起來就像是下面這樣:
Link Global Functions and Features — Sikuli X 1.0 documentation
read morePosts
SikuliX - Matching Target offset
SikuliX 在撰寫上提供了些彈性,能讓圖片在比對時提供模糊比對,或是要決定圖片被按下的位置。
像是下面這邊筆者稍微修改了前面帶到的範例,這邊用執行視窗整個畫面截圖。
那麼執行視窗輸入框內的字樣不一樣時,SikuliX 怎麼比對的到呢?而 Click 時 SikuliX 怎麼知道要點在哪個位置呢?
以這個例子來說,我們可以點選 SikuliX 程式上的圖片,在 Pattern Settings 這頁設定模糊比對的比例。調整模糊比對後如果在畫面中有被成功比對到,被比對到的地方會被遮罩起來。像是這邊將比對的比例調低,輸入框的字樣不論是什麼就都可以比對的到了。
Target Offset 頁面這邊決定著圖片被 Click 的位置,在圖片中點選即可決定圖片被點選的位置。像是這邊筆者就讓它等同點擊 OK 按鈕。
善用這兩個功能我們在撰寫 SikuliX 就可以少擷取很多圖片,除了節省儲存的空間,也會更好撰寫。
read morePosts
SikuliX - Getting started
Sikulix IDE 打開後,左側有放一些常用命令,可以用來撰寫程式,若有需要也可以用 Python 或是 Ruby 輔助撰寫 (主要看安裝時選擇用哪個語言當作 scripting language),像是加入函式,迴圈,或是條件式,或是更複雜的處理等。
像是要開啟 Chrome,我們可以像下面這樣撰寫。
這段程式會按下熱鍵 Win + R,等待執行對話框出現,輸入 chrome 後按下 Enter 按鈕,等待 Google 圖示出現。
撰寫中如果需要截圖,可以按熱鍵 Ctrl + Shift + 2。
撰寫完後按下上方的 Run 即可開始運行。
若要中斷運行,可以按熱鍵 Alt + Shift + C。
read morePosts
SikuliX - Download Setup
Sikulix 程式可到這邊下載。
下載下來後將 sikulixsetup-1.1.0.jar 放至欲安裝的位置,點選兩下進行安裝。
選擇要安裝的項目後按下 Setup Now 按鈕。
按下後會顯示要安裝的項目,如果正確無誤則按下 Yes 按鈕繼續即可。
接著會問是否需要安裝到 Python 2.7 版,視需求決定即可。這邊筆者公司電腦安裝 2.7 會有問題,所以筆者是選 No。
程式開始進行安裝…
安裝完會做些 functional test 驗證安裝是否成功。
安裝成功我們會看到這個畫面,按下 OK 按鈕繼續。
最後還會提醒安裝的細節可以查閱 log 檔。
安裝完後檔案都會跟安裝檔放在一起,所以一開始決定好要安裝的位置後在安裝很重要。
點選 runsikulix.cmd 即可開始運行程式。
最後提醒一下,若安裝上有碰到問題,記得查閱 log 檔(SikuliX-1.1.0-SetupLog.txt)。
Link 1.1.0 “SikuliX” : Series sikulix : Sikuli
read moreTag: NanoProfiler
Posts
NanoProfiler - a light weight .NET profiling library
NanoProfiler 有許多的套件。
如果是 Web 專案,安裝 NanoProfiler.Web 即可 (會連帶安裝 NanoProfiler)。
套件安裝完後要設定 CircularBuffer,可透過程式設定…
protected void Application_Start(object sender, EventArgs e) { ... ProfilingSession.CircularBuffer = new CircularBuffer<ITimingSession>(200, session => false); ... } 也可以透過設定檔設定…
<configuration> <configSections> <section name="slf4net" type="slf4net.Configuration.SlfConfigurationSection, slf4net" /> <section name="nanoprofiler" type="EF.Diagnostics.Profiling.Configuration.NanoProfilerConfigurationSection, NanoProfiler" /> </configSections> ... <nanoprofiler circularBufferSize="200" /> </configuration> CircularBuffer 設定完後,就可以設定要 Profile 的部分,像是每個 Request 的進出。
protected void Application_BeginRequest(object sender, EventArgs e) { ProfilingSession.Start("root"); } protected void Application_EndRequest(object sender, EventArgs e) { ProfilingSession.Stop(); } 以及 Request 中想要監測的部分。
read moreTag: Swashbuckle
Posts
Swashbuckle - Seamlessly adds a swagger to WebApi projects
要在 Web API 加上 Swagger 支援,可以為專案裝上 Swashbuckle 套件。
Install-Package Swashbuckle 安裝完可以看到 App_Start 目錄下會多個 SwaggerConfig.cs 黨,我們需要依需求去做些設定上的調動。
起碼要設定 XML documentation file 的位置,設定只要找到 c.IncludeXmlComments(GetXmlCommentsPath()); 這行,將其註解取消,取消後會看到 GetXmlCommentsPath 這個方法會找不到,這邊需要自己將該方法建立。
GetXmlCommentsPath 方法在實作上只要將 XML documentation file 位置回傳即可。
這邊的 XML documentation file 位置可查閱專案屬性這邊的設定。
設定好後運行將專案運行起來,瀏覽 http://[Domain]/swagger/,沒意外的話就會看到 swagger 頁面。
read moreTag: Common.Logging
Posts
Common.Logging - A portable logging abstraction for .NET
Common.Logging 是一 Log 元件,提供 Log 的抽象接口介面,以及許多不同的實作,支援 Log4net,Nlog,Microsoft Enterprise Library logging,Microsoft Application Insights,Microsoft Event Tracing for Windows,及 Serilog。
使用上大概分為四個步驟,第一要安裝 Common.Logging 與 Adapter 的套件,接著要設定 Common.Logging,再來是設定 Adapter 的設定,最後就可以透過 Common.Logging 將 Log 寫入。
Common.Logging 的套件透過 NuGet 安裝即可,這邊也可以直接安裝 Adapter 套件,像是要用 Log4Net 來寫 Log 的話,可以直接安裝 Common.Logging.Log4Net1215 這個套件。
套件安裝完後要設定 Common.Logging,開啟設定檔設定 common 的 section group,在 common 的 section group 這邊要設定 Adapter 以及其參數,像這邊指定使用 Log4Net 的 Adapter 去處理 Log,指定並監控 Adapter 的設定檔 log4net.config。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="common"> <section name="logging" type="Common.
read moreTag: Grunt
Posts
Grunt - grunt-contrib-imagemin
grunt-contrib-imagemin 套件可以用 Grunt 來將進行檔的壓縮。
使用時先用 npm 安裝 grunt-contrib-imagemin 套件。
npm install grunt-contrib-imagemin --save-dev 接著開啟 gruntfile 設定 task,這邊有些參數可供設定,可參考 gruntjs/grunt-contrib-imagemin: Minify PNG and JPEG images.。
再來將 plugin 載入。
grunt.loadNpmTasks('grunt-contrib-imagemin'); 最後再將 task 註冊即可。
像是下面這邊設定了一個 imagemin 的 task,會將 images 目錄下副檔名為 png/jpg/gif 的圖片進行壓縮,壓縮後會放回到 images 目錄。
var grunt = require('grunt'); grunt.initConfig({ imagemin: { main:{ options: { optimizationLevel: 3, svgoPlugins: [{ removeViewBox: false }] }, files: [{ expand: true, cwd: 'Images/', src: ['**/*.{png,jpg,gif}'], dest: 'Images/’ }] } } }); grunt.
read morePosts
Grunt - Hello Grunt
接著實際來用用看 Grunt,首先 gruntfile 先用 require 載入 grunt,然後用 registerTask 註冊一個任務,這邊帶入任務名為 default,並將任務的動作用 function 指定,這邊這個任務就只是簡單的顯示 hello world 訊息而已。
var grunt = require('grunt'); grunt.registerTask('default', '',function(){ console.log('hello world'); }); 實際透過命令呼叫 grunt,可以看到 default 任務被 grunt 調用了,因此會在螢幕上顯示 hello world。
接著可以試著撰寫難一點的來看看,註冊一個 world 任務,執行時會顯示 hello world,接著註冊一個 hello 任務,需帶入名字執行,執行會顯示 hello 以及帶入的名字,最後註冊 default 任務,執行時會調用 world 任務以及用 adrian 當參數去調用 hello 任務。
var grunt = require('grunt'); grunt.registerTask('world', '', function(){ console.log('hello world'); }); grunt.registerTask('hello', '', function(name){ if(!name || !name.length) grunt.warn('you need to provide a name.
read morePosts
Grunt - Gruntfile
Gruntfile 的設定可以直接從下面例子來看。
module.exports = function(grunt) { grunt.initConfig({ jshint: { files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'], options: { globals: { jQuery: true } } } }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.registerTask('default', ['jshint']); }; 設定大概會分幾個部份,會有 Task 與 Target 的設定,有 npm 套件的載入,以及 Task 的註冊。
以這例子來說,這邊設定了 jshint task,這個 task 會用 jshint 分析指定的 javascript 的程式。
許多套件都會牽扯到檔案的設定,像是上面例子 jshint 要分析的檔案就是要設定的。Grunt 對於檔案設定提供了三種不同的設定方式,分別是 Compact Format、Files Object Format、Files Array Format。
Compact Format 設定方式如下,可指定一組 source 與 destination 檔案。
grunt.initConfig({ jshint: { foo: { src: ['src/aa.js', 'src/aaa.js'] }, }, concat: { bar: { src: ['src/bb.
read morePosts
Grunt - How to use
使用 Grunt 前需先確定環境是否已經安裝了 Node.js 與 grunt-cli。
npm install grunt-cli -g 環境安裝無誤就可以開始使用 Grunt,使用上大致分為下列幾個步驟:
以 Windows 的操作為例,首先需要有專案目錄。
md <folder> 接著需要建立 npm 套件的設定檔。
npm init 再來要建立 Grunt 設定檔。
type NUL > Gruntfile.js 加入 Grunt 套件。
npm install grunt --save-dev 加入 Grunt plug-in。
npm install <plug-in> --save-dev 開啟 Grunt 設定檔設定 Grunt task。
notepad gruntfile.js 運行 Grunt task。
grunt
read morePosts
Grunt - Using Grunt in Visual Studio 2015
Visual Studio 2015 開始支援 Grunt,使用時需先為專案加入 NPM Configuration File。
{% img /images/posts/GruntInVS2015/1.png %}
還有 Grunt Configuration File。
{% img /images/posts/GruntInVS2015/2.png %}
接著在 package.json 中加入要使用的 Grunt plugin。
{% img /images/posts/GruntInVS2015/3.png %}
{% img /images/posts/GruntInVS2015/4.png %}
設定完按下編譯或是滑鼠右鍵快顯選單中的 Restore Packages 選單選項,即可透過 NPM 下載 Grunt plugin。
{% img /images/posts/GruntInVS2015/5.png %}
我們可以透過 Visual Studio 的狀態列觀察到套件下載的狀態。
{% img /images/posts/GruntInVS2015/6.png %}
{% img /images/posts/GruntInVS2015/7.png %}
若有需要也可以透過 Output 視窗查看細部處理資訊。
{% img /images/posts/GruntInVS2015/8.png %}
下載完畢,設定完 gruntfile.js,我們就可以在 Task Runner Explorer 點選對應的 Task 進行運行。
read moreTag: Protobuf-Net
Posts
protobuf-net - Serialize/DeSerialize data
protobuf-net 預設只支援序列化至 stream,或是自 stream 姐序列化回物件。使用上就是透過 Serializer.Serialize 帶入 stream 與物件,帶入的物件就會被序列化至 stream,呼叫 Serializer.Deserialize,帶入 stream,泛型型態設定為指定的類別型態,就可以自 stream 解序列化回指定型態的物件。
private static void SerializeToStream<T>(T obj, Stream stream) { Serializer.Serialize(stream, obj); } private static T DeSerializeFromStream<T>(Stream stream) { return Serializer.Deserialize<T>(stream); } 如果要序列化為字串,可以將物件先序列化到 stream,然後將他轉成 Base 64 的字串。解序列化反向操作即可。
private static string SerializeToText<T>(T obj) { using (var ms = new MemoryStream(1024)) { SerializeToStream(obj, ms); return Convert.ToBase64String(ms.ToArray()); } } private static T DeSerializeFromText<T>(string text) { var buffer = Convert.FromBase64String(text); using (var ms = new MemoryStream(buffer)) { return DeSerializeFromStream<T>(ms); } } 序列化到檔案的話,就是開啟檔案串流,將物件序列化到檔案串流即可。解序列化一樣反向操作。
read morePosts
protobuf-net - Decorate class
protobuf-net 要設定類別怎樣被序列化與解序列化有三種方式‧
像是使用 protobuf-net 提供的 Attribute,類別上用 ProtoContractAttribute、Property 上用 ProtoMemberAttribute‧
[ProtoContract] class Person { [ProtoMember(1)] public int Id {get;set;} [ProtoMember(2)] public string Name {get;set:} [ProtoMember(3)] public Address Address {get;set;} } [ProtoContract] class Address { [ProtoMember(1)] public string Line1 {get;set;} [ProtoMember(2)] public string Line2 {get;set;} } 如果有繼層的類別可以透過 ProtoIncludeAttribute 設定。
[ProtoContract] [ProtoInclude(10, typeof(Male))] [ProtoInclude(11, typeof(Female))] class Person { [ProtoMember(1)] public string Name { get; set; } } [ProtoContract] class Male : Person { } [ProtoContract] class Female : Person { } ProtoContractAttribute 這邊還有提供些設定,像是 SkipConstructor 可以讓類別解序列化時不需要有建構子、ImplicitFields 可以設定全部的欄位或是屬性都序列化解序列化。
read morePosts
protobuf-net - Getting Started
使用 protobuf-net,首先要參照 protobuf-net library,接著設定要用來做序列化或解序列化用的類別,設定完後就可以用 protobuf-net 來序列化或解序列化。
protobuf-net library 透過 NuGet 引用即可。
接著準備用來做序列化或解序列化用的類別,類別可透過 Attribute 的方式決定怎樣序列化或解序列化。
[ProtoContract] class Person { [ProtoMember(1)] public int Id {get;set;} [ProtoMember(2)] public string Name {get;set:} [ProtoMember(3)] public Address Address {get;set;} } [ProtoContract] class Address { [ProtoMember(1)] public string Line1 {get;set;} [ProtoMember(2)] public string Line2 {get;set;} } 序列化時只要調用 Serializer.Serialize 帶入 Stream 與要序列化的物件。
var person = new Person { Id = 12345, Name = "Fred", Address = new Address { Line1 = "Flat 1", Line2 = "The Meadows" } }; using (var file = File.
read moreTag: ASP.NET MVC
Posts
ASP.NET MVC - MVC 5 on IIS 7
在 IIS 7 使用 ASP.NET MVC 5,Routing 功能會無法正常運作,會看到 403 或是 404 頁面。
這邊可以在 Web.Config 的 modules 這邊加上 runAllManagedModulesForAllRequests="true" 設定,並為網站加上 UrlRoutingModule-4.0 模組。
... <system.webServer> <modules runAllManagedModulesForAllRequests="true"> ... <remove name="UrlRoutingModule-4.0"></remove> <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition=""></add> </modules> ... 沒意外的話就會運作正常了。
Link MVC 5 on Windows Server 2008/IIS 7
read morePosts
ASP.NET MVC - Replacing MVC JavascriptSerializer with JSON.NET JsonSerializer
使用 ASP.NET MVC 或是 Web API 做 JSON 格式的回傳,只要將 Model 帶入去建構 JsonResult 物件回傳即可,像是下面這樣:
... return new JsonResult(model); ... 這樣的寫法預設會採用 JavaSriptSerializer 去做 JSON 的序列化,有著效能不佳的問題,且序列化出來的資料有時也不是我們所期望的,像是 DateTime 物件會被序列化成下面這樣:
"/Date(1290181373164)/" Json.Net 提供了 JsonNetResult 可解決這樣的問題,可將程式直接加到專案內使用。
/// <summary> /// Simple Json Result that implements the Json.NET serialiser offering more versatile serialisation /// </summary> public class JsonNetResult : ActionResult { public JsonNetResult() { } public JsonNetResult (object responseBody) { ResponseBody = responseBody; } public JsonNetResult(object responseBody, JsonSerializerSettings settings) { Settings = settings; } /// <summary>Gets or sets the serialiser settings</summary> public JsonSerializerSettings Settings { get; set; } /// <summary>Gets or sets the encoding of the response</summary> public Encoding ContentEncoding { get; set; } /// <summary>Gets or sets the content type for the response</summary> public string ContentType { get; set; } /// <summary>Gets or sets the body of the response</summary> public object ResponseBody { get; set; } /// <summary>Gets the formatting types depending on whether we are in debug mode</summary> private Formatting Formatting { get { return Debugger.
read morePosts
ASP.NET MVC - Post array data to MVC controller
最近在用 JQuery 傳送陣列資料給 MVC Controller,資料無法如預期般的被送過去。查看了一下送過去的資訊,看起來是送的資料格式不符合 Model Binder 預期的格式所導致。
以基本型別的陣列來說, Model Binder 預期的格式為
arrayName = arrayValue1& arrayName = arrayValue2 但是透過 JQuery 發送的資料卻是
arrayName[] = arrayValue1& arrayName[] = arrayValue2 而以物件陣列來說, Model Binder 預期的格式為
arrayName[0] .propertyName1 = property1Value& arrayName[0] .propertyName2 = property2Value 但是透過 JQuery 發送的資料卻是
arrayName[0] [propertyName1] = property1Value& arrayName[0] [propertyName2] = property2Value
要解決這樣的問題要馬可以在 Client 這邊將資料做個轉換,要馬就是在 MVC 這邊要透過客製 Model Binder 的方式自行轉換。這邊筆者是比較傾向 Client Side 處理,且黑暗大那也已有現成又漂亮的解法,
對於基本型態陣列的處理,可參閱使用jQuery.post傳送字串陣列參數到ASP.NET MVC - 黑暗執行緒這篇,透過$.param()將參數序列化,並在traditional參數這邊帶入true,指定用傳統的陣列參數的序列化形式即可。
對於非基本型態的陣列處理,可參閱使用jQuery.ajax傳送物件陣列給ASP.NET MVC - 黑暗執行緒這篇,黑暗大刻了一個 JQuery Plugin 在發送資料前會將資料格式用正規表示式進行對應的轉換。
read morePosts
ASP.NET MVC - Remove unnecessary view engine
ASP.NET MVC 預設會載入多個 View engine,儘管在專案建立之時我們就已明確的指定了所要使用的 View engine。
以一個最簡單的空專案來看,這邊特地將 Home 的 Index view 給刪掉,接著將之運行,運行後因為找不到 View 所以會顯示錯誤頁面。
{% img /images/posts/RemoveUnnecessaryViewEngine/1.png %}
這邊可以看到系統會嘗試載入不同程式語言所撰寫的不同 View engine 檔。然而在大部分的情況下,我們只會選用ㄧ種程式語言與View engine。
因此像這樣載入過多的 View engine 反而形成不必要的耗費,故我們可以在啟動時加入程式將之移除。
protected void Application_Start() { ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new RazorViewEngine()); ... } 再次運行就會看到這樣作就只會嘗試載入我們預期的 View Engine。
{% img /images/posts/RemoveUnnecessaryViewEngine/2.png %}
如果真有同時載入多個 View engine 的需求,那我們就不能像這樣直接的將 View engine 給移除,取而代之的是我們必需去調整 View engine 的順序,取比較好的載入順序。
read moreTag: WinDBG
Posts
WinDBG - Check gcroot
如果檢查出該被回收的物件並為如預期的被回收,這邊可以看一下物件的 gcroot,看看物件是為何被佔住而不能釋放。
像是這邊如果用 !dumpheap –stat 查看發現 7ff5e8859b0 MT 位置的物件有問題,這邊可以調用命令 !dumpheap -mt 7ff5e8859b0,查看其對應到的 Address。
0:000> !dumpheap -mt 7ff5e8859b0 The version of SOS does not match the version of CLR you are debugging. Please load the matching version of SOS for the version of CLR you are debugging. CLR Version: 4.0.30319.17929 SOS Version: 4.5.27.0 Address MT Size 000000865eca7860 000007ff5e8859b0 120 Statistics: MT Count TotalSize Class Name 000007ff5e8859b0 1 120 AgileSlot.Core.GameMachine Total 1 objects Fragmented blocks larger than 0.
read morePosts
WinDBG - Check memory leak with dumpheap
要檢查程式的 Memory leak,我們可以在程式物件應該被釋放時抓取 Dump 檔案,像是程式運行後隔一陣子,理論上 GC 應該已經將物件回收時抓取,抓取後就可以用 WinDBG 進一步的分析。
分析時將 WinDBG 開啟,點選 [File | Symbol File Path…] 。
{% img /images/posts/CheckMemoryLeakWithWinDBG/1.png %}
將 Symbol Server 的位置加入(SRVc:\symbolshttp://msdl.microsoft.com/download/symbols) 。
{% img /images/posts/CheckMemoryLeakWithWinDBG/2.png %}
接著點選 [File | Open Crash Dump…] 載入 Dump File ( 直接將 Dump 檔拖曳至 WinDBG 也可 )。
{% img /images/posts/CheckMemoryLeakWithWinDBG/3.png %}
{% img /images/posts/CheckMemoryLeakWithWinDBG/4.png %}
接著輸入命令 .loadby sos clr,將 SOS 偵錯擴充功能載入。
{% img /images/posts/CheckMemoryLeakWithWinDBG/5.png %}
再輸入命令 !dumpheap –stat 將 heap state dump 出來。
read moreTag: StackExchange.Redis
Posts
StackExchange.Redis - Scripting
使用 StackExchange.Redis 開發 Redis 的 Lua Scripting 程式,只要簡單的透過 Database 物件的 ScriptEvaluateAsync 方法,將 Lua script 及所需的 keys 與 values 帶入即可。
using StackExchange.Redis; ... var configuration = GetConfiguration(); using (var conn = ConnectionMultiplexer.Connect(configuration)) { var db = conn.GetDatabase(); var script = GetScript(); var keys = GetKeys(); var values = GetValues(); var result = db.ScriptEvaluate(script, keys, values); ... } ... 像是下面這邊筆者用 Lua script 實作了類似 Redis 的 MSET 命令,可同時設定三組 Key/Value,寫起來會像下面這樣:
using System; using StackExchange.Redis; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { var configuration = "localhost:6379"; using (var conn = ConnectionMultiplexer.
read morePosts
StackExchange.Redis - Pub/Sub Demo
使用 StackExchange.Redis 開發 Redis 的 Pub/Sub 程式,需先調用 GetSubscriber 方法取得 Subscriber 物件,再透過該 Subscriber 物件去設定事件訂閱以及發佈訂閱即可。
像是下面這邊筆者訂閱了 MemberOnLine 的事件,當事件發生時會將上線資訊顯示在主控台,然後發佈 LarryNung 上線的事件給訂閱者:
using System; using StackExchange.Redis; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { var configuration = "localhost:6379"; using (var conn = ConnectionMultiplexer.Connect(configuration)) { var sub = conn.GetSubscriber(); var key = "MemberOnLine"; sub.Subscribe(key, (c, v) => { Console.WriteLine("{0} Online...", v); }); sub.PublishAsync(key, "LarryNung", CommandFlags.FireAndForget); } } } } 運行結果如下:
{% img /images/posts/PubSubInStackExchange.
read morePosts
StackExchange.Redis - Server Command Demo
要使用 StackeExchange.Redis 取得 Server 的資訊,或是運行 Server 的命令。要先調用 GetServer 方法取得 Server 物件,再透過該 Server 成員屬性或方法去操作即可。
像是下面這邊筆者遍巡了每台 Server,並將其相關的資訊顯示到主控台:
using System; using StackExchange.Redis; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { var configuration = "localhost:6379"; using (var conn = ConnectionMultiplexer.Connect(configuration)) { var endPoints = conn.GetEndPoints(); foreach (var endPoint in endPoints) { var server = conn.GetServer(endPoint); Console.WriteLine("Server: {0}", server.Multiplexer); Console.WriteLine("IsSlave: {0}", server.IsSlave); Console.WriteLine("AllowSlaveWrites: {0}", server.AllowSlaveWrites); Console.WriteLine("ServerType: {0}", server.ServerType); Console.WriteLine("Version: {0}", server.Version); Console.WriteLine("ServerTime: {0}", server.
read morePosts
StackExchange.Redis - Configuration
欲連線至 Redis,需先設定 Configutaion,在 StackExchange.Redis 提供兩種設定方式,一種是用 ConfigurationOptions 物件直接宣告設定:
using StackExchange.Redis; ... var configuration = new ConfigurationOptions() { EndPoints = { {"localhost", 6379}, {"localhost", 6380} }, Password = "LarryNung" }; using (var conn = ConnectionMultiplexer.Connect(configuration)) { ... } ... 一種是透過字串的方式設定:
using StackExchange.Redis; ... var configuration = "localhost:6379,localhost:6380,password=LarryNung"; using (var conn = ConnectionMultiplexer.Connect(configuration)) { ... } ... 如果不清楚有哪些可供設定,可參閱下表:
{% img /images/posts/ConfigurationInStackExchange.Redis/1.png %}
{% img /images/posts/ConfigurationInStackExchange.Redis/2.png %}
read morePosts
StackExchange.Redis - A high performance general purpose redis client for .NET languages
StackExchange.Redis 是 StackExchange 提供的 redis client 實作。
該套件具有以下特點:
High performance multiplexed design, allowing for efficient use of shared connections from multiple calling threads Abstraction over redis node configuration: the client can silently negotiate multiple redis servers for robustness and availability Convenient access to the full redis feature-set Full dual programming model both synchronous and asynchronous usage, without requiring “sync over async” usage of the TPL Support for redis “cluster” 使用上需先透過 NuGet 套件管理視窗安裝套件,他有提供兩種套件,一種是不含強命名簽章的套件 StackExchange.
read moreTag: FX.Configuration
Posts
FX.Configuration - A lightweight/simple/flexible/extensible library to read configurations using strongly typed classes
FX.Configuration 是一號稱輕量,簡單,具彈性,可擴充的 Configuration 讀取套件,可以將 Configuration 讀取到對應的強型別類別中,便於後續 Configuration 設定值得取用。支援 Application/JSON/Mixed Configuration。
使用上可分為幾個步驟。
{% img /images/posts/FxConfiguration/1.png %}
首先需先透過 NuGet 套件管理視窗安裝套件。
{% img /images/posts/FxConfiguration/2.png %}
或是透過 Package Manager Console 輸入下列命令安裝套件。
Install-Package FX.Configuration {% img /images/posts/FxConfiguration/3.png %}
套件安裝完成後,接著要準備 Configuration 設定檔案,視需求決定是要用 Application/JSON/Mixed 哪種 Configuration,並訂定 Configuration 的結構以及要有哪些設定值。
再來要建立 Configuration 對應的類別供後續讀取使用,不同型態的 Configuration 類別需繼承不同的基底類別。
最後建立 Configuration 對應的類別實體,存取該實體的成員屬性即可取得 Configuration 的設定值。
進一步的使用可參閱筆者其它文章,像是讀取Application configuration,讀取JSON configuration,以及讀取mixed configuration。
Link NuGet Gallery | FX.Configuration 0.4.1 friendlyx / fx.configuration — Bitbucket FX.Configuration - Read application configuration - Level Up FX.
read morePosts
FX.Configuration - Read mixed configuration
要用 FX.Configuration 同時讀取 Application 與 JSON Configuration,需先引用 FX.Configuration 套件。
接著在 Application Configuration 中設定資料。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="Setting1" value="Larry Nung"/> </appSettings> </configuration> 以及在 JSON Configuration 中設定資料。
{ "Setting2": "Level Up (http://larrynung.github.io/index.html)" } 再來要設定 Configuration 對應的存取類別,這邊跟一般的 Model 實作類似,只是要類別需繼承自 MixedConfiguration。
using FX.Configuration; namespace ConsoleApplication12 { public class MyMixedConfig : MixedConfiguration { public string Setting1 { get; private set; } public string Setting2 { get; private set; } } } 準備好後就只要將類別實體化即可透過成員屬性取得 Configuration 的設定值。
read morePosts
FX.Configuration - Read JSON configuration
要用 FX.Configuration 讀取 JSON Configuration,需先引用 FX.Configuration 套件。
接著在 JSON Configuration 中設定資料。
{ "Setting1": "Larry Nung", "Setting2": "Level Up (http://larrynung.github.io/index.html)" } 再來要設定 JSON Configuration 對應的存取類別,這邊跟一般的 Model 實作類似,只是要類別需繼承自 JsonConfiguration,另外要注意設定檔的位置在哪,如果是跟組件檔案同目錄下的 Config.json 檔,那我們不需多做處理,如果檔案在其他目錄下,或是檔案名稱不是 Config.json,我們可以透過建構子設定。
using FX.Configuration; namespace ConsoleApplication12 { public class MyJSONConfig: JsonConfiguration { //public MyJSONConfig() // : base("Config.json") //{ //} public string Setting1 { get; private set; } public string Setting2 { get; private set; } } } 準備好後就只要將類別實體化即可透過成員屬性取得 JSON Configuration 的設定值。
using System; namespace ConsoleApplication12 { class Program { static void Main(string[] args) { var config = new MyJSONConfig(); Console.
read morePosts
FX.Configuration - Read application configuration
要用 FX.Configuration 讀取 Application Configuration,需先引用 FX.Configuration 套件。
接著在 Application Configuration 中設定資料。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="Setting1" value="Larry Nung"/> <add key="Setting2" value="Level Up (http://larrynung.github.io/index.html)"/> </appSettings> </configuration> 再來要設定 Application Configuration 對應的存取類別,這邊跟一般的 Model 實作類似,只是要類別需繼承自 AppConfiguration。
using FX.Configuration; namespace ConsoleApplication12 { public class MyAppConfig: AppConfiguration{ public string Setting1 { get; private set; } public string Setting2 { get; private set; } } } 準備好後就只要將類別實體化即可透過成員屬性取得 Application Configuration 的設定值。
using System; namespace ConsoleApplication12 { class Program { static void Main(string[] args) { var config = new MyAppConfig(); Console.
read moreTag: Octopress
Posts
Octopress - Failed to push some refs to GitHub
今天在使用 rake deploy 試圖發佈文章時,在發佈到 Github 這步驟時發生了錯誤,發佈的動作被 rejected 了。
{% img /images/posts/OctopressDeployFail/1.png %}
要解決這樣的問題我們可以依下面步驟操作。
cd _deploy git reset --hard origin/master cd .. 就像下面這樣:
{% img /images/posts/OctopressDeployFail/2.png %}
操作完就重新建立靜態檔案並 Deploy。
rake generate rake deploy 沒意外的話就能正確的發佈。
{% img /images/posts/OctopressDeployFail/3.png %}
Link ruby - Octopress pushing error to GitHub - Stack Overflow
read morePosts
Octopress - Add About Me section in sidebar
新增 About Me 檔,檔案位置存放在 source/_includes/custom/asides 下。
{% img /images/posts/OctopressAboutMe/1.png %}
編輯後存檔退出。
{% img /images/posts/OctopressAboutMe/2.png %}
接著開啟 _config.yml 設定檔找到 blog_index_asides 設定,將剛編輯好的 About Me 檔設上。
{% img /images/posts/OctopressAboutMe/3.png %}
存檔退出,編譯網頁後啟用預覽功能,即會看到側欄這邊多出剛我們設在 About Me 檔的內容。
{% img /images/posts/OctopressAboutMe/4.png %}
Link Theming & Customization - Octopress
read morePosts
Octopress - Add categories page
要為 Octopress 新增 Categories 頁面,首先需先叫用下列命令產生新的頁面:
rake new_page[page] 像是下面這樣:
{% img /images/posts/OctopressCategories/1.png %}
然後開啟剛所建立的頁面,加入用來產生 Categories 頁面的程式。
{% img /images/posts/OctopressCategories/2.png %}
這邊頁面的 Sharing ,Comments 與 Footer 都可以順帶修改將之關閉,一般來說 Categories 頁面是不需要這些的,修改完後存檔離開。
接著開啟 /source/_includes/custom/navigation.html 設定檔設定上方的選單,把我們剛建的 Categories 頁面設定上去。
{% img /images/posts/OctopressCategories/3.png %}
存檔離開,建置後啟用預覽功能,即會看到上方選單多出 Categories 這個選單選項,點擊切換可看的到 Categories 頁面正常的運作。
{% img /images/posts/OctopressCategories/4.png %}
Link Theming & Customization - Octopress
read morePosts
Octopress - Add Linkedin profile link with Octoflat theme
Octoflat Theme 預設就有支援 Linkedin Profile 的連結,只要在 _config.yml 設定檔中設定 linkedin_user,將 Linkedin User ID 設上去就可以了。
{% img /images/posts/OctopressOctoflatLinkedinProfile/1.png %}
呼叫命令產生靜態網頁並啟用預覽:
rake generate rake preview 我們可以看到在部落格的右上方會多出 Linkedin 的 Icon。
{% img /images/posts/OctopressOctoflatLinkedinProfile/2.png %}
點擊該 Icon,沒意外的話應該可以看到 Linkedin 的 Profile 頁面。
但是筆者看到的畫面卻是…
{% img /images/posts/OctopressOctoflatLinkedinProfile/3.png %}
因為 Octoflat 他的 Linkedin Profile 位置是設成 http://www.linkedin.com/in/[UserID],而 Linkedin Profile 的位置看起來是有很多不同的可能,像是筆者的 Profile 位置就不是 Octoflat 預期的那樣。
{% img /images/posts/OctopressOctoflatLinkedinProfile/4.png %}
因此筆者修改 source/_includes/navigation.html 檔案,為其加入 linkedin_url。
{% if site.linkedin_url %} <li><a href="{{ site.linkedin_url }}" title="Linkedin Profile"><i class="icon-linkedin-sign social-navbar"></i></a></li> {% endif %} 像是下面這樣:
read morePosts
Octopress - Change theme
要更換 Octopress 的 Theme,我們可先找到要替換的 Theme。
這部份可參閱 Opthemes · Octopress Themes ,它有將 Octopress 可用的 Theme 做個整理,並以縮圖方式呈現, Theme 套用起來的樣子一目了然。
找到喜歡的 Theme 後可以到範例網站做進一步的預覽。
若沒有什麼問題,也以確定就是要套用該 Theme 的話,可到 GitHub 查閱進一步的安裝與設定步驟。
除了 Opthemes · Octopress Themes 外,也可以到 3rd Party Octopress Themes · imathis/octopress Wiki · GitHub 這邊看看有無喜歡的 Theme,它的 Theme 介紹的比較多,但沒提供縮圖預覽,使用上比較沒那麼直覺。
找到 Theme 後,基本上安裝方式都一樣,就是將 Theme 用 Git Clone 下來,Clone 下來後呼叫 rake install 任務進行安裝,安裝完後叫用 rake generate 產生靜態網頁。
git clone GIT_URL .themes/THEME_NAME rake install['THEME_NAME'] rake generate 安裝完後,各套件可能會要做不同的設定動作,因此建議還是要到對應的 GitHub 網站,餅以上面的操作為主。
read morePosts
Octopress - Notify search engine
sitemap.xml 是 Google 提出來的標準,以 XML 為格式,紀錄著網頁的連結與最後修改的時間。
{% img /images/posts/OctopressNotifySearchEngine/1.png %}
如果要即時通知搜尋引擎更新,而不等待搜尋引擎自行檢測,我們可以主動將 sitmap.xml 上傳給搜尋引擎。
若是想要在 Octopress 中做這動作的話,我們可以編輯 Octopress 的 Rakefile 檔案,將下面腳本加入。
desc 'Ping pingomatic' task :pingomatic do begin require 'xmlrpc/client' puts '* Pinging ping-o-matic' XMLRPC::Client.new('rpc.pingomatic.com', '/').call('weblogUpdates.extendedPing', 'Level Up' , 'http://larrynung.github.io', 'http://larrynung.github.io/atom.xml') rescue LoadError puts '! Could not ping ping-o-matic, because XMLRPC::Client could not be found.' end end desc 'Notify Google of the new sitemap' task :sitemapgoogle do begin require 'net/http' require 'uri' puts '* Pinging Google about our sitemap' Net::HTTP.
read morePosts
Octopress - Remove reduant blog folder
Octopress blog架設好後,預設的部落格網址格式為 /blog/:year/:month/:day/:title/,會在網址那邊多一層不必要的 blog 目錄,要將這層不必要的目錄拿掉,我們可以開啟 _config.yaml 進行些修改,將 permalink、 category_dir、與 pagination_dir 的 /blog 前綴給拿掉 (Demo)。
#permalink: /blog/:year/:month/:day/:title/ permalink: /:year/:month/:day/:title/ #category_dir: blog/categories category_dir: categories #pagination_dir: blog # Directory base for pagination URLs eg. /blog/page/2/ pagination_dir: # Directory base for pagination URLs eg. /page/2/ 接著將 source/_includes/custom/navigation.html 檔案開啟,針對上方巡覽列這邊的連結部分作些修改,一樣將 /blog 前綴給移掉 (Demo)。
<li><a href="/">Home</a></li> <li><a href="/archives">Archives</a></li> 同樣的動作也要對 source/index.html 做一次。
<a href="/archives">Archives</a> 網址跟連結都做完,記得要將本來放在 source/blog 下的資料移到source (Demo)。
mv -v source/blog/archives source/ 最後老樣子建置網頁並預覽
rake generate rake preview 預覽沒什麼問題的話將之佈署上去
read morePosts
Octopress - change rss subscribe link
要修改Octopress部落格的RSS訂閱位置。
可以開啟_config.yaml設定檔,將subscribe_rss設定設為我們想要使用的RSS訂閱位置。
{% img /images/posts/OctopressChangeRssSubscribeLink/1.png %}
像是筆者就將RSS訂閱位置改為FeedBurner。
設定完後建置發佈,將部落格跑起來就會發現RSS訂閱位置已經變成我們所設定的。
{% img /images/posts/OctopressChangeRssSubscribeLink/2.png %}
{% img /images/posts/OctopressChangeRssSubscribeLink/3.png %}
read morePosts
Octopress - Read more excerpt link
在Octopress上撰寫文章時,若不特別做些處理,在Blog分頁那邊會將所有文章的全文依序列出。
這樣的呈現方式很難被訪客所閱讀,通常我們會期望只顯示部分的文章內容,若有興趣在進ㄧ步的去閱讀全文,這樣文章也比較好找。
若您也有這樣的需求,可以開啟_config.yaml這個設定檔,在excerpt_link這邊設定進ㄧ步閱讀的按鈕所要呈現的字樣。
{% img /images/posts/OctopressReadMore/1.png %}
設定好後存檔,並在撰寫文章的同時,加入特定的註解:
<!--More--> 像是這樣
{% img /images/posts/OctopressReadMore/2.png %}
該註解可以用以指定文章的摘要要顯示到哪。
實際將部落格跑起來就會像下面這樣:
{% img /images/posts/OctopressReadMore/3.png %}
read morePostsread more
Integrate disqus comments with Octopress
Disqus是ㄧ提供留言功能的服務,整合了多種社群服務,能用社群帳號直接登入留言,除此之外也支援匿名留言、分享、以及完整的過濾與管理功能。
透過Disqus與Octopress的整合,使用Octopress架設的部落格也能提供留言的功能。
Postsread more
Octopress - A blogging feamework for hackers.
Octopress是ㄧ利用Jekll部落格引擎開發的部落格系統,能簡易的架設、擴充、客製、與套版,因其最後是生成靜態網頁,因此能很輕易的在許多服務上做部署,像是Github、Heroku、與Rsync等。
Tag: Opserver
Posts
Opserver - Stack Exchange's Monitoring System
Opserver 是 Stack Exchange 開發的監控系統,能夠針對以下系統進行監控:
Servers/Switches & anything supported by Bosun, Orion, or direct WMI monitoring SQL Clusters & Single Instances Redis Elasticsearch Exception Logs (from StackExchange.Exceptional) HAproxy PagerDuty CloudFlare DNS 安裝上只需要從 Github 將 Opserver 抓下來,開啟 Opserver 專案,然後設定其對應的 Config,並將之部署到網站伺服器運行即可。
Opserver 的 Config 設定放置於 /Opserver/Config/ 下,參閱放置在裡面的 example 檔設定即可。需先針對 Opserver/Config/SecuritySettings.config 下去設定,設定網站的安全性,再來才是要監控的系統對應的設定。如果設定後本地運行無法看到效果,可將 IISExpress 停掉後重跑看看。
{% img /images/posts/Opserver/1.png %}
{% img /images/posts/Opserver/2.png %}
{% img /images/posts/Opserver/3.png %}
{% img /images/posts/Opserver/4.png %}
{% img /images/posts/Opserver/5.png %}
read moreTag: Disruptor
Posts
Disruptor - WorkerPool
Disruptor 的 EventHandler,Consumer 間會相互合作,會依序消費收到所有的資料。但有的場景我們可能會需要多個 Consumer 分攤處理收到的資料,這時可以採用 WorkerHandler。
像是我們可以撰寫下面這樣的 WorkerHandler:
... public class Data { public string Value { get; set; } } public class DataWorkHandler : IWorkHandler<Data > { public string Name { get; private set; } public DataWorkHandler( string name) { this.Name = name; } public void OnEvent( Data @event) { Console.WriteLine( "Thread = {0}, Handler = {1}, Value = {2} ", Thread.CurrentThread.ManagedThreadId.ToString(), this.Name, @event.Value); } } ... 這邊建造多個 WorkerHandler,帶入 Disruptor 的 HandleEventsWithWorkerPool 方法。
read morePosts
Disruptor - Consumer's WaitStrategy
Disruptor 內建幾種等待策略,可用以設定消費者怎樣等待生產者的資料。在實務上,我們可能要針對不同的產品特性下去調整等待的策略。
預設的等待策略為 BlockingWaitStrategy,內部是用 Lock 與條件變數下去實作,用於對低延遲與高產能不是那麼重視的情境。雖然產能不高,但能確保在不同的環境下有一致的性能表現。
這邊筆者做了簡單的測試,在 Unicast 1p-1c 的狀況下瘋狂寫入,每秒約處理 145 筆資料。
{% img /images/posts/DisruptorWaitStrategy/1.png %}
如果讓 Producer 不要那麼頻繁的產生資料,那會看到消費者在等待的同時 CPU 會忙於等待。
{% img /images/posts/DisruptorWaitStrategy/2.png %}
SleepingWaitStrategy 策略則是用迴圈下去睡眠等待。可以看到這邊的實驗,每秒處理可達到約 18xxxx 筆資料。
{% img /images/posts/DisruptorWaitStrategy/3.png %}
且等待生產者資料時 CPU 耗費也不高。
{% img /images/posts/DisruptorWaitStrategy/4.png %}
BusySpinWaitStrategy 策略套到同樣的實驗,每秒處理約 144 筆資料。
{% img /images/posts/DisruptorWaitStrategy/5.png %}
等待資料時 CPU 也是飆高狀態。
{% img /images/posts/DisruptorWaitStrategy/6.png %}
YieldingWaitStrategy 策略套到同樣的實驗,每秒處理約 24xxxx 筆資料.
{% img /images/posts/DisruptorWaitStrategy/7.png %}
等待資料時 CPU 依舊飆高。
{% img /images/posts/DisruptorWaitStrategy/8.png %}
read morePosts
Disruptor - High Performance Inter-Thread Messaging Library
Disruptor 是 LMAX 提出的高效線程通信套件,能夠以很低的延遲產生很大量的吞吐量,實務上 LMAX 藉此得以在一個線程裡每秒處理6百萬訂單。
高效線程通信套件這個詞彙如果太抽象,我們也可以將之視為高效低延遲的生產者與消費者模式框架,使用這個框架可以很容易的套用生產者與消費者模式,且整個模式的工作流程可輕易的設定與調動。
Disruptor 之所以能有如此優異的效能,是因為裡面運用了很多技術在。像是使用 Compare and swap (CAS) 去避開鎖的開銷,使用 memory barrier 去控制執行緒間的運行順序,使用 Cache line padding 避免 false sharing 的問題,以及預先將記憶體配置並重用以避免不必要的 GC 回收。
Disruptor 最經典的使用架構就是 LMAX 所提出的架構,分為三個部分,一個是輸入的 Disruptor,一個是商業邏輯處理的部份,最後是輸出的 Disruptor。
{% img /images/posts/Disruptor/1.png %}
輸入的 Disruptor 這邊,會先將進來的事件存起來,如果發生什麼問題,可以讓他重新運轉。接著會將事件傳送給其他 Slave 節點(LMAX 這邊是用 IP Multicasting 去同步所有 Slave 節點),以實現 HA 架構。最後是拆解任務與資料,讓後續商業邏輯的處理比較容易。
{% img /images/posts/Disruptor/2.png %}
商業邏輯處理這邊要注意的就是要盡可能的快速,所以需要的資料都放置在記憶體中是最好的,且要避免 IO 的處理。
輸出 Disruptor 這邊,則負責將資料合併,導到該去的地方。
整個架構就像下面這樣:
{% img /images/posts/Disruptor/3.png %}
Link Disruptor by LMAX-Exchange
read morePosts
Disruptor - Diamond: 1P – 3C
使用 Disruptor 時我們必須決定資料要怎樣在 Consumer 間流動,這有些常用的 Pattern 可供參考,只要熟悉這些 Pattern 那 Consumer 間有多複雜的協作應該都不是問題。
這邊要介紹的是 Diamond: 1P – 3C,一個 Producer 負責生產資料,兩個 Consumer 同時消費資料後,再交由第三個 Consumer 處理。其依賴關係圖會像這樣:
{% img /images/posts/DisruptorDiamond1P3C/1.png %}
可以進一步簡化成下面這樣:
{% img /images/posts/DisruptorDiamond1P3C/2.png %}
透過 DSL 的方式撰寫,只要同時將兩個 EventHandler 帶入 HandleEventWith,再用 Then 方法串接第三個 EventHandler 即可,像是下面這樣:
... var disruptor = new Disruptor.Dsl.Disruptor<Data>(() => new Data(), (int)Math.Pow(2,4), TaskScheduler.Default); disruptor.HandleEventsWith(new DataEventHandler("Handler1"), new DataEventHandler("Handler2")).Then(new DataEventHandler("Handler3")); var ringBuffer = disruptor.Start(); ... disruptor.Shutdown(); ... 是改用 Non-DSL 撰寫的話,本來的依賴關係圖形就會變成下面這樣:
{% img /images/posts/DisruptorDiamond1P3C/3.png %}
read morePosts
Disruptor - Multicast: 1P – 3C
使用 Disruptor 時我們必須決定資料要怎樣在 Consumer 間流動,這有些常用的 Pattern 可供參考,只要熟悉這些 Pattern 那 Consumer 間有多複雜的協作應該都不是問題。
這邊要介紹的是 Multicast: 1P – 3C,一個 Producer 負責生產資料,三個 Consumer 同時消費資料。其依賴關係圖會像這樣:
{% img /images/posts/DisruptorMulticast1P3C/1.png %}
可進一步簡化成下面這樣:
{% img /images/posts/DisruptorMulticast1P3C/2.png %}
透過 DSL 的方式撰寫,只要同時將三個 EventHandler 帶入 HandleEventWith 即可,像是下面這樣:
... var disruptor = new Disruptor.Dsl.Disruptor<Data>(() => new Data(), (int)Math.Pow(2,4), TaskScheduler.Default); disruptor.HandleEventsWith(new DataEventHandler("Handler1"), new DataEventHandler("Handler2"), new DataEventHandler("Handler3")); var ringBuffer = disruptor.Start(); ... disruptor.Shutdown(); … 是改用 Non-DSL 撰寫的話,本來的依賴關係圖形就會變成下面這樣:
{% img /images/posts/DisruptorMulticast1P3C/3.png %}
用程式來寫,就是三個 EventProcessor 共用同一個 Barrier。
read morePosts
Disruptor - Three Step Pipeline: 1P – 3C
使用 Disruptor 時我們必須決定資料要怎樣在 Consumer 間流動,這有些常用的 Pattern 可供參考,只要熟悉這些 Pattern 那 Consumer 間有多複雜的協作應該都不是問題。
這邊要介紹的是 Three Step Pipeline: 1P – 3C,一個 Producer 負責生產資料,三個 Consumer 接續消費資料。簡單說,這就是多執行緒程式常見的流水線 Pattern。其依賴關係圖會像這樣:
{% img /images/posts/DisruptorStepPipeline1P3C/1.png %}
可進一步簡化成下面這樣:
{% img /images/posts/DisruptorStepPipeline1P3C/2.png %}
透過 DSL 的方式撰寫,就是用 Then 去串接後續的 EventHandler,像是下面這樣:
... var disruptor = new Disruptor.Dsl.Disruptor<Data>(() => new Data(), (int)Math.Pow(2,4), TaskScheduler.Default); disruptor.HandleEventsWith(new DataEventHandler("Handler1")) .Then(new DataEventHandler("Handler2")) .Then(new DataEventHandler("Handler3")); var ringBuffer = disruptor.Start(); ... disruptor.Shutdown(); … 若是改用 Non-DSL 撰寫的話,依賴關係圖形就會變成下面這樣:
{% img /images/posts/DisruptorStepPipeline1P3C/3.png %}
用程式來寫,就是要建立一個 Barrier 將之帶入並建立 EventProcessor,接著將第一個 EventProcessor 的 Sequence 帶入建立出第二個 Barrier,再用第二個 Barrier 建立第二個 EventProcessor,最後用第二個 EventProcessor 的 Sequence 建立出第三個 Barrier,用第三個 Barrier 去建立第三個 EventProcessor 即可。
read morePosts
Disruptor - Unicast: 1P - 1C
使用 Disruptor 時我們必須決定資料要怎樣在 Consumer 間流動,這有些常用的 Pattern 可供參考,只要熟悉這些 Pattern 那 Consumer 間有多複雜的協作應該都不是問題。
最簡單的 Pattern 就是 Unicast: 1P - 1C,一個 Producer 負責生產資料,一個 Consumer 負責消費資料。依賴關係圖會像這樣:
{% img /images/posts/DisruptorUnicast1P1C/1.png %}
可以將之簡化成下面這樣:
{% img /images/posts/DisruptorUnicast1P1C/2.png %}
透過 DSL 的方式撰寫的話會像下面這樣:
... using Disruptor; namespace ConsoleApplication29 { … class Program { static void Main( string[] args) { var disruptor = new Disruptor.Dsl. Disruptor<Data>(() => new Data(), (int)Math .Pow(2,4), TaskScheduler.Default); disruptor.HandleEventsWith(new DataEventHandler("Handler1”)); var ringBuffer = disruptor.Start(); var idx = 0; while ( true) { var sequenceNo = ringBuffer.
read morePosts
Disruptor - Getting started
要使用 Disruptor 必須先將套件加入專案中,透過 NuGet 將之載入即可:
{% img /images/posts/DisruptorGettingStarted/1.png %}
套件載入後我們就可以開始來使用 Disruptor 了。首先,必須要撰寫 EventHandler,用來消費生產者所生產的資料。撰寫上很簡單,只要實作 IEventHandler 泛型介面即可,泛型介面要指定預期的資料型態,並在 OnEvent 方法中進行資料的處理。
像是如果要在收到資料時顯示一些相關的訊息在主控台上,我們就可像下面這樣撰寫 EventHandler:
... public class Data { public string Value { get; set; } } public class DataEventHandler : IEventHandler<Data> { public string Name { get; private set; } public DataEventHandler(string name) { this.Name = name; } public void OnEvent(Data data, long sequence, bool endOfBatch) { Console.WriteLine("Thread = {0}, Handler = {1}, Sequence = {2}, Value = {3}", Thread.
read morePosts
Disruptor - Ringbuffer
Ringbuffer 是 Disruptor 的核心部分,使用 Disruptor 一定會圍繞著 Ringbuffer,Producer 會往 Ringbuffer 塞資料,Consumer 會從 RingBuffer 消費資料,且必須要觀察 Ringbuffer 的使用狀況並視情況調整架構或是其大小。所以使用 Disruptor 必須要對 Ringbuffer 有一定的認知。
{% img /images/posts/DisruptorRingbuffer/1.png %}
Ringbuffer 是一頭尾串接的環形陣列,資料一邊循序的存放,一邊循序的消耗。就像下面這樣:
{% img /images/posts/DisruptorRingbuffer/2.gif %}
存放在內部的資料都會有一個對應的編號,用 sequence % buffer size 就可以知道資料存放在陣列的哪個位置,但 Disruptor Ringbuffer 這邊是用 Sequence & (buffer size - 1) 的方式去做,以取得較佳的效能,但 buffer size 必須為 2 ^ n。
這邊簡單的做個測試…
usingSystem; usingSystem.Diagnostics; namespaceConsoleApplication25 { classProgram { staticvoidMain(string[] args) { varcounts = newint[] { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; foreach(varcountincounts) { Console.
read moreTag: T4
Posts
T4 Template - T4Enum 1.0
.NET 列舉的很多操作都會有難以避免的 Boxing/UnBoxing,像是要取得特定列舉值的列舉名,取得所有的列舉名,取得所有的列舉值,取得列舉值的 Attribute,都無法避免 Boxing/UnBoxing 的發生。
{% img /images/posts/T4Enum/1.png %}
這邊筆者嘗試用 T4 來解這問題,用 T4 範本可以遍尋專案內的所有列舉,產生對應的輔助類別與擴充方法,藉此避開列舉操作的 Boxing/UnBoxing 問題。
程式可至 NuGet Gallery | LevelUp.T4Enum 1.0.0 這邊抓取。
實際使用會像是下面這樣:
using System; using T4Enum; using T4Enum.Extensions; namespace ConsoleApplication7 { enum Permission { Function1, Function2, Function3 } class Program { static void Main(string[] args) { Console.WriteLine(Enums.Permission.Function1.Name); Console.WriteLine((int)Enums.Permission.Function1.Value); Console.WriteLine(Enums.Permission[Permission.Function2].Name); Console.WriteLine((int)Enums.Permission[Permission.Function2].Value); Console.WriteLine(Enums.Permission.GetName(Permission.Function3)); Console.WriteLine(Permission.Function3.GetName()); foreach (var item in Enums.Permission) { Console.WriteLine(item.Name); Console.WriteLine((int)item.Value); } foreach (var name in Enums.Permission.GetNames()) { Console.
read morePosts
T4 Template - JsResource.tt
在撰寫 ASP.NET 時,.NET 程式部分可用 Resource 去做多語的部分,JavaScript 這邊雖然也有 L10N 的解決方案,但是若走不同的解決方案,難以避免有些詞彙會重複定義。
這邊筆者嘗試使用 T4 來解決這樣的問題。
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ assembly name="System.Windows.Forms" #> <#@ assembly name="System.Core" #> <#@ assembly name="System.Xml" #> <#@ assembly name="EnvDTE" #> <#@ assembly name="Microsoft.VisualStudio.OLE.Interop" #> <#@ assembly name="Microsoft.VisualStudio.Shell" #> <#@ assembly name="Microsoft.VisualStudio.Shell.Interop" #> <#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #> <#@ import namespace="System.Resources" #> <#@ import namespace="System.Diagnostics" #> <#@ import namespace="System.Collections" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.
read morePosts
T4 template - CultureNames.tt
.NET 在操作 Culture 時,免不了要帶入 CultureInfo 的 Name,多半是用 Hard code 的形式帶入,像是下面這樣:
... var currentThread = Thread.CurrentThread; currentThread.CurrentCulture = CultureInfo.GetCultureInfo("zh-tw"); ... {% img /images/posts/T4CultureNames/1.png %}
這邊筆者做了個 T4 Template,期望能解決這樣的問題。
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Globalization" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> namespace System.Globalization { public static class CultureNames { <# var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures); var length = cultures.
read morePosts
T4MVC - Add Timestamp To Static Links
T4MVC 除了解決 ASP.NET MVC Magic String 的問題外,還能解決常見的網頁 Cache 問題。
只要在 T4MVC.tt.settings.xml 設定檔中將 AddTimestampToStaticLinks 設為 True 就可以了。
... <AddTimestampToStaticLinks>True</AddTimestampToStaticLinks> ... 這樣使用 T4MVC 去取用靜態檔案的位置時,T4MVC 就會幫我們在網址後面依照檔案的修改時間去附加雜湊值,避免前端快取。
read morePosts
T4MVC - Generate a single file with everything
T4MVC 預設在產生程式碼時會依 Controller 產生不同的檔案,這樣會在專案目錄下產生很多的檔案,然而以自動產出的檔案來說,只要產生無誤,功能都正常,那麼產生的程式是不是照 Controller 分開,說實話一點都不重要。
且以現階段來說,T4MVC 無法脫離 Visual Studio 運行,因此 CI Server 無法運行 T4MVC 去產生檔案,這樣的設定使得每新增一個檔案就必需記得 Commit 對應的產出檔到版控上,反而造成不便。
好在 T4MVC 有留這部份的設定彈性,我們只要在 T4MVC.tt.settings.xml 設定檔中將 SplitIntoMultipleFiles 設為 False 即可。
... <!-- If true,the template output will be split into multiple files. --> <SplitIntoMultipleFiles>false</SplitIntoMultipleFiles> ...
read morePosts
T4MVC - A T4 template for ASP.NET MVC
玩過 ASP.Net MVC 的應該都有注意到,在寫 ASP.Net MVC 時會用到很多 Magic String。像是在取網址位置時,會需要帶入 Controller Name 以及 Action Name。
@Url.Action("Home", "Index") 在設定連結時,會需要帶入連結名稱、 Controller Name 以及 Action Name。
@Html.ActionLink("Home", "Index", "Home") 導到另外一個 Action 去處理時,又需要 Action Name。
return RedirectToAction("About"); 可以看到這些叫用帶入的都是字串,而且類似的地方還有很多,所以整個 ASP.Net MVC 寫下來會發現 Magic String 充斥在程式中。這樣的問題不僅讓我們開發上無 Intellisense 可用,編寫時不是那麼便利,修改時也容易因此而有所遺漏。
這篇要介紹的 T4MVC 就是一能解決這樣問題的 T4 範本套件。 T4MVC 透過 T4 去遍巡專案內的檔案,產生一些輔助的類別與方法的多載,巧妙的避開 Magic String 的問題。這邊可先快速的瀏覽一下 Channel 9 的相關影片,體驗一下 T4MVC 的魅力。
使用前需先透過 NuGet 搜尋並安裝 T4MVC 套件。
{% img /images/posts/T4MVC/1.png %}
{% img /images/posts/T4MVC/2.png %}
read morePosts
T4 Template - Debugging a T4 Text Template
要對 T4 Template 進行偵錯,首先需將 Template 的 Debug 設定開啟。
{% img /images/posts/DebugT4Template/1.png %}
接著在要除錯的位置上加入中斷點。
{% img /images/posts/DebugT4Template/2.png %}
然後在 T4 Template 檔案上按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中點選 ‘Debug T4 Template’ 選單選項,即可開始進行偵錯。
{% img /images/posts/DebugT4Template/3.png %}
{% img /images/posts/DebugT4Template/4.png %}
{% img /images/posts/DebugT4Template/5.png %}
Link Debugging a T4 Text Template Tiny Happy Features #1 - T4 Template Debugging in Visual Studio 2012 - Scott Hanselman Oleg Sych - » T4 Tutorial: Debugging Code Generation Files
read morePosts
Devart T4 Editor - VS add-in for editing T4 templates
Visual Studio 內建的 T4 Template Editor 很陽春,不僅無法 Syntax Highlighting,也無法 Intellisense,在除錯時查看變數也非常不便,更無法靜態程式碼分析及 Format 程式碼,造成開發 T4 Template 的效率大幅降低。
Devart T4 Template 是ㄧ Visual Studio 的擴充套件,能解決這些煩人的問題,提升 T4 Template 的開發速度。
套件可至 Download Devart T4 Editor 這邊下載安裝。
{% img /images/posts/DevartT4Editor/1.png %}
{% img /images/posts/DevartT4Editor/2.png %}
{% img /images/posts/DevartT4Editor/3.png %}
{% img /images/posts/DevartT4Editor/4.png %}
{% img /images/posts/DevartT4Editor/5.png %}
{% img /images/posts/DevartT4Editor/6.png %}
安裝完重啟 Visual Studio,開啟 T4 Template 檔案,可以看到 Syntax Highlighting 已被支援。
{% img /images/posts/DevartT4Editor/7.png %}
Intrllisense 支援。
read morePosts
T4 template - Auto generate ConnectionString's wrapper class
在 .Net 程式中要使用資料庫的連線字串,多半我們會將資料庫的連線字串設定在 Config 檔中,然後透過 ConfigurationManager.ConnectionStrings 帶入對應的 Key 去將之取出來使用。
用這樣的撰寫方式,連線字串名稱打錯無法立即的被意識到,連線字串名稱調動時也很容易漏改,造成系統運行時的錯誤。因此有的人會將連線字串這邊再包一層,透過這層物件的屬性去取得連線字串,將連線字串的修改都在這層處理,減少人為造成的錯誤。
然而這樣的做法並無法完全解決問題,因為多包的那層還是人工下去做的,仍舊是無法避免連線名稱鍵錯的問題,連線字串變動時仍是會有改錯的可能。故這邊筆者嘗試使用 T4 template,讀取專案的 config 檔,動態產生強型別物件,提供連線字串給系統使用。
首先我們要為專案加入一個 t4 template 檔。
然後將其程式碼替換成下面這樣。
<#@ template debug ="true" hostspecific="True" language= "C#" #> <#@ assembly name ="EnvDTE" #> <#@ assembly name ="System.Core.dll" #> <#@ assembly name ="System.Configuration" #> <#@ assembly name ="System.Xml" #> <#@ import namespace ="System.Collections.Generic" #> <#@ import namespace ="System.Configuration" #> <#@ import namespace ="EnvDTE" #> <#@ import namespace ="System.Xml" #> <#@ output extension =".
read moreTag: T4Enum
Posts
T4 Template - T4Enum 1.0
.NET 列舉的很多操作都會有難以避免的 Boxing/UnBoxing,像是要取得特定列舉值的列舉名,取得所有的列舉名,取得所有的列舉值,取得列舉值的 Attribute,都無法避免 Boxing/UnBoxing 的發生。
{% img /images/posts/T4Enum/1.png %}
這邊筆者嘗試用 T4 來解這問題,用 T4 範本可以遍尋專案內的所有列舉,產生對應的輔助類別與擴充方法,藉此避開列舉操作的 Boxing/UnBoxing 問題。
程式可至 NuGet Gallery | LevelUp.T4Enum 1.0.0 這邊抓取。
實際使用會像是下面這樣:
using System; using T4Enum; using T4Enum.Extensions; namespace ConsoleApplication7 { enum Permission { Function1, Function2, Function3 } class Program { static void Main(string[] args) { Console.WriteLine(Enums.Permission.Function1.Name); Console.WriteLine((int)Enums.Permission.Function1.Value); Console.WriteLine(Enums.Permission[Permission.Function2].Name); Console.WriteLine((int)Enums.Permission[Permission.Function2].Value); Console.WriteLine(Enums.Permission.GetName(Permission.Function3)); Console.WriteLine(Permission.Function3.GetName()); foreach (var item in Enums.Permission) { Console.WriteLine(item.Name); Console.WriteLine((int)item.Value); } foreach (var name in Enums.Permission.GetNames()) { Console.
read moreTag: Log4net
Posts
log4net - BufferingForwardingAppender
為了調效 log4net RollingFileAppender 的性能做了個簡單的測試,測試程式如下:
using System; using System.Diagnostics; using log4net; using log4net.Config; namespace ConsoleApplication27 { class Program { static void Main(string[] args) { XmlConfigurator.Configure(); var count = 100000; var logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); var sw = Stopwatch.StartNew(); for (var idx = 0; idx < count; ++idx) { logger.Debug(idx.ToString()); } Console.WriteLine(sw.ElapsedMilliseconds); } } } {% img /images/posts/log4netBufferingForwardingAppender/1.png %}
套上 BufferingForwardingAppender。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> </configSections> <log4net> <root> <level value="ALL"/> <appender-ref ref="BufferingForwardingAppender"/> </root> <appender name="BufferingForwardingAppender" type="log4net.
read morePosts
log4net - RollingFileAppender's CountDirection Property
log4net 在使用 RollingFileAppender 去做 Log 的紀錄時,我們需要注意 CountDirection 的設定。設定值大於 0,表示以遞增的方式 Rolling。反之,表示以遞減的方式 Rolling。
{% img /images/posts/Log4NetCountDirection/1.png %}
該設定預設值為 -1,所以當新的檔案要產生時,他需要先用 Rename 將檔案往後擠才行,可以想見這樣會有不必要的效能耗費。透過 Process Monitor 可以很清楚的看到背後的運作。
{% img /images/posts/Log4NetCountDirection/2.png %}
所以可以的話,我們可以將設定值改為 1,用以取得較好的效能。
這邊筆者簡單的做個試驗,寫了一個簡單的程式讓它持續的寫 log,而 log4net 設定每 1 KB 產生一個檔案,用以監測效能上的影響。
using log4net; using log4net.Config; using System; using System.Diagnostics; namespace ConsoleApplication6 { class Program { static void Main(string[] args) { XmlConfigurator.Configure(); var count = 500; var logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); Console.WriteLine("{0} ms", DoTest(count, () => { logger.Debug("test"); })); } static long DoTest(int count, Action action) { var sw = Stopwatch.
read moreTag: LeetCode
Posts
LeetCode - Missing Number
LeetCode 的 Missing Number 題目如下:
Given an array containing n distinct numbers taken from 0, 1, 2, …, n, find the one that is missing from the array.
For example,
Given nums = [0, 1, 3] return 2.
Note:
Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?
簡單的說該方法會被帶入一個陣列,裡面的元素為 0 到 n 不重複的數值,需找到並回傳該陣列缺少的數值。像是如果帶入的陣列是 [0, 1, 3],該陣列跳過了 2,所以回傳值會是 2。
因為長度為 n 的陣列如果沒有跳號,裡面的元素應該是 0, …, n,且缺少的數值只有一個。所以我們可以把帶入的陣列跟本來預期的值相減後加總,然後用陣列的長度與之相減。
read morePosts
LeetCode - Move Zeroes
LeetCode 的 Move Zeroes 題目如下:
Given an array nums, write a function to move all 0’s to the end of it while maintaining the relative order of the non-zero elements.
For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].
Note:
You must do this in-place without making a copy of the array.
Minimize the total number of operations.
read morePosts
LeetCode - Number of 1 Bits
LeetCode 的 Number of 1 Bits 題目如下:
Write a function that takes an unsigned integer and returns the number of ’1’ bits it has (also known as the Hamming weight).
For example, the 32-bit integer ’11’ has binary representation 00000000000000000000000000001011, so the function should return 3.
簡單的說就是給予一個整數,回傳該數值用二進制表示時有多少個 1。
這邊我們可以用 while 迴圈持續的用 n-1 去做 and 運算,並計算運行次數,直至 n 變為 0。
public class Solution { public int HammingWeight(uint n) { int count = 0; while(n > 0) { n &= (n-1); ++count; } return count; } } {% img /images/posts/NumberOf1Bits/1.
read morePosts
LeetCode - Power of Three
LeetCode 的 Power of Three 題目如下:
Given an integer, write a function to determine if it is a power of three.
簡單說他要的是要一個功能,給予一個整數,能判別是否為 3 的冪次。
這邊我們只要判斷數值是否大於零,且是否可整除 1162261467 即可。1162261467 是來自 3^19,為最大的 3 冪次整數,如果某數值可以將之整除,即代表該數值為 3 的冪次。
public class Solution { public bool IsPowerOfThree(int n) { return n > 0 && 1162261467 % n == 0; } } {% img /images/posts/PowerOfThree/1.png %}
Link Power of Three | LeetCode OJ
read morePosts
LeetCode - Add Digits
LeetCode 的 Add Digits 題目如下:
Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.
For example:
Given num = 38, the process is like: 3 + 8 = 11, 1 + 1 = 2. Since 2 has only one digit, return it.
簡單的說就是給予一個整數,反覆的將每個位數值加總,直至數值只有一個位數為止。
最直覺得解法就是用迴圈下去處理,判斷數值是否大於等於 10,如果大於等於 10,則將每個位數的數值加總取代本來的數值。如果數值小於 10,則直接將數值回傳。
public class Solution { public int AddDigits(int num) { var value = num; while(value >= 10) { var originalValue = value; var newValue = 0; do { newValue += originalValue / 10; originalValue = originalValue % 10; }while(originalValue >= 10); newValue += originalValue; value = newValue; } return value; } } {% img /images/posts/AddDigits/1.
read morePosts
LeetCode - Happy Number
LeetCode 的 Happy Number 題目如下:
Write an algorithm to determine if a number is “happy”.
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
read morePosts
LeetCode - Roman to Integer
LeetCode 的 Roman to Integer 題目如下:
Given a roman numeral, convert it to an integer.
Input is guaranteed to be within the range from 1 to 3999.
簡單的說他是要一個功能,當給予一個羅馬數字,能將它轉換成對應的數值。
這需要參考 羅馬數字 - 維基百科,自由的百科全書,看羅馬數字背後的規則。
羅馬數字有七個字母組成,分別為 I(1)、V(5)、X(10)、L(50)、C(100)、D(500)和 M(1000)。當字母重複出現,則表示數值為重複倍。如果較大的字母右邊放上較小的字母,表示兩數要相加,反之表示大數要減小數。其它的規則跟這題無關,就不提了。
所以像是 4 對應到的就是 IV (5 - 1),XX 對應到 20 (10 + 10), VIII 對應到 8 (5 + 1 + 1 + 1),以此類推。
這邊筆者是用一個字典檔存放羅馬數字字元與其對應的數值,從輸入參數的後面往前處理,如果前一個字元對應到的數值大於現在這字元的數值,則將回傳值減去當前數值,反之則加上當前數值。
public class Solution { public int RomanToInt(string s) { var dict = new Dictionary<char, int>() { {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000}, }; var ret = 0; var prev = -1; for(var idx = s.
read morePosts
LeetCode - Length of Last Word
LeetCode 的 Length of Last Word 題目如下:
Given a string s consists of upper/lower-case alphabets and empty space characters ’ ‘, return the length of last word in the string.
If the last word does not exist, return 0.
Note: A word is defined as a character sequence consists of non-space characters only.
For example,
Given s = “Hello World”,
return 5.
簡單說他要的是要一個功能,當給予一個由大小寫字元與空字元所組成的字串,會回傳最後一個 Word 的長度。
如果最後一個 Word 不存在,則回傳0。
舉個例子來說:
給予 “Hello World”, 會回傳 5.
read morePosts
LeetCode - Power of Two
LeetCode 的 Power of Two 題目如下:
Given an integer, write a function to determine if it is a power of two.
簡單說他要的是要一個功能,給予一個整數,能判別他是否是 2 的冪次。
可以簡單的用迴圈反覆的除以 2,看是否可以整除。
public class Solution { public bool IsPowerOfTwo(int n) { if (n == 0) return false; if (n == 1) return true; var mod = -1; do { mod = n % 2; n /= 2; } while(n != 1 && mod == 0); return n == 1 && mod == 0; } } 也可以用位元運算下去處理,寫起來會更為簡潔,像是這樣:
read morePosts
LeetCode - Valid Anagram
LeetCode 的 Valid Anagram 題目如下:
Given two strings s and t, write a function to determine if t is an anagram of s.
For example,
s = “anagram”, t = “nagaram”, return true.
s = “rat”, t = “car”, return false.
Note:
You may assume the string contains only lowercase alphabets.
簡單說他要的是要一個功能,當給予兩個字串,能判斷出這兩個字串是否只是不同的組合順序。
舉個例子來說, s = “anagram”, t = “nagaram”, 回傳 ture.
s = “rat”, t = “car”, 回傳 false.
這邊我們可以統計兩個字串中的每個字元出現的個數是否一樣,也可以像筆者這樣簡單的將字串排序後直接比對。
read morePosts
LeetCode - Plus One
LeetCode 的 Plus One 題目如下:
Given a non-negative number represented as an array of digits, plus one to the number.
The digits are stored such that the most significant digit is at the head of the list.
簡單說他要的是要一個類似加法器的功能。給予一個非負的數值陣列用以表示一個非負的數值,能回傳加一後的數值。
這邊筆者是用 for 迴圈從輸入的陣列尾端往前遍巡,第一個處理的陣列元素加一後如果有超過 10,則將當前數值改為除 10 後的餘數,且進位的值帶到下一個陣列數值去做相同的處理。最後跑完如果無進位值,則把當前處理完的陣列回傳。若有進位值,則將進位值與當前處理完的陣列合併回傳。
public class Solution { public int[] PlusOne(int[] digits) { var carry = 1; var result = new int[digits.Length]; for(var idx = digits.Length - 1; idx >= 0; --idx) { var digit = digits[idx]; var newDigit = digit + carry; carry = newDigit / 10; result[idx] = newDigit % 10; } if(carry == 0) return result; return (new int[]{carry}).
read morePosts
LeetCode - Valid Parentheses
LeetCode 的 Valid Parentheses 題目如下:
Given a string containing just the characters ‘(’, ‘)’, ‘{’, ‘}’, ‘[’ and ‘]’, determine if the input string is valid.
The brackets must close in the correct order, “()” and “()[]{}” are all valid but “(]” and “([)]” are not.
簡單說他要的是要一個功能,帶入的字串只會由 ‘(’、’)’、’{’, ‘}’、’[’ 與 ‘]’ 這幾個字元所組成,需判斷輸入是否正確。
輸入的字元需成對並符合一定的順序,成對的字元內不可夾雜不成對的字元,像是 “()” 與 “()[]{}” 就是正確的格式,而 “(]” 與 “([)]” 不是。
這邊筆者是用 Dictionary 去紀錄成對的字元。然後將帶入的字串字元依序處理。如果其字元跟堆疊最後的字元成對,則將堆疊最後的字元取出。若不成對則將當前字元放入堆疊內。
堆疊在使用前會先放一個空的字元,如果處理到最後堆疊內還剩一個字元,代表帶入的字串是正確的,反之則帶入的字串是錯誤的。
public class Solution { public bool IsValid(string s) { var validChars = new Dictionary<char, char>() { {'(', ')'}, {'{', '}'}, {'[', ']'} }; var length = s.
read morePosts
LeetCode - Contains Duplicate III
LeetCode 的 Contains Duplicate III 題目如下:
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.
簡單說他要的是要一個功能,當給予一個整數陣列,能找出兩個不同的索引值,這兩個索引值的差距最多為 k,且這兩個索引值對應整數陣列所得到的整數值相差最多為 t。
這邊筆者是用迴圈搭配 Dictionary 來處理,Dictionary 內只存放 k 筆資料,每次處理一個數值時就去查看 Dictionary 內是否有相差 t 的數值。 如果有則去判斷索引值的差距是否在 k 內,是的話則回傳 true。
public class Solution { public bool ContainsNearbyAlmostDuplicate(int[] nums, int k, int t) { var length = nums.
read morePosts
LeetCode - Contains Duplicate II
LeetCode 的 Contains Duplicate II 題目如下:
Given an array of integers and an integer k, find out whether there there are two distinct indices i and j in the array such that nums[i] = nums[j] and the difference between i and j is at most k.
簡單說他要的是要一個功能,當給予一個整數陣列與一個整數值 k,能找出兩個不同的索引值,這兩個索引值的差距最多為 k,且其對應到的整數陣列的值是相同的。
這邊筆者是用迴圈搭配 Dictionary 來處理,每跑一個數就去判斷 Dictionary 是否有含有一樣的數值,如果有則去判斷索引值的差距是否在 k 內,是的話則回傳 true。如果不是或是數值不存在在 Dictionary 內,則將其加入或是將 Dictionary 中的索引值更新,便於後續查找。如果整個陣列跑完都找不到結果,將 false 回傳。
public class Solution { public bool ContainsNearbyDuplicate(int[] nums, int k) { var length = nums.
read morePosts
LeetCode - Contains Duplicate
LeetCode 的 Contains Duplicate 題目如下:
Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.
簡單說他要的是要一個功能,當給予一個整數陣列,能找出陣列中是否有重複的數值。如果有重複則方法回傳 true,如果沒有重複則回傳 false。
這邊筆者是用迴圈搭配 HashSet 來處理,每跑一個數就去判斷 HashSet 是否有重複的資料,有則回傳 true,沒有則加到 HashSet 中。
public class Solution { public bool ContainsDuplicate(int[] nums) { var length = nums.Length; var hs = new HashSet<int>(); for(var idx = 0; idx < length; ++idx) { var num = nums[idx]; if(hs.
read moreTag: Bootstrap
Posts
Bootstrap - Use Glyphicons with bower
當我們透過 Bower 來使用 Bootstrap Glyphicons。
{% img /images/posts/GlyphiconsWithBower/1.png %}
下載下來的 Glyphicons CSS 內會用相對路徑指定所要使用的 Font 位置,但這樣在載入 CSS 時會指不到正確的 Font。
... @font-face { font-family: 'Glyphicons Halflings'; src: url('../fonts/glyphicons-halflings-regular.eot'); src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype') , url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff') , url('../fonts/glyphicons-halflings-regular.ttf') format('truetype') , url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); } ... {% img /images/posts/GlyphiconsWithBower/2.png %}
當然我們可以透過 Grunt、Gupl 之類的自動化工具將路徑改掉,但這樣的做法感覺並不是很好,因此這邊筆者是使用自己的 CSS 將 Font 的位置改掉。
... @font-face { font-family: 'Glyphicons Halflings'; src: url('/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot'); src: url('/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype') , url('/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff') format('woff'), url('/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.
read moreTag: FontAwesome
Posts
FontAwesome - Use FontAwesome with bower
當我們透過 Bower 來使用 FontAwesome。
{% img /images/posts/FontAwesomeWithBower/1.png %}
下載下來的 FontAwesome CSS 內會用相對路徑指定所要使用的 Font 位置,但這樣在載入 CSS 時會指不到正確的 Font。
... @font-face { font-family: 'FontAwesome'; src: url('../fonts/fontawesome-webfont.eot?v=4.5.0'); src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype') , url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff') , url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype') , url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg') ; font-weight: normal; font-style: normal; } ... {% img /images/posts/FontAwesomeWithBower/2.png %}
當然我們可以透過 Grunt、Gupl 之類的自動化工具將路徑改掉,但這樣的做法感覺並不是很好,因此這邊筆者是使用自己的 CSS 將 Font 的位置改掉。
... @font-face { font-family: 'FontAwesome'; src: url('/wwwroot/lib/fontawesome/fonts/fontawesome-webfont.eot?v=4.5.0'); src: url('/wwwroot/lib/fontawesome/fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype') , url('/wwwroot/lib/fontawesome/fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('/wwwroot/lib/fontawesome/fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('/wwwroot/lib/fontawesome/fonts/fontawesome-webfont.
read moreTag: Bower
Posts
Bower - Using Bower in Visual Studio 2015
Visual Studio 2015 開始支援 Bower,使用時需先為專案加入 Bower Configuration File。
{% img /images/posts/BowerInVS2015/1.png %}
Bower Configuration File 加入後,也會順帶加入 .bowerrc 檔,這邊會指定 Bower 套件放置的位置。
{% img /images/posts/BowerInVS2015/2.png %}
這邊我們可以開啟 bower.json 檔案設定所要使用的 Bower 套件。
{% img /images/posts/BowerInVS2015/3.png %}
或是使用 Manage Bower Packages... 加入 Bower 套件。
{% img /images/posts/BowerInVS2015/4.png %}
{% img /images/posts/BowerInVS2015/5.png %}
在設定 Bower 套件時,我們可能會需要調用 Bower 指令查閱一些資訊,像是 Bower 套件的版本等,這邊可透過 Package Manager Console 視窗調用。
{% img /images/posts/BowerInVS2015/6.png %}
設定完按下編譯或是滑鼠右鍵快顯選單中的 Restore Packages 選單選項,即可透過 Bower 下載 Bower 套件。
read morePosts
Bower - Bower prune
Bower prune 可用來移除未被使用的 bower 套件。
如果有 Bower 套件未被 bower.json 檔參照到,當呼叫 bower prune 時就會被移除。
像是這邊本地已安裝了 Bootstrap 與 JQuery 套件,但這套件並未在 bower.json 有被參照,因此當呼叫了 bower prune 時就會被移除。
{% img /images/posts/BowerPrune/1.png %}
read morePosts
Bower - Bower lookup
Bower lookup 可以查閱 Bower 套件的位置。
使用方式如下:
bower lookup <package> 像是要查閱 jQuery 套件的位置,可以輸入 bower lookup jquery。
{% img /images/posts/BowerLookup/1.png %}
read morePosts
Bower - Bower info
Bower info 可用來查詢 Bower 套件的資訊。
使用方式如下:
bower info <package> bower info <package>#<version> 如果要查詢 jQuery 套件的資訊,可以輸入 bower info jquery。這邊可以看到他會顯示該套件所用的 bower.json 資訊,以及可使用的版本。
{% img /images/posts/BowerInfo/1.png %}
{% img /images/posts/BowerInfo/2.png %}
如果要查閱特定版本,像是 jQuery 1.0.1,可以輸入命令 bower info jquery#1.0.1。
{% img /images/posts/BowerInfo/3.png %}
read morePosts
Bower - Bower cache clean
Bower cache clean 可用來清除 Bower 套件的快取。
只要叫用命令 bower cache clean 即可。
{% img /images/posts/BowerCacheClean/1.png %}
read morePosts
Bower - Bower cache list
Bower cache list 可用來查閱 bower 套件 cache 的情況。
Bower 套件在使用時若有需要,Bower 會將套件快取在本地,像是用 bower install 或是 bower info 叫用時就會進行對應的快取。
像是筆者前面安裝了 Bootstrap,用 bower cache list 查看就會查閱到 Bootstrap 與 jQuery 已經進行了本地快取。
{% img /images/posts/BowerCacheList/1.png %}
read morePosts
Bower - Bower update
Bower update 會根據 bower.json 的設定下去更新 bower 套件。
使用方式如下:
bower update bower update <package> 像是這邊筆者安裝了 jQuery 1.0.1 的版本,開啟 bower.json 將其版號改為 2.1.4,接著運行 bower update jquery,安裝的 jQuery 版本就會變為 2.1.4。
{% img /images/posts/BowerUpdate/1.png %}
read morePosts
Bower - Bower list
Bower list 可用來列出安裝的 bower 套件,以及其之間的依賴關係。
使用方式如下:
bower list 像是如果本地已安裝了 jQuery 與 Bootstrap。
{% img /images/posts/BowerList/1.png %}
那當輸入命令 bower list,則會像下面這樣列出安裝的套件,且會用樹狀結構顯示其依賴關係。
{% img /images/posts/BowerList/2.png %}
read morePosts
Bower - Bower uninstall
Bower uninstall 可用來移除 bower 的 package。
使用方式如下:
bower uninstall <package> 像是要移除安裝的 jQuery bower 套件,可以下 bower uninstall jquery。
{% img /images/posts/BowerUninstall/1.png %}
{% img /images/posts/BowerUninstall/2.png %}
read morePosts
Bower - Bower install
Bower install 可用來安裝 bower 的 package 以及其依類的套件。
使用方式如下:
bower install bower install <package> bower install <package>#<version> bower install 會依據 bower.json 的設定下去安裝 bower 套件。
如果指定安裝 bower 套件,可以直接在 bower install 後接上 bower 套件的名稱。像是要安裝 jQuery,我們就可以下 bower install jquery。
{% img /images/posts/BowerInstall/1.png %}
{% img /images/posts/BowerInstall/2.png %}
如果要安裝特定版本的 bower 套件,就是在 bower install 後接上 bower 套件名稱,再用 # 串接 bower 套件的版本。像是 bower install jquery#2.2.0。
如果想在安裝時一併寫入 bower.json 檔,可加帶 –save。
read morePosts
Bower - Bower search
Bower search 可用來搜尋 bower 的 package。
使用方式如下:
bower search <package> 像是要搜尋 jQuery 的 package,就可以下 bower search jquery。
{% img /images/posts/BowerSearch/1.png %}
read morePosts
Bower - Bower init
Bower init 可用來建立 bower.json 檔。
只要呼叫 bower init,然後依序填寫詢問的問題即可:
{% img /images/posts/BowerInit/1.png %}
填完後即會在當前目錄產生對應的 bower.json 檔。
{% img /images/posts/BowerInit/2.png %}
read morePosts
Bower - Bower help command
Bower help command 可以用來查詢 bower 的命令。
使用方式如下:
bower help bower help <command> 如果要查閱整個 Bower 有哪些命令可以使用,可直接叫用 bower help。
{% img /images/posts/BowerHelpCommand/1.png %}
如果要查閱 Bower 的某個命令用法,像是 install 命令,可叫用 bower help install。
{% img /images/posts/BowerHelpCommand/2.png %}
read morePosts
Bower - Install Bower
Bower 依賴於 Node.js 與 Git,安裝 Bower 需透過 Node.js 內的 npm,只要透過下列 npm 命令安裝即可:
npm install -g bower {% img /images/posts/InstallBower/1.png %}
而 Bower 套件的安裝與使用會用到 Git,所以記得也要將之安裝。
如果是 Ubuntu 用戶,可以透過下列命令將整個環境安裝起來:
sudo apt-get purge nodejs npm sudo apt-get update sudo apt-get install -y python-software-properties python g++ make sudo add-apt-repository ppa:chris-lea/node.js sudo apt-get update sudo apt-get install -y nodejs sudo apt-get install -y git sudo npm install -g bower
read moreTag: T4MVC
Posts
T4MVC - VS2015 Update 1 causes an error - Identifier Expected
T4MVC 在 Visual Studio 2015 安裝完 Update 1 後,產生的程式碼會像這樣。
public override void ExecuteResult(System.Web.Mvc.ControllerContext ) { } 可以看到 ExecuteResult 方法的參數消失了,所以編譯時會報 Identifier Expected 的錯誤。
{% img /images/posts/T4MVCIdentifierExpected/1.png %}
若要解決這問題,可到 Update for Microsoft Visual Studio 2015 (KB3110221) 這邊下載更新套件,安裝後即可解決此問題。
Link VS2015 Update 1 causes an error - Identifier Expected · Issue #54 · T4MVC/T4MVC Update for Microsoft Visual Studio 2015 (KB3110221)
read morePosts
T4MVC - Add Timestamp To Static Links
T4MVC 除了解決 ASP.NET MVC Magic String 的問題外,還能解決常見的網頁 Cache 問題。
只要在 T4MVC.tt.settings.xml 設定檔中將 AddTimestampToStaticLinks 設為 True 就可以了。
... <AddTimestampToStaticLinks>True</AddTimestampToStaticLinks> ... 這樣使用 T4MVC 去取用靜態檔案的位置時,T4MVC 就會幫我們在網址後面依照檔案的修改時間去附加雜湊值,避免前端快取。
read morePosts
T4MVC - Generate a single file with everything
T4MVC 預設在產生程式碼時會依 Controller 產生不同的檔案,這樣會在專案目錄下產生很多的檔案,然而以自動產出的檔案來說,只要產生無誤,功能都正常,那麼產生的程式是不是照 Controller 分開,說實話一點都不重要。
且以現階段來說,T4MVC 無法脫離 Visual Studio 運行,因此 CI Server 無法運行 T4MVC 去產生檔案,這樣的設定使得每新增一個檔案就必需記得 Commit 對應的產出檔到版控上,反而造成不便。
好在 T4MVC 有留這部份的設定彈性,我們只要在 T4MVC.tt.settings.xml 設定檔中將 SplitIntoMultipleFiles 設為 False 即可。
... <!-- If true,the template output will be split into multiple files. --> <SplitIntoMultipleFiles>false</SplitIntoMultipleFiles> ...
read morePosts
T4MVC - A T4 template for ASP.NET MVC
玩過 ASP.Net MVC 的應該都有注意到,在寫 ASP.Net MVC 時會用到很多 Magic String。像是在取網址位置時,會需要帶入 Controller Name 以及 Action Name。
@Url.Action("Home", "Index") 在設定連結時,會需要帶入連結名稱、 Controller Name 以及 Action Name。
@Html.ActionLink("Home", "Index", "Home") 導到另外一個 Action 去處理時,又需要 Action Name。
return RedirectToAction("About"); 可以看到這些叫用帶入的都是字串,而且類似的地方還有很多,所以整個 ASP.Net MVC 寫下來會發現 Magic String 充斥在程式中。這樣的問題不僅讓我們開發上無 Intellisense 可用,編寫時不是那麼便利,修改時也容易因此而有所遺漏。
這篇要介紹的 T4MVC 就是一能解決這樣問題的 T4 範本套件。 T4MVC 透過 T4 去遍巡專案內的檔案,產生一些輔助的類別與方法的多載,巧妙的避開 Magic String 的問題。這邊可先快速的瀏覽一下 Channel 9 的相關影片,體驗一下 T4MVC 的魅力。
使用前需先透過 NuGet 搜尋並安裝 T4MVC 套件。
{% img /images/posts/T4MVC/1.png %}
{% img /images/posts/T4MVC/2.png %}
read moreTag: TypeScript
Posts
TypeScript - Generics
TypeScript 支援泛型語法,使用方式如下:
function GenericsFunction<T>(param:T) { ... } ... class GenericsClass<T> { GenericsField:T; GenericsMethod(param:T) { ... } } 最後附上個簡單的使用範例:
function ShowMessage<T>(message:T) { alert(message); } ShowMessage<string>("test"); ShowMessage<number>(123); {% img /images/posts/TypeScriptGenerics/1.png %}
read morePosts
TypeScript - Class
TypeScript 的類別透過 class 關鍵字宣告,透過 new 關鍵字建立物件實體。
class MyClass { ... } var obj = new MyClass(); ... 建構子的透過 constructor 關鍵字宣告。
... constructor(...) { ... } ... 類別屬性的宣告,是透過 get/set 關鍵字定義 get/set 區塊。
... private _name: string; ... get name():string{ return this._name; } set name(value:string){ this._name = value; } ... 類別方法的宣告不需要加上 function 關鍵字,還可依需求套上不同的存取修飾符,不過目前支援 private/public,若不加上存取修飾服,預設宣告的是 public 的方法。
... MyFunction():void { ... } private PrivateFunction():void { ... } public PublicFunction():void { ... } ... 類別的繼承則是透過 extends 關鍵字。
read morePosts
TypeScript - Lambda
TypeScript 支援 Lambda 語法,語法如下:
(input parameters) => expression (input parameters) => {statement;} 寫起來就像下面這樣:
var Execute = (cmd: string, ...params: string[]): void => alert(cmd + "(" + params.join(", ") + ")"); Execute("Test", "Param1", "Param2"); {% img /images/posts/TypeScriptLambda/1.png %}
read morePosts
TypeScript - Rest Parameters
TypeScript 的方法支援不定數量的參數,使用上只要在最後一個方法的陣列參數前面加上 ... 即可。
像是下面這個例子,定義了一個接口,可傳入要執行的命令名稱與命令要帶入的參數,因為命令的參數的個數可能不定,所以這邊就可以用 Rest Parameters 去做。
function Execute(cmd: string, ...params: string[]): void { alert(cmd + "(" + params.join(", ") + ")"); } Execute("Test", "Param1", "Param2"); {% img /images/posts/TypeScriptRestParameters/1.png %}
read morePosts
TypeScript - Default Parameters
TypeScript 的 Function 支援 Default Parameters,使用上只要在參數名稱後面帶入預設的參數值,當呼叫方法時忽略該參數,該參數則會以預設的參數值下去運行。
像是下面這樣:
function sayHello(name: string = 'World') { var msg:string = 'Hello~'; if (name) msg += name; console.log(msg); } sayHello(); sayHello('Larry Nung');
read morePosts
TypeScript - Optional Parameters
TypeScript 的 Function 支援 Optional Parameters,使用上只要在參數名稱後面加上 ? 即可,但需注意 Optional Parameters 必須放在 Required Parameters 的後面。
使用起來會像下面這樣:
function sayHello(name?: string) { var msg:string = 'Hello~'; if (name) msg += name; console.log(msg); } sayHello(); sayHello('Larry Nung');
read morePosts
TypeScript - Function Types
用 JavaScript 撰寫 Function,要馬是使用 Named function,要馬就是使用 Anonymous function。
//Named function function add(x, y) { return x+y; } //Anonymous function var myAdd = function(x, y) { return x+y; }; 因為 JavaScript 不具型態的關係,Function 有時候會被傳入不如預期的資料,回傳不預期的結果。像是上述的例子可能預期是用做數值的加總,但因為不具型態的關係就有可能被傳入字串,做為字串的串接使用。
TypeScript 可以在定義方法時設定參數與回傳值的型態,像是下面這樣:
function functionName(param1: Type1, [param2: Type2, ...]): Type {...} 所以上述的程式透過 TypeScript 改寫成像下面這樣,就不會碰到本來面臨的問題了。
function add(x: number, y: number): number { return x+y; } var myAdd = function(x: number, y: number): number { return x+y; }; Link Handbook - Welcome to TypeScript
read morePosts
TypeScript - Basic Types
TypeScript 內可用的型態有 Boolean、Number、String、Array、Any、Void、Enum 這幾種。
{% img /images/posts/TypeScriptBasicTypes/1.png %}
其中 Boolean、Number、String、Array、Any、Enum 的宣告方式如下:
var variableName: Type; 所以宣告起來會像下面這樣:
var booleanVariable: boolean; var numberVariable: number; var stringVariable: string; var arrayVariable1: number[]; var arrayVariable2: Array<number>; var anyVariable: any; var enumVariable: enumName; 宣告指定的型態後,該變數就只能賦予相同型態的值,像是 Boolean 型態就只能賦予 true/false、Number 型態只能賦予數值、String 型態只能賦予字串值。若真的有需要讓變數支援賦予多種不同型態的值,只要將變數宣告成 Any 型態即可。
陣列的宣告比較特殊,支援兩種宣告方式。可以直接用型態後面接中括弧表示,也可以用 Array 的泛型的寫法。
列舉型態的宣告跟 C# 類似:
enum enumName{element1 = 1, element2, element3, ...}; 列舉參數的宣告與列舉的操作如下:
var enumValue: enumName = enumName. element1; var enumName: enumName = enumName[2]; Void 型態則是用以指定方法無回傳值時使用:
read moreTag: Jil
Posts
Bmbsqd.JilMediaTypeFormatter - Json MediaTypeFormatter based on JIL
如果要將 Web API 的 JSON 處理改用 Jil 替換,我們可以使用 Bmbsqd.JilMediaTypeFormatter 這個 NuGet 套件。
{% img /images/posts/BmbsqdJilMediaTypeFormatter/1.png %}
{% img /images/posts/BmbsqdJilMediaTypeFormatter/2.png %}
套件安裝完後,開啟 WebApiConfig 將 JsonFormatter 換成 JilMediaTypeFormatter。
using Bmbsqd.JilMediaFormatter; ... config.Formatters.Remove(config.Formatters.JsonFormatter); config.Formatters.Add(new JilMediaTypeFormatter()); ... 像是下面這樣:
{% img /images/posts/BmbsqdJilMediaTypeFormatter/3.png %}
這樣 Web API 的 JSON 處理就會換成用 Jil 去做了。
Link NuGet Gallery | JIL MediaTypeFormatter 0.1.1
read morePosts
Jil - Ignore amp; Custom Element Name
使用 Jil 處理 JSON 時,如果要在序列化時忽略處理某特定屬性,可在其屬性加上 IgnoreDataMemberAttribute,像是下面這樣:
using System; using System. Runtime.Serialization ; using Jil; namespace ConsoleApplication10 { class Program { static void Main( string[] args ) { var larry = new Person { Name = "Larry Nung", NickName = "Larry" }; Console.WriteLine (JSON. Serialize(larry )); } public class Person { [ DataMember] public String Name { get; set ; } [ IgnoreDataMember] public String NickName { get; set ; } } } } 或是帶上 JilDirectiveAttribute,指定 Ignore:
read morePosts
Jil - Serialize DateTime to ISO8601 Format
Jil 在做時間的序列化,預設出來的資料會跟 JavaSriptSerializer 一樣,會序列化成下面這個樣子:
"/Date(1290181373164)/" 若要改成 ISO8601 的格式,我們可以帶入 Options 進行指定:
... Console.WriteLine(JSON.Serialize(dt, new Options(dateFormat : DateTimeFormat.ISO8601))); Console.WriteLine(JSON.Serialize(dt, Options.ISO8601)); ... 完整的範例如下:
using Jil; using System; namespace ConsoleApplication5 { class Program { static void Main(string[] args) { var dt = DateTime.Now; Console.WriteLine(JSON.Serialize(dt)); Console.WriteLine(JSON.Serialize(dt, new Options(dateFormat : DateTimeFormat.ISO8601))); Console.WriteLine(JSON.Serialize(dt, Options.ISO8601)); } } } {% img /images/posts/JilIso8601/1.png %}
read morePosts
Jil - Fast .NET JSON (De)Serializer
Jil 是 JSON 處理的套件,號稱比 JSON.NET 更快,甚至是當前套件中處理起來第二快的,僅次於 Protobuf。
{% img /images/posts/Jil/1.png %}
{% img /images/posts/Jil/2.png %}
{% img /images/posts/Jil/3.png %}
{% img /images/posts/Jil/4.png %}
{% img /images/posts/Jil/5.png %}
{% img /images/posts/Jil/6.png %}
只要加入 NuGet 參考,Using Jil 命名空間即可開始使用。
要序列化時,可將物件帶入 JSON.Serialize 方法,方法會回傳序列化後的 JSON 字串。
... var json = JSON.Serialize(larry); ... 解序列化時,可將 JSON 字串帶入 JSON.Deserialize,並利用範型指定所要解回的物件型態即可。
... larry = JSON.Deserialize<Person>(json); ... 此外,它也支援動態解析的能力,使用上只要將 JSON 字串帶入 JSON.DeserializeDynamic 即會回傳 Dynamic 物件。
... var person = JSON.DeserializeDynamic(json); ... 完整的操作範例如下:
read moreTag: Dropbox
Posts
Permission denied for a Mac OSX Dropbox app
最近 Mac 的 Dropbox 突然出問題,可能是前陣子搬動家目錄所導致,想將他進行重裝還原,但過程中總是會跟我要求提升權限:
{% img /images/posts/DropboxPermissionDenied/1.png %}
輸入密碼後權限好像都沒取道,怎樣都出現權限錯誤的問題。
{% img /images/posts/DropboxPermissionDenied/2.png %}
查了一下要在 Terminal 下下列指令:
mv ~/.dropbox ~/.Trash sudo mv /Library/DropboxHelperTools ~/.Trash 指令下完後重新安裝就可以了。
Link Dropbox asking for permissions to wrong folder after changing account name - Ask Different IPG EMEA Deployment Knowledge Base: After migrating a Mac user’s profile, Dropbox fails to open: keeps asking for permissions
read moreTag: ASP.NET
Posts
ASP.NET - Logging application shutdown events
做網站服務最害怕的就是服務不能正常運作,有時要追出實際發生的問題需要花費我們很多的時間。這時如果系統能將停止服務的原因正確的記錄下來,可有助於我們將問題快速的釐清。
可惜的是服務停止的原因預設是無法取得的,因為並沒有直接開放給開發人員調用。不過好在這樣的資訊還是有的,只是未被開出而已,所以我們仍舊可以透過反射下去取得。
要擷取這樣的資訊我們要從 HttpRuntime 類別下手,類別內有個 _theRuntime 靜態私有欄位用以存放唯一的物件實體,實體內的 _shutDownMessage 與 _shutDownStack 私有欄位分別存放著 Shutdown 的訊息與呼叫堆疊。
程式寫起來就像下面這樣:
... private void LogShutDownInfo() { if (! m_Logger.IsInfoEnabled ) return; var type = typeof (HttpRuntime ); var runtime = ( HttpRuntime) type .InvokeMember( "_theRuntime" , BindingFlags.NonPublic | BindingFlags.Static | BindingFlags .GetField, null, null , null); if (runtime == null) return; var message = ( string) type .InvokeMember( "_shutDownMessage" , BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags .GetField, null, runtime, null); var stack = ( string) type .
read morePosts
ASP.NET - Disable View State
禁用 View State 有幾種方式。若要將所有頁面都禁用,我們可以在 Web.Config 內的 system.web 加入 pages 的 element,並將其 enableViewState attribute 設為 false。
... <system.web> ... <pages enableViewState= "false"/> ... </system.web> ... 若要在單一頁面禁用,可以在該檔案最前面加入…
<%@ Page EnableViewState= "true" ViewStateMode= "Disabled" .. . %> ... 若要指定單一控制項禁用,可直接為控制項加上 EnableViewState attribute,並將其值設為 false…
... <asp:GridView ID= "gdvCustomers" runat= "server" DataSourceID= "mySqlDataSource" AllowPaging="True" EnableViewState ="false"/> ... 若要針對單一控制項啟用,頁面上其餘的控制項禁用,可以像下面這樣處理…
<%@ Page EnableViewState= "true" ViewStateMode= "Disabled" .. . %> ... <asp:GridView ID= "gdvCustomers" runat= "server" DataSourceID= "mySqlDataSource" AllowPaging="True" ViewStateMode= "Enabled"/> .
read moreTag: Outlook
Posts
Outlook - Check mailbox size
要檢查 Outlook 用量大小,我們可以在 Mailbox 上按下滑鼠右鍵,在彈出的滑鼠右鍵快顯選單中選取 Properties 選單選項。
{% img /images/posts/CheckMailBoxSizeWithOutlook/1.png %}
在 Properties 對話框中的 General 頁面找到 Folder Size... 按鈕並點選。
{% img /images/posts/CheckMailBoxSizeWithOutlook/2.png %}
就可以在彈出的 Folder Size 對話框中看到細部的用量資訊。
{% img /images/posts/CheckMailBoxSizeWithOutlook/3.png %}
Link How to Check the Size of Your Mailbox in Outlook
read morePosts
Outlook - Archive Email
要 Archive Outlook Mail Box,可透過 Outlook 的 Auto Archive 的功能。
開啟 Tools 主選單,點選 ‘Option…’ 主選單選項。
{% img /images/posts/ArchiveOutlookMail/1.png %}
在 Options 對話視窗中將頁面切至 Other,點擊 ‘AutoArchive…’ 按鈕。
{% img /images/posts/ArchiveOutlookMail/2.png %}
在 AutoArchive 對話視窗這邊,可以視需求做些對應的設定,像是 Archive 起來的資料要存放的位置、Archive 的週期…等。
{% img /images/posts/ArchiveOutlookMail/3.png %}
除了定期運行的 AutoArchive 外,若有需要我們也可以手動觸發 Archive。
開啟 File 主選單,點選 ‘Archive…’ 主選單選項。
{% img /images/posts/ArchiveOutlookMail/4.png %}
在 Archive 對話視窗這邊要決定是要直接套用 AutoArchive 的設定下去運行,還是要再指定這次運行要 Archive 的資料、多久的資料要 Archive、以及存放的位置。
{% img /images/posts/ArchiveOutlookMail/5.png %}
設定好按下 OK 按鈕即會開始進行 Archive 動作。
Link Outlook 自動封存簡介 - Outlook 思 .
read moreTag: RAML
Posts
RAML Tools for .NET - Generate Web API from RAML
之前筆者在 RAML - RESTful API Modeling Language - Level Up 這篇介紹過的 RAML,近期推出了 RAML Tools for .NET,是一 Visual Studio 的擴充套件,可輔助我們用 RAML 開發 Client 與 Server 端的程式。
使用前需先透過 Extensions and Updates 功能安裝 RAML Tools for .NET 這擴充套件。
{% img /images/posts/GenerateClientFromRAML/1.png %}
安裝完後要輔助開發 Server 端的 Web API 程式的話,我們只要開啟 Web API 專案,透過方案總管在專案的 Reference 上按下滑鼠右鍵,選取 Add RAML Contract... 這個選單選項。
{% img /images/posts/GenerateWebAPIFromRAML/1.png %}
Add RAML Contract 視窗即會跳出,這邊可為該 Web API 創建個新的 RAML contract,或是透過網址及檔案的方式來指定已存在的 RAML 檔案。
{% img /images/posts/GenerateWebAPIFromRAML/2.
read morePosts
RAML Tools for .NET - Generate client from RAML
之前筆者在 RAML - RESTful API Modeling Language - Level Up 這篇介紹過的 RAML,近期推出了 RAML Tools for .NET,是一 Visual Studio 的擴充套件,可輔助我們用 RAML 開發 Client 與 Server 端的程式。
使用前需先透過 Extensions and Updates 功能安裝 RAML Tools for .NET 這擴充套件。
{% img /images/posts/GenerateClientFromRAML/1.png %}
安裝完後要輔助開發 Client 端程式的話,我們只要透過方案總管在專案的 Reference 上按下滑鼠右鍵,選取 Add RAML Reference... 選單選項。
{% img /images/posts/GenerateClientFromRAML/2.png %}
Add RAML Reference 視窗即會跳出,這邊可透過網址或是檔案的方式來指定 RAML 檔案。
{% img /images/posts/GenerateClientFromRAML/3.png %}
這邊筆者用 Twitter 的 RAML 來做個示範,複製其 RAML 的網址。
{% img /images/posts/GenerateClientFromRAML/4.
read morePosts
RAML - RESTful API Modeling Language
RAML (RESTful API Modeling Language) 是ㄧ以YAML為基礎、專門用來描述 RESTful API、且人與機器都看得懂的標記語言。
{% img /images/posts/RAML/1.png %}
因為透過RAML去描述的API,機器也能夠看得懂,所以可以衍生出一些附加的功能服務,像是解析並自動產生對應的 API Console、API Client、API Server、API User Document…等。
Root Section RAML文檔最開始是Root Section,是用來做 API 基本的描述用,像是 API 的標題、API 版本、API 基底位置、相關文檔、與 schema 及其參考…等。
就像下面這樣:
#%RAML 0.8 --- title: GitHub API baseUri: http://api.github.com/{version} version: v1 一開始要描述RAML的版本,接著就是帶入 API 的標題等。以這例子來說,這邊是在描述 GitHub 的 API ,API 的基底位置是 http://api.github.com/{version} ,基底位置內寫的 {version} 會被實際的版本取代,而目前的版本是 v1 。
除了上面範例提到的設定外,還有其它可用的設定,這邊不深究,請直接參閱下表整理:
Resource Root Section設定好我們已經有 API 的基底位置了,所有的 API 都是以這基底下去延伸,我們可能為了讓 API 更為清楚,而在 API 基底位置下再加上幾層 Resource 進去,像是 GitHub API 的 API 基底位置是 https://api.
read moreTag: CSharp 6.0
Posts
C# 6.0 - Await in catch/finally
C# 6.0 以前 await 無法用在 catch/finally 區塊,C# 6.0 後開始支援。
using System; using System.Threading.Tasks; namespace ConsoleApplication10 { class Program { static void Main(string[] args) { Test(); System.Threading.Thread.Sleep(10000); } private static async void Test() { try { throw new Exception(); } catch { Console.WriteLine("Catch..."); await Task.Delay(500); } finally { Console.WriteLine("Finally..."); await Task.Delay(500); } } } }
read morePosts
C# 6.0 - Extension Add methods in collection initializers
C# 6.0 以前,集合類別可以像下面這樣透過 Collection Initializers 初始集合成員:
... var blogs = new List< Blog> { new Blog( "Level Up 1", "http://www.dotblogs.com.tw/larrynung" ), new Blog( "Level Up 2", "http://larrynung.github.io" ) }; ... {% endcodeblock%} <br/> 但無法像 VB 10 以後的版本一樣透過擴充方法客製處理 Collection Initializers 的動作,一直到 C# 6.0 才被加入 C# 內。 <br/> 只要為集合撰寫 Add 擴充方法即可客製處理 Collection Initializers,像是如果預期要讓 List<Blog> 的初始可以直接帶入 name 與 url,就會像下面這樣撰寫: ```c# ... public static class BlogExtension { public static void Add(this List<Blog> list, string name, string url) { list.
read morePosts
C# 6.0 - Parameterless constructors in structs
在 C# 6.0 以前,Struct 會自帶 Parameterless Constructors,且不允許我們自行實作,像是下面這樣的程式碼:
... public Blog() : this( string.Empty, string.Empty) { Console.WriteLine( "Blog.Ctor()..."); } public Blog(string name, string url) { this.Name = name; this.Url = url; } ... 運行在 C# 6.0 以前,編譯器就會告知錯誤:
{% img /images/posts/ParamlessStructConstructor/1.png %}
如果想要在 Parameterless Constructors 自行加些處理,像是用建構子鏈導到別的建構子去建構,在 C# 6.0 以前都沒辦法。
在 C# 6.0 以後,就比較沒有這樣的限制了,我們可以自行撰寫自己的 Paramless Constructor,加上自己想要的處理動作。唯一要注意的是需要透過 new 語法建立的才會觸發自己撰寫的 Paramless Constructor。
... var blog = default( Blog); DumpBlog(blog); blog = new Blog() { Name = "Larry Nung", Url = "http://larrynung.
read morePosts
C# 6.0 - Index initializers
以往我們在撰寫 C#,有 Object Initializer 與 Collection Initializer 可輔助我們作初始的動作,雖然可以初始大多數的資料,但在 Index 與 Event 這邊卻無法直接初始。
如果以 Dictionary 來說,因為他還是屬於集合的一種,所以仍舊可以像下面這樣透過 Collection Initializer 在初始的同時就將內容一併放入:
... var blog1 = new Dictionary<string , string >() { { "Name", "Level Up" }, { "Url", "http://larrynung.github.io/index.html" } }; ... 但並不是所有的情況下都可以用 Collection Initializer 來做 Index 的初始,所以在 C# 6.0 導入了 Index initializers,寫起來會像下面這樣,就像透過索引子塞值一般:
... var blog = new Dictionary<string , string >() { [ "Name"] = "Level Up" , [ "Url"] = "http://larrynung.github.io/index.html" }; .
read morePosts
C# 6.0 - String interpolation
以往在做比較簡單的字串串接,我們可能會用 + 運算符號進行串接,或是用 String.Format 帶入 Pattern 與要串接的字串去處理,像是下面這樣:
... Console.WriteLine((++idx).ToString("D2") + ". " + blog.Name + " (" + blog.Url + ")"); Console.WriteLine( String.Format( "{0:D2}. {1} ({2})", ++idx, blog.Name, blog.Url)); ... 在 C# 6.0 導入了 String Interpolation,可以像下面這樣簡化寫法:
... Console.WriteLine( "\{++idx, 5 :D2 }. \{blog.Name } (\{blog.Url ?? String.Empty})" ); ... 有點像是本來 String.Format 的 Pattern 內直接用斜線與大括號包住帶入運算式,且支援 optional alignment 與 format specifiers 的設定。
這邊來看個完整的使用範例:
using System; using System.Collections.Generic; public class Program { static void Main(string[] args) { var blog = new Blog { Name = "Level Up", Url = "http://larrynung.
read morePosts
C# 6.0 - Expression bodied members
Expression bodied members 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 當撰寫簡單的成員方法或是屬性時,Expression bodied members 能讓我們將程式碼精簡。
在使用上就只要將屬性或方法的宣告後面直接接上 Lambda 表示式即可。
像是成員屬性的處理會像下面這樣,少了本來大括弧的區塊,也少了 Get 區塊。
... public string ID => Guid.NewGuid().ToString(); ... 如果是成員方法處理上也類似,只是本來大括弧區塊內的內容用 Lambda 取代。
... public override string ToString() => this.Name; ... 這邊可以看到用這樣的寫法可能會造成很難區別是屬性還是方法,使用上要特別注意小心,基本上差異只在於後面有沒有接小括弧區塊及方法的參數。
最後看個完整的範例:
using System; public class Program(string name) { public string ID => Guid.NewGuid().ToString(); public string Name { get; private set ; } = name; public override string ToString() => this.
read morePosts
C# 6.0 - Nameof expressions
Nameof expressions 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 CTP3 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> Nameof expressions 能讓開發人員輕易的在程式中取得變數或是類別名稱。
以往我們是無法取得變數名稱的,所以像是在撰寫參數檢查,當丟出的例外需要帶入參數名稱時,多半是自己填入字串帶入。但這樣的做法不是很恰當,因為拼錯時並不容易發現,且當重構參數名稱時很容易遺漏要配合修改。
至於類別名稱的取得,相較於變數名稱的取得是簡單了許多。但是名稱的取得需要 Runtime 進行解析,這樣的做法有時又多了一些無謂的耗費。
Nameof expressions 的出現能幫助開發人員解決這樣的問題,使用上只要叫用nameof,並帶入欲取得名稱的類別或變數即可。
nameof( 欲取得名稱的類別或變數 ) 這邊直接看個完整的使用範例:
using System; namespace ConsoleApplication10 { class Program { static void Main(string[] args) { var blog = new Blog { Name = "Level Up" , Url = "http://larrynung.github.io/" }; DumpBlogInfo(blog); DumpBlogInfo(null); } static void DumpBlogInfo(Blog blog) { Console.WriteLine( string.Format( "Dump data (Type is {0})..." , nameof(Blog ))); if (blog == null) throw new ArgumentNullException(nameof (blog)); Console.
read morePosts
C# 6.0 - Null propagation
— layout: post title: “C# 6.0 - Null propagation” date: 2014-08-21 00:03:00 comments: true tags: [CSharp, CSharp 6.0] keywords: “C#” description: “C# 6.0 - Null propagation”
read morePosts
C# 6.0 - Exception filters
Exception filters 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 或是透過 .Net Fiddle 也可以,Compiler 那邊選取 Roslyn 就可以了。
Exception filters 能讓開發人員很容易的在攔截例外時順帶做些過濾的動作,藉此處理符合過濾條件的例外,且不對例外呼叫堆疊造成不良的影響。
以往我們必須要先將例外攔截,接著進行比對過濾,最後將符合的例外做對應的處理,不符合的例外繼續讓它向外擴出。但是這樣的作法會讓例外呼叫堆疊看不到實際發生的例外點,只看到重新擴出例外的點,造成除錯上的困難。
{% img /images/posts/ExceptionFilters/1.png %}
Exception filters 的出現能幫助開發人員解決這樣的問題。
它的語法很直覺,簡單來說就只是在 Try/Catch 的 Catch 後面加上 if 條件式進行過濾。
try {...} catch(Exception e) if (...) {...} 程式寫起來會像下面這樣:
反組譯看一下,可以看到 Exception filters 這邊會被編譯成 filter 區塊的部份,從 IL 這邊就直接支援。
{% img /images/posts/ExceptionFilters/2.png %}
這樣的寫法不僅直覺,且不會對例外呼叫堆疊造成不良的影響。
{% img /images/posts/ExceptionFilters/3.png %}
最後這邊做個新舊方法的測試比較:
可以看到效能的部份其實是差不多的,新語法感覺是沒有任何的效能優化。
read morePosts
C# 6.0 - Using static members
Using static members 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 或是透過 .Net Fiddle 也可以,Compiler 那邊選取 Roslyn 就可以了。
Using static members 能讓開發人員更方便的對指定類別的靜態成員做存取。對於程式中有大量的靜態成員存取操作時特別好用。
使用上與 Namespace 的 Using 類似,只是後面帶的不是到 Namespace 而已,而是進一步再向下帶到 Class。用 Using 指定要存取的類別後,在程式中就可以直接存取該類別的靜態成員,就如同自身的成員一般。
以一個較完整的例子來看,程式寫起來會像下面這樣:
可以看到這邊程式的一開始就先使用 Using 引用 Console 類別,後續我們就可以在程式中直接存取 Console 類別的靜態成員,像是取用 Title 、或是呼叫 WriteLine 方法。
反組譯看一下,可以發現其實該語法也只是編譯器幫我們在編譯時做了些處理。
{% img /images/posts/UsingStaticMembers/1.png %}
read morePosts
C# 6.0 - Auto-property initializers
Auto-property initializers 是預計要在 C# 6.0 釋出的新功能,目前已可在 Visual Studio 14 中透過設定將功能開啟進行體驗,只要在方案檔中加上:
<LangVersion>experimental</LangVersion> 或是透過 .Net Fiddle 也可以,Compiler 那邊選取 Roslyn 就可以了。
Auto-property initializers 能讓開發人員在宣告 Auto-property 的同時就順道做初始的動作。不用另行在建構子中設定。也不再寫用回一般的 Property 寫法,然後在 Field 宣告時設定。
它的語法很直覺,簡單來說就是本來的 Auto-property 後面直接接上賦值的語法。像是:
public string Property { get; set; } = "Value"; 除了一般可讀可寫的 Property 外,唯讀的甚至是靜態的 Property 該語法也都支援。
以一個較完整的例子來看,程式寫起來會像下面這樣:
程式寫起來可以看到比以往精簡許多,運行後屬性也都有正確的賦值。
反組譯看一下,可以看到比較接近透過變數初始器去做賦值的動作,會在基底類別初始前宣告,也會標注 beforefieldinit。
{% img /images/posts/AutoPropertyInitializers/1.png %}
{% img /images/posts/AutoPropertyInitializers/2.png %}
read moreTag: Json.NET
Posts
Json.Net - Custom Converter
Json.Net 用到後面,我們免不了有時會要 Custom Converter 去做序列化的客製動作。
使用 Json.Net 要做自定義序列化,我們可以 Custom Json.Net 的 Converter,為此需要建立一個 Converter 類別,將之繼承自 JsonConverter,接著將繼承而來的方法實作即可。
CanConverter 用來決定該型別是否可被該 Converter 處理、WriteJson 用來序列化物件、ReadJson 用來解序列化物件。
像是我們可以像下面這樣做個簡易的 Converter,裡面只是單純的將物件序列化與解序列化。
using System; using Newtonsoft.Json; namespace LevelUp.Converter { public class ConcreteTypeConverter<TConcrete> : JsonConverter { public override bool CanConvert( Type objectType) { return true ; } public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return serializer.Deserialize<TConcrete>(reader); } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer) { serializer.
read moreTag: Web API
Posts
Web API - Adding Request.IsLocal to ASP.NET Web API
要判斷 Request 是否為本地 Request,在 ASP.NET 那邊因為 Request 是 HttpRequest 型態,內建有 IsLocal 方法,可以直接叫用判斷。
但在 Web API 就沒辦法那麼直接判斷,因為 APIController.Request 是 HttpRequestMessage 型態,沒有 IsLocal 方法可以直接叫用。要自行處理這樣的判斷可以查閱 Request 內的 MS_IsLocal Property 值,這邊國外的網友已經有現成寫好的擴充方法:
public static class HttpRequestMessageExtensions { public static bool IsLocal(this HttpRequestMessage request) { var localFlag = request.Properties["MS_IsLocal"] as Lazy<bool>; return localFlag != null && localFlag.Value; } } 放進專案中直接使用即可:
public HttpResponseMessage Get() { if (Request.IsLocal()) { //do stuff } } Link Adding Request.IsLocal to ASP.NET Web API StrathWeb How to filter local requests in asp.
read morePosts
Web API - Web API Self Hosting
要 Self Hosting Web API,首先需要安裝 Microsoft.AspNet.WebApi.SelfHost 套件。
建立 HttpSelfHostConfiguration 並指定要監聽的位置。
var config =new HttpSelfHostConfiguration("http://localhost:32767"); 設定 HttpSelfHostConfiguration,像是 URL Routing 資訊。
config.Routes.MapHttpRoute("API","{controller}/{action}/{id}", new{ id =RouteParameter.Optional }); 如果要被 Host 的 Web API 在其它的組件,這邊也可建立一個實作 IAssembliesResolver 的 SelfHostAssemblyResolve 類型。
public class SelfHostAssemblyResolver : IAssembliesResolver { #region Properties /// <summary> /// Gets the path. /// </summary> /// <value> /// The path. /// </value> public string Path { get; private set ; } #endregion Properties #region Constructors /// <summary> /// Initializes a new instance of the <see cref="SelfHostAssemblyResolver"/> class.
read moreTag: Roslyn
Posts
Code Cracker
Code Cracker 是 Roslyn analyzer 的 Library,有點類似 FxCop 的 Rule,依不同的範疇實做了很多相關的檢查,可以看到有 Design、Globalization、Maintainability、Naming、Performance、Portabili、Security …等。雖然還未完全實作完畢,但目前已經相當多的檢查 Rule 了。
{% img /images/posts/CodeCracker/1.png %}
安裝上一樣是提供 VSIX 或是 NuGet Package 兩種,若是要套到所有專案,可直接透過 Extension and Updates 安裝。
{% img /images/posts/CodeCracker/2.png %}
若是只要套用到單一專案,可直接透過 NuGet 安裝。不論是要用 NuGet 的 GUI 介面。
{% img /images/posts/CodeCracker/3.png %}
或是直接透過 NuGet 命令都可以。
Install-Package CodeCracker.CSharp -IncludePrerelease Install-Package CodeCracker.VisualBasic -IncludePrerelease 用 NuGet 安裝的話,Analyzer 會出現在方案總管的 References\Analyzers 節點下。
{% img /images/posts/CodeCracker/4.png %}
展開 Analyzer 節點可進一步看到支援的 Rule。
{% img /images/posts/CodeCracker/5.png %}
read morePosts
Roslyn - Introduce diagnostic analyzer
Diagnostic Analyzer 功能是用來診斷分析程式碼的,開發人員可自行撰寫 Diagnostic Analyzer 去擴充 Roslyn 的編譯器,實作自己的程式碼診斷邏輯。
他有兩種不同的使用方式,一種是包裝成 VSIX 檔,需要安裝使用。安裝後 Diagnostic Analyzer 的診斷會針對 Visual Studio 開啟的所有專案,就好像是內建的診斷一般。
另一種則是建置成一般的 Dll 檔,需要依需求在個別專案中引用使用。使用上需搭配 Visual Studio 14 以後的版本,在方案總管中找到 Analyzers 節點,按右鍵加入 Analyzer。或是直接透過 NuGet 加入引用也可以。
最後這邊可以看一下 Channel9 的介紹,這段影片會介紹他自己寫的 Diagnostic Analyzer是如何對 C# 6.0 的 Feature 做出診斷與建議,並帶到一些實作上的細節,看完相信對於 Diagnostic Analyzer 會更加的了解。
read morePosts
Clr C# Heap Allocation Analyzer
Clr C# Heap Allocation Analyzer 是 Diagnostic Analyzers 的套件,功能上有點類似 ReSharper - Heap Allocation Viewer Extension,能對 Heap 的操作部分做些 Highlight。
這邊可先參閱一下影片的介紹:
該套件提供兩種安裝方式,一種是選擇安裝 VSIX,用 Extension Manager 搜尋安裝或是自 NuGet Gallery | Clr C# Heap Allocation Analyzer 1.0.0.5 下載安裝,好處是可以將效果套用至所有專案。
{% img /images/posts/HeapAllocationAnalyzer/1.png %}
一種則是用 NuGet By 專案安裝,好處是可以只套用至特定的專案。
{% img /images/posts/HeapAllocationAnalyzer/2.png %}
安裝完後,在程式編輯時即會呈現進行對應的分析,像是筆者這邊的程式即被偵測出有 Boxing 的動作。
{% img /images/posts/HeapAllocationAnalyzer/3.png %}
Link NuGet Gallery | Clr C# Heap Allocation Analyzer 1.0.0.5 Clr Heap Allocation Analyzer extension
read morePosts
Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers
Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers 是一個 Diagnostic Analyzer 套件,是 FxCop 部分檢查規則的 Analyzer 實作。
{% img /images/posts/FxCopAnalyzers/1.png %}
因為目前仍是 Preview 版本,所以這邊在使用時需先叫出 Package Manager Console,然後叫用命令安裝:
Install-Package Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers -Pre {% img /images/posts/FxCopAnalyzers/2.png %}
安裝完後,我們可以看到方案總管的 Analyzers 節點下多了兩個 Analyzer。
{% img /images/posts/FxCopAnalyzers/3.png %}
展開節點可以看到該 Analyzer 所 Support 的分析。
{% img /images/posts/FxCopAnalyzers/4.png %}
回到程式編輯這邊,可以看到當我們程式撰寫不符合 Analyzer 的規定時,編譯器就會提出對應的警告,像這邊就告知我們要實作 IDisposible 介面,也提供了對應的修正。
{% img /images/posts/FxCopAnalyzers/5.png %}
read morePosts
Roslyn Syntax Visualizers
在使用 Roslyn 做開發時,常免不了會要去處理語法的解析,這時我們會需要輔助工具將語法解析轉換為語法樹,以視覺的方式呈現,讓 Roslyn 的開發上更為便利。
所以開發前我們要到 .NET Compiler Platform Syntax Visualizer extension 這邊下載 Roslyn Syntax Visualizer。
{% img /images/posts/RoslynSyntaxVisualizer/1.png %}
下載完後進行安裝。
{% img /images/posts/RoslynSyntaxVisualizer/2.png %}
{% img /images/posts/RoslynSyntaxVisualizer/3.png %}
安裝完我們可以透過 Visual Studio 的主選單選項(View\Other Windows\Roslyn Syntax Visualizer)將 Roslyn Syntax Visualizer Tool Window 叫出。
{% img /images/posts/RoslynSyntaxVisualizer/4.png %}
叫出後 Roslyn Syntax Visualizer 後,它會偵測目前所編輯的程式碼,將之解析成語法樹。且會偵測編輯區的選取,反映在語法樹上。
{% img /images/posts/RoslynSyntaxVisualizer/5.png %}
反之亦然。
{% img /images/posts/RoslynSyntaxVisualizer/6.png %}
語法樹上的節點有做顏色的區分,可以透過上方的 Legend 按鈕查閱各顏色所代表的意義。
{% img /images/posts/RoslynSyntaxVisualizer/7.png %}
語法樹上節點的滑鼠右鍵快顯選單也有提供一些功能,像是可以用更直覺的圖形方式呈現。
{% img /images/posts/RoslynSyntaxVisualizer/8.
read moreTag: PostSharp
Posts
PostSharp - Contract Inheritance
PostSharp 的 Contract 跟 Conde Contract 一樣,具備可被繼承的特性。凡是套用在 abstract、virtual、或 interface 方法上的 Contract,其子類別都會繼承到,在開發上十分的好用。
這邊來看個例子,筆者撰寫了個 IWritable 的介面,在其 Write 方法上我們加上了 RequiredAttribute,再建立個 Blog 類別去實作該介面。
Using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using PostSharp.Patterns.Contracts; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { IWriteable blog = new Blog("LevelUp", "http://larrynung.github.io"); blog.Write("PostSharp Contract Inheritance", "Hello~Contract"); blog.Write("", ""); } } public interface IWritable { void Write([Required]string title, string content); } public class Blog : IWritable { public string Name { get; set; } public string Url { get; set; } public Blog(string name, string url) { this.
read morePosts
PostSharp - Custom Contract
PostSharp 內建的 Contracts 能支援我們做些常見的檢查,若是內建的無法滿足,我們也可以自行擴建 Contract。
擴建時要先確保 PostSharp.Patterns.Model 的引用已加入專案中,若無可透過 NuGet 將套件安裝起來。
{% img /images/posts/CustomPostSharpContract/1.png %}
接著建立個繼承自 LocationContractAttribute 的 Contract 類別,LocationContractAttribute 會提供我們建立 Contract Attribute 所需的基本功能,像是 CreateArgumentException、CreateArgumentNullException、CreateArgumentOutOfRangeException、及 ErrorMessage 等。
{% img /images/posts/CustomPostSharpContract/2.png %}
並實作 ILocationValidationAspect<T> ,在 ValudateValue 方法中撰寫自己的判斷邏輯,當不符合規範時叫用繼承自 LocationContractAttribute 的方法拋出例外即可。
筆者這邊以建立個 RegexMatch 的 Contract 為例,讓使用上可以帶上不同的正規表示式進行驗證。建立個繼承自 LocationContractAttribute 的類別 ,因為這邊要檢查的參數型態為字串,故還要實作 ILocationValidationAspect<string> 介面,在 ValudateValue 方法中會去判斷值是否符合我們設定的 Pattern,若否則叫用 CreateArgumentException 丟出例外。
public class RegexMatchAttribute : LocationContractAttribute , ILocationValidationAspect <string> { public String Pattern { get; set; } public RegexMatchAttribute(string pattern) : base() { this.
read morePosts
PostSharp - Contracts
以往我們在寫函式的時候,若要作參數的檢查,我們可能會自行去檢查參數是否 Null 或是 Empty,若是 Null 或 Empty 則丟出 ArgumentNullException。這樣的參數動作會混在程式邏輯的前面,PostSharp 的 Contract 功能就有點像是 Code Contract 一樣,能讓我們做前置條件的檢查,並將檢查抽離程式核心。
使用上只要在要加入檢查的參數上面按下滑鼠右鍵,然後在彈出的滑鼠右鍵快顯選單中,選取 Require a non-null and non whitespace value 這個選單選項。
{% img /images/posts/PostSharpContracts/1.png %}
接著 PostSharp 擴充套件會帶出精靈視窗,第一頁是 Summary 頁面,這邊只是告訴我們繼續下去會做什麼事,不外乎就是加入套件引用與加上對應的 RequiredAttribute,這邊直接 Next。
{% img /images/posts/PostSharpContracts/2.png %}
如 Summary 頁面所提,要處理的東西有點多,進度要稍微跑一下。
{% img /images/posts/PostSharpContracts/3.png %}
進度跑完後按下 Finish 按鈕結束精靈視窗即可。
可以看到專案已套上對應的修改,已將該引用的套件引用、RequiredAttribute 也已正確的加上。
{% img /images/posts/PostSharpContracts/4.png %}
滑鼠移上去再次確認,沒意外的話就會看到確實已經套用完成(若沒有這畫面可能是因為資料還未更新完成,可嘗試重建專案看看)。
{% img /images/posts/PostSharpContracts/5.png %}
{% img /images/posts/PostSharpContracts/6.png %}
運行後可看到帶入空值時確實會做參數的檢查,得到了預期的 ArgunemtNullException。
{% img /images/posts/PostSharpContracts/7.png %}
read morePosts
PostSharp - Changing the Logging Back-End
前面介紹 PostSharp 時,筆者多半都是透過精靈介面將之套用至專案之中,在加 Log 時有一步驟是設定 Log 機制背後要用的服務,這個在精靈介面設定完後,若有修改的必要,我們可以參閱下表:
{% img /images/posts/PostSharpChangLoggingBackEnd/1.png %}
將本來使用到的 Log Profile 其對應的 NuGet Package 移除,然後將欲使用 Log Profile 對應的 NuGet Package 加入專案中,接著開啟副檔名為 psproj 的設定檔,將其 LoggingBackend 的值設為對應的 Log Profile Name。
{% img /images/posts/PostSharpChangLoggingBackEnd/2.png %}
Link Walkthrough: Changing the Logging Back-End
read morePosts
PostSharp - Tracing Parameter Values Upon Exception
要使用 PostSharp 為程式加入 Exception 的 Log 處理,在安裝完 PostSharp 擴充套件後,我們可以在類別上直接按下右鍵,在彈出的滑鼠右鍵快顯選單中,選取 Add logging... 選單選項。
{% img /images/posts/PostSharpTracingUponException/1.png %}
接著 PostSharp 擴充套件會帶出精靈視窗,這邊要我們選取 Log 的 Profile,因為要這篇要示範 Exception 的處理,所以遠取 Exceptions 的 Profile 後按下 Next 按鈕即可。
{% img /images/posts/PostSharpTracingUponException/2.png %}
再來是要決定 Log 機制背後要用哪種服務,有 Trace、Console、Log4Net、NLog、Enterprise Library,一樣選取完後按下 Next 按鈕繼續。
{% img /images/posts/PostSharpTracingUponException/3.png %}
Summary 頁面這邊只是告訴我們繼續下去會做什麼事,不外乎就是加入套件引用、加上 LogException Attribute、 設定 Config,一樣按下 Next 繼續。
{% img /images/posts/PostSharpTracingUponException/4.png %}
如 Summary 頁面所提,要處理的東西有點多,進度要稍微跑一下。
{% img /images/posts/PostSharpTracingUponException/5.png %}
跑完後按下 Finish 按鈕結束精靈頁面。
{% img /images/posts/PostSharpTracingUponException/6.png %}
read morePosts
PostSharp - Customizing Logging
如果預設的 Log 設定不敷使用,像是 Log 的層級應該是 Error 而不是 Warning,或是 Log 應該含更多的資訊,這邊PostSharp 也支援我們有限幅度的客製。我們可以在類別上直接按下右鍵,在彈出的滑鼠右鍵快顯選單中,選取 Add logging… 選單選項。
{% img /images/posts/PostSharpCustomLogging/1.png %}
在 Log 設定這邊注意到下方有個 New logging profile... 連結按鈕,按下該連結按鈕即可建立一個新的設定。
{% img /images/posts/PostSharpCustomLogging/2.png %}
按下後會彈出 Log 設定的設定對話框,依需求決定這個設定的名稱、何時進行 Log 的紀錄、Log 紀錄時所要包含的資訊、以及 Log 的層級。
{% img /images/posts/PostSharpCustomLogging/3.png %}
選取剛所建立的設定,按下 Next 按鈕繼續。
{% img /images/posts/PostSharpCustomLogging/4.png %}
再來是要決定 Log 機制背後要用哪種服務,有 Trace、Console、Log4Net、NLog、Enterprise Library,一樣選取完後按下 Next 按鈕繼續。
{% img /images/posts/PostSharpCustomLogging/5.png %}
Summary 頁面這邊只是告訴我們繼續下去會做什麼事,不外乎就是加入套件引用、加上 Attribute、 設定 Config,一樣按下 Next 繼續。
{% img /images/posts/PostSharpCustomLogging/6.png %}
read morePosts
PostSharp - Adding Detailed Tracing to a Code Base
要使用 PostSharp 為程式加入些簡易的 Log 資訊,在安裝完 PostSharp 擴充套件後,我們可以在類別上直接按下右鍵,在彈出的滑鼠右鍵快顯選單中,選取 Add logging... 選單選項。
{% img /images/posts/PostSharpDetailedTraching/1.png %}
接著 PostSharp 擴充套件會帶出精靈視窗,這邊要我們選取 Log 的 Profile,這邊選取 Default Profile 後按下 Next 按鈕即可。
{% img /images/posts/PostSharpDetailedTraching/2.png %}
再來是要決定 Log 機制背後要用哪種服務,有 Trace、Console、Log4Net、NLog、Enterprise Library,一樣選取完後按下 Next 按鈕繼續。
{% img /images/posts/PostSharpDetailedTraching/3.png %}
Summary 頁面這邊只是告訴我們繼續下去會做什麼事,不外乎就是加入套件引用、加上 Attribute、 設定 Config,一樣按下 Next 繼續。
{% img /images/posts/PostSharpDetailedTraching/4.png %}
如 Summary 頁面所提,要處理的東西有點多,進度要稍微跑一下。
{% img /images/posts/PostSharpDetailedTraching/5.png %}
跑完後按下 Finish 按鈕結束精靈頁面。
可以看到專案已套上對應的修改,已引用該引用的套件、產生副檔名為 psproj 的設定檔、Attribute 也正確的加上。
{% img /images/posts/PostSharpDetailedTraching/6.png %}
滑鼠移上去再次確認,沒意外的話就會看到確實已經套用完成(若沒有這畫面可能是因為資料還未更新完成,可嘗試重建專案看看)。
read morePosts
PostSharp - Automatically Implementing INotifyPropertyChanged
要用 PostSharp 自動實作 INotifyPropertyChanged,在安裝完 PostSharp 擴充套件後,我們可以在類別上直接按下右鍵,在彈出的滑鼠右鍵快顯選單中,選取 Implement INotifyPropertyChanged 選單選項。
{% img /images/posts/PostSharpINotifyPropertyChangedImplement/1.png %}
接著 PostSharp 擴充套件會帶出精靈視窗,第一頁是 Summary 頁面,這邊只是告訴我們繼續下去會做什麼事,不外乎就是加入套件引用與加上對應的 Attribute,這邊直接 Next。
{% img /images/posts/PostSharpINotifyPropertyChangedImplement/2.png %}
如 Summary 頁面所提,要處理的東西有點多,進度要稍微跑一下。
{% img /images/posts/PostSharpINotifyPropertyChangedImplement/3.png %}
進度跑完後按下 Finish 按鈕結束精靈視窗即可。
{% img /images/posts/PostSharpINotifyPropertyChangedImplement/4.png %}
回過頭來看一下我們的專案,可以發現缺少的 PostSharp 參考被加入專案,且我們的類別上面被加上了 NotifyPropertyChanged 的 Attribute (可參閱 NotifyPropertyChangedAttribute Class,套上這 Attribute 會讓該類別及其子類都實作 INotifyPropertyChanged)。
{% img /images/posts/PostSharpINotifyPropertyChangedImplement/5.png %}
到這邊已經用 PostSharp 幫我們自動實作完 INotifyPropertyChanged 了,若有需要可將滑鼠移至類別上再次進行確認,沒意外的話就會看到確實已經套用完成(若沒有這畫面可能是因為資料還未更新完成,可嘗試重建專案看看)。
{% img /images/posts/PostSharpINotifyPropertyChangedImplement/6.png %}
若再次用反射進行解析。
using System; using System. Collections.Generic ; using System.
read moreTag: MediaWiki
Posts
MediaWiki - Change Wiki Logo
要改變 MediaWiki 的 Logo,我們可以先開啟 LocalSetting.php 檔,查閱 $wgLogo 設定的檔案位置。
{% img /images/posts/ChangeMediaWikiLogo/1.png %}
將要替換的 Logo 檔案放置設定的檔案位置即可。
{% img /images/posts/ChangeMediaWikiLogo/2.png %}
檔案放置完畢回到 Wiki 頁面即可看到設定的 Logo 生效。
{% img /images/posts/ChangeMediaWikiLogo/3.png %}
read morePosts
Windows Azure - Enable MediaWiki File Upload
使用 Azure 架設 MediaWiki,若要啟動檔案上傳的功能,我們需要在建立 MediaWiki 時,將 Enable MediaWiki File Uplad 以及 Use Windows Azure Storage As File Backend 設定開啟,並設定 Windows Azure Storage Account Name 以及 Windows Azure Storage Account Key。
{% img /images/posts/EnableAzureMediaWikiFileUplad/1.png %}
填寫 Windows Azure Storage Account Name 以及 Windows Azure Storage Account Key 的值時,可參閱儲存體的存取金鑰。
{% img /images/posts/EnableAzureMediaWikiFileUplad/2.png %}
這樣建立出來的 MediaWiki 就會啟用 MediaWiki 的 WindowsAzureStorage Extension,可以看到建立好的 LocalSetting.php 內會自動設好相關的設定。
{% img /images/posts/EnableAzureMediaWikiFileUplad/3.png %}
建立出來的 MediaWiki 也可以正常的將檔案上傳上去。
read morePosts
Windows Azure - MediaWiki in Azure
用 Azure 架設 MediaWiki,我們可以到 Azure 的入口網站,切換至網頁管理頁面。
{% img /images/posts/MediaWikiInAzure/1.png %}
按下左下角的新增按鈕。
{% img /images/posts/MediaWikiInAzure/2.png %}
然後從組件庫中建立我們要的服務。
{% img /images/posts/MediaWikiInAzure/3.png %}
也就是 MediaWiki 服務,選取後按下 Next 繼續。
{% img /images/posts/MediaWikiInAzure/4.png %}
接著要進行服務的細部設定,像是服務的網址、Wiki 的名稱、登入的帳密…等。設定完一樣按下 Next 繼續。
{% img /images/posts/MediaWikiInAzure/5.png %}
最後是設定 MySQL 資料庫。
{% img /images/posts/MediaWikiInAzure/6.png %}
到這邊設定告一段落,系統會開始進行服務的佈署。
{% img /images/posts/MediaWikiInAzure/7.png %}
佈署完成按下下方的瀏覽按鍵。
{% img /images/posts/MediaWikiInAzure/8.png %}
我們即可看到 MediaWiki 服務運行的結果,但因為是第一次使用,所以此時還未有 LocalSettings.php 設定檔,為此我們可以按下畫面中的連結產生預設的設定先。
{% img /images/posts/MediaWikiInAzure/9.png %}
按下後 MediaWiki 就可正常使用了,這邊直接用服務建立時所設定的帳密進行登入就可以了。
{% img /images/posts/MediaWikiInAzure/10.png %}
read morePosts
MediaWiki - How to check MediaWiki's version
有些時候我們會需要知道已安裝的 MediaWiki 版本,像是要安裝 MediaWiki 的套件前我們就會需要明確的知道是否能在其上正常運作。
要查閱安裝的 MediaWiki 版本,我們有三種方式。
一種是進到 Wiki 的 Version 頁面查閱(搜尋框輸入Special:Version)。
{% img /images/posts/CheckMediaWikiVersion/1.png %}
或是透過網頁原始碼查閱。
{% img /images/posts/CheckMediaWikiVersion/2.png %}
抑或是透過 DefaultSettings.php 檔的 $wgVersion 設定也可得知。
{% img /images/posts/CheckMediaWikiVersion/3.png %}
read morePosts
MediaWiki - Auto-number headings
MediaWiki 在使用標頭時,預設是不會有自動編號的,這樣的呈現方式在瀏覽時我們會不易知道是哪個章節。當然你也可以自己在撰寫標頭時附上編號,但總是比較麻煩點,如果沒有太特殊的需求,我們是可以直接將 MediaWiki 的標頭自動編號功能給開啟。
要將自動編號功能給開啟,首先要先將 LocalSettings.php 檔案開啟。
{% img /images/posts/MediaWikiAutoNumberHeadings/1.png %}
找到 $wgDefaultUserOptions['numberheadings'] 設定,將其值設定為 1。
$wgDefaultUserOptions['numberheadings'] = 1; {% img /images/posts/MediaWikiAutoNumberHeadings/2.png %}
這樣 MediaWiki 的標頭前面就會自動編號。
{% img /images/posts/MediaWikiAutoNumberHeadings/3.png %}
Link Auto-number headings - MediaWiki
read morePosts
MediaWiki - Unlock upload file size limitation
MediaWiki 在檔案上傳這邊預設是有 2MB 的限制在。
{% img /images/posts/MediaWikiUnlickFileLimit/1.png %}
若要對此設定值做些調整,我們可以開啟 Php.ini。
{% img /images/posts/MediaWikiUnlickFileLimit/2.png %}
調整 upload_max_filesize 設定值。
{% img /images/posts/MediaWikiUnlickFileLimit/3.png %}
以及調整 post_max_size 設定值。
{% img /images/posts/MediaWikiUnlickFileLimit/4.png %}
調整完存檔退出,檔案上傳這邊就會生效。
{% img /images/posts/MediaWikiUnlickFileLimit/5.png %}
read morePosts
MediaWiki - Install MediaWiki
欲安裝 MediaWiki,首先需先準備 Apache 網站伺服器及 MySQL 資料庫,這邊偷懶一點就不個別裝了,直接安裝 Xampp 軟件。
{% img /images/posts/SetupMediaWiki/1.png %}
{% img /images/posts/SetupMediaWiki/2.png %}
{% img /images/posts/SetupMediaWiki/3.png %}
{% img /images/posts/SetupMediaWiki/4.png %}
{% img /images/posts/SetupMediaWiki/5.png %}
{% img /images/posts/SetupMediaWiki/6.png %}
{% img /images/posts/SetupMediaWiki/7.png %}
安裝完後將 Xampp Control Panel 開起,啟用 Apache 與 MySQL 服務。
{% img /images/posts/SetupMediaWiki/8.png %}
接著將 MediaWiki 解壓縮放至 Apache 的網站放置目錄下。
{% img /images/posts/SetupMediaWiki/9.png %}
輸入對應的網址瀏覽 MediaWiki,因為還未進行安裝,所以會偵測到尚未有相關的設定,這邊點選 ‘set up the wiki’ 開始進行安裝的動作。
{% img /images/posts/SetupMediaWiki/10.png %}
安裝時比較重要的是一開始會要求選定所要使用的語系。
read morePosts
MediaWiki - Create wiki page
MediaWiki 要建立 Wiki Page,大致來說有下列幾種方式:
透過網址列去建立 透過連結 Wiki Page 的方式建立 透過搜尋框搜尋後建立 這邊分別簡單的帶過…
透過網址列去建立 使用這種方式去建立 Wiki Page,需要帶入特定格式的網址至網址列。
網址格式會像下面這樣:
http://[Wiki url]/index.php?title=[Title]&action=edit 將特定的網址帶入
{% img /images/posts/CreateMediaWikiPage/1.png %}
就可以建立出對應的 Wiki Page。
{% img /images/posts/CreateMediaWikiPage/2.png %}
透過連結 Wiki Page 的方式建立 要建立一個 Wiki Page,通常是因為有連結的需求。可能是側邊欄,也有可能是其它 Wiki Page。無論是哪種,我們都會透過語法將 Wiki Page 做個連結。
連結後回頭看一下撰寫的 Wiki Page,這時將滑鼠移上去,會很明顯的看到該連結頁面不存在。
{% img /images/posts/CreateMediaWikiPage/3.png %}
點擊連結即可建立對應的 Wiki Page。
透過搜尋框搜尋後建立 這邊需先透過搜尋框搜尋欲建立的 Wiki Page 是否已經存在。
{% img /images/posts/CreateMediaWikiPage/4.png %}
若不存在, MediaWiki 會在這邊告知搜尋的 Wiki Page 不存在,同時會有個建立頁面的快速連結,點擊下去即可建立指定的 Wiki Page。
{% img /images/posts/CreateMediaWikiPage/5.
read moreTag: Windows Azure
Posts
Windows Azure - Enable MediaWiki File Upload
使用 Azure 架設 MediaWiki,若要啟動檔案上傳的功能,我們需要在建立 MediaWiki 時,將 Enable MediaWiki File Uplad 以及 Use Windows Azure Storage As File Backend 設定開啟,並設定 Windows Azure Storage Account Name 以及 Windows Azure Storage Account Key。
{% img /images/posts/EnableAzureMediaWikiFileUplad/1.png %}
填寫 Windows Azure Storage Account Name 以及 Windows Azure Storage Account Key 的值時,可參閱儲存體的存取金鑰。
{% img /images/posts/EnableAzureMediaWikiFileUplad/2.png %}
這樣建立出來的 MediaWiki 就會啟用 MediaWiki 的 WindowsAzureStorage Extension,可以看到建立好的 LocalSetting.php 內會自動設好相關的設定。
{% img /images/posts/EnableAzureMediaWikiFileUplad/3.png %}
建立出來的 MediaWiki 也可以正常的將檔案上傳上去。
read morePosts
Windows Azure - MediaWiki in Azure
用 Azure 架設 MediaWiki,我們可以到 Azure 的入口網站,切換至網頁管理頁面。
{% img /images/posts/MediaWikiInAzure/1.png %}
按下左下角的新增按鈕。
{% img /images/posts/MediaWikiInAzure/2.png %}
然後從組件庫中建立我們要的服務。
{% img /images/posts/MediaWikiInAzure/3.png %}
也就是 MediaWiki 服務,選取後按下 Next 繼續。
{% img /images/posts/MediaWikiInAzure/4.png %}
接著要進行服務的細部設定,像是服務的網址、Wiki 的名稱、登入的帳密…等。設定完一樣按下 Next 繼續。
{% img /images/posts/MediaWikiInAzure/5.png %}
最後是設定 MySQL 資料庫。
{% img /images/posts/MediaWikiInAzure/6.png %}
到這邊設定告一段落,系統會開始進行服務的佈署。
{% img /images/posts/MediaWikiInAzure/7.png %}
佈署完成按下下方的瀏覽按鍵。
{% img /images/posts/MediaWikiInAzure/8.png %}
我們即可看到 MediaWiki 服務運行的結果,但因為是第一次使用,所以此時還未有 LocalSettings.php 設定檔,為此我們可以按下畫面中的連結產生預設的設定先。
{% img /images/posts/MediaWikiInAzure/9.png %}
按下後 MediaWiki 就可正常使用了,這邊直接用服務建立時所設定的帳密進行登入就可以了。
{% img /images/posts/MediaWikiInAzure/10.png %}
read moreTag: Web.Config Transformation
Posts
SlowCheetah - XML Transforms extension
Web.Config Transformation 功能在我們有多個環境需要部署時很方便,但預設只支援 Web.config 的轉換,且發佈時才會做轉換的動作,開發上總是有些不便。
要對 Web.config 以外的設定檔案做轉換,或是要在建置時做轉換,可以參考 Web.Config Transformation - Transform on build 這篇,修改專案檔讓 Microsoft.WebApplication.targets 幫我們做設定檔的轉換。但這樣的處理方式轉換檔需要自行手動加上去,設定起來是有點費工。
若是使用 SlowCheetah 這個 Visual Studio 擴充套件相較起來就簡單了許多,可以很輕易的為設定檔加上建置時轉換。
{% img /images/posts/SlowCheetah/1.png %}
SlowCheetah 可直接透過 Extension Manager 進行安裝。
{% img /images/posts/SlowCheetah/2.png %}
{% img /images/posts/SlowCheetah/3.png %}
{% img /images/posts/SlowCheetah/4.png %}
{% img /images/posts/SlowCheetah/5.png %}
使用時只要在方案總管中找到欲加入建置轉換的設定檔,按下滑鼠右鍵,在彈出的滑鼠右鍵選單中選取 Add Transform 滑鼠右鍵選單選項。
{% img /images/posts/SlowCheetah/6.png %}
在彈出的確認視窗中按下 Yes 按鈕繼續。
{% img /images/posts/SlowCheetah/7.png %}
對應的轉換檔即會幫我們產生。
{% img /images/posts/SlowCheetah/8.png %}
專案檔中也會做對應的修改,會加入 SlowCheetah 自己的 Targets 去做轉換,而非使用現成的 Microsoft.
read morePosts
Web.config Transformation Tester
Web.config Transformation Tester 是可用來測試 Web.Config Transformation 的線上服務,若要學習 Web.Config Transformation 或是要驗證轉換這是個不錯的服務。
使用上也很簡單,將要做轉換的 Web.Config 檔內容放入 Web.Config 區塊。
{% img /images/posts/ConfigTransformationTester/1.png %}
轉換的設定檔內容放入 Transform (eg. Web.Debug.config) 區塊。
{% img /images/posts/ConfigTransformationTester/2.png %}
接著按下 Transform 按鈕,轉換後的結果即會出現在 Result 區塊。
{% img /images/posts/ConfigTransformationTester/3.png %}
Link Web.config Transformation Tester
read morePosts
Web.Config Transformation - Transform on build
Web.Config Transformation 功能在我們有多個環境需要部署時很方便,但預設只會在發佈時做對應的轉換,因此當我們需要針對特定環境下去排解問題時,就不能很直接的切換 Profile 去做偵錯的動作。
若要在建置時也做 Web.Config 的轉換,讓除錯時更為方便。我們可以複製 Web.Config,降之更名為 Web.Base.config,然後卸載並開啟專案檔,將 Web.Base.config 設定為 DependentUpon Web.Config。
... <Content Include="Web.Base.config"> <DependentUpon>Web.config</DependentUpon> </Content> ... 然後在專案檔中設定建置前用 Microsoft.WebApplication.targets 將 Web.Base.config 套用 Web.$(Configuration).config 的轉換設定產出實際我們需要的 Web.config。
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio11.0\WebApplications\Microsoft.WebApplication.targets" /> <Target Name="BeforeBuild"> <TransformXml Source="Web.Base.config" Transform="Web.$(Configuration).config" Destination="Web.config" /> </Target> 設定好存檔,將專案檔載回方案檔,以後建置時即會運行轉換的動作。
除了建置時驅動轉換外,若是想要將 Web.Config Transformation 功能套用到 Web.Config 外的 Config 檔,也可以使用該方法如法泡製。
read morePosts
Web.Config Transformation - Add Config Transform File
當我們建立一個 Web 專案,Visual Studio 預設就會幫我們產生好 Debug 與 Release 這兩個轉換檔。但隨著專案的進行,專案中的 Build Configuration 可能會隨之增加。此時我們需要為新建的建置組態建立對應的 Config Transform 檔。
建立新的 Config Transform 檔很簡單,只要在方案總管中找到 Web.config 檔,在檔案上按下滑鼠右鍵。在彈出的滑鼠右鍵快顯選單中,選取 Add Config Transform 選單選項。Visual Studio 即會比對 Build Configuration 去產生缺少的 Config Transform 檔案。
{% img /images/posts/AddConfigTransform/1.png %}
read morePosts
Web.Config Transformation - Transform Web.config When Deploying a Web Application Project
Web.Config Transformation 允許開發人員依照特定的語法設定部署時 Web.Config 所要做的轉換動作,像是移除除錯設定、或是連線字串。該功能在 Visual Studio 2012 開始整進 Visual Studio,若要在 Visual Studio 2010 使用,需為 Visual Studio 加裝 Visual Studio Web Publish Update 套件。
在使用上,當我們用 Visual Studio 建立一個 Web 專案,預設就會幫我們建好 Debug 跟 Release 最基本的轉換設定。以預設的設定來說,Debug 沒作任何的轉換動作,而 Release 會將 Web.Config 中除錯的設定拔除。
... <system.web> <compilation xdt:Transform="RemoveAttributes(debug)" /> ... 我們可以參閱 Release 的轉換設定檔,設定檔內的註解會稍稍提示使用的方式,以及說明文件的位置,確實參閱後做些基本的設定應該都不成問題。
<?xml version="1.0" encoding="utf-8"?> <!-- 有關使用 web.config 轉換的詳細資訊,請造訪 http://go.microsoft.com/fwlink/?LinkId=125889 --> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <!-- 在下面的範例中,"SetAttributes" 轉換只會在 "Match" 定位程式找到 值為 "MyDB" 的屬性 "name" 時,才將 "connectionString" 的值變 更為使用 "ReleaseSQLServer"。 <connectionStrings> <add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/> </connectionStrings> --> <system.
read moreTag: Dos
Posts
Dos - Execute multiple commands in a single line
要將多行 Dos 命令寫在同一行,依據不同的使用情境,有著不同的寫法。
像是要在運行 Command A 完後接著運行 Command B,可以用 & 串接。
Command A & Command B 要在運行 Command A 後接著運行 Command B,並將 Command A 的運行輸出導到 Command B 的輸入,可以用 | 串接。
Command A | Command B 要在運行 Command A 後,判別 ErrorLevel 為 0 才繼續運行 Command B 的話,可以用 && 串接。
Command A && Command B 要在運行 Command A 後,判別 ErrorLevel 不為 0 才繼續運行 Command B 的話,可以用 || 串接。
Command A || Command B Link dos - How to execute multiple commands in a single line - Stack Overflow
read moreTag: .NET
Posts
Auto assign assembly's build/revision number
在做軟體開發時,總是會碰到遞增產品版號的需求,通常這種時候我們會撰寫 Script 在建置之前對 Assembly.vs 檔內的版本資訊進行修改,以達到像這樣的需求。
然而有些時後我們只是想要讓建置的版號跟前次建立的有所區隔,不一定要將版號遞增的話,其實不需要到撰寫 Script 這樣麻煩,只要透過 Visual Studio 內建的機制就可以做到了。
將 Assembly.vs 檔開啟,視需求將 AssemblyVersion 的 Build 或 Revision Number 部份用 * 替換。並將 AssemblyFileVersion 設定移除。
{% img /images/posts/AutoAssignAssemblyVersion/1.png %}
接著存檔建置,即會發現每次建置的版號會有所不同。
Build 的部份會是當前本地時間與 2000 年 1 月 1 日之間所差天數,Revision 部分為與本地午夜所差的秒數除以 2。
Link AssemblyVersionAttribute 建構函式 (System.Reflection) Auto-Incrementing Build Numbers in Visual Studio.NET c# - Can I automatically increment the file build version when using Visual Studio? - Stack Overflow
read morePosts
.NET - A Simple Finite State Machine Solution
想要用實現有限狀態機的功能,看了一下網路上的解決方案以及 State Pattern,覺得都不怎麼適用,因此利用 Tuple 與 Dictionary 去實作了一個簡易又可重複使用的 State Machine:
public sealed class StateMachine<TState, TCommand> { #region Fields Dictionary<Tuple<TState, TCommand>, TState> _transitions; #endregion Fields #region Properties /// <summary> /// Gets the m_ transitions. /// </summary> /// <value> /// The m_ transitions. /// </value> private Dictionary<Tuple<TState, TCommand>, TState> m_Transitions { get { return _transitions ?? (_transitions = new Dictionary<Tuple<TState, TCommand>, TState>()); } } /// <summary> /// Gets the state of the current. /// </summary> /// <value> /// The state of the current.
read moreTag: JQuery
Posts
JQuery DataTables - Table plug-in for jQuery
JQuery DataTables 是 JQuery 的 DataTable 元件,需要使用 jQuery 1.7 以後的版本。
使用時需再 HTML 檔建立 Table,設定 Header 與 Footer,如果是要用 Client side 處理的話,這邊可連帶設定欲呈現的資料:
<table id="table_id" class="display"> <thead> <tr> <th>Column 1</th> <th>Column 2</th> </tr> </thead> <tbody> <tr> <td>Row 1 Data 1</td> <td>Row 1 Data 2</td> </tr> <tr> <td>Row 2 Data 1</td> <td>Row 2 Data 2</td> </tr> </tbody> </table> Table 建好後,加上對應的 JavaScript 檔引用:
<!-- DataTables CSS --> <link rel="stylesheet" type="text/css" href="/DataTables-1.10.0/css/jquery.dataTables.css"> <!-- jQuery --> <script type="text/javascript" charset="utf8" src="/DataTables-1.
read moreTag: ODP.NET
Posts
ODP.NET - Oracle Data Provider for .NET
要用 C# 存取 Oracle,通常我們會使用 ODP.NET。
ODP.NET 目前有 x86、 x64 與 Managed 三個版本可供使用。
Managed 版本為純 .NET 的解決方案,具備位元適應性, 能兼容於 x86 與 x64 的環境,可不安裝 Oracle client 使用,只是目前尚未支援 UDT 操作。
x86 與 x64 版本的 ODP.NET 不具位元適應性,需依運行環境使用正確的組件,且需安裝對應的 Oracle client,或是將會用到的 Oracle client 組件一併發佈,使用起來較 Managed 的麻煩,但能使用完整的功能。
不論選用哪個版本做開發,使用前都需先將組件加入參考,這邊可直接透過 NuGet 安裝對應的套件。
{% img /images/posts/ODP.NET/1.png %}
{% img /images/posts/ODP.NET/2.png %}
{% img /images/posts/ODP.NET/3.png %}
{% img /images/posts/ODP.NET/4.png %}
組件載入後,程式撰寫起來跟一般的 ADO.NET 程式沒什麼兩樣。
首先要先建立資料庫的連線。
using(var conn = new OracleConnection(connstring)) { ... } 接著將建立的資料庫連線開啟。
read moreTag: WCF
Posts
WCF - Self hosting service
要 Self hosting WCF 的服務。首先要先將 System.ServiceModel 加入參考。
{% img /images/posts/WCFSelfHosting/1.png %}
接著在程式設計中建立 ServiceHost。建立的同時要指定欲運行的 Service 型態,以及要 Host 的位置。
var serviceUrl = "http://localhost:6525/ExecuteService"; var serviceUri = new Uri( serviceUrl ); using (var host = new ServiceHost (typeof(WcfServiceLibrary1. ExecuteService), serviceUri)) { ... } 再來要建立 ServiceMetadataBehavior 並對其做些對應的設定,像是啟用 HttpGet。
... var smb = new ServiceMetadataBehavior (); smb.HttpGetEnabled = true; smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; ... 將剛建立的 ServiceMetadataBehavior 加到 ServiceHost.Description.Behaviors。
... host.Description.Behaviors.Add(smb); ... 在開始需要服務時,叫用 ServiceHost 的 Open 方法啟用 WCF 服務。
read morePosts
WCF - Test WCF service with WCF Test Client
WCF Test Client 是ㄧ用來測試 WCF 的工具。使用時只要透過上方的功能選單。
{% img /images/posts/WCFTestClient/1.png %}
或是透過左側節點的滑鼠右鍵功能選單去觸發 ‘Add Service…’ 功能。
{% img /images/posts/WCFTestClient/2.png %}
將欲測試的 WCF Service 位置加入…
{% img /images/posts/WCFTestClient/3.png %}
{% img /images/posts/WCFTestClient/4.png %}
加入後左側的樹會展出該 Service 的節點,下方會有該 Service 可提供叫用的功能。
{% img /images/posts/WCFTestClient/5.png %}
在左側的樹這邊找到想要測試的功能,點擊切換。
{% img /images/posts/WCFTestClient/6.png %}
可以看到右側這邊會有該功能的輸入參數可供設定。
輸入參數設定完後,按下 Invoke 按鈕發送 Request。
{% img /images/posts/WCFTestClient/7.png %}
即可取得對應的 Response。
{% img /images/posts/WCFTestClient/8.png %}
{% img /images/posts/WCFTestClient/9.png %}
read moreTag: JIT
Posts
.NET 4.5 - Multicore JIT
以往我們的程式要增快啟動速度時,我們會使用 ngen 去產生原生映像檔,讓程式運行時改運行預先編譯過的原生映像檔,以減少 JIT 編譯的耗費。
然而 ngen 這種改善方案只適用於某些情境下,像是有安裝包的部署。並不是所有的情境都可以套用 ngen 這種改善方案。故在 .Net Framework 4.5 出現了 Multicore JIT 的概念,以並行編譯的方式來提升程式的啟動速度,預期可加速約 20% - 50% 。
微軟官方也有提供一些比較數據可供參考。
{% img /images/posts/MultiCoreJIT/1.png %}
{% img /images/posts/MultiCoreJIT/2.png %}
Multicore JIT 的運作原理主要是將運行分為兩種 Mode。一個是 Recording mode,於程式第一次運行時啟動,會將跟 Compile 要求的編譯紀錄到指定的 Profile 檔案。
{% img /images/posts/MultiCoreJIT/3.png %}
一個是 Plackback mode,會依照 Recording mode 所紀錄的 Profile 用另外一個 CPU 下去在背景編譯。
{% img /images/posts/MultiCoreJIT/4.png %}
以程式面來說,Asp.Net 4.5 與 Silverlight 5 這邊會自動啟用 Multicore JIT 功能,不需要做什麼特別的設定,如果有需要也可以修改 web.config 去將之關閉。
<system.web> <compilation profileGuidedOptimizations="None" /> </system.
read moreTag: Code Contracts
Posts
Code Contracts - Contract Reference Assembly
在使用 Code Contracts 時,程式會加上很多驗證的程式,可能是前置條件、可能是後置條件、也有可能是些不變性的驗證,因此很多人對於程式效能上都有相當的疑慮。
但其實 Code Contracts 在使用上有很大的彈性,因為它底層是透過 CCRewrite 去將驗證的程式插入至正確的位置,所以它可以在專案屬性那邊將驗證檢查給直接抽掉。因此在 Release 時就可以只保留前置條件做參數的驗證,甚至是整個抽掉,這部分就比以往利用 if-throw 來驗證要來的有彈性,也不會有多餘的效能耗費。
雖然無效能耗費,但如果是開發 DLL ,那抽掉 Code Contracts 後 Release,使用該 DLL 的程式就無法享有 Code Contracts 所帶來的好處,這不是我們所樂見的。故 Code Contracts 提供了 Contract Reference Assembly 功能,在抽掉 Code Contracts 的同時,可將 Code Contracts 抽至另外ㄧ個獨立的組件,連同對應的設定提示也可一併帶到組件的 XML 中,別的組件在引用時就仍可享有 Code Contracts 所帶來的好處。
{% img /images/posts/ContractReferenceAssembly/1.png %}
這個功能在 .Net Framework 中就有被廣泛使用。可以看到 .Net Framework 這邊就有提供許多的 Contract Reference Assembly 。
{% img /images/posts/ContractReferenceAssembly/2.png %}
反組譯可以看到裡面只有存放 Code Contracts 的部分。
{% img /images/posts/ContractReferenceAssembly/3.png %}
read moreTag: SQL
Posts
SQL Server - Change Collation
要變更 Database Collation ,可以透過 GUI 開啟 Database Property 去調整 Collation 欄位值。
在調整之前必需先將 Restrict Access 欄位值為 SINGLE_USER,不然會無法切換 Collation。
{% img /images/posts/ChangeSqlCollation/1.png %}
透過 GUI 設定是比較簡易,但是資料庫一多就不怎麼適用,這時可以用 SQL 語法來做處理,開啟一個新的 Query ,填入下列語法,修改 Collation name,接著依序針對不同的資料庫下去執行就可以了。
declare @dbname varchar (100) set @dbname= quotename(db_name ()) set @collationName = 'SQL_Latin1_General_CP1_CI_AS' exec('ALTER DATABASE ' + @dbname + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE'); exec('ALTER DATABASE ' + @dbname + ' COLLATE ' + @collationName); exec('ALTER DATABASE ' + @dbname + ' SET MULTI_USER'); 變更 Column 的 Collation 比較麻煩一點,雖然一樣可以用 GUI 去做切換,但欄位一多這方法也不怎麼適用。這時一樣得改用 SQL 語法來做處理,開啟一個新的 Query ,填入下列語法 ,修改 Collation name 後運行,即會自動產生出所有資料表內的 Column Collation 轉換語法,將之依序帶入 SQL Query 視窗運行即可。這邊比較麻煩的是若有設定PK、FK之類的,需先抽掉才能轉換。
read moreTag: MEF
Posts
Mefx - MEF Composition Analysis Tool
Mefx 是一用來分析與診斷 MEF 錯誤的命令列工具。當 MEF 在運作上不如預期時,我們可藉由此工具下去做些查驗。
程式主檔可至 Managed Extensibility Framework - Download: MEF Analysis Tool (mefx) for .NET 4.0 Beta 這邊下載。
{% img /images/posts/Mefx/1.png %}
命令列的使用語法如下:
mefx [files and directories] [action] [options] 使用時首先要帶入 /file 或是 /dir 參數,並指定要進行分析的檔案或目錄。
mefx /file:MyAddIn.dll /directory:Program\AddIns [action...] 接著視需要加入其它參數。像是在後面帶入 /parts 參數用以查閱組件內內含哪些可以使用的 part。
mefx /file:MyAddIn.dll /parts 帶入 /type 查閱特定的 part。
mefx /file:MyAddIn.dll /type:MyAddIn.AddIn 或是帶入 /imports 查閱 import 點。
mefx /file:MyAddIn.dll /imports 帶入 /exports 查閱 export 點。
mefx /file:MyAddIn.dll /exports 帶入 /verbose 顯示更為詳細的資訊。
read morePosts
MEF - Handle ReflectionTypeLoadException during MEF composition
使用 MEF 去 Compose 指定目錄下的所有 Part,我們可能會像下面這樣透過 DirectoryCatalog 去提供 Export Parts,讓 CompositionContainer 去做 Compose。
private void ComposeCurrentDirectoryParts() { using (var catalog = new DirectoryCatalog(Environment.CurrentDirectory)) using (var container = new CompositionContainer(catalog)) { container.ComposeParts(this); } } 多半上面這段程式能夠運行良好。但有的時候會發生不如預期的效果,因為 DirectoryCatalog 會去找目錄下指定的檔案,可能會找到一些組件會相依於其它不存在的組件,導致發生 ReflectionTypeLoadException 錯誤。如果你碰到這樣的問題,可以避開使用 DirectoryCatalog,改成自己去遍巡處理,並用 AssemblyCatalog 載入,載入失敗則將之忽略不予處理。像是下面這樣:
public class SafeDirectoryCatalog : ComposablePartCatalog { #region Fields private AggregateCatalog _catalog; #endregion Fields #region Properties /// <summary> /// Gets the catalog. /// </summary> /// <value> /// The catalog. /// </value> private AggregateCatalog m_Catalog { get { return _catalog ?
read morePosts
[C#]MEF開發系列 - Managed Extensibility Framework(MEF)的概念與簡介
public MainForm() { InitializeComponent(); var catalog = new DirectoryCatalog(Environment.CurrentDirectory, "*.dll"); var container = new CompositionContainer(catalog); container.ComposeParts(this); foreach (IModule module in Modules) { module.Host = this; 模組MToolStripMenuItem.DropDownItems.Add(module.Name, null, Module_Click).Tag = module; } } ... } }
read moreTag: WPF
Posts
WPF - Refresh / Update WPF controls
相信大家都知道若要釋放些資源去讓畫面得以更新,若不將運算處理切離主執行緒,我們可能會偷懶用 DoEvents 來做。然而, DoEvents 這個方法的功用只是釋放資源,而釋放出的資源為誰所用,這部分我們無法掌控。因此釋放出的資源可能會被拿去做不相干的處理,造成效能嚴重低落。
在 WinForm 的世界裡,這樣的問題比較好處理,因為有許多現成的方法可以指定特定元件去做更新,像是 Update、Refresh、或是 Invalidate。
在 WPF 的世界裡,我們沒現有的方法可以直接叫用,只能用些小技巧兜出類似的功能。像是將下面這段擴充方法加入…
public static class ExtensionMethods { private static Action EmptyDelegate = delegate() { }; public static void Refresh(this UIElement uiElement) { uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); } } 程式在撰寫時就可以像下面這樣直接透過 UI 元件觸發更新。
control.Refresh(); Link Refresh / Update WPF controls
read morePosts
WPF - Binding a ListView to DataTable
要在 WPF 中將 DataTable binding 到 ListView 上,我們主要有幾種做法…
像是把 DataTable 轉型成 IListSource 後,叫用 GetList 方法,並將回傳值塞進 ListView 的 ItemSource 屬性
lvTable.ItemsSource = ((IListSource)dt).GetList(); 或是直接將 DataTable 的 DefaultView 塞進 ListView 的 ItemSource 屬性
lvTable.ItemsSource = dt.DefaultView; XAML 這邊我們只要直接將 DataTable 的 Column 繫上 ListView 內 Grid Column 的 DisplayMemberBinding 就可以了。
以個簡單的例子來看,假設我們要繫結的表單長的像下面這樣:
var dt = new DataTable(); dt.Columns.Add( "Key"); dt.Columns.Add( "Value"); dt.Rows.Add( new object[] { "Key1", "Value1"}); dt.Rows.Add( new object[] { "Key2", "Value2"}); ... lvTable.
read morePosts
WPF - DoEvents in WPF
在做大量的運算處理時,不能避免的有時候會需要做 UI 更新的動作,以給予使用者一些反饋。理想上來說,這時我們應該將處理動作切離主執行緒,在另外一個執行緒去處理,需要反饋時再將更新動作帶回主執行緒。但難免有時會偷懶將處理動作直接放在主執行緒上運行,並利用 DoEvents 去釋放資源,讓 UI 得以更新。
以這樣的情景來說,WinForm 中可直接叫用現成的 DoEvents ,但在 WPF 中則無現成的方法可供叫用,所以我們必須借用 WinForm 的 DoEvents 方法。
只要將 System.Windows.Forms.dll 組件加入參考,接著將命名空間 System.Windows.Forms 加入,再呼叫 Application.DoEvents() 方法即可。
using System.Windows.Forms; ... Application.DoEvents(); ... 或者是自行撰寫像下面這樣的程式來處理也可以。
void DoEvents(){ DispatcherFrame f = new DispatcherFrame(); Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate(object arg) { DispatcherFrame fr = arg as DispatcherFrame; fr.Continue=True; }, f); Dispatcher.PushFrame(frame); } Link DispatcherFrame Class (System.Windows.Threading) 程湘之間: WPF的UI更新方式 Application.Doevents in WPF
read morePosts
WPF - Auto select ListBoxItem when mouse over
在使用 WPF 的 ListBoxItem,若有要在滑鼠游標經過時自動選取的需求,可以為 ListBoxItem 套用像下面這樣的Style:
<ListBox.Resources> <Style BasedOn="{StaticResource {x:Type ListBoxItem}}" TargetType="{x:Type ListBoxItem}"> <Style.Triggers> <DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True"> <Setter Property="IsSelected" Value="True" /> </DataTrigger> </Style.Triggers> </Style> </ListBox.Resources> 這個 Style 只是很簡單的透過 DataTrigger 去偵測 ListBoxItem 的 IsMouseOver屬性值,當屬性值為True時觸發,透過 Setter 將 ListBoxItem 的 IsSelected 屬性值設為True。
Style 套上後,滑鼠游標移動過去,就會自動將 ListBoxItem 給選取起來。
read morePosts
[C#][WPF]WPF程式接收視窗訊息
namespace WpfApplication2 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.SourceInitialized += new EventHandler(MainWindow_SourceInitialized); }
void MainWindow_SourceInitialized(object sender, EventArgs e) { IntPtr hwnd = new WindowInteropHelper(this).Handle; HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc)); } IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { //... } return IntPtr.Zero; } } }
read morePosts
[WPF]FlowDocument
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[WPF]TextBlock
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[WPF]WrapPanel
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[WPF]Canvas
<pre> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <pre class="alt"> <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <pre> <span class="attr">Title</span><span class="kwrd">="Window1"</span> <span class="attr">Height</span><span class="kwrd">="300"</span> <span class="attr">Width</span><span class="kwrd">="300"</span><span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">Canvas</span><span class="kwrd">></span></pre> <pre> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Canvas</span>.<span class="attr">Left</span><span class="kwrd">="20"</span> <span class="attr">Canvas</span>.<span class="attr">Top</span><span class="kwrd">="50"</span><span class="kwrd">></span></pre> <pre class="alt"> ● <span class="attr">&lt;</span>- 學校 (20,50)</pre> <pre> <span class="kwrd"></</span><span class="html">TextBlock</span><span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Canvas</span>.<span class="attr">Left</span><span class="kwrd">="150"</span> <span class="attr">Canvas</span>.<span class="attr">Top</span><span class="kwrd">="200"</span><span class="kwrd">></span></pre> <pre> ● <span class="attr">&lt;</span>- 火車站 (150,200)</pre> <pre class="alt"> <span class="kwrd"></</span><span class="html">TextBlock</span><span class="kwrd">></span></pre> <pre> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Canvas</span>.
read morePosts
[WPF]Grid
<pre> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <pre class="alt"> <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <pre> <span class="attr">Title</span><span class="kwrd">="Window1"</span> <span class="attr">Height</span><span class="kwrd">="300"</span> <span class="attr">Width</span><span class="kwrd">="300"</span><span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">Grid</span><span class="kwrd">></span></pre> <pre> <span class="kwrd"><</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">RowDefinition</span><span class="kwrd">/></span></pre> <pre> <span class="kwrd"><</span><span class="html">RowDefinition</span><span class="kwrd">/></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">RowDefinition</span><span class="kwrd">/></span></pre> <pre> <span class="kwrd"></</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">Grid.ColumnDefinitions</span> <span class="kwrd">></span></pre> <pre> <span class="kwrd"><</span><span class="html">ColumnDefinition</span><span class="kwrd">/></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">ColumnDefinition</span><span class="kwrd">/></span></pre> <pre> <span class="kwrd"><</span><span class="html">ColumnDefinition</span><span class="kwrd">/></span></pre> <pre class="alt"> <span class="kwrd"></</span><span class="html">Grid.
read morePosts
[WPF]DockPanel
<pre> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <pre class="alt"> <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <pre> <span class="attr">Title</span><span class="kwrd">="Window1"</span> <span class="attr">Height</span><span class="kwrd">="300"</span> <span class="attr">Width</span><span class="kwrd">="300"</span><span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">DockPanel</span> <span class="attr">Height</span><span class="kwrd">="263"</span> <span class="attr">Name</span><span class="kwrd">="DockPanel1"</span> <span class="attr">Width</span><span class="kwrd">="276"</span><span class="kwrd">></span></pre> <pre> <span class="kwrd"><</span><span class="html">Menu</span> <span class="attr">DockPanel</span>.<span class="attr">Dock</span><span class="kwrd">="Top"</span> <span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"><</span><span class="html">MenuItem</span> <span class="attr">Header</span><span class="kwrd">="File"</span><span class="kwrd">></span></pre> <pre> <span class="kwrd"><</span><span class="html">MenuItem</span> <span class="attr">Header</span><span class="kwrd">="Open"</span><span class="kwrd">></</span><span class="html">MenuItem</span><span class="kwrd">></span></pre> <pre class="alt"> <span class="kwrd"></</span><span class="html">MenuItem</span><span class="kwrd">></span></pre> <pre> <span class="kwrd"></</span><span class="html">Menu</span><span class="kwrd">></span></pre> <pre class="alt"> </pre> <pre> <span class="kwrd"><</span><span class="html">ToolBarPanel</span> <span class="attr">DockPanel</span>.
read morePosts
[WPF]StackPanel
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read moreTag: CI
Posts
Travis CI - Trigger build with service hook test
一般來說, Travis CI 在使用時會主動在程式碼 Push 到 Server 時自動做建置的動作,但難以避免的,有的時候我們還是會需要在特定時機點手動觸發建置。這時如果為此特意 Commit ,整個版控紀錄會變得很亂,所以要透過 GitHub 的 Test Service Hook 功能去觸發 Travis CI 建置。
使用前要先進入 Repository 的 Service Hooks 頁面。
這邊可直接由 GitHub repository’s setting 進入, 或是由 Travis CI 進入。
{% img /images/posts/TravisCIServiceHookTest/1.png %}
進入後會看到像這樣的畫面:
{% img /images/posts/TravisCIServiceHookTest/2.png %}
往下捲動找到 Travis CI 後點擊。
{% img /images/posts/TravisCIServiceHookTest/3.png %}
接著點選 Test Hook 按鈕觸發 Travis CI 建置就可以了。
{% img /images/posts/TravisCIServiceHookTest/4.png %}
{% img /images/posts/TravisCIServiceHookTest/5.png %}
read morePosts
Travis CI - Build Status images
Travis CI 支援 Build status image,能讓我們將 Repository 建置的狀態嵌至網站上。
使用時只要開啟 Travis CI,將左側這邊切換至 My Repositories。
{% img /images/posts/TravisCIBuildStatusImages/1.png %}
切換至欲使用的 Repository ,在右側的建置資訊這邊,可以看到右上方有個圖片表示著這個 Repository 的建置狀態,這就是我們要拿來內嵌的圖片。
{% img /images/posts/TravisCIBuildStatusImages/2.png %}
滑鼠點擊後會出現像下面這樣的對話框。
{% img /images/posts/TravisCIBuildStatusImages/3.png %}
對話框裡面有提供嵌入用的語法,將之複製並貼入欲嵌入的位置就可以了。
多半我們會將它嵌在 GitHub 的 README.md 內。
{% img /images/posts/TravisCIBuildStatusImages/4.png %}
瀏覽 Repository 時就能一眼看出是否能成功的建置。
{% img /images/posts/TravisCIBuildStatusImages/5.png %}
Link [Travis CI: Status Images] (http://about.travis-ci.org/docs/user/status-images/)
read morePosts
Travis CI - Build .NET project
Travis CI 內建支援 C、C++、Clojure、Erlang、Go、Groovy、Haskell、Java、Python、Ruby 等語言,卻沒有支援 .Net 的,這表示官方並不特別的去做 .Net 語言的支援。然而 Travis CI 具備有相當程度的彈性,經由設定能在建置前先進行套件的安裝,因此我們還是能透過安裝 Mono 套件去建置 .Net 的專案。
在設定檔的撰寫上,Language 這邊指定語言為 C ,因為前面提到的 Travis CI 並不支援 C# 。
language: c install 這邊透過 apt-get 安裝 mono-devel 、 mono-gmcs 。
install: - sudo apt-get install mono-devel mono-gmcs script 這邊直接叫用 xbuild 去建置我們的專案或是方案就可以了。
script: - xbuild Source/LevelUp.Extensions.Core/LevelUp.Extensions.Core.csproj - xbuild Source/LevelUp.Extensions.Control/LevelUp.Extensions.Control.csproj 整個設定檔撰寫起來會像下面這個樣子:
Travis CI Integration language: c install: - sudo apt-get install mono-devel mono-gmcs script: - xbuild Source/LevelUp.Extensions.Core/LevelUp.Extensions.Core.csproj - xbuild Source/LevelUp.
read morePosts
Travis CI - Free Hosted Continuous Integration Platform for the Open Source Community
Travis CI 是免費的 CI 服務,支援 C、C++、Clojure、Erlang、Go、Groovy、Haskell、Java、Python、Ruby等語言。能用來建置 GitHub 上的 Repository, 為 GitHub 加上 CI 的能力,不需另行為此架設 CI Server。只要在 Repository 放置個 Travis CI 的設定檔,並授權給 Travis CI,最後再將 Service Hook 啟用就可以了。
此外,Travis CI 也提供狀態貼紙的功能,能將建置的狀態內嵌在想放置的位置,讓建置狀態一目了然。
使用時需先至 Travis CI 做 GitHub 的登入
{% img /images/posts/TravisCI/1.png %}
登入後會 Travis CI 會向我們要求授權
{% img /images/posts/TravisCI/2.png %}
若對要求的權限沒什麼意見,可以進一步按下 Allow access 按鈕授予權限。
{% img /images/posts/TravisCI/3.png %}
授予權限時,為了安全起見,GitHub 會再次請求輸入密碼。
{% img /images/posts/TravisCI/4.png %}
密碼確認無誤,Travis CI 即會開始將我們的 Repository 給拉回來。
{% img /images/posts/TravisCI/5.png %}
read moreTag: Win32 API
Posts
Check empty folder with IsDirectoryEmplty Win32 API
在判斷目錄是否為空這邊,.NET 4.0 以前,很多人都會很直覺的去使用 Directory.GetFiles 、Directory.GetDirectories 、或 Directory.GetFileSystemEntries 方法,用個數判斷是否為空。
public bool IsDirectoryEmplty(string directory) { //return !Directory.GetFiles(directory).Any() && !Directory.GetDirectories(directory).Any(); return !Directory.GetFileSystemEntries(directory).Any(); } 用這樣的方式處理,必須等待所有檔案都找出來後回傳才能進行空目錄的判斷,效能十分的低落。
在 .NET 4.0 後可改用 Directory.EnumerateFiles 、Directory.EnumerateDirectories 、或 Directory.EnumerateFileSystemEntries 替代。
public bool IsDirectoryEmplty(string directory) { //return !Directory.EnumerateFiles(directory).Any() && !Directory.EnumerateDirectories(directory).Any(); return !Directory.EnumerateFileSystemEntries(directory).Any(); } 相較於 .NET 4.0 以前的處理方式,檔案變成找到就立刻回傳,因此我們找到一個檔案就可以將搜尋的動作中斷,效能問題獲得了改善。
雖然效能的問題解決了,不過像這樣的處理方式會受限於 .NET Framework 的版本,不是一個比較通用的解法。而且空目錄判斷這樣的動作其實跟前面提到的取得目錄大小一樣,用 Win32 API 去跟 OS 問多半是最快的方式。
以這邊來說,我們可以將之改用 IsDirectoryEmplty API 去處理。
[ DllImport("Shlwapi.dll" , EntryPoint = "PathIsDirectoryEmpty")] [ return: MarshalAs (UnmanagedType.Bool)] public static extern bool IsDirectoryEmplty([MarshalAs (UnmanagedType.
read moreTag: Batch
Posts
Batch - Run as administrator
Windows Vista 後的作業系統開始導入 UAC ,在運行某些操作時必須要提升至管理者權限才能繼續。這在程式中只要加上 MetaData 就可以了,但在批次檔中卻沒有比較直接的做法。
好在有好心的網友整理好了下面這樣的程式碼片段
:: BatchGotAdmin :------------------------------------- REM --> Check for permissions >nul 2>&1 "%SYSTEMROOT%\system32
read morePosts
Change color in batch file
要在批次檔中設定顯示的顏色,我們可以像下面這樣撰寫批次檔
@ECHO off SETLOCAL EnableDelayedExpansion for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do ( set "DEL=%%a" ) #========== #Main Action #=========== goto :eof :AppendColorText echo off <nul set /p ".=%DEL%" > "%~2" findstr /v /a:%1 /R "^$" "%~2" nul del "%~2" > nul 2>&1 goto :eof :AppendColorTextLine echo off call :AppendColorText %~1 %~2 Echo. goto :eof 筆者在這邊宣告了兩個Method可以直接叫用,一個是AppendColorText,一個是AppendColorTextLine,差異只在於是否要做換行的動作
需要叫用時可像下面這樣呼叫
call :AppendColorText [TextColor] [DisplayText] call :AppendColorTextLine [TextColor] [DisplayText] 第一個參數帶入要顯示的顏色,第二個參數帶入要顯示的字串就可以了
read moreTag: FxCop
Posts
FxCop - assembly reference cannot be resolved
在使用 FxCop 分析組件時,某些組件在用命令列載入時會跳出 cannot be resolve 這樣的錯誤訊息。
{% img /images/posts/FxCopUnresolvedAssembly/1.png %}
改用 FxCop 嘗試載入的話,也會找不到相依的組件而彈出詢問對話框。
{% img /images/posts/FxCopUnresolvedAssembly/2.png %}
這樣的問題是由於某些相依的組件找不到所導致,而這些組件有時候只是在 GAC 內。所以要解決這樣的問題,可以在 FxCop 點選 Project/Options... 主選單選項,將開出的 Options 對話視窗切換至 Spelling & Analysis 頁籤,勾選 Search Global Assembly Cache for missing references 勾選框。
{% img /images/posts/FxCopUnresolvedAssembly/3.png %}
{% img /images/posts/FxCopUnresolvedAssembly/4.png %}
若是使用命令列驅動 FxCop 分析,可帶入命令列參數 /gac。
FxCopCmd /file:[Assembly] /gac 這樣 FxCop 就會嘗試由 GAC 中找尋遺失的組件參考。
read moreTag: MS-Dos
Posts
MS-DOS - Merge files with copy command
若要在 MS-Dos 下撰寫 Script 去合併檔案,很直覺得會想到用 Type Command 將內容秀出並將之導到指定的檔案流做存放。
像是要將所有的 txt 檔進行合併並儲存到 outputFile.txt 的話,就可以像下面這樣叫用:
type *.txt >> outputFile.txt 但在 MS-DOS 下的 Copy Command 也能做到一樣的效果,只要像下面這樣叫用:
copy *.txt outputFile.txt 就可以將所有的 txt 合併儲存至outputFile.txt 內。
若是要合併的檔案不是單純的可用萬用字元濾出,或是需要精確的控制合併的順序,我們可以像下面這樣透過 + 去串接多個來源檔案:
Copy file1.txt+file2.txt+file3.txt outputFile.txt Link Copy /b 合併檔案語法 你知道 Windows 命令提示字元 的 copy 指令也可以合併檔案嗎? 複製串連命令語法為基礎的檔案
read moreTag: VMware
Posts
Virtualization in VMware
在VMware下若欲跑些需要虛擬化的程式,可將VMware的Virtualization功能開啟
首先將VMware的Settings對話框開啟,點擊選取Advanced按鈕
{% img /images/posts/VMwareVirtualization/1.png %}
將Preferred virtualization engine欄位的值設為Intel VT-x with EPT.
{% img /images/posts/VMwareVirtualization/2.png %}
找到對應的.vmx檔將之開啟,將下列內容填入後存檔
hypervisor.cpuid.v0 = “FALSE” mce.enable = “TRUE” vhv.enable = “TRUE” 像是下面這樣
{% img /images/posts/VMwareVirtualization/3.png %}
{% img /images/posts/VMwareVirtualization/4.png %}
{% img /images/posts/VMwareVirtualization/5.png %}
設定完後將虛擬機啟動,就可以在裡面使用虛擬化的功能了,像是Windows Phone的模擬器就可以在VMware內運行良好。
{% img /images/posts/VMwareVirtualization/6.png %}
read moreTag: C++
Posts
[C++]使用Global Flags偵測記憶體越界錯誤
int _tmain(int argc, _TCHAR* argv[]) { int m_len = 5; char *m_p = (char *)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, m_len);
m_p[m_len] = 0;
HeapFree (GetProcessHeap (),0, m_p);
return 0; }
read morePosts
[C++]使用Visual Leak Detector for Visual C++ 2008/2010輔助偵測程式中記憶體洩漏的問題
#include “stdafx.h” #include “vld.h”
int _tmain(int argc, _TCHAR* argv[]) { char* buffer = new char[512]; return 0; }
read morePosts
[C++]event_source attribute的功用
void BindingEvent(){ __hook(&TestObj::Executed,this,&TestObj::OnExecuted); } void UnBindingEvent(){ __hook(&TestObj::Executed,this,&TestObj::OnExecuted); } };
read morePosts
[C++]使用nsiqcppstyle輔助檢查C/C++的Coding Style
[Example] nsiqcppstyle . nsiqcppstyle targetdir nsiqcppstyle -f filefilterpath targetfilepath
[Options] -h Show this help -v Show detail ouput(verbose mode) -r Show rule list -o path Set the output path. It’s only applied when the output is csv or xml. -f path Set the filefilter path. If not provided, it uses the default fi lterpath (target/filefilter.txt) If you provide the file path(not folder path) for the target, -f option should be provided.
read morePosts
[C++]使用TinyXml讀寫Xml
TiXmlNode* rootElement = xmlDoc.InsertEndChild(TiXmlElement("Person")); rootElement ->InsertEndChild(TiXmlElement("Name")) ->InsertEndChild(TiXmlText(person->m_sName.c_str())); rootElement ->InsertEndChild(TiXmlElement("NickName")) ->InsertEndChild(TiXmlText(person->m_sNickName.c_str())); char buffer[256]; _itoa(person->m_nAge, buffer,10); rootElement ->InsertEndChild(TiXmlElement("Age")) ->InsertEndChild(TiXmlText(buffer)); xmlDoc.SaveFile(file.c_str()); }
xmlDoc.LoadFile(); if(xmlDoc.ErrorId() > 0) return; TiXmlElement* pRootElement = xmlDoc.RootElement(); if(!pRootElement) return; TiXmlElement* pNode = NULL; pNode = pRootElement->FirstChildElement("Name"); if(pNode) { person->m_sName = pNode->GetText(); } pNode = pRootElement->FirstChildElement("NickName"); if(pNode) { person->m_sNickName = pNode->GetText(); } pNode = pRootElement->FirstChildElement("Age"); if(pNode) { person->m_nAge = atoi(pNode->GetText()); } }
#include “stdafx.h” #include <string> #include “tinyxml.h”
#include “tinystr.
read morePosts
[C++]使用Pageheap偵測記憶體越界錯誤
pageheap Displays pageheap enabled programs
pageheap /enable PROGRAM Enables page heap for PROGRAM pageheap /enable PROGRAM FLAGS Enables page heap for PROGRAM using
FLAGS (hex number) for heap flags.
pageheap /disable PROGRAM Disables page heap for PROGRAM pageheap PROGRAM Displays current setting for PROGRAM
Example: pageheap /enable notepad pageheap /disable pbrush
Note. Enabling page heap does not affect currently running processes. If you need to use page heap for processes that are already running and cannot be restarted (csrss.
read morePosts
[C++]使用ReadDirectoryChangesW API監控檔案系統的改變
hDirectoryHandle = ::CreateFileA( file, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
if(hDirectoryHandle == INVALID_HANDLE_VALUE) return;
memset(buffer, 0, nBufferSize);
if(!::ReadDirectoryChangesW( hDirectoryHandle, buffer, nBufferSize, bIncludeSubdirectories, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME, &dwBytes, NULL, NULL) || GetLastError() == ERROR_INVALID_HANDLE) { break; }
if(!dwBytes) { printf(“Buffer overflow~~ “); }
do { switch (record->Action) { case FILE_ACTION_ADDED: printf(“FILE_ACTION_ADDED:”); break; case FILE_ACTION_REMOVED: printf(“FILE_ACTION_REMOVED:”); break; case FILE_ACTION_MODIFIED: printf(“FILE_ACTION_MODIFIED:”); break; case FILE_ACTION_RENAMED_OLD_NAME: printf(“FILE_ACTION_RENAMED_OLD_NAME:”); break;
read morePosts
[C++]Simple nativated timer class
};
#pragma region Constructor & DeConstructor EventArgs::EventArgs(void) { }
EventArgs::~EventArgs(void) { }
#pragma endregion
[event_source] [event_receiver] class Timer { #pragma region Var private: int _nTimerID; int _nInterval; bool _bIsEnabled; #pragma endregion
#pragma region Private Property private: __declspec(property(get=Get_nTimerID,put=Set_nTimerID)) int m_nTimerID; #pragma endregion
#pragma region Public Property public: __declspec(property(get=Get_nInterval,put=Set_nInterval)) int m_nInterval;
__declspec(property(get=Get_bIsEnabled,put=Set_bIsEnabled)) bool m_bIsEnabled; #pragma endregion
#pragma region Event public: __event void IntervalChanging(void* sender, EventArgs* e); __event void IntervalChanged(void* sender, EventArgs* e); __event void IsEnabledChanging(void* sender, EventArgs* e); __event void IsEnabledChanged(void* sender, EventArgs* e); __event void Tick(void* sender, EventArgs* e); #pragma endregion
read morePosts
[C++]使用Cppcheck靜態分析工具輔助檢查C++程式潛在問題
Syntax: cppcheck [OPTIONS] [files or paths]
If a directory is given instead of a filename, *.cpp, *.cxx, *.cc, *.c++, *.c, *.tpp, and *.txx files are checked recursively from the given directory.
Options: –append=<file> This allows you to provide information about functions by providing an implementation for them. –check-config Check cppcheck configuration. The normal code analysis is disabled by this flag. -D<ID> By default Cppcheck checks all configurations. Use -D to limit the checking.
read morePosts
[C++]C++ Nativated Property With Event Code Snippet
#pragma region Public Property public: declspec(property(get=Get$field$,put=Set$field$)) $type$ m_$field$; #pragma endregion
#pragma region Event public: __event void $field$Changing(void* sender, $eventArgs$* e); __event void $field$Changed(void* sender, $eventArgs$* e); #pragma endregion
#pragma region Property Process Method public: inline $type$ Get_$field$() { return _$field$; }
inline void Set_$field$($type$ value) { if(_$field$ == value) return; $eventArgs$ e; On$field$Changing(&e); _$field$ = value; On$field$Changed(&e); } #pragma endregion
#pragma region Protected Method protected: void On$field$Changing($eventArgs$* e) { __raise $field$Changing(this, e); }
read morePosts
[C++]C++ Nativated Property Code Snippet
#pragma region Public Property public: declspec(property(get=Get$field$,put=Set$field$)) $type$ m_$field$; #pragma endregion
#pragma region Property Process Method public: inline $type$ Get_$field$() { return _$field$; }
inline void Set_$field$($type$ value) { if(_$field$ == value) return; _$field$ = value; } #pragma endregion]]></Code> </Snippet> </CodeSnippet> </CodeSnippets>
read morePosts
[C++]C++ Create GUID
GUID *pguid = new GUID; CoCreateGuid(pguid); // Convert the GUID to a string UuidToString(pguid, (RPC_WSTR*)&guidStr); delete pguid; return wstring(guidStr); }
#include “stdafx.h” #include <objbase.h> #include <string>
using namespace std;
wstring GetGUID() { _TUCHAR *guidStr = NULL;
GUID *pguid = new GUID; CoCreateGuid(pguid); // Convert the GUID to a string UuidToString(pguid, (RPC_WSTR*)&guidStr); delete pguid; return wstring(guidStr); }
int _tmain(int argc, _TCHAR* argv[]) { wstring guid = GetGUID(); wprintf(guid.c_str()); return 0; }
read morePosts
[C++]C++ Simple Lazy class
template<class T> class Lazy { #pragma region Var private: std::function<T (void)> _func; T _result; bool _bIsValueCreated; #pragma endregion
#pragma region Private Property private: __declspec(property(get=Get_func,put=Set_func)) std::function<T (void)> m_func; #pragma endregion
#pragma region Public Property public: __declspec(property(get=Get_result)) T m_result;
__declspec(property(get=Get_bIsValueCreated,put=Set_bIsValueCreated)) bool m_bIsValueCreated; #pragma endregion
#pragma region Constructor & DeConstructor public: Lazy(std::function<T (void)> func) { Reset(); m_func = func; }
~Lazy(void) { Reset(); } #pragma endregion
#pragma region Property Process Method private: inline std::function<T (void)> Get_func() { return _func; }
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: lambda
auto result = lambda(1,2);
auto result = lambda(1,2);
auto lambda = = -> int { return val1 + val2; };
result = lambda();
lambda(1,2);
lambda(1,2);
auto lambda = =, &result { result = val1 + val2; };
lambda();
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: nullptr
void Test(int value) { cout << “void Test(int value)”; }
int _tmain(int argc, _TCHAR* argv[]) { Test(NULL); return 0; }
#include “stdafx.h” #include <iostream>
using namespace std;
void Test(int* value) { cout << “void Test(int* value) “; }
void Test(int value) { cout << “void Test(int value) “; }
int _tmain(int argc, _TCHAR* argv[]) { Test(NULL); Test((int*)NULL); Test(nullptr); return 0; }
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: auto
#include “stdafx.h” #include <string> #include <list> #include <map>
using namespace std;
int _tmain(int argc, _TCHAR* argv[]) { auto x = 1, *y = &x, **z = &y; // Resolves to int. auto a(2.01), *b (&a); // Resolves to double. auto c = ‘a’, *d(&c); // Resolves to char. auto m = 1, &n = m; // Resolves to int.
map<int,list<string>> mapObj; map<int,list<string>>::iterator i1 = mapObj.begin(); auto i2 = mapObj.begin(); auto lambda = []()->int { return 0; }; return 0; }
read morePosts
[C++][Visual Studio]Visual studio 2010 C++0x new feature: static_assert
#include “stdafx.h”
#define DEFAULT_VALUE 0 #define MAX_VALUE 100
const int VALUE = 10;
struct MyStruct { char data[1024]; };
template < class T, int Size > class Vector { static_assert(Size > 0, “Vector size must be bigger than zero!”);
T m_values[Size]; };
int _tmain(int argc, _TCHAR* argv[]) { static_assert( sizeof(void ) == 4, “64-bit code generation is not supported.”); static_assert( MAX_VALUE > DEFAULT_VALUE, “DEFAULT_VALUE must be smaller than MAX_VALUE” ); static_assert( MAX_VALUE > VALUE, “VALUE must be smaller than MAX_VALUE” ); static_assert( sizeof( MyStruct ) < 10241024, “The structure size exceeds stack size” ); Vector<int, 10> intArray; return 0; }
read morePosts
[C++][Visual Studio]Natived C++使用Visual Studio做單元測試
//Act actual = myObj.Add(x, y); //Assert Assert::AreEqual(actual, expected); }; }; }
read morePosts
[C++/CLI]Nativated物件處理Managed物件的事件
void OnAutoRunTimerTick(System::Object^ sender, System::EventArgs^ e) { _handler->AutoRunTimer_Tick(sender, e); } };
read morePosts
[VC.NET] 如何修復 quot;C2039: lsquo;GetCurrentDirectoryA()rsquo; : is Not a Member of lsquo;System::IO::Directoryrsquo;quot;問題
int main(array<System::String ^> ^args) { Console::WriteLine(L"Dir: “+System::IO::Directory::GetCurrentDirectory()); // Error! return 0; } #undef GetCurrentDirectory
int main(array<System::String ^> ^args) { Console::WriteLine(L"Dir: “+System::IO::Directory::GetCurrentDirectory()); return 0; }
read morePosts
VC.NET Natived Property
int _tmain(int argc, _TCHAR* argv[]) { TestObj obj; obj.m_bIsRunning = true; return 0; }
read morePosts
C++/CLI索引子
int _tmain(int argc, _TCHAR* argv[]) { ArrayClass a; for (int i=0;i<1024;++i){ a[i]=i; } return 0; }
read moreTag: Software
Posts
[C++]使用Global Flags偵測記憶體越界錯誤
int _tmain(int argc, _TCHAR* argv[]) { int m_len = 5; char *m_p = (char *)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, m_len);
m_p[m_len] = 0;
HeapFree (GetProcessHeap (),0, m_p);
return 0; }
read morePosts
[C++]使用nsiqcppstyle輔助檢查C/C++的Coding Style
[Example] nsiqcppstyle . nsiqcppstyle targetdir nsiqcppstyle -f filefilterpath targetfilepath
[Options] -h Show this help -v Show detail ouput(verbose mode) -r Show rule list -o path Set the output path. It’s only applied when the output is csv or xml. -f path Set the filefilter path. If not provided, it uses the default fi lterpath (target/filefilter.txt) If you provide the file path(not folder path) for the target, -f option should be provided.
read moreTag: Control
Posts
[C#][Control]BitsControl概念與簡易實做
int bitWith = width / 8; bit8.Width = bitWith; bit7.Width = bitWith; bit6.Width = bitWith; bit5.Width = bitWith; bit4.Width = bitWith; bit3.Width = bitWith; bit2.Width = bitWith; bit1.Width = bitWith; int bitHeight = flowLayoutPanel1.ClientSize.Height - bit8.Margin.Top * 2; bit8.Height = bitHeight; bit7.Height = bitHeight; bit6.Height = bitHeight; bit5.Height = bitHeight; bit4.Height = bitHeight; bit3.Height = bitHeight; bit2.Height = bitHeight; bit1.Height = bitHeight; }</pre> public void LoadBitsState(string hexValue) { LoadBitsState(Convert.ToInt32(hexValue, 16)); }</pre> namespace WindowsFormsApplication6 { public partial class BitsControl : UserControl { public BitsControl() { InitializeComponent(); }
read morePosts
[C#][Control]指撥開關控制項的概念與簡易實作
private SwitchState _state; public SwitchState State { get { return _state; } set { if (_state == value) return; _state = value; AdjustOnOffButton(); } } private void AdjustOnOffButton() { switch (State) { case SwitchState.On: OnOffButton.Dock = DockStyle.Top; break; case SwitchState.Off: OnOffButton.Dock = DockStyle.Bottom; break; default: break; } }</pre> private void OnOffButton_Click(object sender, EventArgs e) { Toggle(); }</pre> namespace WindowsFormsApplication3 { public partial class SwitchButton : UserControl {
public enum SwitchState { On, Off } private SwitchState _state; public SwitchState State { get { return _state; } set { if (_state == value) return; _state = value; AdjustOnOffButton(); } } public SwitchButton() { InitializeComponent(); State = SwitchState.
read morePosts
[Control][C#]WebCamPictureBox Control
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read moreTag: .NET Concept
Posts
[.Net concept]使用方法與屬性時適時為其值做快取
//Calculate count.... ... return count; }
int count = myObj.Count; for (int i = 0; i < count; ++i) { for (int j = 0; j < count; ++j) ... } }
read morePosts
[.Net Concept]理解事件的宣告方式與用法
#region Event event NameChangingEventHandler NameChanging; event NameChangedEventHandler NameChanged; #endregion</pre> #region Event event EventHandler<FriendEventArgs> FriendAdded; #endregion
#region Protected Method protected void OnFriendAdded(FriendEventArgs e) { if (FriendAdded == null) return; FriendAdded(this, e); } #endregion
#region Public Method public void AddFriend(Person friend) { Friends.Add(friend); OnFriendAdded(new FriendEventArgs(friend.Name)); } #endregion
…
class FriendEventArgs : EventArgs { #region Var private String _name; #endregion
#region Property public String Name { get { if (_name == null) return String.
read morePosts
[.Net Concept]理解並善用String pool
Console.WriteLine(string.Format("ReferenceEquals(str1, str2) = {0}", ReferenceEquals(str1, str2))); Console.WriteLine(string.Format("ReferenceEquals(str1, str3) = {0}", ReferenceEquals(str1, str3))); Console.WriteLine(string.Format("ReferenceEquals(str1, str4) = {0}", ReferenceEquals(str1, str4))); </pre></div> Console.WriteLine(string.Format("ReferenceEquals(str1, str2) = {0}", ReferenceEquals(str1, str2))); Console.WriteLine(string.Format("ReferenceEquals(str1, str3) = {0}", ReferenceEquals(str1, str3))); </pre></div> str2 = string.Intern(str2); str3 = string.Intern(str3); Console.WriteLine(string.Format("ReferenceEquals(str1, str2) = {0}", ReferenceEquals(str1, str2))); Console.WriteLine(string.Format("ReferenceEquals(str1, str3) = {0}", ReferenceEquals(str1, str3)));</pre></div> str1 = string.Intern(str1); Console.WriteLine(string.Format(@"String.IsInterned(str1) = {0}", String.IsInterned(str1) != null));</pre></div> private static void Test(int testCount, int stringLength) { NormalCompare1(string.Empty, string.Empty); NormalCompare2(string.
read morePosts
[.NET Concept]throw V.S throw ex
namespace ConsoleApplication6 { class Program {
static void Main() { TestThrow(); TestThrowEx(); } static void ThrowException() { throw new Exception(); } static void TestThrow() { try { try { ThrowException(); } catch (Exception) { throw; } } catch (Exception ex) { Console.WriteLine("TestThrow"); Console.WriteLine(ex.StackTrace); Console.WriteLine(new string('=',50)); } } static void TestThrowEx() { try { try { ThrowException(); } catch (Exception ex) { throw ex; } } catch (Exception ex) { Console.
read morePosts
[.NET Concept]使用BeginXXX/EndXXX與SuspendLayout/ResumeLayout時,考慮加上Try/Finally
Private Sub Application_ThreadException(ByVal sender As Object, ByVal e As EventArgs) ... End Sub</pre></div>
read morePosts
[.Net Concept]適時採用事件動態繫結來替代用If判斷作功能的啟用
Private _enableLogData As Boolean Public Property EnableLogData() As Boolean Get Return _enableLogData End Get Set(ByVal value As Boolean) _enableLogData = value End Set End Property Event Executing As EventHandler Event Executed As EventHandler Protected Sub OnExecuting(ByVal e As EventArgs) RaiseEvent Executing(Me, e) End Sub Protected Sub OnExecuted(ByVal e As EventArgs) RaiseEvent Executed(Me, e) End Sub Sub GoExecute() For i As Integer = 1 To 100000000 OnExecuting(New EventArgs) '運行動作,這邊為了看出差異,故不做動作 If EnableLogData Then '紀錄動作,這邊為了看出差異,故不做動作 End If OnExecuted(New EventArgs) Next End Sub End Class
read morePosts
[.NET Concept][Security].NET程式保護機制概述
//不影響結果 if(i == a){ Console.WriteLine("Some Thing Error!!"); } } 3.加入一些冗贅的運算 int a = 10;改為 int b = 2; int c = 5; int a = b * c; 值得注意的是,使用混淆保護的程式仍是可以使用反組譯工具看到混淆後的MSIL,且很容易被有心人反推回去的,只是增加了反推的難度而已。微軟自帶的Dotfuscator Community Edition好像已經有現成反推回去的程式在網路上流佈,像水瓶大介紹的DF Stack就是一例。 內核級加密保護若採用內核級加密來保護,使用反組譯工具去看MSIL時。會顯示不是CLR程式,無法看到反組譯過後的程式碼。有比混淆稍微安全些的感覺。類似的軟體有MaxToCode、XeonCode。 硬體保護硬體保護方面,有聖天狗、Aladdin等硬體加密鎖。多半這類產品除了本身會提供API可以讓程式呼叫做保護的動作外,也會附上基本的混淆與程式加密功能。 Conclusion在.NET保護這塊我涉略不深,只能做初步的介紹。這邊我要順帶一提,其實我們用來反組譯的.NET Reflector工具在加密上算是還做的不錯。畢竟本身就是反組譯用的工具,在這方面會有一定的程度,網路上也有許多相關研究。有興趣的可以從該工具的保護機制著手研究。像是Reflector保護方法初探等,還有很多篇,請自行打上關鍵字Reflector 保護,Google一下就有了。 LinkMSDN大內高手專欄 - To De or Not to De? DF Stack 1.0 - .NET 的反混淆器?DF StackReflector保護方法初探
read morePosts
[.NET Concept][C#][VB.NET].NET兩個表單間的資料互通
Public Class Form2 … Public MainForm As Form1 … ‘Form2透過Form1傳進的物件參考控制Form1 MainForm.Value = Me.NumericUpDown1.Value … End Class
read morePosts
[.NET Concept][C#][VB.NET]四捨六入五成雙
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read moreTag: VB.NET
Posts
[C#][VB.NET]最大公因數 amp; 最小公倍數
private int LCM(int num1, int num2) { return num1 * num2 / GCD(num1, num2); }</pre></div> Private Function LCM(ByVal num1 As Integer, ByVal num2 As Integer) As Integer Return num1 * num2 / GCD(num1, num2) End Function</pre></div> namespace ConsoleApplication1 { class Program { private static int GCD(int num1, int num2) { int min = 0; int max = 0; int maxModMin = 0; min = Math.Min(num1, num2); max = Math.Max(num1, num2); maxModMin = max % min; return maxModMin > 0 ?
read morePosts
PermissionController權限管理類別
#Region “Var” Private _allPermission As T Private _permission As T #End Region
#Region “Public Property” Public Property AllPermission() As T Get Return _allPermission End Get Private Set(ByVal value As T) _allPermission = value End Set End Property
''' <summary> ''' Gets the permission. ''' </summary> ''' <value>The permission.</value> Public Property Permission() As T Get Return _permission End Get Private Set(ByVal value As T) _permission = value End Set End Property #End Region
read morePosts
.NET 4.0 New Feature - Memory Mapped File
.NET Framework 在 4.0 新增了記憶體對應檔案(Memory Mapped File)功能,將以前需透過 API 才能使用的功能包在 .NET Framework 的 System.IO.MemoryMappedFiles 命名空間中,可用以編輯大小極大的檔案、減少IO的存取次數、提高檔案處理的效能、與在多個處理序中共享其內容。
要使用記憶體對應檔案物件,首先要先建立記憶體對應檔案物件,須了解到記憶體對應檔案有兩種類型;
保存的記憶體對應檔案 非保存的記憶體對應檔案 保存的記憶體對應檔案顧名思義其記憶體對應檔案的內容會與磁碟中的檔案做對應,可將檔案內容放至記憶體對應檔案中用以處理極大的檔案,當處理完畢資料會自動回存回對應檔案。
非保存的記憶體對應檔案則沒有與磁碟中的檔案對應,其所存放的值只是記憶體中的資料,可用來作處理序間通訊(IPC)的共用記憶體,當處理完畢其記憶體對應檔案的資料會被捨棄,且會被GC回收。
使用上是透過 MemoryMappedFile 類別內含的 CreateNew、 CreateOrOpen、與 CreateFromFile 等方法來建立記憶體對應檔案物件。
Method Description CreateNew 建立非保存的記憶體對應檔案物件 CreateOrOpen 建立或開啟非保存的記憶體對應檔案物件 CreateFromFile 建立保存的記憶體對應檔案物件 若是有已建好的記憶體對應檔案,也可以透過 MemoryMappedFile 類別內含的 OpenExisting 方法將已經建立好的記憶體對應檔案物件開啟。
有了記憶體對應檔案物件後,剩下的就是透過記憶體對應檔案檢視去對其作存取的動作。一個記憶體對應檔案物件可產生多個記憶體對應檔案檢視,可設定要針對記憶體對應檔案物件整體或是部份來檢視,需特別注意到記憶體對應檔案檢視也分為兩種類型:
資料流存取檢視 隨機存取檢視 資料流存取檢視透過 MemoryMappedFile.CreateViewStream 建立,採循序存取的方式處理資料,適用於非保存的記憶體對應檔案。
隨機存取檢視透過 MemoryMappedFile.CreateViewAccessor 建立,採隨機存取的方式處理資料,適用於保存的記憶體對應檔案。
這邊來看個非保存的記憶體對應檔案物件的使用範例:
Imports System.IO.MemoryMappedFiles Imports System.Collections.Specialized Imports System.Runtime.Serialization.Formatters.Binary Module Module1 Sub Main() Const capacity As Integer = 512 Const mmfKey As String = "Larry" Dim levelUpBlog As New Blog With {.
read morePosts
使用Extension Method計算漢字筆畫
public static int GetStrokesNumber(this char c) { String hex = BitConverter.ToString(Encoding.GetEncoding("Big5").GetBytes(new char[] { c })).Replace("-", string.Empty); for (int i = 0; i < _strokesNumberData.Length; ++i) { for (int j = 0; j < _strokesNumberData[i].Length; j += 2) { if (hex.CompareTo(_strokesNumberData[i][j]) >= 0 && hex.CompareTo(_strokesNumberData[i][j + 1]) <= 0) return i+1; } } return 0; } }</pre></div> Module CharExtension
Private _strokesNumberData As String()() = { _ New String() {"A440", "A441"}, _ New String() {"A442", "A453", "C940", "C944"}, _ New String() {"A454", "A47E", "C945", "C94C"}, _ New String() {"A4A1", "A4FD", "C94D", "C95C"}, _ New String() {"A4FE", "A5DF", "C95D", "C9AA"}, _ New String() {"A5E0", "A6E9", "C9AB", "C959"}, _ New String() {"A6EA", "A8C2", "CA5A", "CBB0"}, _ New String() {"A8C3", "AB44", "CBB1", "CDDC"}, _ New String() {"AB45", "ADBB", "CDDD", "D0C7", "F9DA", "F9DA"}, _ New String() {"ADBC", "B0AD", "D0C8", "D44A"}, _ New String() {"B0AE", "B3C2", "D44B", "D850"}, _ New String() {"B3C3", "B6C3", "D851", "DCB0", "F9DB", "F9DB"}, _ New String() {"B6C4", "B9AB", "DCB1", "E0EF", "F9D6", "F9D8"}, _ New String() {"B9AC", "BBF4", "E0F0", "E4E5"}, _ New String() {"BBF5", "BEA6", "E4E6", "E8F3", "F9DC", "F9DC"}, _ New String() {"BEA7", "C074", "E8F4", "ECB8", "F9D9", "F9D9"}, _ New String() {"C075", "C24E", "ECB9", "EFB6"}, _ New String() {"C24F", "C35E", "EFB7", "F1EA"}, _ New String() {"C35F", "C454", "F1EB", "F3FC"}, _ New String() {"C455", "C4D6", "F3FD", "F5BF"}, _ New String() {"C3D7", "C56A", "F5C0", "F6D5"}, _ New String() {"C56B", "C5C7", "F6D6", "F7CF"}, _ New String() {"C5C8", "C5C7", "F6D6", "F7CF"}, _ New String() {"C5F1", "C654", "F8A5", "F8ED"}, _ New String() {"C655", "C664", "F8E9", "F96A"}, _ New String() {"C665", "C66B", "F96B", "F9A1"}, _ New String() {"C66C", "C675", "F9A2", "F9B9"}, _ New String() {"C676", "C67A", "F9BA", "F9C5"}, _ New String() {"C67B", "C67E", "F9C6", "F9DC"}} <Extension()> _ Public Function GetStrokesNumber(ByVal c As Char) As Integer Dim hex As [String] = BitConverter.
read morePosts
[VB.NET]用Extension Method移除控制項
Public Module ControlExtension
#Region “Public Method” <Extension()> _ Public Sub Remove(ByVal ctrl As Control) Dim parent As Control = ctrl.Parent If parent Is Nothing Then Return End If parent.Controls.Remove(ctrl) End Sub #End Region
End Module
read morePosts
.NET 4.0 New Feature - Complex
Sub Main() ShowDetail("Complex.Zero", Complex.Zero) ShowDetail("Complex.One", Complex.One) Dim c1 As New Complex(1, 2) Dim c2 As New Complex(3, 4) ShowDetail("C1", c1) ShowDetail("C2", c2) 'Complex +-*/ Console.WriteLine("{0} + {1} = {2}", c1, c2, c1 + c2) Console.WriteLine("{0} - {1} = {2}", c1, c2, c1 - c2) Console.WriteLine("{0} * {1} = {2}", c1, c2, c1 * c2) Console.WriteLine("{0} / {1} = {2}", c1, c2, c1 / c2) Console.WriteLine() Console.WriteLine("Complex.Add({0}, {1}) = {2}", c1, c2, Complex.
read morePosts
.NET 4.0 New Feature - StringBuilder.Clear
Module Module1
Sub Main() Dim str As New StringBuilder Dim size As Integer = 100000000 Dim sw As New Stopwatch '預先編譯降低測試誤差 AppendData(str, size) ClearData1(str) ClearData2(str) ClearData3(str) '開始測試 AppendData(str, size) Console.WriteLine("Test Remove...") sw.Restart() ClearData1(str) Console.WriteLine(sw.ElapsedMilliseconds) AppendData(str, size) Console.WriteLine("Test Length...") sw.Restart() ClearData2(str) Console.WriteLine(sw.ElapsedMilliseconds) AppendData(str, size) Console.WriteLine("Test Clear...") sw.Restart() ClearData3(str) Console.WriteLine(sw.ElapsedMilliseconds) End Sub Private Sub AppendData(ByVal str As StringBuilder, ByVal size As Integer) str.Append(New String("0", size)) End Sub Private Sub ClearData1(ByVal str As StringBuilder) str.
read morePosts
.NET 4.0 New Feature - Enum.HasFlag
… Dim myOrder As DinnerItems = DinnerItems.Appetizer Or DinnerItems.Entree Or DinnerItems.Beverage Or DinnerItems.Dessert Dim hasFlag As Boolean = myOrder.HasFlag(DinnerItems.Entree Or DinnerItems.Beverage) …
read morePosts
[VB.NET]用Extension Method取得CustomAttributes
Module EnumExtension
<Extension()> _ Function GetCustomAttributes(Of T)(ByVal e As [Enum]) As IEnumerable(Of T) Return e.GetType.GetField(e.ToString).GetCustomAttributes(GetType(T), False).Cast(Of T)() End Function <Extension()> _ Function GetCustomAttribute(Of T)(ByVal e As [Enum]) As T Return GetCustomAttributes(Of T)(e).FirstOrDefault End Function End Module
Module TypeExtension
<Extension()> _ Function GetCustomAttributes(Of T)(ByVal type As Type) As IEnumerable(Of T) Return type.GetCustomAttributes(GetType(T), False).Cast(Of T)() End Function <Extension()> _ Function GetCustomAttribute(Of T)(ByVal type As Type) As T Return DirectCast(GetCustomAttributes(Of T)(type).FirstOrDefault, T) End Function <Extension()> _ Function GetCustomAttributes(Of T)(ByVal type As Type, ByVal memberName As String) As IEnumerable(Of T) Dim m = type.
read morePosts
[VB.NET]Attribute與反射的搭配使用
Property Data as Object End Class
Property RelativedType As Type Sub New(ByVal relativedType As Type) Me.RelativedType = relativedType End Sub End Class
Enum ApplicationType <RelativedType(GetType(LevelUp.Office.Word))> _ Word
<RelativedType(GetType(LevelUp.Office.Excel))> _ Excel <RelativedType(GetType(LevelUp.Office.Access))> _ Access <RelativedType(GetType(LevelUp.Office.PowerPoint))> _ PowerPoint <RelativedType(GetType(LevelUp.Office.Visio))> _ Visio End Enum
Sub StartApplication(ByVal apType As ApplicationType) Dim type As Type = apType.GetType() Dim field = type.GetField(apType.ToString) Dim att = field.GetCustomAttributes(GetType(RelativedTypeAttribute), False).Cast(Of RelativedTypeAttribute)().FirstOrDefault() Activator.CreateInstance(att.RelativedType).Start() End Sub</pre></div> Property ResourceID As String Sub New(ByVal resourceID As String) Me.
read morePosts
[VB.NET]Merge MDI ToolStrip
ReadOnly Property MainToolStrip() As ToolStrip End Interface 子視窗實做IChildForm介面,把子視窗的工具列開出。 Public Class Form1 Implements IChildForm
Public ReadOnly Property MainToolStrip() As System.Windows.Forms.ToolStrip Implements IChildForm.MainToolStrip Get Return ToolStrip1 End Get End Property End Class 在父視窗中處理MDIChildActivate事件,將工具列合併。 Public Class MDIParent1 Protected Overrides Sub OnMdiChildActivate(ByVal e As System.EventArgs) MyBase.OnMdiChildActivate(e) ToolStripManager.RevertMerge(ToolStrip) Dim childForm As IChildForm = CType(ActiveMdiChild, IChildForm) If childForm IsNot Nothing Then ToolStripManager.Merge(childForm.MainToolStrip, ToolStrip) End If End Sub End Class DownloadMergeMDIToolStrip.zip
read morePosts
[VB.NET]MDI Thumbnail Preview
Public Class ThumbnailDialog
Private _mdiParent As Form Private _thumbnailPool As Dictionary(Of Form, Image) Private Property m_MDIParent As Form Get Return _mdiParent End Get Set(ByVal value As Form) _mdiParent = value End Set End Property Private ReadOnly Property m_ThumbnailPool As Dictionary(Of Form, Image) Get If _thumbnailPool Is Nothing Then _thumbnailPool = New Dictionary(Of Form, Image) End If Return _thumbnailPool End Get End Property Public ReadOnly Property SelectedChildForm As Form Get Return If(ListBox1.
read morePosts
用Extension Method在執行階段進行控制項的拖曳
Public Module ControlExtension
#Region “Var” Private _runtimeDragClickPoint As Point #End Region
#Region “Private Property” Private Property m_RuntimeDragClickPoint() As Point Get Return _runtimeDragClickPoint End Get Set(ByVal value As Point) If _runtimeDragClickPoint <> value Then _runtimeDragClickPoint = value End If End Set End Property #End Region
#Region “Public Method” <Extension()> _ Public Sub EnableRuntimeDrag(ByVal ctrl As Control) DisableRuntimeDrag(ctrl) AddHandler ctrl.MouseDown, AddressOf ctrl_MouseDown AddHandler ctrl.MouseMove, AddressOf ctrl_MouseMove AddHandler ctrl.HandleDestroyed, AddressOf ctrl_HandleDestroyed End Sub
read morePosts
[VB.NET]利用反射載入並運行資源檔中的組件
Module MainModule
<STAThread()> _ Public Sub main(ByVal args() As String) Assembly.Load(My.Resources.ColorPicker).EntryPoint.Invoke(Nothing, New Object() {args}) End Sub End Module
同樣的概念,其實放在資源檔中的組件可以先經過壓縮處理,再放入資源檔中。載入時只要先經過解壓縮的動作,把要執行的組件從壓縮中解出,就可以執行了。 Imports System.IO Imports System.Reflection Imports ICSharpCode.SharpZipLib.Zip
Module MainModule
<STAThread()> _ Public Sub main(ByVal args() As String) Using compressedMS As New MemoryStream(My.Resources.ColorPicker) Dim zf As New ZipFile(compressedMS) Dim ze As ZipEntry = zf.GetEntry("ColorPicker.exe") Dim zs As Stream = zf.GetInputStream(ze) Dim buffer(ze.Size - 1) As Byte zs.Read(buffer, 0, buffer.Length - 1) Assembly.Load(buffer).EntryPoint.Invoke(Nothing, New Object() {args}) End Using End Sub End Module 那若是放在資源檔中的組件需要參考多個組件呢?
read morePosts
[VB.NET]MDI子視窗清單的實作
Private Sub WindowsMenu_DropDownOpening(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles WindowsMenu.DropDownOpening If ActiveMdiChild Is Nothing Then Return End If Dim sp As New ToolStripSeparator sp.Name = "MdiWindowListSeperator" WindowsMenu.DropDownItems.Add(sp) For Each f As Form In MdiChildren If Not f.Visible Then Continue For End If WindowsMenu.DropDownItems.Add(New ToolStripMenuItem(f.Text, Nothing, AddressOf MDIChildren_Click) With {.Checked = ActiveMdiChild Is f, .Tag = f}) Next End Sub Private Sub MDIChildren_Click(ByVal sender As Object, ByVal e As EventArgs) DirectCast(DirectCast(sender, ToolStripMenuItem).
read morePosts
[VB.NET]使用Win32 API擷取滑鼠游標位置的顏色
Private Function GetColor() As Color Return GetColor(Cursor.Position) End Function Private Function GetColor(ByVal point As Point) As Color Return GetColor(point.X, point.Y) End Function Private Function GetColor(ByVal x As Integer, ByVal y As Integer) As Color Dim hdc As IntPtr hdc = GetDC(IntPtr.Zero) '取該Handle值的DC GetColor = ColorTranslator.FromWin32(GetPixel(hdc, x, y)) ReleaseDC(IntPtr.Zero, hdc) '將DC 釋放 End Function</pre></div> Public Class Form1 <DllImport(“User32.dll”, EntryPoint:=“GetDC”, _ CallingConvention:=CallingConvention.StdCall, _ CharSet:=CharSet.Auto, exactspelling:=True)> _ Public Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr End Function Public Declare Function GetPixel Lib “gdi32” Alias “GetPixel” (ByVal hdc As IntPtr, ByVal X As Int32, ByVal Y As Int32) As Int32 <DllImport(“user32.
read morePosts
[VB.NET]使用mouse_event API 來操控滑鼠動作
<td valign="top" width="404">說明</td> </tr> <tr> <td valign="top" width="91"><em>dwFlags</em></td> <td valign="top" width="404">指示滑鼠動作</td> </tr> <tr> <td valign="top" width="91">dx</td> <td valign="top" width="404">x座標 (dwFlags有設MOUSEEVENTF_ABSOLUTE時,該座標為絕對座標)</td> </tr> <tr> <td valign="top" width="91">dy</td> <td valign="top" width="404">y座標 (dwFlags有設MOUSEEVENTF_ABSOLUTE時,該座標為絕對座標)</td> </tr> <tr> <td valign="top" width="91">dwData</td> <td valign="top" width="404">dwFlags為MOUSEEVENTF_HWHEEL時,該值代表捲軸捲動的量。 <br /> <br />dwFlags為MOUSEEVENTF_XDOWN或MOUSEEVENTF_XUP時,該值可為XBUTTON1 (&H0001)或XBUTTON2 (&H0002)。 <br /> <br />當dwFlags不為MOUSEEVENTF_HWHEEL、 <br />MOUSEEVENTF_XDOWN或MOUSEEVENTF_XUP,該值為0。</td> </tr> <tr> <td valign="top" width="91">dwExtraInfo</td> <td valign="top" width="404">An additional value associated with the mouse event. An application calls <strong>GetMessageExtraInfo</strong> to obtain this extra information.
read morePosts
[VB.NET]將集合類別繫結至DataGridView並使其具備新增功能
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim lst As New List(Of Person) lst.Add(New Person With {.Name = "Larry"}) DataGridView1.DataSource = lst End Sub End Class
Class Person Dim _name As String Property Name() As String Get Return _name End Get Set(ByVal value As String) _name = value End Set End Property End Class
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.
read morePosts
[VB.NET]SecureString較為安全的加密字串類別
Public Sub PrintSecureString(ByVal secureString As SecureString) ... End Sub</pre></div> Module Module1
Sub Main() Console.WriteLine("Please enter your password to be encrypted:") Dim password As SecureString = ReadPassword() Console.WriteLine() Console.WriteLine("Decripted password:") PrintPassword(password) End Sub Public Function ReadPassword() As SecureString Dim password As New SecureString() Dim nextKey As ConsoleKeyInfo = Console.ReadKey(True) While nextKey.Key <> ConsoleKey.Enter If nextKey.Key = ConsoleKey.Backspace Then If password.Length > 0 Then password.RemoveAt(password.Length - 1) ' erase the last * as well Console.
read morePosts
[VB.NET]Keys lt;=gt; Char
Module Module1
Sub Main() Dim key As Keys = Keys.A Dim keyChar As Char = Convert.ToChar(key) Console.WriteLine(Convert.ToChar(key)) Console.WriteLine(Asc(keyChar)) Console.WriteLine(Microsoft.VisualBasic.ChrW(key)) End Sub End Module
read morePosts
[Extension Method][VB.NET]ErrorProvider.GerErrorMsgs amp; ErrorProvider.HasError
Public Module ErrorProviderExtension
<Extension()> _ Public Function GetErrorMsgs(ByVal ep As ErrorProvider) As String() If ep.ContainerControl Is Nothing Then Return New String() {} End If Dim linq = From c In ep.ContainerControl.Controls Let msg = ep.GetError(c) Where msg.Length > 0 Select msg Return linq.ToArray End Function <Extension()> _ Public Function HasError(ByVal ep As ErrorProvider) As Boolean Return ep.GetErrorMsgs.Length > 0 End Function End Module
read morePosts
[VB.NET]密碼框顯示程式探討與其簡易的保護之道
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _ Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean End Function
Const EM_SETPASSWORDCHAR = &HCC Private Sub TargetSelectedControl1_TargetSelected(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TargetSelectedControl1.TargetSelected Dim hWnd As IntPtr = WindowFromPoint(MousePosition) PostMessage(hWnd, EM_SETPASSWORDCHAR, 0, 0) End Sub</pre></div> Const WM_SETTEXT As Integer = &HC Const WM_GETTEXT As Integer = &HD Const EM_SETPASSWORDCHAR = &HCC Sub New() With Me .
read morePosts
[VB.NET]自定義.NET WindowForm表單介面(三)
<DllImport("user32.dll", SetLastError:=True)> _ Private Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer End Function
Public Const WS_SYSMENU As Integer = &H80000 Const WS_MINIMIZEBOX As Integer = &H20000 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim winLong As Integer = GetWindowLong(New HandleRef(Me, Me.Handle), -16) SetWindowLong(New HandleRef(Me, Me.Handle), -16, winLong Or WS_SYSMENU Or WS_MINIMIZEBOX) End Sub</pre></div>
read morePosts
[Linq]Linq程式逐步執行與偵錯
foreach (var item in linq) { Console.WriteLine(item); } }</pre></div> For Each item In linq Console.WriteLine(item) Next End Sub</pre>
read morePosts
[Extension Method][VB.NET]使用擴充方法過濾出組件內的特定類別
Module AssembleExtension <Extension()> _ Public Function GetTypes(ByVal asm As Assembly, ByVal filterTypeName As String, Optional ByVal includeSubClass As Boolean = False) As Type() Return GetTypes(asm, Type.GetType(filterTypeName), includeSubClass) End Function
<Extension()> _ Public Function GetTypes(ByVal asm As Assembly, ByVal filterType As Type, Optional ByVal includeSubClass As Boolean = False) As Type() Dim linq = From t In asm.GetTypes Where t Is filterType OrElse (includeSubClass AndAlso t.IsSubclassOf(filterType)) Select t Return linq.ToArray End Function End Module
read morePosts
[VB.NET]比對兩個目錄中不同的檔案
Module DirectoryInfoExtension <Extension()> _ Function GetDifferentFileList(ByVal sourceDirectoryInfo As DirectoryInfo, ByVal targetDirectoryInfo As DirectoryInfo, Optional ByVal searchPattern As String = “.”, Optional ByVal searchOption As SearchOption = SearchOption.TopDirectoryOnly) As FileInfo() If sourceDirectoryInfo Is Nothing Then Throw New ArgumentNullException(“sourceDirectoryInfo”) End If If targetDirectoryInfo Is Nothing Then Throw New ArgumentNullException(“targetDirectoryInfo”) End If If targetDirectoryInfo.FullName = sourceDirectoryInfo.FullName Then Return New FileInfo() {} End If Dim sourceFiles = sourceDirectoryInfo.GetFiles(searchPattern, searchOption) Dim destFiles = targetDirectoryInfo.GetFiles(searchPattern, searchOption) Dim intersectFiles = sourceFiles.
read morePosts
[Extension Method]使用擴充方法來做物件的深層複製
Public Module ObjectExtension
#Region “Const” Const BUFFER_SIZE As Integer = 512 #End Region
#Region “Public Method”
<Extension()> _ Public Function Clone(Of T)(ByVal obj As T, Optional ByVal serializeType As SerializationFormat = SerializationFormat.Binary) As T Select Case serializeType Case SerializationFormat.Binary Dim br As New BinaryFormatter() Using ms As New MemoryStream(BUFFER_SIZE) br.Serialize(ms, obj) ms.Seek(0, SeekOrigin.Begin) Return DirectCast(br.Deserialize(ms), T) End Using Case SerializationFormat.Xml Dim x As New XmlSerializer(obj.GetType) Using ms As New MemoryStream(BUFFER_SIZE) x.
read morePosts
[Extension Method]使用擴充方法來做二維陣列排序
T[] tempArray = new T[count]; for (int idx = 0; idx < count; ++idx) { tempArray[idx] = array[idx, d2Idx]; } Array.Sort(tempArray); for (int idx = 0; idx < count; ++idx) { T tempValue = tempArray[idx]; for (int idx2 = idx+1; idx2 < count; ++idx2) { if (array[idx2, d2Idx].Equals(tempValue)) { array.Swap(idx, d2Idx, idx2, d2Idx); int d2Idx2 = (d2Idx == 0) ? 1 : 0; array.Swap(idx, d2Idx2, idx2, d2Idx2); } } } } public static void Swap<T>(this T[,] array, int idx1, int idx2, int targetIdx1, int targetIdx2) { T temp; temp = array[targetIdx1, targetIdx2]; array[targetIdx1, targetIdx2] = array[idx1, idx2]; array[idx1, idx2] = temp; } 使用上呼叫Sort方法,並傳入要排序依據的索引即可。
read morePosts
[VB.NET]用FindExecutable API取得開啟文件用的執行檔位置
<td valign="top" width="200">指定的檔案不存在</td> </tr> <tr> <td valign="top" width="200">SE_ERR_NOASSOC (31)</td> <td valign="top" width="200">沒有對應用來開啟的執行檔</td> </tr> <tr> <td valign="top" width="200">SE_ERR_OOM (8)</td> <td valign="top" width="200">Windows XP only. 系統記憶體資源不足</td> </tr> Public Class NoAssociatedFileTypeException Inherits ApplicationException
End Class
Public Class Win32API Const SE_ERR_FNF As Integer = 2 Const SE_ERR_OOM As Integer = 8 Const SE_ERR_NOASSOC As Integer = 31
<Runtime.InteropServices.DllImport("shell32.DLL", EntryPoint:="FindExecutable")> _ Private Shared Function FindExecutable(ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As StringBuilder) As Integer End Function
read morePosts
[VB.NET]如何自製使用者控制項測試容器(User Control Test Container)
Private Sub SetPreviewControl(ByVal c As Control) With pnlControlContainer.Controls .Clear() .Add(c) End With Me.PropertyGrid1.SelectedObject = c End Sub</pre></div><p>如此簡易的User Control Test Container就完成了。</p><p> </p><p>這邊附上我寫好的範例程式,主要介面仿照User Test Container。除提供User Test Container的功能外,另加上語系切換,與預覽表單的功能。程式介面外觀如下:</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" width="602" height="522" src="\images\posts\13810\image_thumb.png" /></a></p><p> </p> <h2>Download</h2><p><a href="http://Files.Dotblogs.com.tw/larrynung/1002/2010227232727262.zip">User Control Test Container.zip</p>
read morePosts
[VB.NET]調整TreeView或TreeNode下的節點
Private Function GetAllNodes(ByVal treeOrNode As Object) As TreeNode() If Not TypeOf treeOrNode Is TreeNode AndAlso Not TypeOf treeOrNode Is TreeView Then Throw New ArgumentException("Error param type!!") End If Dim nodes As New List(Of TreeNode) If TypeOf treeOrNode Is TreeNode Then nodes.Add(treeOrNode) End If For Each tn As TreeNode In treeOrNode.Nodes nodes.AddRange(GetAllNodes(tn)) Next Return nodes.ToArray End Function</pre></div> Public Module TreeViewExtension
#Region “Private Method” Private Function GetAllTreeNodes(ByVal treeOrNode As Object) As TreeNode() If Not TypeOf treeOrNode Is TreeNode AndAlso Not TypeOf treeOrNode Is TreeView Then Throw New ArgumentException(“Error param type!
read morePosts
[VB.NET]取得TreeView或TreeNode下的樹葉節點
Private Function GetAllNodes(ByVal treeOrNode As Object) As TreeNode() If Not TypeOf treeOrNode Is TreeNode AndAlso Not TypeOf treeOrNode Is TreeView Then Throw New ArgumentException("Error param type!!") End If Dim nodes As New List(Of TreeNode) If TypeOf treeOrNode Is TreeNode Then nodes.Add(treeOrNode) End If For Each tn As TreeNode In treeOrNode.Nodes nodes.AddRange(GetAllNodes(tn)) Next Return nodes.ToArray End Function</pre></div> Public Module TreeViewExtension
#Region “Private Method” Private Function GetAllTreeNodes(ByVal treeOrNode As Object) As TreeNode() If Not TypeOf treeOrNode Is TreeNode AndAlso Not TypeOf treeOrNode Is TreeView Then Throw New ArgumentException(“Error param type!
read morePosts
[VB.NET]取得Gif動畫圖檔內含的圖片
Private Sub btnFileBrowser_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFileBrowser.Click If Me.OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then Me.tbxGifFile.Text = Me.OpenFileDialog1.FileName SplitGifFrame(New Bitmap(Me.tbxGifFile.Text)) End If End Sub Private Sub SplitGifFrame(ByVal gifBmp As Bitmap) Me.flpGifFrames.Controls.Clear() Dim gifFrames() As Bitmap = GetGifFrames(gifBmp) flpGifFrames.SuspendLayout() For Each frame As Bitmap In gifFrames flpGifFrames.Controls.Add(New PictureBox With {.Image = frame}) Next flpGifFrames.ResumeLayout() Me.tsslStatus.Text = My.Computer.FileSystem.GetName(Me.tbxGifFile.Text) & " 內含 " & gifFrames.Count.ToString & " 個圖片" End Sub Private Function GetGifFrames(ByVal gifBmp As Bitmap) As Bitmap() Dim imgFrmDim As Imaging.
read morePosts
[C#][VB.NET]FullScreen the winform
static class FullScreenExtension { #region Struct struct FullScreenData { public FormBorderStyle FormBorderStyle { get; set; } public FormWindowState WindowState { get; set; }
public FullScreenData(FormBorderStyle formBorderStyle, FormWindowState windowState):this() { this.FormBorderStyle = formBorderStyle; this.WindowState = windowState; } } #endregion #region Var private static Dictionary<Form, FullScreenData> _fullScreenDataPool; #endregion #region Private Property private static Dictionary<Form, FullScreenData> m_FullScreenDataPool { get { if (_fullScreenDataPool == null) _fullScreenDataPool = new Dictionary<Form, FullScreenData>(); return _fullScreenDataPool; } } #endregion #region Public Method public static void FullScreen(this Form frm) { if (m_FullScreenDataPool.
read morePosts
[VB.NET]為控制項加上顯示載入動畫的機制
#End Region
Public Module ControlLoadingExtension
#Region “Class” Class LoadingInfo Private _loaddingBmp As Image Private _loaddingBmpActiveFrameIdx As Integer Private _loaddingBmpDimension As FrameDimension Private _loaddingBmpFrameCount As Integer Private _displayLocation As Point
Property LoaddingBmp As Image Get Return _loaddingBmp End Get Set(ByVal value As Image) If _loaddingBmp IsNot value Then _loaddingBmp = value LoaddingBmpDimension = New FrameDimension(value.FrameDimensionsList(0)) LoaddingBmpFrameCount = value.GetFrameCount(LoaddingBmpDimension) LoaddingBmpActiveFrameIdx = 0 End If End Set End Property Property LoaddingBmpActiveFrameIdx As Integer Get Return _loaddingBmpActiveFrameIdx End Get Set(ByVal value As Integer) _loaddingBmpActiveFrameIdx = value LoaddingBmp.
read morePosts
[VB.NET]Change MDI Parent BackColor
Private Sub SetMdiBackColor() For Each c As Control In Me.Controls If TypeOf c Is MdiClient Then c.BackColor = Me.BackColor Exit For End If Next End Sub End Class
Private Sub SetMdiBackColor() Me.Controls(Me.Controls.Count - 1).BackColor = Me.BackColor End Sub End Class
read morePosts
[VB.NET]ASCII String與Hex String的互轉
Public Function AsciiStringToHexString(ByVal asciiString As String) As String Dim ascii() As Byte = System.Text.Encoding.Default.GetBytes(asciiString) Dim count As Integer = ascii.Length Dim hexArray(count - 1) As String For idx As Integer = 0 To count - 1 hexArray(idx) = ascii(idx).ToString("x2") Next Return String.Join(" ", hexArray) End Function Public Function HexStringToAsciiString(ByVal hexString As String) As String Dim array() As String = hexString.Split(New Char() {" "c}, StringSplitOptions.RemoveEmptyEntries) For idx As Integer = 0 To array.
read morePosts
[VB.NET]MFC CArchive的讀取
#Region “Config” Private ReadOnly BYTES_COUNT_IN_BOOL As Byte = 4 ‘VC6的BOOL佔 4 Bytes Private ReadOnly BYTES_COUNT_IN_INT As Byte = 4 ‘VC6的Int佔 4 Bytes Private ReadOnly BYTES_COUNT_IN_FLOAT As Byte = 4 ‘VC6的Float佔 4 Bytes Private ReadOnly BYTES_COUNT_IN_DOUBLE As Byte = 8 ‘VC6的Double佔 8 Bytes Private ReadOnly BUFFERSIZE As Integer = 512
#End Region
#Region “Private Var”
Private m_baryBinaryData(BUFFERSIZE) As Byte Private m_fsFileStream As FileStream Private m_nDataLength As Integer Private m_strData As String Private m_nData As Integer Private m_sData As Single Private m_dData As Double Private m_bData As Boolean #End Region
read morePosts
[VB.NET]統計英文字串中字母個數
For Each c As Char In inputString idx = Asc(c) - startAscii symbolCount(idx) = symbolCount(idx) + 1 If symbolCount(idx) > symbolCount(maxSymbolIdx) Then maxSymbolIdx = idx End If Next For idx = 0 To 25 Console.Write(Chr(startAscii + idx) & ": ") Console.WriteLine(symbolCount(idx).ToString) Next Console.WriteLine() Console.Write("Max Count Symbol: ") Console.WriteLine(Chr(startAscii + maxSymbolIdx)) End Sub</pre></div><p> </p><h2> </h2><h2>解法二</h2><p> </p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:313a96f2-0f63-4ed7-aa9d-e6b0bc28f245" class="wlWriterEditableSmartContent"><pre class="vb:nocontrols" name="code"> Sub Test(ByVal inputString As String) Dim chars() As Char = inputString.
read morePosts
[VB.NET]列舉型別字串處理的注意事項
Sub Main() Dim msg As String Dim sex As SexType = SexType.Boy msg = "Sex: " & sex.ToString & " (" & sex & ")" Console.WriteLine(msg) msg = String.Format("Sex: {0} ({1})", sex, CInt(sex)) Console.WriteLine(msg) End Sub End Module 執行結果
read morePosts
[C#][VB.NET].NET 4.0 Barrier Class
Module Module1
Private sync As Barrier Sub Main(ByVal args() As String) sync = New Barrier(3) Dim charlie = New Thread(Sub() DriveToBoston("Charlie", TimeSpan.FromSeconds(1))) charlie.Start() Dim mac = New Thread(Sub() DriveToBoston("Mac", TimeSpan.FromSeconds(2))) mac.Start() Dim dennis = New Thread(Sub() DriveToBoston("Dennis", TimeSpan.FromSeconds(3))) dennis.Start() charlie.Join() mac.Join() dennis.Join() Console.ReadKey() End Sub Sub DriveToBoston(ByVal name As String, ByVal timeToGasStation As TimeSpan) Console.WriteLine("[{0}] Leaving House", name) ' Perform some work Thread.Sleep(timeToGasStation) Console.WriteLine("[{0}] Arrived at Gas Station", name) ' Need to sync here sync.
read morePosts
[VB.NET].NET多語系程式(四) - 已開啟表單的語系切換
For Each ctl As Control In form.Controls ApplyControlResource(ctl, rm) Next Finally rm = Nothing End Try End Sub ''' <summary> ''' 套用資源設定到控制項(含選單與工具列) ''' </summary> ''' <param name="control">The control.</param> ''' <param name="rm">The ComponentResourceManager.</param> ''' <remarks></remarks> Private Shared Sub ApplyControlResource(ByRef control As Control, ByRef rm As ComponentResourceManager) '------------------------------- 'Author: Larry Nung Date:2008/12/11 'Memo: 參數檢查 '------------------------------- If control Is Nothing Then Throw New ArgumentNullException("control") End If If rm Is Nothing Then Throw New ArgumentNullException("rm") End If '------------------------------- 'Author: Larry Nung Date:2008/12/11 'Memo: '------------------------------- rm.
read morePosts
[VB.NET]VB 10.0 Statement Lambdas
'呼叫addLambdas Console.WriteLine(addLambdas(123, 456))</pre></div><p> </p><p>同樣的程式我們也可以明確的定義回傳值型態</p><p> </p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:15d67606-728e-475d-991c-500cc1d0da0d" class="wlWriterEditableSmartContent"><pre class="vb:nocontrols" name="code"> Dim addLambdas = Function(num1, num2) As Integer 也可以明確的指定帶入的參數型態 Dim addLambdas = Function(num1 As Integer, num2 As Integer) As Integer 若有要傳遞參考的需求,也可以在函式參數前加上ByRef Dim addLambdas = Function(ByRef num1 As Integer, num2 As Integer) As Integer Sub LambdasSub Lambdas使用上就跟一般的Lambdas運算式一樣,不同的是Sub Lambdas呼叫後不會有回傳值。就跟副程式一樣是沒有回傳值的,使用上只需把Lambdas運算式的Function關鍵字改為Sub即可。跟副程式的寫法類似。Sub Lambdas跟一般的Lambdas一樣,除了有Multiline lambdas外 ‘宣告addLambdas Dim addLambdas = Sub(num1, num2) Console.WriteLine(num1 + num2) End Sub
read morePosts
[VB.NET]VB 10.0 Auto-Implemented Properties
Property Name As String Get Return _name End Get Set(ByVal value As String) _name = value End Set End Property</pre></div><p> </p><p>透過VB.NET 10.0的Auto-Implemented Properties功能,我們可以將屬性的撰寫給簡化。像是上面的例子可簡化為像下面這樣:</p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:636f2abe-f420-46bd-a9e4-5ced6d93ac70" class="wlWriterEditableSmartContent"><pre class="vb:nocontrols" name="code"> Property Name As String 短短的一行就可以取代本來冗長的程式,是不是很方便呢?除此之外,Auto-Implemented Properties也可以利用變數初始器來設定屬性的預設值。就像: Property Name As String = “Larry” 若是使用較為複雜的型別也可以 Property SupplierList() As New List(Of Supplier) Property OrderList() As New List(Of Order) With {.Capacity = 100} 也可以用在介面屬性的實作上 Property Name() As String Implements ICustomer.
read morePosts
[C#][VB.NET]擴充方法 (Extension Method)
public static class EnumExtension { public static string GetName(this Enum e) { return Enum.GetName(e.GetType(), e); } } class Program { static void Main(string[] args) { Console.WriteLine(Grade.APlus.GetName()); } }</pre></div> Enum Grade APlus A B C D End Enum
Module Module1 Sub Main() Console.WriteLine(Grade.APlus.GetName) End Sub End Module
Module EnumExtension <Extension()> _ Public Function GetName(ByVal e As [Enum]) As String Return [Enum].GetName(e.GetType, e) End Function End Module
class Program { static void Main(string[] args) { string str = null; Console.
read morePosts
[VB.NET]用.NET實作檔案總管
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]從登錄檔中讀取CPU資訊
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]HatchBrush
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]ErrorProvider
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]自定義ComboBox下拉清單選項
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]用MyDataBase更新DataGridView上變動的資料
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]增加圖片亮度
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]彩色濾鏡
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]反轉圖片顏色
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]彩色圖片轉為黑白圖片
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]突破Disable按鈕的封鎖與限制
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]壓縮.NET程式的記憶體用量
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[Library][VB.NET].NET簡易測試用表單類別
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET]Lambda運算式
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET].NET多語系程式(三)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET].NET多語系程式(一)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[VB.NET].NET多語系程式(二)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]Isolated Storage 隔離儲存區
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[.NET Concept][C#][VB.NET].NET兩個表單間的資料互通
Public Class Form2 … Public MainForm As Form1 … ‘Form2透過Form1傳進的物件參考控制Form1 MainForm.Value = Me.NumericUpDown1.Value … End Class
read morePosts
[C#][VB.NET]自定義.NET WindowForm表單介面(二)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[Performance][VB.NET].NET空字串判斷徹底研究
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[Performance][VB.NET]If V.S IIf
<td valign="top" width="133">If</td> <td valign="top" width="133">IIf</td> </tr> <tr> <td valign="top" width="133">10000</td> <td valign="top" width="133">0 ms</td> <td valign="top" width="133">0 ms</td> </tr> <tr> <td valign="top" width="133">100000</td> <td valign="top" width="133">1 ms</td> <td valign="top" width="133">3 ms</td> </tr> <tr> <td valign="top" width="133">1000000</td> <td valign="top" width="133">10 ms</td> <td valign="top" width="133">32 ms</td> </tr> <tr> <td valign="top" width="133">10000000</td> <td valign="top" width="133">101 ms</td> <td valign="top" width="133">326 ms</td> </tr>
read morePosts
[C#][VB.NET]使用AxWindowsMediaPlayer撥放多媒體
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]使用AxMediaPlayer撥放多媒體
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[.NET Concept][C#][VB.NET]四捨六入五成雙
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[C#][VB.NET]XML序列化私有欄位
#Region “Enum” Enum SexType Boy Girl End Enum #End Region
#Region “Var” Private _name As String Private _year As Integer Private _sex As SexType Private _friendNames As New List(Of String) #End Region
#Region “Property” Public Property Name() As String Get If String.IsNullOrEmpty(_name) Then Return String.Empty End If Return _name End Get Set(ByVal value As String) _name = value End Set End Property
Public Property Year() As Integer Get Return _year End Get Set(ByVal value As Integer) _year = value End Set End Property Public Property Sex() As SexType Get Return _sex End Get Set(ByVal value As SexType) _sex = value End Set End Property #End Region
read morePosts
[C#][VB.NET]自製桌面小玩意
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove If PictureBox1.Capture = True Then '如果滑鼠按著拖曳 '設定新的視窗位置 Me.Top = e.Y + nOldWndTop - nClickY Me.Left = e.X + nOldWndLeft - nClickX '更新紀錄的視窗位置 nOldWndLeft = Me.Left nOldWndTop = Me.Top End If End Sub</pre></div><p> </p><p>C#</p><p> </p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f0c57834-e54e-4456-896a-5ebc58634d32" class="wlWriterSmartContent"><pre class="c#" name="code"> private void PictureBox1_MouseDown(object sender, MouseEventArgs e)
read morePosts
[C#][VB.NET]自定義.NET WindowForm表單介面
Private Sub pnlTitleBar_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pnlTitleBar.MouseMove If pnlTitleBar.Capture = True Then '如果滑鼠按著拖曳 '設定新的視窗位置 Me.Top = e.Y + nOldWndTop - nClickY Me.Left = e.X + nOldWndLeft - nClickX '更新紀錄的視窗位置 nOldWndLeft = Me.Left nOldWndTop = Me.Top End If End Sub</pre></div><p> </p><p>C#</p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:0d2adec9-5189-493d-821d-1272f208c5e0" class="wlWriterSmartContent"><pre class="c#" name="code"> private void pnlTitleBar_MouseDown(object sender, MouseEventArgs e) { //紀錄滑鼠點選時的視窗位置與滑鼠點選位置 nOldWndLeft = this.
read morePosts
[C#][VB.NET]設定.NET透明表單
Abstract Introduction Form.Opacity屬性設定不透明度 Form.TransparencyKey屬性設定透明的顏色 Form.Opacity VS Form.TransparencyKey Conclusion Introduction 在.NET WinForm程式中,要設定透明表單有兩種方式。一種是用Form.Opacity屬性來設定表單的不透明度,一種則是用Form.TransparencyKey屬性來設定表單上視為透明的顏色。本篇將會對兩種方法做個簡單的介紹,並針對兩者做點小小的比較。
Form.Opacity屬性設定不透明度 以Form.Opacity屬性為例,該屬性值所設定的是0~1之間的雙精度浮點數(Double),用以表示表單的不透明度比例。如下圖所示,該值越小越透明、越大則越不透明。
完整範例如下:
VB.NET
C#
Form.TransparencyKey屬性設定透明的顏色 要用Form.TransparencyKey屬性來設定表單透明度,只須把該屬性設為欲透明的顏色,則當表單上存在著被設為透明色的顏色區塊時,該顏色區塊就會被視為是透明的。用該方法設定的透明效果跟用Form.Opacity的方法是不同的。該方法的透明是完全的透明(透明度100%),且若用滑鼠點選在表單中透明的區塊上,滑鼠的點選動作會穿透目前的表單點選到目前表單下方的視窗,而Form.Opacity的透明除非是設為完全透明,不然無法穿透目前的表單。
**P.S.**Form.Opacity = 0 雖然也可以完全穿透目前表單,但是表單上面的元件也會跟著透明。
Form.Opacity VS Form.TransparencyKey 可調整透明度比例 點選表單透明區塊可穿透表單 可設定表單一部份為透明區塊,只會影響跟設定相同顏色的區塊 點選表單不完全透明區塊(Form.Opacity != 0)不可穿透表單 透明度會影響整個表單上的元件 不可調整透明度比例 Conclusion 本篇介紹了WinForm中改變表單透明度的兩種方法。雖然兩種方法都可以達到透明表單的效果,但在實際的應用上,我個人覺得用Form.TransparencyKey來設定表單透明度較為實用。雖此方法無法調整透明程度,但是其所具備的穿透透明區塊與可透明表單中部分區塊的特性,大幅增加了應用上的彈性。
read morePosts
[C#][VB.NET].NET捷徑(ShortCut)控制
Function GetLnkWorkingDirectory(ByVal shortCutFile As String) As String Return GetLnkObj(shortCutFile).WorkingDirectory End Function
Function GetLnkPath(ByVal shortCutFile As String) As String Return GetLnkObj(shortCutFile).Path End Function C# private String GetLnkArguments(string shortCutFile) { return GetLnkObj(shortCutFile).Arguments; }
private String GetLnkWorkingDirectory(string shortCutFile) { return GetLnkObj(shortCutFile).WorkingDirectory; }
private String GetLnkPath(string shortCutFile) { return GetLnkObj(shortCutFile).Path; } 這邊須注意的是,使用此方法建立捷徑時,若捷徑檔不存在於指定位置,則須先建立個空的捷徑檔案,才可取得ShellLinkObject物件。VB.NET If Not My.Computer.FileSystem.FileExists(shortCutFile) Then File.Create(shortCutFile).Close() End If C# if (!My.Computer.FileSystem.FileExists(shortCutFile)) { File.Create(shortCutFile).Close(); } 取得ShellLinkObject物件後,捷徑的建立與寫入也就只是設定對應的屬性值後呼叫Save方法。VB.NET lnkObj = GetLnkObj(shortCutFile) With lnkObj .Arguments = arguments .
read moreTag: Linq
Posts
[C#][Linq]Linq to Wikipedia
private IQueryable<WikipediaKeywordSearchResult>KeyWordSearch(string keyWord) { return from item in (new WikipediaContext()).KeywordSearch where item.Keyword == keyWord select item; }</pre></div>
read morePosts
[C#][Linq]LINQ To WMI
foreach (Win32_UserAccount account in query) { Console.WriteLine(account.Name); } } }
read morePosts
[C#][Linq]BLinq - Linq To Bing
private IEnumerable<ImageSearchResult> SearchImages(string keyWord) { return from item in m_Bing.Images where item.Query == keyWord select item; }</pre>
read morePosts
LINQ to CSV library
Read<T>(string fileName) Read<T>(string fileName, CsvFileDescription fileDescription) Read<T>(StreamReader stream) Read<T>(StreamReader stream, CsvFileDescription fileDescription)
[CsvColumn(Name = "LastName", FieldIndex = 1)] public String LastName { get; set; } [CsvColumn(Name = "Sex", FieldIndex = 2)] public String Sex { get; set; } [CsvColumn(Name = "Birthday", FieldIndex = 3)] public String Birthday { get; set; } public String Memo { get; set; } public override string ToString() { return string.Join(",", new string[] { FirstName, LastName, Sex, Birthday, Memo }); } }</pre> CsvContext cc = new CsvContext(); Person[] persons = new Person[] { new Person() { FirstName = "Larry", LastName = "Nung", Sex = "Boy", Birthday = "1980/04/19" } }; cc.
read morePosts
Linq To Excel Provider
using System.Linq; using System.ComponentModel;
[ExcelSheet(Name=“Sheet1”)] public class Person: INotifyPropertyChanged {
private double _id; private string _firstname; private string _lastname; private DateTime _birthdate; public event PropertyChangedEventHandler PropertyChanged; protected virtual void SendPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } [ExcelColumn(Name="ID", Storage="_id")] public double ID { get { return _id;} set { _id = value; SendPropertyChanged("ID"); } } [ExcelColumn(Name="FirstName", Storage="_firstname")] public string FirstName { get { return _firstname;} set { _firstname = value; SendPropertyChanged("FirstName"); } } [ExcelColumn(Name="LastName", Storage="_lastname")] public string LastName { get { return _lastname;} set { _lastname = value; SendPropertyChanged("LastName"); } } [ExcelColumn(Name="BirthDate", Storage="_birthdate")] public DateTime BirthDate { get { return _birthdate;} set { _birthdate = value; SendPropertyChanged("BirthDate"); } } }
read morePosts
Linq To Excel
//自己可自行加要過濾的條件,這邊只是示範 var linq = from item in excel.Worksheet(sheetName) select item; ...</pre> //這邊會取使用Sheet1的工作表內容去做查詢動作 var linq = from item in excel.Worksheet() select item; ...</pre> var linq = from item in excel.Worksheet<Blogger>(sheetName) where item.Sex==SexType.Boy select item; ...</pre> namespace ConsoleApplication1 { class Blogger { public int ID { get; set; } public String FirstName { get; set; } public String LastName { get; set; } public SexType Sex { get; set; } public int Age { get; set; } public String Blog { get; set; }
read morePosts
Linq to GPU (Brahma)
// Create a data-parallel array and fill it with data var data = new DataParallelArray<float>(computationProvider, new[] { 0f, 1f, 2f, 3f, 4f, 5f, 6f }); // Compile the query CompiledQuery query = computationProvider.Compile<DataParallelArray<float>> ( d => from value in d select value * 2f ); // Run the query on this data IQueryable result = computationProvider.Run(query, data); // Print out the results foreach (float value in result) Console.WriteLine(value); // Get rid of all the stuff we created computationProvider.
read morePosts
[Linq]Linq程式逐步執行與偵錯
foreach (var item in linq) { Console.WriteLine(item); } }</pre></div> For Each item In linq Console.WriteLine(item) Next End Sub</pre>
read moreTag: .NET Resource
Posts
MaxToCode
-project=<projectfile> 從 MaxtoCode 項目文件中的信息開始加密 (.mcproj)
-p 參數不可以與其它參數共同使用 -out=<out directory> 加密后的程序集輸出目錄
-runtime=<Mruntime3.dll> 運行庫名稱
-bind 合并運行庫
-string 加密用戶字符串
-blob 加密用戶blob信息
-resource 加密用戶資源
-new 加密構造函數
-support64 支持64位操作系統
-autoconfusion 自動混淆當前程序集,如沒此選項都不混淆程序集
-metaconfusion 混淆原數據
-strongname=<snk file> 使用引命名簽此文件
-weboptimize 如果是Web相關程序,請帶上此參數
read moreTag: Web
Tag: Other
Tag: UML
Tag: Performance
Posts
[Performance][C#]絕對值的取得
namespace WindowsFormsApplication35 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
static int ABS1(int value) { return value < 0 ? -value : value; } static int ABS2(int value) { return Math.Abs(value); } private void button1_Click(object sender, EventArgs e) { int count = (int)numericUpDown1.Value; int value = -1; textBox1.AppendText("Count: " + count.ToString() + Environment.NewLine); Stopwatch sw = Stopwatch.StartNew(); for (int idx = 0; idx < count; ++idx) ABS1(value); sw.
read morePosts
[Performance]Set Form's Position
Dim _f As New Form Private Sub btnSetByPoint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSetByPoint.Click _f.Show() Dim sw As Stopwatch = Stopwatch.StartNew For i As Integer = 0 To NumericUpDown1.Value _f.Location = New Point(10, 10) Next sw.Stop() _f.Hide() MsgBox("SetByPoint: " & sw.ElapsedMilliseconds.ToString) End Sub Private Sub btnSetByProperty_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSetByProperty.Click _f.Show() Dim sw As Stopwatch = Stopwatch.StartNew For i As Integer = 0 To NumericUpDown1.
read morePosts
[Performance][C#]String.Empty V.S ldquo;rdquo;
Console.Clear(); int count = 1000000000; for (int idx = 0; idx < 3; ++idx) { EmptyString1(count); EmptyString2(count); EmptyString3(count); Console.WriteLine(); } } private static void EmptyString1(int count) { String test; Stopwatch sw = Stopwatch.StartNew(); for (int idx = 0; idx < count; ++idx) { test = ""; } sw.Stop(); Console.WriteLine("EmptyString1: " + sw.ElapsedMilliseconds.ToString()); } private static void EmptyString2(int count) { String test; Stopwatch sw = Stopwatch.StartNew(); for (int idx = 0; idx < count; ++idx) { test = string.
read morePosts
[Performance][C#]同時判斷多個字串是否為數值型態
sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric2_1(values); } sw.Stop(); Console.WriteLine("Method2-1: " + sw.ElapsedMilliseconds + " ms"); sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric2_2(values); } sw.Stop(); Console.WriteLine("Method2-2: " + sw.ElapsedMilliseconds + " ms"); sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric3(values); } sw.Stop(); Console.WriteLine("Method3: " + sw.ElapsedMilliseconds + " ms"); sw.Reset(); sw.Start(); for (int idx = 0; idx < testCount; ++idx) { IsNumeric4(values); } sw.
read morePosts
[Performance][C#]StringBuilder與String.Join串接字串時的效能比較
namespace ConsoleApplication17 { class Program { static void Main(string[] args) { int testTimes = 10; int dataCount = 1000000; GoTest(dataCount, testTimes); }
static void GoTest(int dataCount,int testTimes) { //Let JIT compiler precompiler Test1(1); Test2(1); //Test performance Stopwatch sw; long[] elapsedTimes = new long[testTimes]; Console.WriteLine("String.Join..."); for (int i = 0; i < testTimes; i++) { sw = Stopwatch.StartNew(); Test1(dataCount); elapsedTimes[i] = sw.ElapsedMilliseconds; Console.WriteLine("Elapsed Time: " + elapsedTimes[i]); } Console.WriteLine("Average Elapsed Time: " + elapsedTimes.
read morePosts
[Performance][C#]List V.S SortedList
<pre><span class="kwrd">using</span> System.Collections.Generic;</pre> <pre class="alt"><span class="kwrd">using</span> System.ComponentModel;</pre> <pre><span class="kwrd">using</span> System.Data;</pre> <pre class="alt"><span class="kwrd">using</span> System.Drawing;</pre> <pre><span class="kwrd">using</span> System.Linq;</pre> <pre class="alt"><span class="kwrd">using</span> System.Text;</pre> <pre><span class="kwrd">using</span> System.Windows.Forms;</pre> <pre class="alt"><span class="kwrd">using</span> System.Collections;</pre> <pre><span class="kwrd">using</span> System.Diagnostics;</pre> <pre class="alt"> </pre> <pre><span class="kwrd">namespace</span> HashTableVSSortedList</pre> <pre class="alt">{</pre> <pre> <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> Form1 : Form</pre> <pre class="alt"> {</pre> <pre> <span class="kwrd">public</span> Form1()</pre> <pre class="alt"> {</pre> <pre> InitializeComponent();</pre> <pre class="alt"> }</pre> <pre> </pre> <pre class="alt"> <span class="kwrd">private</span> <span class="kwrd">void</span> button1_Click(<span class="kwrd">object</span> sender, EventArgs e)</pre> <pre> {</pre> <pre class="alt"> button1.
read morePosts
[Performance][VB.NET].NET空字串判斷徹底研究
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read morePosts
[Performance][VB.NET]If V.S IIf
<td valign="top" width="133">If</td> <td valign="top" width="133">IIf</td> </tr> <tr> <td valign="top" width="133">10000</td> <td valign="top" width="133">0 ms</td> <td valign="top" width="133">0 ms</td> </tr> <tr> <td valign="top" width="133">100000</td> <td valign="top" width="133">1 ms</td> <td valign="top" width="133">3 ms</td> </tr> <tr> <td valign="top" width="133">1000000</td> <td valign="top" width="133">10 ms</td> <td valign="top" width="133">32 ms</td> </tr> <tr> <td valign="top" width="133">10000000</td> <td valign="top" width="133">101 ms</td> <td valign="top" width="133">326 ms</td> </tr>
read moreTag: WLW
Tag: Security
Posts
[.NET Concept][Security].NET程式保護機制概述
//不影響結果 if(i == a){ Console.WriteLine("Some Thing Error!!"); } } 3.加入一些冗贅的運算 int a = 10;改為 int b = 2; int c = 5; int a = b * c; 值得注意的是,使用混淆保護的程式仍是可以使用反組譯工具看到混淆後的MSIL,且很容易被有心人反推回去的,只是增加了反推的難度而已。微軟自帶的Dotfuscator Community Edition好像已經有現成反推回去的程式在網路上流佈,像水瓶大介紹的DF Stack就是一例。 內核級加密保護若採用內核級加密來保護,使用反組譯工具去看MSIL時。會顯示不是CLR程式,無法看到反組譯過後的程式碼。有比混淆稍微安全些的感覺。類似的軟體有MaxToCode、XeonCode。 硬體保護硬體保護方面,有聖天狗、Aladdin等硬體加密鎖。多半這類產品除了本身會提供API可以讓程式呼叫做保護的動作外,也會附上基本的混淆與程式加密功能。 Conclusion在.NET保護這塊我涉略不深,只能做初步的介紹。這邊我要順帶一提,其實我們用來反組譯的.NET Reflector工具在加密上算是還做的不錯。畢竟本身就是反組譯用的工具,在這方面會有一定的程度,網路上也有許多相關研究。有興趣的可以從該工具的保護機制著手研究。像是Reflector保護方法初探等,還有很多篇,請自行打上關鍵字Reflector 保護,Google一下就有了。 LinkMSDN大內高手專欄 - To De or Not to De? DF Stack 1.0 - .NET 的反混淆器?DF StackReflector保護方法初探
read moreTag: Library
Posts
[Library][VB.NET].NET簡易測試用表單類別
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .
read more