星期一, 2月 15, 2016
藉由 WebServices 開放資料
通常在跨系統整合面臨的抉擇:到底要直接開放應用系統後端的資料庫,或是在應用系統上準備一些 WebServices 來服務其他的應用系統?比較安全的作法當然是後者,不過通常被認為成本較高,但果真如此嗎?其實這些輪子通常是已經存在的。以 Oracle 來說可以參考這篇,以 MS SQL 來說可以參考這篇以及這篇。
星期三, 1月 20, 2016
IIS + Oracle 的系統開發
- .NET Framework 內建 System.Data.OracleClient,已被標為 Obsolete,就別再留戀了。
- 開發環境一般會安裝 Oracle Client 與 ODAC (Oracle Data Access Component) 兩者,但事實上只要 ODAC 就夠了。若是要直接連 Oracle 查、改資料這個理由,除了 Oracle Client 之外,DBeaver、TOAD、甚至 Visual Studio 都可以用才對。
- ODAC 也有分 XCopy 或其他一大堆帶不同元件的包裝,看來 XCopy 的比較單純,利用解壓後批次檔安裝所有部份比較保險,記得要用系統管理權限,事後還要對安裝路徑加入全域 PATH 環境變數,甚至較舊的作業系統可能還要調整該目錄的安全性,開放給所有 Authenticated Users,如果已經開了 Visual Studio 也要重開才能讀到新的環境變數。
- 在 64 位元的作業環境,32 / 64 位元的 ODAC 都可運作,但事實上 32 位元的比較方便,原因是 Visual Studio 附帶的 IIS Express 預設還是 32 位元(設定在 Tools -> Options -> Projects and Solutions -> Web Projects),兩者必須搭配。
- ODAC 畢竟還是 Native,其實早就有 Oracle ManagedDataAccess NuGet Package 可用,安裝管理都方便。就算是舊程式轉換也只要改 Namespace (Oracle.DataAccess -> Oracle.ManagedDataAccess) 就好。
- 也不再仰賴 tnsnames.ora 設定連線資訊,可以查查 Oracle 有個名詞叫 EZCONNECT。例如我們以前在設定檔寫 DataSource=abc;User Id=... 還要搭配 tnsnames.ora 其中一段 abc=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=...,現在只要改成 DataSource=<HostNameOrIP>:<Port>/abc;User Id=... 就夠了,幹嘛要分兩個地方設定?
星期日, 1月 17, 2016
調校 64 位元環境下的 Visual Studio + IIS Express 執行 32 位元應用程式
過去常在 64 位元環境下的 IIS 接觸到這個議題,通常都是多人共用的測試機或正式機,沒想到為了難搞的 Oracle,連個人開發環境也要講究 32 / 64 位元的參考與執行環境搭配,而且驚訝於許多人們因此被迫放棄了 IIS Express。其實這個問題不難,但由於 IIS Express 一直沒有管理介面,讓人總搞不清楚設定,就參考一下這篇吧。
星期五, 12月 25, 2015
Jenkins + Central Authentication Service, CAS
在 Windows 伺服器上的 Jenkins 要由 https://abc.com/cas 單一簽入的做法:
- 取得 https://abc.com 憑證簽署單位的憑證,假設檔名為 StartCom.crt。
- 以系統管理員身分在 Jenkins 安裝目錄下命令:jre\bin\keytool.exe -keystore jre\lib\security\cacerts -import -trustcacerts -file StartCom.crt -alias StartCom。
- 在 Jenkins 安裝 CAS Plugin,並設定 Security Realm CAS 的 URL、Protocol。
星期二, 12月 15, 2015
CentOS 6 as a Selenium node with Chrome
過去已有 Windows 當 Selenium (web driver) node 的經驗,原本以為換到 Linux 是件很簡單的事,不過實際試著做下來,才知若是 Firefox 還好,Chrome 就很麻煩了:
- 若 CentOS 6 還沒有 GUI,要下指令安裝:yum groupinstall "X Window System" "GNOME Desktop Environment" "Desktop" "Chinese Support"。
- 若要從遠端操控 CentOS 6 的圖形介面,可以用 VNC。在 CentOS 6 安裝 VNC Server,執行 vncserver :1,用 vncpasswd 命令設遠端連線密碼。從 Mac 連過去甚至 VNC Viewer 都不用裝,在 Safari 瀏覽 vnc://hostname:5901 就可以了。
- 在 CentOS 6 安裝 Chrome 已不被 Google 原廠支援,幸好還有位大師指導。
- 不像 Firefox,所有其他的瀏覽器都需要 Driver 才能與 Selenium hub 溝通,所以要另外下載。所謂「安裝」就是把下載的檔案放在 PATH 所指的路徑即可。
- 以上都做了,結果還是不通?可以直接在終端機執行 chromedriver 看是什麼問題,原來還是 libstdc++.so.6 惹的禍。經過上述大師的修正,應該會有兩個以上,可以透過「find / -name libstdc++.so.6」來確認,而且每一個的差異可透過「strings <PATH>/libstdc++.so.6 | grep GLIBC」識別,換另一個版本的也許就好了。
[2016/09/10 補充]
- CentOS 7 安裝各種 GUI 的說明可參考這篇。
- Chrome 有自動更新的機制,每次事後都要把 /usr/lib64 目錄下的 libstdc++.so.6 指到 /opt/google/chrome/lib 去,否則就是找不到 Chrome Web Driver 的錯誤。
星期六, 12月 12, 2015
Convert .bat to .sh
有一行很簡單的命令:
java -jar a.jar fileB
以上就是 c.bat 批次檔的內容,與 a.jar、fileB 都在同一目錄下,在 Windows 的環境沒問題。既然 Java 是跨平台的,想必可移到 Linux / Mac 的指令稿,但一直不行?也確定這行直接放在終端機跑過沒問題,只是不能從 c.sh 間接地執行。除了 chmod +x 還有別的事要做?後來改成這樣:
#!/bin/bash
java -jar a.jar fileB
結果在 Mac 上是出現這個訊息:
-bash: ./c.sh: /bin/bash^M: bad interpreter: No such file or directory
半信半疑,加了到底是有幫助還是把事情搞得更複雜?幸好看到這篇,在 vi 編輯 c.sh 下兩道指令:
:set ff=unix
:x
終於修好了!
java -jar a.jar fileB
以上就是 c.bat 批次檔的內容,與 a.jar、fileB 都在同一目錄下,在 Windows 的環境沒問題。既然 Java 是跨平台的,想必可移到 Linux / Mac 的指令稿,但一直不行?也確定這行直接放在終端機跑過沒問題,只是不能從 c.sh 間接地執行。除了 chmod +x 還有別的事要做?後來改成這樣:
#!/bin/bash
java -jar a.jar fileB
結果在 Mac 上是出現這個訊息:
-bash: ./c.sh: /bin/bash^M: bad interpreter: No such file or directory
半信半疑,加了到底是有幫助還是把事情搞得更複雜?幸好看到這篇,在 vi 編輯 c.sh 下兩道指令:
:set ff=unix
:x
終於修好了!
星期三, 12月 09, 2015
C# 對民國年的處理
最近看到很多人自成一格的處理民國年,很醜的就不提了,有的猛一看還不錯:
private string FormatDate0(DateTime dateTime)
{
return dateTime.AddYears(-1911).ToString("yyy/MM/dd");
}
private string FormatDate1(DateTime dateTime)
{
string returnValue = null;
Calendar taiwanCalendar = new TaiwanCalendar();
int year = taiwanCalendar.GetYear(dateTime);
int month = taiwanCalendar.GetMonth(dateTime);
int day = taiwanCalendar.GetDayOfMonth(dateTime);
returnValue = String.Format("{0:000}/{1:00}/{2:00}", year, month, day);
return returnValue;
}
雖然有點長,但感覺是用比較「正統」的方式在處理。如果真要挑毛病的話,就是年月日必須分開處理,難道沒辦法保留在一起嗎?有人介紹了以下這種:
[SecurityPermission(SecurityAction.Assert, ControlThread = true)]
private string FormatDate2(DateTime dateTime)
{
string returnValue = null;
CultureInfo taiwanCulture = new CultureInfo("zh-TW");
DateTimeFormatInfo formatInfo = taiwanCulture.DateTimeFormat;
Calendar taiwanCalendar = new TaiwanCalendar();
formatInfo.Calendar = taiwanCalendar;
Thread currentThread = Thread.CurrentThread;
currentThread.CurrentCulture = taiwanCulture;
returnValue = dateTime.ToString("yyy/MM/dd");
return returnValue;
}
真的是複雜但優雅!但別急著高興,先不論 SecurityPermission 帶來的一絲不安,有個測試案例結果不太妙,FormatDate2(new Date(2010, 1, 23)) => 99/01/23,開頭的零跑哪去了?怎麼看都是微軟的問題,自力救濟吧:
...
// bugfix begin
//returnValue = dateTime.ToString("yyy/MM/dd");
int year = taiwanCalendar.GetYear(dateTime);
returnValue = String.Format("{0:000}", year);
returnValue += dateTime.ToString("/MM/dd");
// bugfix end
return returnValue;
}
有些畫蛇添足的感覺,看得真不舒服。
private string FormatDate0(DateTime dateTime)
{
return dateTime.AddYears(-1911).ToString("yyy/MM/dd");
}
以今天為例,結果是 104/12/09,看來沒問題?但試試 FormatDate0(new Date(2016, 2, 29)) => 105/02/28,知道不行了吧?改進如下:
private string FormatDate1(DateTime dateTime)
{
string returnValue = null;
Calendar taiwanCalendar = new TaiwanCalendar();
int year = taiwanCalendar.GetYear(dateTime);
int month = taiwanCalendar.GetMonth(dateTime);
int day = taiwanCalendar.GetDayOfMonth(dateTime);
returnValue = String.Format("{0:000}/{1:00}/{2:00}", year, month, day);
return returnValue;
}
[SecurityPermission(SecurityAction.Assert, ControlThread = true)]
private string FormatDate2(DateTime dateTime)
{
string returnValue = null;
CultureInfo taiwanCulture = new CultureInfo("zh-TW");
DateTimeFormatInfo formatInfo = taiwanCulture.DateTimeFormat;
Calendar taiwanCalendar = new TaiwanCalendar();
formatInfo.Calendar = taiwanCalendar;
Thread currentThread = Thread.CurrentThread;
currentThread.CurrentCulture = taiwanCulture;
returnValue = dateTime.ToString("yyy/MM/dd");
return returnValue;
}
...
// bugfix begin
//returnValue = dateTime.ToString("yyy/MM/dd");
int year = taiwanCalendar.GetYear(dateTime);
returnValue = String.Format("{0:000}", year);
returnValue += dateTime.ToString("/MM/dd");
// bugfix end
return returnValue;
}
訂閱:
文章 (Atom)