October 2007 - Posts

Coding Smarter Tips 1 - String

身為程式老鳥,程式寫多了,總會發展出自己處理某些邏輯的一套慣用方法,有些演算法觀念甚至還跨語言: 在VBScript時代想出來的演算法,轉換成C#後,一樣在.NET上虎虎生風。

觸類旁通、得心應手的快意,其實也讓老鳥們喪失了一部份探索新語言、學習新工具的樂趣 --- 其實新語言、新工具已經提供了更快速簡潔的處理方法,當你總能用舊方法打發問題,無形中也忽略進化到用更少程式碼完成相同工作的機會。

以我自己的經驗來說,近年來已少有耐心好好地翻完一本書,新語言、新工具的學習總依賴Google,要用了才臨時去找。沒有靜下心來全面了解熟悉語言工具的後果,即使有能力寫Code解決各式各樣的難題,卻往往不是最更效率、更嚴謹的解題方法。於是我常常在Trace別人的Code時,或是經由旁人的提醒,才知道自己用了幾年的方法,其實是個愚公移山的笨方法,根本可以用一行打死。(一個典型的例子在這裡)

【Coding Smarter系列】搜集了我陸續發現處理常用作業的"最佳".NET實作方法跟大家分享。也歡迎大家來踢館,讓我學到更棒的方法!!

   1:  //需求1: 將CheckBoxList中選取的項目Value用分號串起來
   2:   
   3:  //老方法,跑迴圈,第一筆資料不加;
   4:  StringBuilder sb = new StringBuilder();
   5:  foreach (ListItem item in CheckBoxList1.Items)
   6:  {
   7:      if (!item.Selected) continue;
   8:      if (sb.Length > 0) sb.Append(";");
   9:      sb.Append(item.Value);
  10:  }
  11:  Response.Write(sb.ToString());
  12:   
  13:  //改良法1,不花功夫決定加不加分號,最後再移除多餘的分號
  14:  sb = new StringBuilder();
  15:  foreach (ListItem item in CheckBoxList1.Items)
  16:      if (item.Selected)
  17:          sb.AppendFormat("{0};", item.Value);
  18:  //直接用TrimEnd移掉多餘的分號
  19:  Response.Write(sb.ToString().TrimEnd(';'));
  20:   
  21:  //改良法2,利用Join
  22:  List<string> lst = new List<string>();
  23:  foreach (ListItem item in CheckBoxList1.Items)
  24:      if (item.Selected) lst.Add(item.Value);
  25:  //string.Join會將陣列組裝成字串
  26:  Response.Write(string.Join(";", lst.ToArray()));
  27:   
  28:  //需求2 將數字補零至四位
  29:  int i = 5;
  30:   
  31:  //VBScript常見做法
  32:  string s = "0000" + i.ToString();
  33:  //VB.NET還可用RIGHT$
  34:  Response.Write(s.Substring(s.Length - 4));
  35:   
  36:  //Format會簡單一些
  37:  s = string.Format("{0:0000}", i);
  38:   
  39:  //PadLeft也佷酷,還可以用在非數字上
  40:  s = i.ToString().PadLeft(4, '0'); 
Update 2007-11-13 這裡也可以寫成i.ToString("0000"); 謝謝evakey補充

最後再補充幾個好用的String Member:

  • StartsWith、EndsWith: 比對字串對尾,支援不分大小寫比對。 (Update 2007-11-13 少了s, 謝謝Leem指正)
  • Insert: 插入字串,不用再s.Substsring(0, i) + "AAA" + s.Substring(i)了
  • IndexOf: 不只是VBScript中的Instr而已,支援不分大小寫比對。
Google AdSense,好樣的!

酪梨壽司是我非常崇拜的網路作家,她的文筆犀利流暢,許多傳神的比喻常讓我會心一笑(斷氣的海參? 妙呀!),或許因為幼時長期沈浸於文學作品中,她的文章用字遣詞總多了幾分當下"國文式微世代"所沒有的五彩繽紛與饒富典故。但最讓我折服的是,你永遠可以從她的詼諧中感受到背後的真情流露,這應該是只會跟只敢寫論說文的我,此生都無法觸及的境界吧!

放眼部落格界,雄霸一方的多半是吃喝食記、旅遊記趣,再不就是靠漫畫或網路小說聚集人氣,像壽司靠生活文章走紅,也算是另一種典型吧!!  我印象很深的是,壽司在今年初單靠著Google AdSense在一個月內海削數萬元,讓人不免發起"有為者亦若是"的短暫豪情壯志... (豪情多半會在幾分鐘後因回歸現實而消失殆盡)

今天中午吃便當,配著壽司的出差狂想曲下飯,明明是講外遇,但文裡甜蜜洋溢,閃光閃到我快睜不開眼睛,瞎子都看得出這是不折不扣的炫耀文... 讀到文末,曾經讓壽司發過小財的Google AdSense天外飛來一筆絕妙廣告,實在是太點題了!! 我笑了~~~

Windows Form AutoScaling

寫Windows Form的人應該都會面對這類問題。

一直跑得好好的程式傳來噩耗,在某某大官的機器上圖歪字斜,最要命的是老爺子找不到送出鈕可按,正暴怒中。戒慎恐懼地前往"命案現場"(沒處理好的話,馬上就是了)查看,載著厚重老花眼的層峰長官,怒指著LCD控訴你寫的什麼鬼表單,居然沒有送出鈕。定神一看,媽呀! 設成800X600還加大字型(120DPI),原本精巧可愛、手帕大小的表單,現在大如床單,一個個國字猶如魚丸,按此比例推算,原本在右方的送出鈕現在應該位於隔壁祕書Partition隔板的分機表上...

Windows彈性化的桌面解析度及大小字型設計方便了許多髮蒼蒼視茫茫的"資深"使用者(相信很快我也會用到),但這顯然是許多在慣用高解析度的開發者較難想像的情境。雖然我們可以透過基本解析度要求的方式排除部分差異太大的作業環境,但使用大字型是一些眼力不佳使用者不得不的選擇。幸好,.NET程式很貼心地提供了自動縮放的功能,在.NET 1.1可以設定Form.AutoScale,.NET 2.0則有Form.AutoScaleMode更進一步可以選擇跟著Font大小或螢幕DPI大小調整Form的大小(例如: 希望表單佔螢幕一定的比例)。

底下是一個用.NET 1.1寫的簡單範例:

其中(1)是在我1280x1024+96DPI Font本機桌面的顯示,(2)是AutoScale=false在1024x768+120DPI Font桌面的顯示,字變大了,但表單寬度沒變大(但Form Title有變高),所以右方的"高度"兩個字就看不到了。 (3)是AutoScale=true(預設值)的情形,可以看到表單隨著字型變寬也變高,文字可以完整展現。

但問題來了,並不是所有的配置元素都可以等比例放大(例如: 圖檔),或是放大後有可能超出原本預估的螢幕寬度,於是畫面配置錯亂,有些按鈕則飛到九天之外。要解決這個困擾,我想到的幾種解決辦法是:
1) 善用Panel等Container的Scroller功能,允許使用者捲動可視範圍玩一下尋寶遊戲。(操作起來會很累)
2) 針對不同解析度設計多組版型。(使用者很爽,開發者很累)
3) 將字型大小設為固定的Pixel單位(預設為Point),則字的大小將不隨使用者桌面的DPI而有所變化。(使用者可能抱怨字型過小)

每個解決辦法都有其缺點,就視不同的情境運用吧!

另外,今天發現VS.NET 2003有個Bug,使用96DPI環境設計的專案,在另一台120DPI的機器上以VS.NET 2003開啟時,PictureBox等物件會被偷改尺寸加以放大,這個雞婆的舉動糟透了。要避免此一問題,可以將Form.AutoScale先設為false。參考資料如後: http://www.dotnet247.com/247reference/msgs/37/186063.aspx

KB-UTF8Encoding And BOM
static void TestXMLWriter()
{
    MemoryStream ms = new MemoryStream();
    XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
    xtw.Formatting = Formatting.Indented;
    XmlDocument xd = new XmlDocument();
    xd.LoadXml("<Group><User>Jeffrey</User></Group>");
    xd.Save(xtw);
    xtw.Flush();
    xtw.Close();
    string xml = Encoding.UTF8.GetString(ms.ToArray());
    Console.WriteLine(xml);
    xd.LoadXml(xml);
}

XmlTextWriter設為Fomatting.Indented時,可以把XML整成美美的縮排格式,於是我寫了以上的Code。但是這段程式有點問題,明明是XmlTextWriter輸出的Byte Array轉成字串後,再被另一個XmlDocument.LoadXml()卻會發生Data at the root level is invalid. Line 1, Position 1.的錯誤!

問題出在BOM!! Byte Order Mark,相信有很多人在使用文字編輯軟體都有發現Save UTF-8 with BOM這類的選項,BOM是加在文字檔前的幾個位元,可以協助應用程式識別文字的儲存格式(多用於Windows,許多被這幾個位元搞暈頭的開發者視之為微軟的餘毒),這裡有篇好文章

Byte order mark Description
EF BB BF UTF-8
FF FE UTF-16, little endian
FE FF UTF-16, big endian
FF FE 00 00 UTF-32, little endian
00 00 FE FF UTF-32, big-endian

先前的程式寫法,XmlTextWriter在寫入MemoryStream時,預設就會加上BOM。若我們將Byte Array寫入檔案,再用StreamReader或XmlDocument.Load讀取,BOM被用來識別編碼格式後將被丟棄不出現在內容字串中;當我們直接用Encoding.GetString轉成字串時,BOM則會被帶入,造成LoadXml()解析錯誤,雖可以設法Trim掉,但我覺得更好的方法是利用UTF8Encoding建構式所支援的encoderShouldEmitUTF8Identifier參數,設為false,輸出結果即不會加註BOM。因此程式要改成:

XmlTextWriter xtw = new XmlTextWriter(ms, new System.Text.UTF8Encoding(false));

That's all, folks.

部落格十萬人次紀念

上週看網站計數次站上99,000,依目前週一到週五每天600-700次的數字計算,大概就有預感在11月前可以破十萬人次,今早MSN標題改成"部落格十萬人次倒數中..."後,本想留意一下,特別去拍數字停在100K的歷史畫面,結果一鑽進Code裡便寒盡不知年,直到前同事MSN敲我,說他看我的Counter 99996,再Refresh就10004了,哇... 錯過了~~~

其實還好,目前的StateCounter計數器是去年4月才裝的,當時平台還在Blogger上,移到Community Server後則繼續延用至今。所以計數器不是從Blog一開始就有的,加上StatCounter每次IE Refresh就會加1,並不算精準。但另一方面,我的RSS採取的是全文揭露方式,訂戶不用到網站就可以讀取全文,實際點閱數字也可能稍微被低估。由此來看,十萬這個數字的實質意義並不大,況且AdSense、StatCounter、訂閱數都不是我寫Blog追求的目標,撫慰好為人師的劣根性才是背後最可怕的陰謀,哈!!

在十萬人次這個小小的里程碑,謝謝許多曾在網站上與我互動的網友,從大家的問題上學到不少,許多人也不吝跟我分享自己的心得,讓我知道更多,甚至不時有路過的高人,隨便露個兩手就讓我瞠目結舌,提醒我要更謙卑要更努力(有為的中年人不好當呀!)... 這些都是當初開始寫Blog所沒想過的事,而我也算在Web 2.0的漫天熱潮中沒有缺席。Anyway,大家以後有空要常來哦!

 

TIPS-Calculating Percentage In SQL Query

有一個資料表,內有四筆資料,數量分別是2, 3, 5, 10,我希望用SQL查出如下包含百分比10%,15%, 25%, 50%的結果:

ID     AMT     PERC   
-----  ------  -------
1      2       10%    
2      3       15%    
3      5       25%    
4      10      50%
   

同事出了這個考題給我,算是讓我學會SUM() OVER (PARTITION BY ...)的用法。以上問題的解法如下:

--FOR ORACLE
SELECT ID, AMT, 
AMT * 100 / SUM(AMT) OVER (PARTITION BY NULL) || '%' 
AS PERC
FROM JEFF
 
--FOR SQL Server
SELECT ID, AMT, 
CONVERT(VARCHAR(3), 
            AMT * 100 / SUM(AMT) OVER (PARTITION BY NULL)
        ) + '%'
AS PERC
FROM JEFF

UPDATE @ 2007-10-27
SUM(AMT) OVER (PARTITION BY NULL) 寫成 SUM(AMT) OVER () 即可算全部的總和

Artile-Automatic Web Testing, With IEUnit

 

已經上線運作的網站系統,使用者又提出會動搖國本的核心功能修改需求,此時你會?

1) 警告使用者修改後可能導致家破人亡,然後立即裝忙忘記使用者曾說過什麼?
2) 硬著頭皮改完,苦著一張臉花十八小時把所有相關功能重新測過一次
3) 修改程式後即刻上線,將使用者編制為”虛擬測試團隊”,等著蒐集”虛擬測試員”回報的Bug

測試工作很煩人卻很重要,尤其理論上系統只要經過修改,就應該再做一次完整的系統測試,避免修掉一個Bug又冒出兩個Bug的鳥事。但將所有的網站功能操作做完一輪可能得耗上數小時,誰能有此等耐性在每次修改後都演一次鐵杵磨成繡花針的悲情戲? (如果真有人樂此不疲,建議該去醫院精神科掛個號,檢查一下是否罹患了強迫性精神官能症?)

比較好的做法是將這些測試程序自動化,把枯燥的工作丟給不會喊累不會嫌煩的機器人,避免自己陷入手工測試的無間地獄,把時間拿來做更有意義的事。

看過好多人都有驚人的耐性不厭其煩地一測在測,沒有耐心的我自嘆弗如之餘,只能去找來自動測試的工具—IEUnit(目前還有Selenium等其他選擇,但我IEUnit已經上手,各功能也都齊備,就沒想要換),一開始要投入很多時間熟悉工具,撰寫Test Script,但之後就可以翹著二郎腿用一根手指頭搞定系統測試,算是先苦後甘。

關於IEUnit的介紹,以下是我早先發表在RUN!PC雜誌的文章,給大家參考。

文章下載

【黑暗信箱】RegEx應用的簡單探討

網友William提了一個有意思的問題,他想要分析出程式碼中的各Class, Method, Loop等以{ }夾成的區塊,是否可以用RegEx來達成?

舉例來說,程式碼

main()
{
  int count=0;
  printf ("hello world");
  for (i=0; i<10; i++)
  {
      count++;
  }
}
fun1(int a)
{ return a+1; }
fun2()
{
    doSomething();
}

希望能分解成三個字串"main() {.... }"、"fun1(int a) {...}"跟"fun2() {...}"

我的看法是,以RegEx的文字解析的靈活度,要做出基本的雛型並不難,但如果要做到100%涵蓋所有可能出現的樣式,就得耗費相當可觀的功夫。

如果只以將main, fun1, fun2三個Member抓出來為目標,原則上用一個RegEx Pattern "(?ims)\S+?[(].*?[)]\s*{.*?}"就可以打死,如下: (我借用了CodeProject上的.NET RegText Test來示範)

是不是很簡單呀? 不過Demo多半只會Show較犀利的一面,這個寫法在遇到某些特殊組合時破功。例如: 我如果將"for (i=0..."改成"if (true) { } for(i=0;...",for (i=0馬上被誤認成method,我們可以再限制( )中間不准出現=,Pattern改成"(?ims)\S+?[(][^=]*?[)]\s*{.*?}",就可以解決誤認for的問題,但是while(someBoolean)就不會出現等號,於是我們又要再想如何避開。

這就是我平時應用RegEx處理問題的步驟,先設計出基本Pattern->試跑資料->發現例外->只對例外修改Pattern->跑更多資料->又發現例外->再修改Pattern... 有時候,某些例外實在太難處理了,我還會預先變動文字排列或用Replace的技巧先把某些文字取代掉,避免干擾RegEx的比對,等都處理完了再將它們還原。

以上就是我應用RegEx的一些心得,供大家參考。

KB-From Form1 to form1

古早之前寫了一個做表單欄位檢核的JS檔,裡面的第一項工作是先取得Form物件,指定給區域變數:

var defaultFormName = "Form1";
var theForm = document.forms[defaultFormName];

因為VS.NET 2003所建立的ASPX,裡面只會有一個HTML Form,名稱一律預設為Form1,在大部分的情形下,這段Code跟ASPX結合得很好。

後來手上的專案開發多半是將原有ASP.NET 1.1直接升級成ASP.NET 2.0繼續發展,用起來也一直相安無事,直到有同事建了ASP.NET 2.0的新專案,引用這個JS時卻冒出了找不到物件的Error。細究之下,發現了一個天大的祕密...

VS.NET 2003 新增ASPX的表單名稱為Form1
VS 2005新增ASPX的表單名稱為form1

雖然這個不知意義為何的改革讓人很無奈,幸好改起來不算麻煩,如下:

var defaultFormName = "form1";
if (!document.forms[defaultFormName]) defaultFormName="Form1";
var theForm = document.forms[defaultFormName];

PS: form1改在Form1前面是因應未來form1出現的比例會愈來愈高。

Update @ 2007-10-26
剛才又發現一個祕密,document.all("form1")不分大小寫,不論Form1, form1都可以被找到(注意: all()是IE Only),而document.forms[]則遵循Javascript的傳統,會區分大小寫。

XML Notepad Improvement

XML Notepad is good but it just doesn't fit my need...

I wrote a workflow system and it stores the form context and flow context in XML format.  While trouble-shooting, I often need to query context data and analyze the XML string.  When I use SQL Server Management Studio or my customize debugger to fetch the context data, what I get is a XML string.  But XML Notepad only accepts XML files, so I have to press ctrl-C to copy the string, open notepad, paste the XML string, save it as a file and open it  from XMLNotepad, quite a long road. 

I have seen another tool, XMLSpy, it can accept XML string from clipboard and parse it immediately.  Yeah, that's what I need, but XMLSpy is quite expensive.  In the other way, XMLSpy is too rich for me, what I really need is a XML Notepad which can import XML string from clipboard directly.

Thanks God, XML Notepad is open source.  I downloaded the source code from CodePlex and added two menu items, wrote a couple of  code, my dream XML Notepad is coming...

private void toolStripMenuItem13_Click(object sender, EventArgs e)
{
    this.xmlTreeView1.CancelEdit();
    //Save the text form clipboard as file
    string rawXml = Clipboard.GetText();
    //Validate the XML data
    XmlDocument xd = new XmlDocument();
    try
    {
        //Remove <?xml> declaration
        if (rawXml.StartsWith("<?xml version"))
            rawXml =
                System.Text.RegularExpressions.Regex.Replace(
                rawXml, "[<][?]xml.+?[?]>", "");
        if (!rawXml.StartsWith("<"))
            rawXml = rawXml.Substring(rawXml.IndexOf("<"));
        //Use LoadXml to test if the XML is valid
        xd.LoadXml(rawXml);
        //Save it as a temp file
        string fileName = System.IO.Path.GetTempFileName() + ".xml";
        File.WriteAllText(fileName, Clipboard.GetText());
        //Call internal method to open the file
        InternalOpen(fileName);
    }
    catch (Exception ex)
    {
        MessageBox.Show("Invliad XML document.");
    }
}
 
private void toolStripMenuItem14_Click(object sender, EventArgs e)
{
    //Commit changes
    this.xmlTreeView1.Commit();
    //Prepare the XmlTextWriter
    MemoryStream ms = new MemoryStream();
    XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
    xtw.Formatting = Formatting.Indented;
    //Dump XML to the XmlTextWriter
    this.model.Document.Save(xtw);
    xtw.Flush();
    xtw.Close();
    //Send it to the clipboard
    Clipboard.SetText(Encoding.UTF8.GetString(ms.ToArray()));
}

 

KB-Can't Create Scripting.Dictionary

Scripting.Dictionary源於Microsoft Scripting Runtime(\Windows\System32\scrrun.dll),是讓我有機會在VB6, VBScript使用Hashtable的救星。

我一直以為Scripting Runtime是所有Windows內建且必備的核心元件,今天才發現並不盡然...

寫了個VBA,在User的機器上一直出現ActiveX Component can't create object.(ActiveX元件無法產生物件)的錯誤訊息,開始我以為是裡面用到的MSXML2.XMLHttp30版本不存在,後來才發現其實錯在建立Scripting.Dictionary時,仔細檢查了一下專案參照,scrrun.dll好好地躺在Windows\System32目錄下,若非是Scripting Host的安裝損壞了嗎??

用regedit搜尋,沒看到Scripting.Dictionary的元件註冊機碼,已有重裝Scripting Host的心理準備。暫且先Goggle了一下,發現有人提到遇到Scripting.Dictionary或FileSystemObject建立失敗時,可以先跑一下regsvr32 scrrun.dll,試試也沒損失... 噹噹~~~ 註冊scrrun.dll後,功能就正常了。

【結論】大家如果遇到Scripting.*家族的物件無法建立時,記得先試試regsvr32 scrrun.dll,如果還不行,就乖乖重裝Scripting Host吧!

參考文章

Self Test - Value Type vs Reference Type

一個小測驗,請用大腦編譯並執行以下的程式,試著回答Q1-Q7的結果為何?

這個測驗可以檢定你是否對.NET的Value Type與Reference Type已有正確認識。

struct MyStruc 
{
    public string Name;
    public string Data;
    public MyStruc(string name, string data)
    {
        Name = name;
        Data = data;
    }
    public override string ToString()
    {
        return Name + ":" + Data;
    }
}
 
class MyClass
{
    public string Name;
    public string Data;
    public MyClass(string name, string data)
    {
        Name = name;
        Data = data;
    }
    public override string ToString()
    {
        return Name + ":" + Data;
    }
}
 
 
static void Func1(MyClass c)
{
    c.Data = "F1";
}
 
static void Func2(MyClass c)
{
    MyClass c2 = new MyClass("Foo", "F2");
    c = c2;
}
 
static void Func3(ref MyClass c)
{
    c.Data = "F3";
}
 
static void Func4(ref MyClass c)
{
    MyClass c2 = new MyClass("Foo", "F4");
    c = c2;
}
 
 
static void Func5(MyStruc s)
{
    s.Data = "F5";
}
 
static void Func6(MyStruc s)
{
    MyStruc s2 = new MyStruc("Bar", "F6");
    s = s2;
}
 
static void Func7(ref MyStruc s)
{
    s.Data = "F7";
}
 
static void VarTest()
{
    MyClass c = new MyClass("Init", "Null");
    Func1(c);
    Console.WriteLine("Q1=" + c.ToString());
    Func2(c);
    Console.WriteLine("Q2=" + c.ToString());
    Func3(ref c);
    Console.WriteLine("Q3=" + c.ToString());
    Func4(ref c);
    Console.WriteLine("Q4=" + c.ToString());
    MyStruc s = new MyStruc("Init", "Null");
    Func5(s);
    Console.WriteLine("Q5=" + s.ToString());
    Func6(s);
    Console.WriteLine("Q6=" + s.ToString());
    Func7(ref s);
    Console.WriteLine("Q7=" + s.ToString());
    Console.Read();
}

比較容易搞混的地方Func1及Func3,Class是Reference Type,所以不管是以By Value或By Reference的方式將物件變數傳入函數中,函數中存取及變更的都是你傳入的物件本尊,而不是另外複製的複本。但Func2, Func4倒是可以看出By Reference造成傳入函數的變數c有複本及本尊的差別。Structure在.NET中是Value Type,當成參數傳入時,除非用ref宣告By Reference,否則傳入的都是分身。

正確答案:
Q1=Init:F1
Q2=Init:F1
Q3=Init:F3
Q4=Foo:F4
Q5=Init:Null
Q6=Init:Null
Q7=Init:F7

PS:  昨天在寫程式時,遇到了Q2的Scenario,忽然迷惑了一下,就寫了一小段Code來確認,索性稍加修改變成一個小測驗讓大家玩一玩。

【茶包射手專橺】Reporting Service圖表無法顯示

同事回報一個問題,在測試台檢視Reporting Service報表時,應該顯示長條圖、圓餅圖的地方出現一個大叉叉,同一程式在正式台則一切正常。

首先出場的工具是Fiddler,很快就抓到在GET圖檔的Request有以下錯誤:
ERROR: Throwing Microsoft.ReportingServices.Diagnostics.Utilities.StreamNotFoundException: The stream cannot be found. The stream identifier that is provided to an operation cannot be located in the report server database. ; (找不到資料流。報表伺服器資料庫中找不到提供給作業的資料流識別項。)
 Info: Microsoft.ReportingServices.Diagnostics.Utilities.StreamNotFoundException: The stream cannot be found. The stream identifier that is provided to an operation cannot be located in the report server database. (找不到資料流。報表伺服器資料庫中找不到提供給作業的資料流識別項。)

用rsStreamNotFound當關鍵字,我Google到一篇文章,說明這可能與Cookie有關。我仔細看了一下,有問題的網頁是用ASPX在其中包含Frame指向Reporting Service報表所在的httq://192.168.1.1/ReportServer?... URL。

依我多年吃餅乾的經驗,這種情境很符合3rd Party Cookie被禁用的條件,Check了一下IE的工具列,果然有個被禁止的眼睛Icon(參見這篇文件關於Cookie Filtering的說明)。點開後確認一個來自httq://192.168.1.1/ReportServer的Cookie被Block掉了,在正式台上,Reporting Service報表主機的URL用的是Machine-Name所以沒問題,這印證了先前找到那篇文章所說的Cookie Issue。

為了進一步驗證真的是Cookie問題,我將httq://192.168.1.1設為IE的被信任網站,報表中的圖表就可順利顯示,宣布破案。

解決方式有二: 1) 將Reporting Service Server的IP加為IE的信任站台(Trusted  Sites)解決Cookie被阻擋的問題,2) 連至Reporting Service的URL不要用IP,改用機器名稱(當然,要確保名稱解析是OK的),利用Local Intranet安全區域避開Cookie阻擋問題。我個人建議使用後者。

TIPS-VBScript Intellisense In VS 2005

即使.NET 3.5推出在即,VBScript仍是許多管理用Script的主力Language(將來可能會被Powershell所取代)。過去我都用NotePad、EmEditor、UltraEdit之類的純文字工具編輯,心想VBScript屬於Late Binding,ActiveX Object的屬性、方法都得自己輸入,頂多文字編輯工具能將指令用不同顏色顯示就偷笑了。

今天無意間用Visual Studio 2005開啟了一個VBS檔編輯,才發現這個了不起的功能。瞧! VS 2005可以解析CreateObject要建的物件型別,接著就提供起Intellisense呢! 酷~~~

TIPS-Log Deadlock Event For SQL 2005

之前介紹過如何用Profiler抓到Deadlock事件,在實務上,Deadlock的發生時機不是很容易掌握,而且多發生在尖峰時刻,一直開著Profiler將是挺沈重的系統負擔。因此,我認為以錯誤事件的態度面對Deadlock, 要求其在發生時留下Log是比較有效率掌握Deadlock相關情報(尤其是導致Deadlock的T-SQL指令)的做法。查了一下,SQL Server上可以利用DBCC TRACEON開啟與Deadlock相關的幾個Flag: 1204, 1205, 3605,如要長期開啟,則可以加入-T1205等啟動參數,詳細說明可以參考這篇官方KB[Update @ 2007/10/23] SQL Server 2005 是開 1204 與 1222才對,前述的KB 832524 是針對 SQL Server 2000 的。細節可參考 http://msdn2.microsoft.com/en-us/library/ms178104.aspx,謝謝網友默默指正。

傳統做法似乎要另外開SQLDiag工具蒐集Log,但我發現從SQL 2005的Log Viewer就可以找到發生Deadlock的SQL指令囉!

More Posts Next page »

Search

Go

<October 2007>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
 
RSS
【工商服務】


BlogLook Score and Rank

Syndication