March 2008 - 文章

【茶包射手專欄】追查電子郵件傳送歷程(下)

【前情提要】快一年前,我處理了一件Email異常延遲傳送的案件,原本計劃分兩篇說明,第一篇談Mail Client端的偵察,第二篇談Exchange Log的追蹤。結果,事多人忙心頹手懶,Post完上集,第二篇就被我遺留在火星上...

前幾天驚聞網友Leo詢問下集,心頭一驚,這這這... 趕緊登陸火星,挖出塵封的KB...


細看過IMS主機案發當時的Log,最後的推斷傾向SMTP Mail Server並沒有問題,純粹只是Queue太長導致。我的分析如下:

這是我第一次看Message Tracking Log,被它龐大的資料量及瑣碎的記錄搞到頭暈,找到一份重要的參考資料: KB-821905 Message tracking event IDs in Exchange Server 2003。由這份文件的指引,理出了一些頭緒。

當Exchange送出一份Mail時(下例為由phoenix.com.tw寄到foocorp.com.tw的正常記錄),會在Message Tracking Log中寫入如下的Log記錄(Log每一列很長,重點在前面,所以後方省略)

2007-4-21  2:3:55 GMT           192.168.9.113  ims03.phoenix.com.tw      -         IMS01          192.168.9.111   amy@foocorp.com.tw     1019           001301c78397$b3bd0c80$06d19934@rincon
2007-4-21  2:3:55 GMT           192.168.9.113  ims03.phoenix.com.tw      -         IMS01          192.168.9.111   amy@foocorp.com.tw     1025           001301c78397$b3bd0c80$06d19934@rincon
2007-4-21  2:3:55 GMT           192.168.9.113  ims03.phoenix.com.tw      -         IMS01          192.168.9.111   amy@foocorp.com.tw     1024           001301c78397$b3bd0c80$06d19934@rincon
2007-4-21  2:3:55 GMT           192.168.9.113  ims03.phoenix.com.tw      -         IMS01          192.168.9.111   amy@foocorp.com.tw     1033           001301c78397$b3bd0c80$06d19934@rincon
2007-4-21  2:3:55 GMT           192.168.9.113  ims03.phoenix.com.tw      -         IMS01          192.168.9.111   amy@foocorp.com.tw     1034           001301c78397$b3bd0c80$06d19934@rincon
2007-4-21  2:4:19 GMT           192.168.9.113  ims03.phoenix.com.tw      -         IMS01          192.168.9.111   amy@foocorp.com.tw     1020           001301c78397$b3bd0c80$06d19934@rincon
2007-4-21  2:4:19 GMT           192.168.9.113  ims03.phoenix.com.tw      s1mail.foocorp.com.tw   IMS01          192.168.9.111           amy@foocorp.com.tw     1031 001301c78397$b3bd0c80$06d19934@rincon

amy@foocorp.com.tw後方的那個數字欄位叫做Event-ID,參照MS的官方文件,我們可以整理出以下的順序:

1019(SMTP submit message to AG) -> 1025(SMTP begin submit message) -> 1024(SMTP submit message to cat) -> 1033(SMTP message categorized and queued for routing) -> 1034(SMTP message routed and queued for remote delivery) -> 1020(SMTP begin outbound transfer) -> 1031(SMTP end outbound transfer)

值得注意的是1034(排入Qeue)到1020(開始送信)這段會拖得比較久一點,上面的例子是花了24秒。而在1031時,會Show對方Mail Server的名稱(Partner Name,但是似乎可以由Mail Server自行命名,有時會亂取),如上例為s1mail.foocorp.com.tw

回頭看4-19有問題的Mail,我們可以由Log追出它的完整寄出過程: (收信人為mary@ coolcorp.com及katherine@ boocorp.net兩人)

2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   mary@coolcorp.com           1019
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   katherine@boocorp.net           1019
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   mary@coolcorp.com           1025
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   katherine@boocorp.net           1025
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   mary@coolcorp.com           1024
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   katherine@boocorp.net           1024
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   mary@coolcorp.com           1033
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   katherine@boocorp.net           1033
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   mary@coolcorp.com           1034
2007-4-19  3:33:27 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   katherine@boocorp.net           1034
2007-4-19  3:33:36 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   mary@coolcorp.com           1020
2007-4-19  3:33:36 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   katherine@boocorp.net           1020
2007-4-19 3:33:38 GMT         192.168.8.30          nmail07.phoenix.com.tw  mh4pdmz3b.boocorp.net  IMS01          192.168.9.111           mary@coolcorp.com    1031
2007-4-19  3:33:38 GMT         192.168.8.30          nmail07.phoenix.com.tw  mh4pdmz3b.boocorp.net  IMS01          192.168.9.111           katherine@boocorp.net         1031
2007-4-19  4:19:29 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   mary@coolcorp.com           1020
2007-4-19  4:19:29 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   katherine@boocorp.net           1020
2007-4-19  4:19:30 GMT         192.168.8.30          nmail07.phoenix.com.tw  ************************   IMS01          192.168.9.111           mary@coolcorp.com    1031
2007-4-19  4:19:30 GMT         192.168.8.30          nmail07.phoenix.com.tw  ************************   IMS01          192.168.9.111           katherine@boocorp.net         1031

在11:33:38(Log中的時間是UTC,要+8才是台北時間),兩封出去的信已走完一次完整的1019->1025->1024->1033->1034->1020->1031的流程,但是到了12:19:30,1020->1031的流程又跑了一次。這兩次有點不同,第一次IMS01前方出現的字是mh4pdmz3b.boocorp.net,表示寄到BooCorp公司,而12:19:30出現的則是************************,對照收方的記錄,應該就是寄給CoolCorp的。於是我找了另一封寄給兩個收信人(jennifer@ mail.woocorp.com.tw及john@ ms3.coocorp.com.tw)的Log做比對。

2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   jennifer@mail.woocorp.com.tw           1019
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   john@ms3.coocorp.com.tw           1019
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   jennifer@mail.woocorp.com.tw           1025
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   john@ms3.coocorp.com.tw           1025
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   jennifer@mail.woocorp.com.tw           1024
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   john@ms3.coocorp.com.tw           1024
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   jennifer@mail.woocorp.com.tw           1033
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   john@ms3.coocorp.com.tw           1033
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   jennifer@mail.woocorp.com.tw           1034
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   john@ms3.coocorp.com.tw           1034
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   jennifer@mail.woocorp.com.tw           1020
2007-4-21  4:38:40 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   john@ms3.coocorp.com.tw           1020
2007-4-21  4:38:42 GMT         192.168.8.30          nmail07.phoenix.com.tw  [st3.coocorp.com.tw    IMS01          192.168.9.111           jennifer@mail.woocorp.com.tw      1031
2007-4-21  4:38:42 GMT         192.168.8.30          nmail07.phoenix.com.tw  [st3.coocorp.com.tw    IMS01          192.168.9.111           john@ms3.coocorp.com.tw          1031 2007-4-21  4:38:46 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   jennifer@mail.woocorp.com.tw           1020
2007-4-21  4:38:46 GMT         192.168.8.30          nmail07.phoenix.com.tw  -         IMS01          192.168.9.111   john@ms3.coocorp.com.tw           1020
2007-4-21  4:38:54 GMT         192.168.8.30          nmail07.phoenix.com.tw  mail.woocorp.com.tw   IMS01          192.168.9.111           jennifer@mail.woocorp.com.tw      1031
2007-4-21  4:38:54 GMT         192.168.8.30          nmail07.phoenix.com.tw  mail.woocorp.com.tw   IMS01          192.168.9.111           john@ms3.coocorp.com.tw          1031

兩相比較,二者的Pattern相同,都有兩組1020->1031的Log,寄給收信人甲的Mail Server時,收信人乙的Mail Address也會出現在Log中,所以共有4筆1020, 4筆1031。但最重要的差別,在於正常案例中兩組1020->1031的間隔時間只差了12秒,而4/19的異常Mail則差了近45分鐘。

看來關鍵出在1034(SMTP message queued for remote delivery,丟到Queue中排隊)到1020(SMTP begin outbound transfer,真正開始傳遞)的時間,由於信得乖乖在Queue裡等待寄出,如果Queue很長,那麼等上45分鐘並非不可能的事。

重點是,要怎麼證明它是在Queue中等待,而不是出了狀況? 我不是很清楚IMS Queue的結構及原理,但試圖找來相關證明:

2007-4-19  4:22:23 GMT         192.168.8.30          nmail07.phoenix.com.tw  port.sing.net  IMS01          192.168.9.111           rd@koocorp.com.tw           1031 B3C781785A2914458D97ABD324E5E97A3A662D@nmail07.phoenix.com.tw           1        0           227436       434    2007-4-19 2:44:48 GMT          0        Version: 5.0.2195.6713 -         The Next-Generation AI Engine-Secret Report (Phoenix Foundation)     research@phoenix.com.tw       --

以上這封信是10:44:48寄出的,是風凰城基金會(XD)寄給434個散佈在不同Mail Server收信人的研究報告信件。寄到port.sing.net時,已經過了1小時又37分。

  • 大轟炸信件(434個收件者)Delay時間為10:44:48 -> 12:22:23 = 約97分鐘
  • 另一封CoolCorp異常延遲信件的Delay時間為11:38:36 -> 12:19:30 = 約45分鐘

兩封信差了53分鐘發出,卻差不多同時送達,我大膽推論這是Queue差不多在12:20左右消化完畢的象徵。

由以上的分析,我研判有可能IMS01的傳送延遲,有可能來自於Queue大爆滿。不過,要明確指出這個推論是否正確,有待很了解Exchange SMTP Queue行為的專家依原理面加以證實。

【文章】Windows Form UI優化入門課 – 非同步作業

用Visual Studio開發Windows Form不是件難事,但我們很容易在使用過程膲出程式師的功力! 舉凡一執行長時間作業UI就會凍結沒反應的,肯定是菜鳥的作品。本文以Windows Form初學開發者為對象,介紹如何利用非同步作業概念,改善使用者的操作經驗。

文章下載

PS: 同事今天問到在WinForm下寫多執行緒程式的建議,我想起之前曾在RUN!PC上發表過的文章,整理了一下,Post出來給大家參考。

【延伸閱讀】

Posted 26 March 2008 11:08 PMJeffrey | 3 comment(s)
Filed under:
SSRS列印報表錯誤0x8007F304

最近上了一批SSRS的新報表,使用者抱怨列印時,會出現"列印時發生錯誤。(0x8007F304)"的錯誤訊息。

印象中,Reporting Service由SQL 2000版本昇級至SQL 2005的SSRS後,有遇過類似問題,絕大部分的原因都來自於列印時會用到的一顆ActiveX元件--RSClientPrint Class。

Google了一下,研判這次遇到的問題也肇因於RSClientPrint的Bug,而MS在SQL 2005 SP1裡已修復了這類問題。因此,我猜想是使用者連上了未裝SP1的Reporting Service主機,安裝到舊版的SSRS RSClientPrint。

要驗證安裝版本,可以開啟C:\WINDOWS\Downloaded Program Files,在清單中找尋一下RSClientPrint Class,後方有個版本欄位: [參考資料]

  • SQL 2000        : 2000.80.1038.0
  • SQL 2005 RTM : 2005.90.1399.0
  • SQL 2005 SP1 : 2005.90.2047.0
  • SQL 2005 SP2 : 2005.90.3042.0

不過,檢測的結果,出問題的機器安裝的RSClientPrint是2000.89.1038.0,不是想像中的2005舊版。進一步詢問,使用者曾試著更新為2005.90.1399.0,但更新後,變成印舊版報表有錯誤。基於先查到的資訊,決定換用SP2最新版2005.90.3042試試手氣,賭一下Bug在SP1後已經修好。

將所有IE關閉,在RSClientPrint Class上按右鍵選移除後,再重新連上SP2版的Reporting Service重新安裝列印元件,問題排除。

PS: 還有個問題,安裝列印元件需要Admin的權限,一般使用者多半不具有管理者身份,導致無法安裝。MSDN提到可否下載安裝ActiveX Control與IE的安全設定有關,另外,也有人找到自動部署安裝的方法,兩種做法都可考慮。

技客的蝴蝶夢

【前情提要】自從在陽台的櫻桃蘿蔔上發現加菲毛後,決心用他為女兒上一堂自然課(雖然事後覺得真正想上這堂課的人是我)。神蟲見首不見尾的他,一度失蹤好幾天,再度出現時,已在葉子上結蛹...

2008-03-18 07:00 發現已可約略看出翅膀上的斑點

03-18 20:30 不到一天的時間,翅膀上的黑色斑點變得非常清晰,依據先前在網路上查到的資料,這是羽化前一天的徵兆。

03-18 23:30 將蛹移入室內,在電腦桌下架設小小攝影棚。設備: Sony DCR-PC120 + Vista + webcamXP

03-19 01:00 早先查到的資料,羽化時間約在凌晨3-4點,不過對於預估的羽化時間沒把握,加上年老體衰,無力通宵博命。啟動錄影功能後就寢,但還是訂了鬧鐘02:30、04:30起來檢查。

03-19 02:30 發現尚無動靜,先將錄影檔刪除後再重新開始,節省空間。(1分鐘約20MB)

03-19 04:30 第二次起床檢查,睡眼朦朧間忽然發現葉子上掛著白白的東西,哇!! 醜小鴨已經變天鵝了... 檢查了一下影片檔,實際破蛹的時間約在02:46,就在上回起床檢查後沒多久,讓我有些扼腕錯失親眼目睹的機會。幸好DV還是捕捉到清楚的羽化過程,只是加菲毛未免太害羞了,臉一直藏在葉子後方... (實際的羽化步調十分緩慢,我放在YouTube上的影片已加速一倍,但仍然有5分鐘)

 

看到蝴蝶睡意全消,自此相機快門聲不絕,直到天明。

03-19 04:47,"翅膀硬了"(XD)的加菲毛,勉力飛離了原本的葉子,停在房間的一件衣服上,趕緊把他移到陽台,再補了幾張照片。

  

03-19 09:35 屋外雨勢漸歇,加菲毛拍動翅膀,離開窩居月餘的陽台,迎向另一段人生...

最後,花一點時間解開加菲毛的身世之謎,"她"是一隻"台灣紋白蝶"... (鄉親吶,這就是愛台灣啦~~)

辦識依據: 日本紋白蝶後翅外緣無黑斑,雌台灣紋白蝶黑斑較發達。
參考資料: http://tw.myblog.yahoo.com/jw!DSRSuzWfEQXNWVnBDdtjog--/article?mid=2002&sc=1

Posted 20 March 2008 01:36 AMJeffrey | 2 comment(s)
Filed under:
20萬人次紀念

依據StatCounter的記錄,2007/03/18 13:15:19,來自219-84-220-15-adsl-chu.STATIC.so-net.net.tw (219.84.220.15)的朋友,使用Windows XP+IE6踏上blog.darkthread.net/blogs/darkthreadtw/archive/2007/05.aspx,成為本站第20萬人次的訪客!

特此紀念

加菲毛近況

上回在家中觀賞用蘿蔔上發現了加菲毛,隔天就沒了它的蹤跡,再隔天卻又忽然出現,只是明顯體型小許多,讓我有點狐疑,這是前蛹期排出體內廢物後的正常縮水? 還是其實是另一隻?

加菲毛"神蟲見首不見尾",常常一下子就換到不同的葉子上出没,再過了幾天,找遍整顆蘿蔔,就是看不到他。心想應該是爬到花盆邊或其他地方結蛹去了,再不然就是被來來往往的鳥兒當了點心,就隨緣吧!

上週日(3/9)沒事去蘿蔔前晃了一下,忽然在一片葉子上看到...

已經化蛹的加菲毛,在我專心觀察的時候還用力扭動一下,嚇了我一大跳。

Goggle了一下紋白蝶的羽化過程,找到一篇很詳細的資料,上面提到羽化的前一天蛹會透明化,且可以清楚看到看到白色的蝴蝶翅膀跟上面的黑色斑點,今天(3/15)看到的加菲毛像這樣...

已經隱約看到白色翅膀及紋理,不過黑色斑點還沒出現,看來醜小鴨變天鵝還要等幾天。期待中...

【延伸閱讀】

【警告】以下部分內容,已滿40歲之單身中壯老年男子需由親友陪同觀賞 (*警語由來*)

PS: 跟女兒說加菲毛快要變成蝴蝶,她連忙要我趕快把他移到屋子來,免得他飛走就看不到了。我跟她說,蝴蝶在屋子裡沒法生活,他需要吃花蜜、飛來飛去才能過生活,還要跟別的蝴蝶結婚生小毛毛蟲... 她的感想是,那還是可以養在家裡,她每天會放他出去幾個小時吃東西,之後再抓回來(用網子XD) 而且她希望他最好能在我們家的陽台結婚...

哈! 童心!!

Posted 16 March 2008 12:10 AMJeffrey | 1 comment(s)
Filed under:
【茶包射手專欄】System.Data.OracleClient問題

部署一個新程式到一台主機上,得到以下錯誤訊息:

System.Data.OracleClient requires Oracle client software version 8.1.7 or greater.

同一程式在另一台主機上表現正常,而這台機器上其他ASP.NET程式跑ODP.NET連線Oracle也正常,可以推論已裝了Oracle 9.2 Client。那這是怎麼一回事呢?

在與Oracle Client交戰的經驗中,這類狀況多半是Oracle Client相關檔案存取問題引起的。廢話不多說,喚出抓鬼一哥--Process Monitor!!

輕輕鬆鬆就抓到以下的Log:

由這個Log來看,ASP.NET正沿著PATH環境變數列出的路徑一一尋找oci.dll,但始終沒找到,看來就是讓System.Date.OracleClient判定Oracle Client Software沒裝的原因。比對了其他機器,oci.dll理應出現在bin目錄下,但該台主機卻缺了這個檔案。

由其他機器Copy oci.dll到bin目錄下,問題就消失了。Case Closed! 收工回家。

杏花林

話說上回在二格山頂巧遇142大哥,他說228的時候去了一趟貓空杏花林,杏花已經盛開,再晚可能就謝了。

"孩子的成長不能等",杏花亦然,於是決心隔週六要一定要去看一下,沒想到週五下午開始下起雨,木柵還下得頗大,心想這下泡湯了,杏花就算沒謝也要被雨打殘吧!

週日早上,暫且先放下難解的三角習題,由政大->後山->樟山寺->待老坑山一路直奔杏花林。嘩~~~ 滿山的花! 沒謝沒謝

不過,杏花的茂密度不若櫻花,不太容易用數大便是美取勝;單朵入鏡又要考驗我三腳貓級的構圖技巧,再加上鏡頭最長焦只有135mm*1.6,自然無法跟大白、小白、小小白相提並論(例如以下的這位白鏡大哥,人家這才叫PRO唄),更何況天空陰暗、空氣迷濛,本來就不適合照相... (謎之聲: 喂! 你夠了沒?)

不過,入寶山,豈有空手而回的道理,還是秀個一兩張圖給大家看看好了...

在山上東拍西拍耗了不少時間,一路狂趕下山,從杏花林到指南路上的麥當勞,只花了35分鐘,創下個人的新記錄。

PS: 我的【特殊註記】這回攻上待老坑山囉!

 

Posted 14 March 2008 02:35 AMJeffrey | 1 comment(s)
Filed under:
TIPS-SqlConnection的ConnectionString保密機制

在設計資料庫相關程式時,連線字串最好能以加密方式存在config檔案裡;再進一步,最好連解密字串的機制都封裝在特定的資料存取元件中,開發人員及呼叫端程式只需傳入SqlCommand或更高階的抽象化資料物件,就可以完成資料庫存取作業,不必也不能得知連線字串的相關細節。

只是依我自己的實務經驗,有時直接傳連線物件(SqlConnection)給呼叫端是較省事的做法(丟一個連線給你自己玩,別來煩我! 是有點不負責任,但元件開發者未必有時間陪著在每個案子中抱著各式不同的需求打滾),連線丟出去了,呼叫端來個SqlConnection.ConnectionString會不會就讓辛苦加密保護的連線字串瞬間曝光呢?

答案是不會,但也可能會!

SqlConnection中有個屬性Persist Security Info,預設值為false,意思是使用SqlConnection.ConnectionString取得的連線字串,密碼的部分會被移除。

既然如此,為什麼又說可能會呢? 經過實測的結果,這個去除密碼的動作,在SqlConnectoin.Open()後才會發生效果(我猜是要等到密碼用過後才將它去掉,其實這可以用設內用外用兩組字串來克服,但SqlConnection的行為是如此設計),若是傳回尚未開啟的SqlConnection,連線字串會原原本本傳回,就失去保護效果囉!

所以,如果在設計上資料存取元件要傳出可用連線給呼叫端,切記"開了再上",就可以靠這個機制多少提供基本的防護,但最安全的方式還是用資料存取層將企業邏輯與實體資料存取完全隔離開來,只是要達成這個理想得付出些代價就是了。

以下是簡單的ConnectionString密碼隱藏效果測試碼:

static void TestConnString()
{
    SqlConnection cn = 
        new SqlConnection("Data Source=(local); Initial Catalog=myDB; 
User Id=user1; Password=pwd;"
);
    Console.WriteLine("Before: " + cn.ConnectionString);
    cn.Open();
    SqlCommand cmd = new SqlCommand("SELECT GETDATE() AS D", cn);
    SqlDataReader dr = cmd.ExecuteReader();
    dr.Read();
    Console.WriteLine("Now={0:yyyy-MM-dd HH:mm:ss}", dr["D"].ToString());
    Console.WriteLine("After: " + cn.ConnectionString);
    cn.Close();
}

【延伸閱讀】MSDN裡關於ADO.NET連線保密的說明

Born to Be An Engineer

幾天前,部門辦了春酒,部門巨頭們分別扮演了鄧不利多、卡門、小丸子她娘、哈雷騎士跟"瑪麗蓮夢露"(男生扮的,orz)娛樂大眾。

為了增加可看性,大會還辦了一場才藝競賽,區區幾千元獎金,又是四隊取前三名,沒想到居然逼出了大家的潛能。

有女伍佰帶著內衣短褲拖鞋舞群唱"妳是我的花朵",最後還由內衣壯漢抬著特務J扮相的蔡依林進場當演唱會神祕來賓(想當然,又是男生扮的,而且還是平日坐在我旁邊的寡言斯文男變裝的,讓我完全無法與台上的豪放女關聯在一起 orz orz),驚駭莫名的我在下一組草裙舞"女"郎出場時徹底崩潰... (我必須承認,體重破百的男子赤身化作夏威夷草裙舞女,所能產生的震懾效果不是常人可以抵擋的 orz orz orz)

總而言之,這場春酒揭穿了同事們不為人知的黑暗一面,莫非大伴平日在辦公室裝羞澀、扮木訥全是假象? 不不不,這一切都是幻覺,嚇不倒我的~~~

講了大半天春酒,跟旁邊的幾何圖形又有何關聯? 原來,工程師傾向的IT Head出了幾道燈謎給大家猜,幾題冷笑話級的就甭提了,最後兩題進入高潮,這是倒數第二題。(最後一題更機車,考2^58-1是否為質數? 不過我一見題目就投降,反而沒提起興趣挑戰)

此題一出,立即在工程師性格指數特高的資訊部門引超騷動,立時各桌都出現有人抄來紙筆,振筆疾書,並且分組討論起來。而我,大概是其中病情最嚴重的,此題一出,盡管台上的表演、摸彩、遊戲高潮不斷,笑鬧聲震耳欲穿,我卻早已出竅到了青康藏高原的不知名山巔,孤寂一人靜坐菩提樹下,無言地在泥土上畫著一個又一個的三角形,沈思著: 為什麼是30度? 應該要用輔助線解題吧? 輔助線又要加在哪裡呢?
(這境界實非常人能達,嘖嘖嘖嘖...)

春酒結束,工程師的靈魂卻未安歇,回家洗完澡又在紙上畫了十來個三角形試解,體力不支才甘心上床;隔天被晨起運動的鬧鐘喚醒,半夢半醒間腦中卻浮現一絲靈感,人就從床上彈了起來開始畫三角形跟一堆亂七八糟的線,拖了近一個小時才不甘願地出門爬山。即使人在山上,腦中還是不時有三角形飄來飄去... 總算,忽然想出用加三條輔助線配合等腰三角形與正三角形特性推論出結果。算算前後已經耗了六小時去了,但是在求得解答的一瞬間,我有苦修後悟道般的解脫感... (孩子,你病得不輕耶!)

相信本Blog的讀者也有不少工程師性格濃烈的宅男IT人,或是專攻數學幾何的高人,這題就留給大家玩玩吧! 我相信應該存在比加三條輔助線更簡單的解法,May the force be with you.

Posted 12 March 2008 02:25 AMJeffrey | 2 comment(s)
Filed under:
TIPS-Failed to Access IIS Metabase

小事一件,不過前後已經遇到很多次(今天又發現一起),看來也算常見問題,索性整理一下我的處理心得給大家參考。

錯誤訊息如下:

中文版

無法存取 IIS Metabase。
描述: 在執行目前 Web 要求的過程中發生未處理的例外情形。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。
例外詳細資訊: System.Web.Hosting.HostingEnvironmentException: 無法存取 IIS Metabase。
用來執行 ASP.NET 的處理序帳戶必須擁有 IIS Metabase (例如 IIS://servername/W3SVC) 的讀取權限。如需修改 Metabase 使用權限的詳細資訊,請參閱
http://support.microsoft.com/?kbid=267904

英文版

Failed to access IIS metabase.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.Hosting.HostingEnvironmentException: Failed to access IIS metabase.
The process account used to run ASP.NET must have read access to the IIS metabase (e.g. IIS://servername/W3SVC). For information on modifying metabase permissions, please see
http://support.microsoft.com/?kbid=267904.


常見情境:

  • 已經安裝好.NET Framework 2.0的機器,事後才加裝IIS
  • IIS被移除重裝過

一般來說,安裝.NET Framework 2.0時,若安裝程式偵測到機器上有IIS,會向IIS註冊以便能執行ASP.NET 2.0。若先裝了.NET 2.0才裝IIS,就漏掉這個一註冊ASP.NET程序了(不過就算沒註冊,IIS的應用程式選項裡還是可以看到ASP.NET 2.0,讓人誤以為ASP.NET 2.0已 裝好,又一個陷阱),必須手動執行,如下:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis.exe -i

(PS: 完全不知道上面這行在搞什麼飛機或是重註冊無效的朋友,可以試看看執行.NET 2.0修復)

本來只是個小問題,不過由於錯誤訊息給得不甚明確,又扯了一堆W3SVC, IIS Metabase看似可怕的名詞,最後還扯到了權限問題,應該嚇壞一堆裝好IIS正要埋頭開始學ASP.NET的熱血新人。網路上看到不少人問了這個問題,就用這篇文章讓Google查詢"無法存取IIS Metabase"的傳回結果多一則吧!

TIPS-SideBySide Error Event

有台機器不定期出現以下錯誤:

  • Source: SideBySide
    Event ID: 59

    Resolve Partial Assembly failed for Microsoft.VC80.CRT.mui. Reference error message: Access is denied.
  • Source: SidebySide
    EventID: 59

    Generate Activation Context failed for D:\Program Files\Microsoft SQL Server\MSSQL.2\OLAP\bin\msmdctr90.DLL. Reference error message: Access is denied.

查詢了一下,很幸運地找到一篇相同的問題,並且有Microsoft Online Community Support的回答。

依據文中的說法,問題出在Performance Log Users群組對
\Program Files\Microsoft SQL Server\MSSQL.1\mssql\binn
\Program Files\Microsoft SQL Server\MSSQL.2\OLAP\bin

兩個目錄沒有讀取權限。檢查的結果,MSSQL.1\mssql\binn權限OK,但MSSQL.2\OLAP\bin的確沒有授予權限給Performance Log Users群組。

另外,在同一台機器上我還發現了一大堆Performance Counter Error Event: (有些可能與前面的權限問題有關,有些看起來又不像)

  • Source: Perflib
    Event ID: 1008

    The Open Procedure for service "ContentFilter" in DLL "C:\WINDOWS\System32\query.dll" failed. Performance data for this service will not be available. The Status code returned is the first DWORD in the attached data.
  • Source: Perflib
    Event ID: 1005

    Windows cannot access the file 푸ǖ for one of the following reasons: there is a problem with the network connection, the disk that the file is stored on, or the storage drivers installed on this computer; or the disk is missing. Windows closed the program C:\WINDOWS\system32\sqlctr90.dll because of this error.
    Program: C:\WINDOWS\system32\sqlctr90.dll
    File: 푸ǖ
    The error value is listed in the Additional Data section...(後略)
  • Source: Perflib
    Event ID: 1018

    Performance counter data collection from the "MSSQL$MICROSOFT##SSEE" service has been disabled for this session due to one or more errors generated by the performance counter library for that service. The error(s) that forced this action have been written to the application event log.
  • Source: Perflib
    Event ID: 1023

    Windows cannot load extensible counter DLL MSSQLServerOLAPService, the first DWORD in data section is the Windows error code.

Performance Counter的Error問題還挺常見的,今天找到Windows 2000 Resource Kit裡有個exctrlst.exe工具可以列出及停用某些損壞的Performance Counter,只要眼不見為淨,不失為一個良好的鋸箭法。

【下載】Extensible Performance Counter List(exctrlst.exe)
http://www.microsoft.com/downloads/details.aspx?familyid=7ff99683-b7ec-4da6-92ab-793193604ba4&displaylang=en

jQuery, I LOVE YOU~~~

不久之前,我低調且不經意地(謎之聲: 在Blog公佈? 好"低調"哦~~)透露了與jQuery正在交往的消息,換言之:

ASP.NET AJAX Client Library,你是個好人...
但jQuery看來可以讓我少奮鬥十幾個小時,所以...

在我的Web開發工作裡,Javascript佔了相當的比重。

雖然ASPX的Client-Side Event/ASP.NET AJAX Update Panel,幾乎可以讓你用C#/VB.NET搞定大部分的Web功能,偏偏自己有效能潔癖,對Response Time及Round-Trip Bandwidth斤斤計較,於是用Client-Side手段解決成了唯一的方案。

Javascript雖然彈性無窮,但寫來總覺又臭又長,少了.NET裡一大票的Base Class Library及好用的現成Method,一堆在.NET裡一行打死的功能都要DIY寫個數十上百行,再加上還要考慮瀏覽器相容的問題,同一件事要為IE寫一段,FireFox寫另一段,令人煩燥到不行。在我的眼裡,如果用C#寫Code是開著轟炸機掃平目標,寫Javascript就好像拿著小步槍在廢棄的城市裡進行巷戰。

Javascript Framework可以替我們處理掉一些跨瀏覽器的問題,也提供一些便利化的函數,的確可以省去不少惱人的瑣碎工作。坊間可用的免費Framework有很多,例如: Prototype、jQuery, Mootools...等等(Wiki上有列表整理),過去我的想法是借重ASP.NET AJAX Client Library,一來它系出名門,二來學到的技能可以繼續應用在ASP.NET AJAX Control開發上,一魚兩吃。

不過,無意間邂逅jQuery之後,馬上被它的簡潔精巧深深吸引,花了點時間學習了解,並試做過幾個介面,就不禁愛上了她,決定與她一起在Javascript巷戰中出生入死。

不過,要先標註一下警語,jQuery並不好學,語法簡潔、設計精巧,意味著我們能用短短幾行Code搞定過去數十上百行Code才能做到的事;但換個角度想,要能做"幾行換百行"有點像智力測驗,得通曉各種可用的函數工具,加上腦筋狂轉才能想出漂亮的解法。在開發語言裡,有個很接近的比喻---Regular Expression,二者乍看都像天書,但因為可以省下可觀的Coding量,還是吸引了很多人付出時間心力去學習了解。

在我的初步心得中,認為jQuery以下這幾點特性最具魔力:

  1. 用jQuery Wrapper就地升級:
    所有的元素經過jQuery Wrapper的包裝,馬上就可直接引用jQuery額外提供的豐富功能。
    例如: 用$()一包,就可以$(myInput).hide(),立即取代myInput.style.display = "none"一長串Code。
  2. Wrapper Set批次處理:
    Wrapper裡包的可以是單一元素,也可以是上百個元素組成的陣列,後面接上的Method則會以迴圈方式套用到陣列裡的每個元素上。例如: $("p.clsMenuItem").hide()可以一口氣將整個網頁下所有的class="clsMenuItme"的<p>都隱藏起來。
  3. 威力強大的Selector:
    用搞過CSS的人相信都用過div p.clsName這類Selector去找【被包在DIV裡class="clsName"的P】。我之前常常想,為什麼CSS可以,在Javascript裡只能用document.all這種笨方法自己過濾。jQuery最大的功德,應該就是讓Javascript也支援CSS Selector語法搜尋網頁元素。應用CSS Selector可以讓我們快速定位,只用一步就抓到指定的元素,比起過去要自己跑迴圈逐一檢查比對,或是千方百計為元素加上特定ID都省事許多。
    除了CSS Selector,jQuery也支援XPATH查詢,不過我覺得大部分的情況下,單單CSS Selector就綽綽有餘。
  4. 接接樂大絕技:
    生命不夠浪費在打字上,所以大部分的jQuery Wrapper Method執行完會繼續將本身當成結果傳回,所以馬上又可以接著呼叫下一個Method。
    例如:
    把ID="divHint"的DIV設成黃色背景、寬度300px並指定內容文字,原本至少要寫四行:
    var d = document.getElementById("divHint");
    d.style.backgroundColor="yellow";
    d.style.width = "300px";
    d.innerHTML = "This is a hint";
    jQuery用接接樂 $("div#divHint").css("background-color", "yellow").width("300px").html("This is a hint"); 一行就搞定。
  5. 事件模型的簡化:
    ASP.NET AJAX Client Library裡有 $addHandler可用,但是jQuery裡的寫法更簡單:
    $("div").click(function() {
         alert("Div [ID=" + this.id + "] is clicked!");
    });

    一口氣就為所有的事件加上Click事件,而其中this可以用來存取觸發事件的對象。
    另外還有好幾種巧妙的事件掛法,例如: one(type, data, fn)可以掛上按一次就作廢的事件、hover(over, out)可以同時設定onmouseover及onmouseout、toggle(even, odd)則可設定Click與下次Click執行不同的事件。
  6. 動態建立HTML元素:
    以前要用Javascript動態建立HTML元素得用createElement加上一堆有的沒的步驟,是件苦差事;在jQuery裡新增HTML元素則非常簡單。例如: 在<span id="spnX">後方接上一個<img>可以用 $("#spnX").after("<img src=\"xxx.gif\" />"); 輕鬆搞定!!

除了上述的特性外,jQuery用Extender擴充新功能的概念挺不賴的,而且已有不少Plug-In可以用,資源頗豐。AJAX的部分,如果是單純的GET/POST取值,可以用極簡短的寫法幾行打死(跟我設計函數時的理念很像),也都深得我心。

以下先列出一些資源,稍後有時間我再分享幾個小範例,讓大家瞧瞧她的美色。

IE8 Beta 1來了

配合MIX08大會舉行,微軟開放了IE8 Beta 1的下載。

這個Beta版本強調為提供Web Developer及Web Designer預覽IE8的功能,給想在IE8上市時就提供同步提供新功能的網頁開發者一個偷跑的機會。IE8做了不小的改革(CSS 2.1, HTML5),因此在回溯相容(Backwards Compatibility)上不得不做了一些取捨,所以有些過去顯示正常的網站可能會在IE8裡格式會走樣。IE8採行的解決方式讓IE8同時具備三具網頁呈現引擎(Formatting Engine),包含了最新的IE 8 Standards Mode, 與IE7相容的Strict Mode, 以及要求與IE5相容的Quirks Mode(可以稱作原始人模式嗎? XD)。IE8上有個Emulate IE7鈕可以讓使用者自行切換成Strict Mode, Web Developer則可透過HTML Header/Meta宣告要求使用特定的顯示引擎,詳細說明可以看這裡

除了支援新的標準,IE8也宣稱在HTML解析, CSS規則, DOM物件, GC/記憶體管理, Scripting Engine上都做了優化,效能比以前提升許多。不過,對我而言最有看頭的還是新推出的Activities及WebSplices, 簡單來說,Activities像是Plug-In, 在網頁上按右鍵就可以叫出選單呼叫這些額外加掛的新功能,例如以下這個即時翻譯:

原則上這個概念之前就可以透過IE Add-On的方式做到,只是這次微軟提供了公開的實作規格,並鼔勵大家利用。

至於WebSlices則是網頁開發者在網頁上動手腳,另外切割出一個個較小的獨立單位(稱為WebSlice),讓IE8 User可以獨立訂閱及檢視。目前最典型的應用展示是eBay拍賣網站把一個個拍賣物件包成WebSlice, 於是買家就可以單獨訂閱其中某個物件,未來用較簡便的方式檢視自己關心的項目,省去每天回網站報到檢查更新的麻煩。(不過,這樣子網站流量與廣告收益或多或少會受影響吧!)

另外,Firefox裡的Firebug整合了一大串網頁開發人員需要的偵錯功能,用過就會上癮。(好用到有時我會換用Firefox Debug Javascript) 過去在IE上,得裝好幾套工具才能蒐集齊相同的功能(IE Dev Toolbar, Web Development Helper, HttpWatch) 看來Firebug的確對IE形成不小的壓力,所以IE8內建了Developer用的偵錯工具,試圖急起直追。(粗略看了一下,似乎還是少了HTTP Traffic的追蹤)

至於AJAX Navigation看起來挺酷的,在網頁上動一些手腳,就可以將AJAX動態變化的過程納入歷史,例如: 點地圖放大的過程可以回上一步回上一步的還原回去。

以上這些新功能,可以看首頁Demos裡(即上圖中的左側第二個Tab)的四段展示影片(各3分鐘左右)。

【相關資源】

IE8首頁: http://www.microsoft.com/windows/products/winfamily/ie/ie8/default.mspx (Demo裡有預錄的展示影片)

IE8 Beta 1下載 http://www.microsoft.com/windows/products/winfamily/ie/ie8/getitnow.mspx

Posted 07 March 2008 07:45 AMJeffrey | no comments
Filed under:
TIPS-Enable SSRS Remote Errors

SQL 2000的Reporting Service在報表錯誤時會將錯誤訊息顯示在網頁上,但SQL 2005的SSRS在錯誤時只會傳回:

如需有關此錯誤的詳細資料,請導覽至本機伺服器電腦上的報表伺服器,或啟用遠端錯誤
(原文: For more information about this error, navigate to the report server on the local server machine, or enable remote errors.)

此時我們很容易被誤導聯想到web.config中的<customErrors mode="Off" />,但事實上它是個被Catch到Exception,顯示的訊息由SSRS掌控,並不算是ASP.NET層次的錯誤,因此改web.config是沒有用的。

查了一下,才發現要開啟它有點麻煩,官方KB介紹的做法是要寫一段Code存成rss,再用rs.exe執行。http://technet.microsoft.com/en-us/library/aa337165.aspx

手續有點麻煩,不過KB中有提到可以直接改ConfigurationInfo Table,我找到了一篇教學,嘿... 省事多了。

SELECT [Name],[Value]
FROM [dbo].[ConfigurationInfo]
where name like '%EnableRemoteErrors%'
GO
update [dbo].[ConfigurationInfo]
set value = 'True'
where name like '%EnableRemoteErrors%'
GO

PS: 改完後ReportServer Web Application要重啟才會生效,不想IISRESET的話,可以去重新存檔C:\Program Files\Microsoft SQL Server\MSSQL.2\Reporting Services\ReportServer\web.config

更多文章 下一頁 »

搜尋

Go

<March 2008>
SunMonTueWedThuFriSat
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication