August 2007 - 文章

【茶包射手專欄】錯怪Oracle~~

本來以為自己堪稱台灣地區Trouble-Shoot MSDTC問題的權威,沒想到這幾天陰溝裡翻船,為了解決一台新灌XP SP2無法啟用分散式交易的問題,耗掉近一個人天...

同事回報,照著我先前的KB設定了分散式交易,但是執行以下的Code,程式卻會卡在第11開啟Oracle Connection上,卡住約三分鐘,然後丟出Communication with the underlying transaction manager has failed.之類的Error。

   1:  private static void oraDtc() 
   2:  {
   3:      using (TransactionScope tx = new TransactionScope())
   4:      {
   5:          string sqlCnStr = "Data Source=theSQL2005;User Id=blah;Password=blah";
   6:          SqlConnection cnS = new SqlConnection(sqlCnStr);
   7:          cnS.Open();
   8:          cnS.Close();
   9:          string oraCnStr = "Data Source=theOracle;User Id=blah;Password=blah";
  10:          System.Data.OracleClient.OracleConnection cnO =
 new OracleConnection(oraCnStr);
  11:          cnO.Open();
  12:          cnO.Close();
  13:      }
  14:  }

一時鬼迷心竅(當然,也有可能農曆七月的關係),看程式停在Oracle的連線開啟上,就認定問題出在Oracle上,忘了System.Transactions具有LTM->OleTx的精巧特性(後面會再介紹),死命地查Oracle Service for MTS、Oracle Client版本,甚至還重裝了一次Oracle Client,動用了Net Monitor 3Process Monitor等重量級工具,還學會了設定ORAMTS_CP_TRACE_LEVEL Registry追蹤ORAMTS Log的技巧(真是意外的收獲)。不過,各式重量級武器精鈍盡出,我卻只得到一個結論: Oracle連線沒出現任何錯誤,程式Hang住的那三分鐘,nothing happened, of course, nothing wrong。我另外做了一個實驗,在ASP裡透過宣告<%@ Transaction=Required%>包了一個OLE DB的Oracle Connection,卻可以達陣成功(MSDTC的Commit數加1)... 這...

一陣膠著之後,忽然福至心靈,到目前為止一直以Oracle為焦點,並沒有親眼見證SQL的分散式交易成功,該不會問題出在SQL的分散式交易上??

這就對了,關鍵在於LTM(Light Weight Transaction Manager)! 當.NET 2.0發現整個TransactionScope中只涉及一台SQL Server 2005時,可以不啟用OleTx,不驚動MSDTC,直接使用LTM更有效率地完成交易。而最方便的一點是,.NET 2.0會依參與交易的對象、數目決定使用LTM或是OleTx,對開發人員完全透明。所以我遇到的情況應該是在開啟Oracle Connection時,.NET 2.0發現已達啟用分散式交易的條件,原本的SQL連線須由LTM改為OleTx,若SQL連線升級失敗,或許就是導致分散式交易失敗的原因。

這解釋了為什麼Oracle Connection在開啟時Hang住,沒有動作好一陣子後傳回Transaction錯誤的現象。Oracle Connection的出現導致先前的SQL Connection要升級為分散式交易,苦等不到SQL Connection註冊MSDTC成功,Oracle Connection只有含淚背上了"導致交易失敗"的黑鍋。

再做兩個測試,TransactionScope包兩條SQL Connection失敗,包兩條Oracle Connection成功,Bingo!! 問題根源一旦明確,解決過程就變成一塊蛋糕(Piece of Cake)。依照先前TIPS-TransactionScope過三關的技巧,很快地問題就排除了,Case Closed!

PS: 9月的RUN!PC會有一篇我的文章,介紹搞分散式交易的一些實務技巧(血淚辛酸? XD),還用實驗驗證與觀察TransactionScope的特性(包含上述LTM->OleTx的過程),有興趣的人可以去書店翻翻。

TIPS-ASP.NET Cache Mini Guide

過去在ASP時代,若想將資料保存在Server端,我們可以用Session或Application(雖然在談Scalability時,會建議避用這類Stateful的設計,不過那又是另一個一千零一夜的故事了,這裡先不提)。在ASP.NET中,有另一個好用的選擇: Cache

比較起來,Cache比較像Application,因為它是所有的ASPX共享的空間,不屬於特定的Session;但它跟Application又有點不同: 它是"Cache",代表萬一記憶體不足時,它可是會被清掉的,所以我在寫Cache的邏輯時,多半會用以下的做法: (遇到記憶體不足時,CachItemPriority設得愈低,會愈先被放棄)

if (Cache[key]==null) {
   //...略... 重新產生要被Cache的物件, 放入變數t
   Cache.Add(key, t, null, DateTime.Now.AddHours(1),
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.High, null);
}
return Cache[key];

如此,就可以達到On-Demand重建的效果,任何Request一旦發現Cache中找不到資料或已過期,立刻重新產生要Cache的物件放入Cache中,造福後人。

要將資料放入Cache,可以用InsertAdd,二者最大的不同是Insert時會不論Cache中是否已有該Key值的CacheItem時,一律新增或覆寫為傳入的value;而Add在Cache中已存在該Key時,會直接傳回現有物件,不做更新。

跟Application比起來,Cache多了很多彈性,它可以設定Dependency(例如: 某個File一旦變動Cache內容就會自動被移除)、設定某個時間後移除、也可以設定無人使用後多久自動消失(這點又跟Session的20分鐘保存期限很像),還可以指定當Cache被移除時要呼叫的函數(CacheItemRemovedCallback)。不過,一般我倒很少用到那麼複雜的功能,多半只用到兩個參數: absoluteExpiration與slidingExpiration。

二者的使用時機有點不同,absoluteExpiration我多會用在常被查詢的龐大資料表,例如: 系統中常常要將員工編號換成員工姓名,若每次都去資料庫現場查,勞民傷財。所以我會讀取一次,轉成Dictionary<string, string>或Hashtable後放入Cache,並設上一或兩個小時後失效。反正員工資料也不會分分秒秒都在變化,最壞的情況是修改員工資料後,要等上兩個小時後才會生效。不過實務上為了避免發生某位大長官大為了某個臭工程師在效能上的堅持苦等兩小時,我多半還是會設計清除該Cache的功能,必要時呼叫一下,即刻將Cache移除,資料馬上就更新了。使用絕對過期時間時,除了指定DateTime物件(我通常是用DateTime.Now.AddHours()設時間)給absoluteExpiration參數外,slidingExpiration要設為System.Web.Caching.NoSlidingExpiration。

用到slidingExpiration多半是要模仿Session物件的效果,只要有繼續存取Cache[key],物件就會一直保留在Cache中,直到閒置超過slidingExpiration指定的時間為止。不過,Cache的Scope是全Process,並不限於某個User Session,如果我把Key值取為"AAA",豈不等於全部User都把資料放進同一個置物櫃中,保證天下大亂。所以一定要為每個Session取個唯一的Key值,ASP.NET的SessionID,Logon User都可以被考量,但我還是最愛Guid,Page_OnLoad生一個出來,放進ViewState中,後面就好辦了。

private string getSessionKey() {
    if (ViewState["SessionKey"]==null)
        ViewState["SessionKey"]=Guid.NewGuid().ToString();
    return ViewState["SessionKey"].ToString();
}
 
private void saveToCache(object obj) {
    Cache.Insert(getSessionKey(), obj, null, 
System.Web.Caching.Cache.NoAboluteExpiration, imeSpan.FromMinutes(20), 
System.Web.Caching.CacheItemPriority.High, null);
}

以上就是我最常應用Cache的做法,大家如果有什麼獨到的心得,也歡迎拿出來分享一下。

【茶包射手專欄】詭異的二次登入

今天又遇到詭異的問題,某個使用者開啟網頁OK,填好資料要送出時,IE會跳出詢問帳號密碼的對話框。IIS設定為整合式驗證,理論上開啟網頁時就已完成身份驗證了,Postback到同一網頁,實在沒理由再問第二次。更何況,其他的使用者使用同一網頁並沒有任何問題。

這個謎團在同事耐心連試三次登入後露出曙光...

連續用某個帳號登入三次後,網頁顯示寫入Log檔案存取被拒的訊息。這下真相大白了! 該使用者的個人資料有誤(這解釋了為什麼只有這位苦主要受此磨難),在Postback時引發錯誤,而Exception Handling的Code試圖寫記錄到Log檔,再因Log所在的目錄權限沒設好,寫檔被拒,因此IIS要求使用者另外提供身份,這就是Postback時又跑出登入視窗的由來。

由以上所結,ASP.NET程式在遇到Access Denied時都會要求重新認證身份嗎? 為什麼我印象中ASP.NET會直接傳回Access Denied訊息?

於是我做了以下的測試:

public partial class PermIssue : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
 
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        System.IO.File.WriteAllText("X:\\Temp\\NoPerm\\Test.txt", "AAA");
    }
}

我將X:\Temp\NoPerm設定成只有一個特定User才有權讀寫,按下Button1之後,結果立即傳回
Access to the path 'X:\Temp\NoPerm\Test.txt' is denied.
IIS並沒有顯示登入視窗要求提供其他身份? 這...這...這... 又是因為農曆七月嗎?

經過一番嘗試,我終於找到IIS會不會重新要求認證的關鍵在於web.config中的<identity impersonate="true"/>!

當impersonate設為true時,ASP.NET才會用使用者的身份去存取檔案等資源;預設值為false,不管用什麼身份登入網頁,ASP.NET永遠會用NETWORK SERVICE或ASPNET等專屬帳號存取資源,自然沒有換身份的必要。補上這點,所有的疑問都獲得解答,Case Closed!

月全蝕

晚上七點要動身回家才知道今天有月全蝕,回到家月蝕已近尾聲,但我還是抄起10D,勉強用135mm打幾下月亮意思意思,不知是焦長不足、焦距不對還是技術欠佳,再怎麼拍,照片中的一輪明月始終難脫"朦朧美"...

Posted 29 August 2007 01:18 AMJeffrey | 5 comment(s)
Filed under:
有趣的視覺遊戲

有沒有看過這個有趣的視覺遊戲?
(本想註明原出處,用Google查"Spinning Silhouette Illusion"可以找到很多,但實在無法判別最早來自何處。)

圖中旋轉的火辣美眉,你覺得她是順時鐘轉還是逆時鐘轉? 有時專心看一陣子後,會忽然發現旋轉方向反過來,然後眨個幾下眼睛又再反回來,讓人不禁懷疑圖片被動過手腳,會在特定時間改變施轉方向。

不過,最妙的一件事是,如果你多找幾個朋友擠在螢幕前一起看,在同一時點,會發生有些人覺得是順時針,有些覺得是逆時針的狀況,由此推論,問題不在動態GIF檔被搞鬼,而是人眼的錯覺。

我是個愛鑽牛角尖的邏輯狂人,仔細分析了一下,發現這個圖的玄機出在圖案是全黑的剪影,某個畫面你可以解釋成美眉正對著你或是美眉背對著你,解釋不同,旋轉方向就不同。用更簡單的方法來定義,當你認定美眉站在地上的是左腳,她就是順時針旋轉;若你覺得她的右腳才是軸心,就是逆時針旋轉。

還是很難理解,對吧?

記得以前學生時代解幾何問題,原本亳無頭緒的難題,往往在加上一兩條輔助線後豁然開朗。各位同學,這題讓我們也用輔助線來解吧!! 我在動畫中加幾條提示線,分別做了兩個動畫GIF,排在一起看,雖然二者黑影的部分100%相同,但左圖是順時針,右圖是逆時針,故得證!

Posted 26 August 2007 03:25 AMJeffrey | 6 comment(s)
Filed under:
TIPS-Get Process ID of Application Pool

今天在Debug WinForm程式時,想要一併Attach它所呼叫的Web Service,以便可以在Web Service的Method中也設定Breakpoint。

我的Windows 2003上設了兩個IIS的Virtual Server,使用不同的TCP Port Number,不同的Application Pool,所以在Attach Processes時可以看到有兩個不同Process ID的w3wp.exe在跑,靠... 我要Attach哪一個才對?

本以為用IIS管理員或元件服務管理員就可以輕鬆查到Application Pool的Process ID,但代誌並不像憨人所想的哈尼甘單! 我們無法從這兩個介面查到各Application Pool的Process ID。

用Goggle找到解法,文中的第一種方法比較簡單,不需要額外安裝Debugging Tool(雖然它是值得好好學習的可怕武器),記得要先CD到WINDOWS\SYSTEM32目錄。

C:\WINDOWS\system32>cscript iisapp.vbs
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

W3WP.exe PID: 5680   AppPoolId: SharePoint
W3WP.exe PID: 5044   AppPoolId: JurassicPark

 

Updated 2007-08-24 12:00
文章貼出來幾分鐘後,同事小熊子提供了用GUI式查詢的好方法--Process Explorer檢視法,如下:

KB-Deadlock Detection And Retrial Sample

最近在處理表單引擎的Deadlock問題,由於引擎核心以物件導向方式開發,很難為了資料庫的更新問題去挪動物件的呼叫順序。但還是努力做了調整,每天Deadlock的發生次數終於壓到個位數,但要100%避免看來是不可能的(至少以我的能力來說是如此)。既然逃不掉,就乖乖面對吧!

一般處理Deadlock的準則是Wait And Retrial,換句話說,程式邏輯本身並沒有任何錯誤,純粹是運氣不好,跟其他Process的資料庫更新作業強碰且被SQL Server挑中變成犠牲品,在絕大部份的情況下,在我們接到Exception的同時,冤家Process也已完成它的作業,釋放Lock。所以只要再試一次,幾乎都會成功。

不過,由於Connection在歷經錯誤後,就無法再參與Tranascation,因此得重新建立Connection再跑。(我自己試的結果,連TransactionScope也要重來才會成功)

測試了好久,總算湊出Workable的演算法如下。其中DataProvider在建立時會開一條Connection,Dispose()時關閉,從頭到尾都用同一條連線做事,如此在TransactionScope可以用效率較佳的LTM機制,不必動用到OleTx(MSDTC)。重試的部分則利用SqlException.Number==-2(Lock timeout)或1205(Deadlock victim)來判定是否需要重試,若是則等待1秒後再試一次。若遇到的不是Lock或Deadlock問題,則沒有理由重試,直接throw Exception。

static void doUpdate()
{
    using (TransactionScope tx = new TransactionScope())
    {
        using (DataProvider dp = new DataProvider())
        {
            //接連新增資料到Emp及Cust兩個Table
            //如果同時有其他Process先新增Cust再新增Emp就會發生Deadlock
            dp.ExecCommand(
                "INSERT INTO Emp VALUES (999, 'Jeffrey', 1)");
            dp.ExecCommand(
                "INSERT INTO Cust VALUES (999, 'Darkthread', 1)");
        }
        tx.Complete();
    }
}
 
static void testDeadlock()
{
    for (int i = 0; i < 3; i++)
    {
        try
        {
            doUpdate();
            break;
        }
        catch (SqlException se)
        {
            if (
                se.Number == -2 //Lock Timeout
                || se.Number == 1205 //Deadlock
                )
            {
                //理論上要寫Log記下這個錯誤
                //這裡用Console.Write意思一下
                Console.WriteLine(se.Message);
                if (i == 2) //第三次不等了,丟Exception
                    throw new
                        ApplicationException("資料庫重試3次失敗!");
                else
                    //前兩次,先等待一小段時間再跑迴圈重試
                    Thread.Sleep(1000);
            }
            else
                throw;
        }
    }
}
Life-Amazing Chinese Translation

http://www.mydigitallife.info/2007/04/09/windows-vista-tcpipsys-connection-limit-patch-for-event-id-4226/

 在網站上看到這個,多國語言自動翻譯?? 酷~~~

按下咱們的國旗,接著正體中文映入眼簾...

顯然,在windowsvista微軟目前仍在執行和硬限制(硬編碼tcpip.sys)最高同時半開放式(不全),遊tcp連接企圖每秒該系統可以使像 Windows XP SP2在,以保護系統免受正在使用惡意代碼,如病毒和蠕蟲,擴散到未被感染的計算機,或發動分佈式拒絕服務攻擊(分佈式拒絕服務). 當配額用完的,在事件查看器,將有這樣一個條目:

嗯... 有點不順,但還猜得出意思,但再向下看,就開始有點不知所云了...

然而,沉重的p2p(點對點)應用等用戶utorrent,但bittorrent,bitcomet信息,azureus,廣播,帕特里克(驢網)等,或p2ptv如tvants,周俊,周俊,周俊,等,可能會遇到一些錯誤或慢,下載及上傳速度,

帕特里克? 驢網? 周俊,周俊,周俊? 要不是先讀過英文版,我會以為這是哈利波特中的橋段。向往下看,我終於忍不住笑出來!!

1. takeown/女性丙:\窗戶\system32\和司機\tcpip.sys
2. cacls丙:\窗戶\system32\和司機\tcpip.sys/克的"用戶":六

說實在話,這也不全然是翻譯程式寫得好壞的問題,目前人工智慧離人腦處理語言的能力仍有相當的距離,要翻出順口的語句及正確識別其中的領域專業術語幾乎是不可能的,自動翻譯時候未到,大家還是乖乖學好語言吧! (不只學英文,這年頭,中文也愈來愈重要了)

想知道上面的咒語原文是啥嗎?

帕特里克 = eMule
驢網 = eDonkey network
周俊,周俊,周俊 = PPLive, PPStream, Sopcast
/女性丙: = /F c:
窗戶 = 當然就是windows囉
和司機 = drivers,"和"字應該是要"司機"要跟"窗戶"在一起而加的連字詞,等等,應該是司機"們"吧?

Posted 18 August 2007 05:24 PMJeffrey | no comments
Filed under:
【茶包射手專欄】Unicode UrlEncode Link續集

昨天看了電腦玩物介紹了FeedJIT,可以介紹最近十個到站網友從何處連來,由於挺好玩的,又很容易安裝,所以我就順手裝到我的Blog上(請看右方SideBar最下方)。

沒想到從此網頁就跳出了以下的BLOCKED SCRIPT
Line: 1 Error: Invalid argument.

用Visual Studio Debugger追到的結果是出在FeedJIT的Script,問題出在這一列:
if(/^(http:\/\/|\/)/.test(_c[i].href))

立刻用偵錯視窗檢查一下,原來是上回介紹IE7拒絕承認Unicode UrlEncode Link的Blog文章,編輯時有個示範連結被CS 2.1變成真的Link了: (我把http換成httq了,省得又被誤轉成Link)

?_c[i].outerHTML
"<A href="httq://myweb/MyApp/%u4E0A%u4E0B.htm">httq://myweb/MyApp/%u4E0A%u4E0B.htm</A>"

接著下面這個測試更有意思了:

?_c[i].href
Invalid argument

原來在IE7裡,若Link被判定有問題,連.href都會失效。

知道了問題所在,把前述的Unicode UrlEncode URL移除,問題就消失了。我還發了封Mail給FeedJIT,提醒他們的script要加上try會比較保險,如果有獲得善意回應(註),再跟大家報告。

註: 我是個雞婆的人,發現別人網站有Script Error之類的,都會寫信給網站上列出的WebMaster信箱,只是做過幾次都沒什麼下文。其中回報地瓜新聞在IE會有Script Error(大概他們只用Firefox吧!)沒人理我,還有一次抓到某個活動網站有SQL Injection漏洞,對方回覆說問了廠商,廠商說沒問題就當沒事,直到活動結束,漏洞都還留著,唉~~~

【茶包射手專欄】Process Monitor基本操作教學

有網友在問Process Monitor如何使用,我想了想,這位茶包一哥在本Blog出生入死破案無數,卻還真的沒正式介紹過它的操作使用方式。所以,Process Monitor的初級使用教學來了!

SysInternals的兩位天才被挖去微軟後的第一個代表作,就是將原本的File Monitor(FileMon)與Registry Monitor(RegMon)兩套工具,金剛合體成Process Monitor,這真是個叫人感動落淚的舉動呀~~~

以往在排除問題時,常常要同時留意File及Registry存取狀況,所以就要同時開FileMon跟RegMon,故意讓問題再發生,然後同時關閉FileMon及RegMon,開始比對二者的記錄: 找出FileMon讀取A檔的時點,對照到RegMon看當時讀了哪個Registry,在還沒有搞出雙螢幕之前,我還常得把RegMon的記錄檔Copy到Notebook上,一眼看PC,一眼看Notebook方便比對。對不起,我又開始碎碎唸了,這些吃蕃薯籤的回憶,還是留給中年人獨自品嚐好了。XD

總之,ProcMon把RegMon與FileMon的監控放在一起,實在是佛心來著!

要用ProcMon的第一步當然要先去下載,網址在這裡,免安裝,我都只解EXE檔出來放在桌面就開始幹活。

開啟後,你會看到如上圖的畫面,通常我都只用到Toolbar的那一排按鈕就玩得不亦樂乎。我用顏色標出來幾個重要功能,說明如下:

1 開啟/停止記錄事件: 打X時表示現在停止捕捉事件

2.自動下捲: 由於監聽過程中,清單會不斷增長,你可以選擇ProcMon永遠顯示清單最下方的最新記錄。不過清單通常長得很快,會捲到你眼花。

3.清除目前清單中的記錄

4.設定Filter: 超重要! ProcMon是廢鐵或是寶劍全看你會不會設Filter,後面再做詳細介紹

5.指定桌面程式: 這個小瞄準器在SPY++裡很有名。如果你今天想要觀察某個桌面程式讀了哪些Registry、寫了哪幾個File,將小瞄準器拖拉到那個程式的UI上,ProcMon就會在Filter中加入限定該程式的條件(指定Process ID)

6.搜尋: 在現有的記錄中找尋特定文字

7.跳至Registry/File: 粉方便的功能! 在記錄中會看到某些Registry或File的名稱,點選那一列記錄後按下去,若是Registry記錄就會開Registry Editor停在該Registry Key上,若是File就會開啟FileMonitor停在該檔案的所在目錄上。在記錄上按右鍵也有個Jump To,效果相同。

8, 9, 10: 用來指定你要監聽的範圍,分別是Registry、File及Process活動,如果你只關心File存取,就只開啟File,真正的線索才不會被埋藏在一大堆沒用的Registry記錄中。

好了,接著來看ProcMon操作的精華所在,設定Filter!!

每一則Filter條件分為三個部分,第一部分是欄位,每一筆記錄有很多欄位,你可以限定某個欄位必須符合某個條件的事件才要"顯示",第二部分可指定要等於、包含等運算子,第三部分則是特定的字串值,最後要指定這個條件要包含進來還是排除掉。

注意到沒有,我剛才說Filter指的是"顯示"條件,而不是"捕捉"條件哦! 第一張圖的Status Bar中有個Showing 11,894 of 39,380,意思是ProcMon保留了四萬筆記錄,依現在的Filter條件只Show其中的30%,可以事後再修改條件,篩選不同的記錄來看。這又是一個本著佛心的新設計,過去使用FileMon/RegMon時常發生因條件太嚴沒抓到關鍵事件,只好改條件再來一次的狀況,現在Filter可以事後再Tune,節省了很多重頭來過的時間。

不過修改Filter的操作有點奇特,在下方清單點兩下,該條件會從清單中移除,移到上方,修改後要按Add把它加回清單,如果你改完直接按OK,條件就消失了,剛開始用要花點時間習慣。

用個實例來說,如果我想在XP/2003/Vista下觀察IIS的活動,可以設定以下的Filter:

Process Name is 'w3wp.exe'  這樣子ProcMon會抓到所有w3wp.exe對File及Registry的存取,若你的IIS有多個Application Pool,則會有多個PID不同的w3wp.exe,你可以試著再找到關注對象的Process ID,進一步縮小範圍。

 

按下閞始捕捉後,會得到如上圖的一大串記錄,清單中Operation是RegOpenKey、RegCloseKey、RegQueryValue的是Registry記錄,CreateFile、CloseFile、ReadFile等則是File存取記錄。在每則記錄上按右鍵還有好幾個貼心的功能,你可以用Exclude/Include加入與這筆記錄相關的Filter條件後立即生效。這樣我們可以先設較寬的Filter組合,在檢視結果的同時再一一排除無關者,迅速縮小範圍。Property則可看到該筆記錄的全部細節,例如: 發生Access Denied時,甚至還可以看到Impersonate的情形。

上圖中沒顯示出來,但Path後方還有個重要欄位叫Result,就是這個動作的執行結果,NOT FOUND/ACCESS DENIED之類的,通常是值得我們關注的焦點。

今天的Process Monitor基本使用課程就講到這裡,下課!!

TIPS-Excute EXE And Get Its Output From .NET

如果大家跟我一樣,常整合外部程式搞一些有的沒的,那一定可以用到這個函數。

它最常見的情境是整合一些好用的命令列工具(通常是用來查詢資訊),把它辛苦執行的結果佔為已有。例如: netstat -oa可以列出機器的網路連線狀況。如果我們希望要在.NET程式中提供這類資訊,要怎麼寫?

我們當然可以設法想辦法四處張羅Library、Windows API、WMI... 在程式中實作出類似的效果。

另一種鋸箭式的思考是"撿現成"!! 由我們的程式呼叫netstat.exe, 再去解讀它的輸出結果。其實,這種Pipeline的觀念,本來就是UNIX或PowerShell裡整合不同程式的慣用手法,大家也不必有什麼罪惡感。唯一要考量的是因為它會另起一個Process,耗用資源較多,對效能也稍有減損,不適合用在Web之類效能敏感的應用。

//執行外部程式並將執行結果以字串方式傳回
public string Shell(string exeFile, string argument)
{
    Process pShell = new Process();
    pShell.StartInfo.FileName = exeFile;
    pShell.StartInfo.Arguments = argument;
    //必須要設定以下兩個屬性才可將輸出結果導向
    pShell.StartInfo.UseShellExecute = false;
    pShell.StartInfo.RedirectStandardOutput = true;
    //不顯示任何視窗
    pShell.StartInfo.CreateNoWindow = true;
    //開始執行
    pShell.Start();
    pShell.WaitForExit();
    //將StdOUT的結果轉為字串, 其中StandardOutput屬性類別為StreamReader
    return pShell.StandardOutput.ReadToEnd();
}

以下是一個超簡單的應用範例,呼叫Ping.exe並解析結果看IP是否活著:

bool bAlive = (Shell("ping.exe", "-n 1 192.168.1.254").IndexOf("Reply")>-1);

Posted 17 August 2007 03:20 PMJeffrey | no comments
Filed under: , ,
【茶包射手專欄】IE Developer Toolbar破案奇錄

接獲通報,Sharepoint Portal的首頁,原本在IE6上看是藍底白字的MenuBar,在IE7上看到的是白底白字。

這回破案的主角不是茶包一哥Process Monitor了,而是IE Developer Toolbar!!

利用Find/Find By Click的功能找到MenuBar的DOM處,再用下圖的好功能一舉追出它的CSS套用狀況。

在IE7中看到以下的異象:

-: #75A3DF... 這是啥? (咳! 不准想歪)

跟IE6比對的結果,應該是BACKGROUD-COLOR : #75A3DF才對。

由於已知是core.css,追到該檔案,發現.linebg Style誤打了一個Dash(-)在左大括號後方,看來IE6會忽略這個誤打的"-",但IE7卻誤認"-"是Property Name,造成了我們看到的結果。

.linebg
{-
background-color:#75A3DF;
}

這次只花了20分鐘破案,但如果沒有IE Developer Toolbar,得花多少時間找出多出的這一根? 我不敢想像。

TOOL-Create Your Own AJAX-Style Waiting Animation

  

上面這種轉轉轉跟著AJAX一起紅了起來,陪許多User渡過漫長的"非同步傳輸"等待期間。

我的Window Form Project裡加了用Multithread方式跟Server要資料的功能,所以也想找一個來陪伴可憐的User,結果找到這個不錯的網站: http://ajaxload.info/

可以指定樣式、背景色、前景色做出各式"AJAX Style"的等待動畫GIF,直接下載回家,COOL~~~

TIPS-Uncachable ASP.NET Page

遙想ASP時代,如果要避免ASP網頁被Cache住,每次瀏覽都要重新讀取,我們會用以下的寫法:

Response.Expires = -1

所以在ASPX中,我也用同樣的寫法來強制每次都重新執行。沒想到,網頁還是被Cache住了!
使用Fiddler檢查,發現就Header來看,網頁是過期了沒錯,不過回上一頁時,IE還是直接顯示Cache中的版本,沒有更新... orz

Google了一下,現在大家比較常用的做法是在Header中加入"no-cache",不過ASPX提供另一個簡便的函數:

Response.Cache.SetCacheability(HttpCacheability.NoCache);

如此,Header的Cache-Control, Pragma, Expires一次設足,就可以確保網頁內容不被Cache住了。

PS: 經驗中,no-cache的招數在Modal Dialog中還是可能失效,建議URL上加亂數比較保險。

【茶包射手專欄】使用ProcMon五分鐘內破案的經典案例

Could not load file or assembly 'System.EnterpriseServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. Access is denied.

小組裡有台"鬧鬼"(註)的測試機器,老愛出些稀奇古怪的錯誤。今天執行某支ASPX時,發生以上錯誤...

一般人遇到這種狀況,除了重灌.NET Framework、重灌IIS、重灌Windows、去行天宮拜拜跟改行不寫程式之外,多半就只能束手無策。不過如果有Process Monitor在手,情況就不一樣了。

遇到Access Denied型的Error的,我的反射動作就是開啟Process Monitor;由於這個錯誤訊息很精確地指出無法存取的檔案是System.EnterpriseServices.dll,因此加個Path Contains "System.EnterpriseServices"的Filter,再瀏覽一次有問題的URL,立即就找到Access Denied的證據。

利用Jump To直接跳至GAC下的問題Folder,檢查一下權限,果然! 不知怎麼地,該目錄只剩下SYSTEM跟Administrators有權讀取,難怪用NETWORK SERVICE執行的w3wp.exe會吃閉門羹。參考其他類似目錄,補上權限,問題就消失了! 前後只花了不到五分鐘。

講到SystemInternals的這些好工具,306期iTHome的封面故事剛好就以它為主題,而兩位MVP(賴榮樞鄭子璉)與我也分享了自己的使用心得(咳... 還有照片哦,要簽名的人請帶週刊私下找我,目前沒有辦簽書會的計劃),有興趣的人可以去找來翻翻,。

====== 我是分隔線 ======

註: 所謂"鬧鬼"有兩種解釋: 一是指機器上常出現無法理解的怪現象,讓人直呼見"鬼"了;第二種是有程式麻瓜、電腦白目在搞"鬼",進行各種不可思議的系統修改與設定,任誰都猜不出問題會出在這種地方。

更多文章 下一頁 »

搜尋

Go

<August 2007>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

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

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication