June 2008 - 文章

【茶包射手專欄】愛亂跑的日期格式

有台VM測試台,最近老出狀況。

VM上有些ASP及ASP.NET程式寫得不夠嚴謹,將日期直接轉型成字串,此時輸出結果便要受到控制台國別設定(Control Panel/Regional and Language Option,正確翻譯為地區及語言選項,我習慣稱它為國別設定)裡的日期時間格式左右。

不知是否因為VM環境不夠力加上系統太過沈重(CPU跟RAM常在破表邊緣),每隔一陣子就會發生ASP/ASP.NET日期格式同時都跑掉的狀況(變成美式m/d/yyyy,該Windows 2003為英文版)。ASP.NET的部分可以用上回介紹過的技巧強制指定culture閃開問題,ASP的部分則比較棘手...

在測試台上的ASP程式會呼叫VB6 COM+產生資料,而日期轉換便發生在VB6 COM+中,因此其使用的日期格式應由COM+ Application所指定的識別身分決定,但檢查該身分的國別語系設定,在出問題時仍設定為台灣沒有跑掉。進一步發現,Restart COM+ Application後,日期格式就會恢復正常,但隔一陣子又會再跑掉。

我的推測是,或許因機器太忙或某些不明因素,導致COM+ Application在讀取識別身分Profile中日期格式時失敗,改用預設語系設定,但因為是英文版OS,因此得到m/d/yyyy的結果。

無法徹底確認問題就如我們所推測,但我想到了鋸箭之法--將預設的國別設定也改為台灣,如此即使沒能正確讀到識別身分的設定,也不致出錯。用以下的方法將台灣設為預設國別,問題從此不再發生。Case Closed!

TIPS-處理onClick事件中的特例

各位同學,我們今天要解的題目如下:

ASP.NET網頁中有一個控件產生的DataGrid,其在<TR>上放入了onclick事件,以達到點選該列的任何位置都會觸發特定事件,但如果其中有個<TD>裡希望在onclick時執行特定邏輯,而不要觸發原本<TR>上的onclick,要怎麼做?

面對以上的例子,低年級同學可能會想: 那就不要放onclick在TR上,每個TD上放一個onclick,不就可以任意控制? 這個構想不能說錯,但有點囉嗦。試想,如果一個TR裡有30個TD,豈不要寫29個onclickA加1個onclickB,更何況題目中的TR onclick是控件放的,怎麼做等於干擾了原本的設計。

比較有效率的方法,是讓指定的TD變成整個TR onclick事件的【特例】,這樣程式會比較簡潔。要做到所謂的事件邏輯中的特例,就不能不提到Event Bubbling的觀念,當某個容器元素(如<TR>)包著另一個子元素(如<TD>),使用者按下滑鼠,這兩個元素的onclick事件會被"先後"觸發,這個觀念在UI相關的程式開發中都有,中年級同學應該都有學過。參考資料

由於onclick事件的觸發順序會是先TD再TR,因此我們可以為TD指定另外的onclick事件,並在其中要求停止觸發後續的onclick事件。在IE中的寫法是window.event.cancelBubble = true;,Firefox中則可以用e.stopPropagation();

我寫成以下的例子,有興趣的同學可以實驗一下:

<html><body>
<table border="1">
<tr onclick="rowClick();">
<td>AA</td>
<td><input type="button" value="BB" onclick="btnClick()" /></td>
<td><span onclick="cellClick(event);">CC</span></td>
</tr>
</table>
<script type="text/javascript">
function rowClick() { alert("ROW!"); }
function cellClick(evt) { 
    alert("CELL!"); 
    if (window.event) //for IE
        window.event.cancelBubble = true;
    else //for Firefox
        evt.stopPropagation();
}
function btnClick() { alert("BUTTON!"); }
</script>
</body></html>
部落格30萬人次紀念

依照預測,本站的點閱人次今天應該就會突破30萬大關。(前陣子StatCounter主機所在的IDC失火,不然應該會在昨天)

今天特地開了StatCounter的統計數據網頁留意人數,不過忙著處理事情,一回頭就忘了這事。嘿,說有多巧的! 再想起觀察時,剛好是第300,001,我馬上點下300,002照相留念。

回頭查Log,查出踩到第30萬人次的幸運兒是來自高雄"某公營企業"的朋友,在15:59:01使用Windows XP + IE6達陣,雖然沒有獎品,在此還是要恭喜他一下。(謎之聲: 又沒獎品送人家,你在嗨什麼?)

 【成長歷程】

Posted 25 June 2008 07:27 PMJeffrey | 1 comment(s)
Filed under:
螳螂捕蟬

螳螂捕蟬”這句成語相信大家都聽過,但親眼看過的人應該屈指可數。很幸運地,我已經升級成後者囉~~~

週日走了一趟樟湖步道,順道重返鵝角格山。從樟湖步道途中右方叉路上行,大約幾百公尺就可以到達山頂(需要拉繩,相當喘的幾百公尺),交通尚稱方便。不過途中有一段築在斜坡上的窄路不及20公分寬,加上一段時有泉水流過路面的濕地(上回還在此遇上生平第一隻吸血鬼),以及近百公尺要拉繩而上的陡坡,路程並不算好走。即使常走貓空,這座山頭卻很少造訪(最主要還是穿短褲的勇腳再遇不測)。

氣喘噓噓到了山頂,看到久違的三角點,照例要留下黑暗註記一枚。山頂的展望很好,但天氣實在很糟,看過去的台北市中心白茫茫一片。

  

在山頂休息片刻,決定不原路折回,改繼續前行三玄宮。走沒多久,忽然小徑旁傳來清晰的蟬鳴,聽起來近在咫尺,但不像一般中氣十足響亮到刺耳的知了叫聲,而是叫兩三秒,停四五秒的短促蟬鳴,莫非有人需要來顆京都念慈庵枇杷潤喉糖保養喉嚨?

在樹葉間撥找了一陣子,總算看到...

一隻大螳螂用兩隻鐮刀板著一隻體型碩大黑蟬的雙翅,沈重的身驅拖著螳螂幾乎要呈倒吊狀,這就是傳說中的"螳螂捕蟬"嗎?

原來方才聽到的怪異蟬叫,其實是一聲聲的掙扎悲鳴。看過這般景象,之後再入耳的斷續蟬鳴,便不再新鮮有趣;聽起來略帶顫抖的蟬鳴,透露出無助驚恐,壓得人有點喘不過氣來。不過這就是大自然,人類無權置喙。我,選擇了靜靜旁觀...

回程經過樟山寺時,又再次看到一隻大冠鷲從附近的山頭起飛,正搏扶搖而上,跟上回的情況幾乎完全相同,但這回我拔搶的速度快一些,拍到比上回清楚的照片。

真是一趟國文陶養與生態教育兼顧的充實行程!

Posted 24 June 2008 07:50 AMJeffrey | 3 comment(s)
Filed under:
KB-Cache.Add vs Cache.Insert

被困住快半個小時,才發現問題在Cache.Add上。

先來個小測驗,以下這段Code,請問Test1, Test2的結果為何?

    protected void Page_Load(object sender, EventArgs e)
    {
        string key = "KEY";
        string str = "A";
        Cache.Add(key, str, null, 
            System.Web.Caching.Cache.NoAbsoluteExpiration, 
            new TimeSpan(0, 10, 0), CacheItemPriority.High, 
            null);
        str = "B";
        Cache.Add(key, str, null,
            System.Web.Caching.Cache.NoAbsoluteExpiration,
            new TimeSpan(0, 10, 0), CacheItemPriority.High,
            null);
        Response.Write("<li />Test1=" + Cache[key].ToString());
        str = "C";
        Cache.Insert(key, str, null,
            System.Web.Caching.Cache.NoAbsoluteExpiration,
            new TimeSpan(0, 10, 0), CacheItemPriority.High,
            null);
        str = "D";
        Cache.Insert(key, str, null,
            System.Web.Caching.Cache.NoAbsoluteExpiration,
            new TimeSpan(0, 10, 0), CacheItemPriority.High,
            null);
        Response.Write("<li />Test2=" + Cache[key].ToString());        
    }

答案: Test1=A, Test2=D

在Cache重複塞入Key已存在的項目,在.NET 1.1與.NET 2.0+裡的行為不同,依據文件的說法,在.NET 1.1中,Add會失敗,Insert則會取代。

... Second, their behavior is different if you call these methods and add an item to the Cache that is already stored there. The Insert method replaces the item, while the Add method fails. ...

從.NET 2.0起,Add重複Key值的項目,不會取代也不會觸發Exception。

... Additionally, if you use the Add method and an item with the same name already exists in the cache, the method will not replace the item and will not raise an exception.

另外,Cache[key]=value的寫法可以快速設定Cache項目(第二次設定會取代),但無法指定逾時、Dependency等設定。

Posted 23 June 2008 01:15 PMJeffrey | 4 comment(s)
Filed under: ,
TIPS-小心Eval潛藏XSS漏洞

.NET 3.5裡多了些新玩意,看過保哥的超完美組合:LinqDataSource + ListView + DataPager + jQuery及Rick Strahl的ListView and DataPager in ASP.NET 3.5兩篇介紹ListView的文章,ListView對前端有極佳主控權的特色深得我心,我打算逐步在未來的專案中用ListView取代DataGrid或GridView。

不過我有注意到大部分文章在介紹Templated Control時都省略了資安風險的提醒(也許是假設這是讀者的基本常識),擔心有些朋友看完這類Sample就直接拿來用在正式系統中,在此特地嘮叨兩句。

例如以下的例子,它示範如何用Eval(fileName)的寫法,將結果顯示在ItemTemplate中。

<%@ Page Language="C#" AutoEventWireup="true" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"><title>Eval XSS Test</title>
<script type="text/C#" runat="server">
protected void Page_Load(object sender, EventArgs e)
{
    DateTime d = DateTime.Today;
    var ds = new[]
    {
        new { SN=1, EntryDate = d.AddDays(-15), Name = "Jeffrey", Remark = "Verified"},
        new { SN=2, EntryDate = d.AddDays(-7), Name = "Linda", Remark = "NA"},
        new { SN=3, EntryDate = d.AddDays(-2), Name = "Sharon", Remark = ""}
    };
    ListView1.DataSource = ds;
    ListView1.DataBind();        
}
</script></head><body>
    <form id="form1" runat="server">
    <asp:ListView ID="ListView1" runat="server">
    <LayoutTemplate>
        <table border=1>
        <thead><tr><th>Sn</th><th>EntryDate</th><th>Name</th><th>Remark</th></tr></thead>
        <tbody runat="server" id="itemPlaceholder"></tbody>
        </table>
    </LayoutTemplate>
    <ItemTemplate>
        <tr><td><%#Eval("SN")%></td><td><%#Eval("EntryDate", "{0:yyyy/MM/dd}") %></td>
        <td><%#Eval("Name", "")%>
        </td><td><asp:Label ID="lblRemark" runat="server" Text='<%#Eval("Remark", "")%>'>
        </asp:Label></td>
        </tr>
    </ItemTemplate>
    </asp:ListView>
    </form>
</body></html>

註: Eval("Remark", "")的寫法可以防止資料為null時發生Exception,跟之前保哥提過的Convert.ToString()用意差不多,而Eval("EntryDate", "{0:yyyy/MM/dd}") 則示範了Eval的格式化功能。

以上的程式碼可以順利執行沒有問題,卻潛在XSS的風險。

在此例中,我們用自建匿名類別陣列的方式製作出DataSource,但實務上DataSource常是由資料庫查詢取得的資料,而資料來源又常來自於使用者(或駭客)的輸入,若輸入時未能確實檢核,或是遭人篡改(例如前陣子很熱門的游擊式的SQL Injection攻擊),就有可能夾帶XSS攻擊的內容。用以上的例子,我們來模擬資料有毒的狀況,如下:

    var ds = new[]    
    {        
        new { SN=1, EntryDate = d.AddDays(-15), Name = "Jeffrey", Remark = "Verified"},
        new { SN=2, EntryDate = d.AddDays(-7), Name = "Linda", Remark = "NA"},
        new { SN=3, EntryDate = d.AddDays(-2), Name = "Sharon", Remark = ""},
        new { SN=4, EntryDate = d, Name = "Hacker<script>alert('Hacked!');<" + "/script>", 
                Remark = "XSS<script>alert('XSS!!');<" + "/script>" }
     }; 

網頁閃出兩個Javascript alert,代表駭客已在你的網頁搶灘成功,可以開始為非作歹了。而且不管是直接插入欄位文字(如Name)或是設成Label.Text(如Remark),一樣都會中鏢。(順便提一下,Label1.Text = myDataRow["userInput"].ToString()這類的寫法也是不安全的)

要如何因應? 其實不難! 不可能或不該出現HTML Code的地方,記得加上HttpUtility.HtmlEncode轉換。除了防止XSS,萬一有使用者在內容中輸了</td>之類描述HTML Tag的文字,也不會產生干擾,讓你的HTML內容大亂。
(分享一個頗經典的例子,測試員在系統Bug資料庫的問題主旨欄位填寫了"Some.aspx有多餘的</td></tr></table>",結果整個Bug清單Table當場腰斬,Bug少一半,讓RD好高興!)

     <td><%#HttpUtility.HtmlEncode(Eval("Name", ""))%></td>
     <td><asp:Label ID="lblRemark" runat="server" Text='<%#HttpUtility.HtmlEncode(Eval("Remark", ""))%>'>
     </asp:Label></td>

小小動作,永保安康。各位勞苦功高的開發人員,不要忘了隨手做資安哦!

【延伸閱讀】ASP.NET防駭指南你的網站在裸奔嗎?游擊式的SQL Injection攻擊

IE8 Actvities on Firefox 3

Firefox 3正式版已從台北時間2008/06/18 01:00開放下載,官方準備用單日下載次數挑戰金氏世界記錄,頗富創意。

Firefox的新功能已有不少部落格介紹,這裡來講一點跟IE8有關的有趣延伸。之前介紹IE8 Beta 1時,有提過最吸引我注意的兩個新功能: Activities及WebSlicies。其中Activities可透過滑鼠右鍵直接整合網站服務,這個點子挺不賴的,因此很快就有人寫出了Actvities for Firefox的附加元件,在Firefox 3上運行時,連預覽功能都可以100%原味重現,Cool!

附帶一提,Activity架構單純,開發也十分容易,有網頁設計經驗的人只要看完官方的Whitepaper就可以輕鬆搞定。下個月的RUN!PC雜誌裡我有一篇文章簡單示範Activity的開發,有興趣的朋友屆時可以參考。

延伸閱讀: Mobile01 Firefox Extension仿IE8 Activities

Posted 18 June 2008 10:28 AMJeffrey | no comments
Filed under:
Visual Studio: 詭異的即時監看結果

同事反應給我的問題,程式裡有段寫法if (r["F"] == "Y")的判別結果很怪,Line by Line Debug時,r["F"]的內容是"Y"沒錯,用Command Window檢查或監看(r["F"] == "Y")的結果是true,但實際的流程卻跑到false的分支。

首先要聲明,r["F"] == "Y"的寫法是有問題的。Visual Studio.NET 2003會提出警告,指出不應該將object與string直接相比。但是有趣的地方在於,實際流程中的二者比對結果是不相等,但即時運算視窗檢測卻二者相等。

我本來怪罪這是VS.NET 2003的老Bug,於是寫了一小段程式做實驗,卻發現更好玩的狀況。下圖是在VS.NET 2003的測試結果,我使用Watch監看r["F"]=="Y"跟在程式中比對(r["Y"]=="Y")後存入Boolean的變數b,二者的結果都是true。與我同事程式中為false,監看為true的狀況不同。

同樣的程式搬到VS2008(後來再測試VS2005的結果與VS2008相同),結果大異其趣。監看r["F"]=="Y"為false, 程式中的比對結果則為true,跟同事程式中的結果剛好相反。

感覺上是Visual Studio在除錯模式下判定比對結果的邏輯與實際Runtime不同所致,但VS2003, VS2005, VS2008, 實際程式與測試Code的結果理不出頭緒。

我把用VS2008 Submit a Bug功能把這問題反應給MS,當天得到回覆說已將問題轉交RD研究。如果有進一步消息,再報給大家知。

Posted 16 June 2008 02:59 PMJeffrey | 5 comment(s)
Filed under:
嫌Mini C# Lab太陽春的人看這裡!!

如果你嫌Mini C# Lab不支援Intellisense、沒有語法提示、關鍵字顏色顯示有點兩光,那你一定要試試這個--Snippet Compiler

看到如此華麗的程式碼編輯畫面,當場就讓不少人流口水了吧?

有Intellisense,語法參數提示,自動縮排控制,大括弧Block可以展開收合,甚至也有#region,功能直逼Visual Studio!!

用華麗程度來評比,如果Snippet Compiler是一隻鮮嫩肥美的北京烤鴨,Mini C# Lab大概只能勉強算是餐前的一小碟泡菜或是辣椒小魚乾... (不過用泡菜就換來烤鴨,真是無比划算!!)

謝謝elleryq的推薦,這是個了不得的好工具!

PS: 神奇的程式碼編輯器控件來自這家廠商,可惜是要錢的,不然我也要讓Mini C# Lab華麗一下!

Posted 13 June 2008 09:34 PMJeffrey | 7 comment(s)
Filed under:
C# 3.0 極簡風 - Lambda Expression

Lambda Expression是C# 3.0的新特性之一,對我來說,它跟自動實作屬性一樣,明明已看過不少文章,卻還不太明白它怎麼來的跟想做什麼。(開始有點懷疑自己是否其實資質駑鈍,一路是靠勤能補拙才混到今天,難怪老覺得睡覺時間不夠)

花了點時間研究,算是比較理解Lambda Expression的優點,寫成以下的例子,希望有突顯出Lambda Expression語法的簡潔之處:

using System;
using System.Linq;
 
public class CSharpLab
{
    //宣告一個delegate, 自訂a, b二數運算的邏輯
    delegate int myLogic(int a, int b);
 
    public static void Test()
    {
        int x=3, y=5;
        //原本的標準delegate寫法, 要額外宣告一個Method
        calc(x, y,  new myLogic(addMethod));
        //省事一點的匿名寫法
        calc(x, y, delegate(int a, int b) { return a+b; });
        //再省下去,就來段黏巴達(Lambada)Lambda吧
        calc(x, y, (a,b)=>a+b);
        calc(x, y, (a,b)=>a-b);   
        calc(x, y, (a,b)=>a*b);
    }
    static void calc(int x, int y, myLogic cc) 
    {
        Console.WriteLine(cc(x, y));
    }
    static int addMethod(int a, int b) {
        return a+b;
    }
}
 
Posted 13 June 2008 10:00 AMJeffrey | 3 comment(s)
Filed under:
KB-ASP.NET 1.1發生DLL Access is denied錯誤

這是同事遇到的問題,長久以來,他的個人電腦對他呵護倍至,深怕他寫程式抓Bug太過勞累,每天會有十幾次不定期的強迫休息時間。前一秒鐘還跑得好好的ASP.NET網站,下一秒要用Visual Studio Debug時,便浮出以下的錯誤訊息,此時除了等待或重新開機外,IISRESET也無濟於事。依據經驗,等待時間長短不一,最長可能會持續五分鐘。

Server Error in '/DT' Application.

Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Access is denied: 'MyUtility'.

Source Error:

Line 196:			<add assembly="System.EnterpriseServices, ...
Line 197:			<add assembly="System.Web.Mobile, ...
Line 198:			<add assembly="*"/>
Line 199:		</assemblies>
Line 200:	</compilation>

Source File: c:\windows\microsoft.net\framework\v1.1.4322\Config\machine.config    Line: 198

Assembly Load Trace: The following information can be helpful to determine why the assembly 'MyUtility' could not be loaded.

=== Pre-bind state information ===
LOG: DisplayName = MyUtility
 (Partial)
LOG: Appbase = file:///c:/inetpub/wwwroot/DT
LOG: Initial PrivatePath = bin
Calling assembly : (Unknown).
===

LOG: Policy not being applied to reference at this time (private, custom,
partial, or location-based assembly bind).
LOG: Post-policy reference: MyUtility
LOG: Attempting download of new URL file:///c:/windows/microsoft.net/framework/
v1.1.4322/Temporary ASP.NET Files/fe/ffe28ec7/fa5d1b07/MyUtility.DLL.
LOG: Attempting download of new URL file:///c:/windows/microsoft.net/framework/
v1.1.4322/Temporary ASP.NET Files/fe/ffe28ec7/fa5d1b07/MyUtility/MyUtility.DLL.
LOG: Attempting download of new URL file:///c:/inetpub/wwwroot/DT/bin/MyUtility.DLL.
LOG: Policy not being applied to reference at this time (private, custom, partial,
 or location-based assembly bind).
LOG: Post-policy reference: MyUtility, Version=1.0.2636.34223, ...


Version Information: Microsoft .NET Framework Version:1.1.4322.2407; ASP.NET Version:1.1.4322.2407

由於訊息中出現Access is denied: 'MyUtility',原本期望用Process Monitor可以快速找出問題,沒想到連半個Access Denied的Log也沒看到。

重新出發,用錯誤訊息的關鍵字找到這篇微軟KB,原來是Indexing Service搞的鬼,在製作索引的過程中會鎖定Temporary ASP.NET目錄一到五分鐘(剛好與經驗中等待時間吻合),造成ASP.NET程式無法運作。解決方式是停用Indexing Service或將Temporary ASP.NET目錄排除在索引掃瞄範圍之外,今天停用服務後跑了一整天,同事再也沒藉口進行"非自願休息"了。

令人感動! 六面到位的魔術方塊耶

魔術方塊?

轉出六面的魔術方塊? 上次見到六面到位的魔術方塊是什麼時候的事? 應該是小學吧? 而且實際擁有六面正確的時間應該沒超過五分鐘,在公車上就迫不及待地轉亂玩將起來。從此之後,轉出兩面已是瞎貓碰上死秏子的極限,可憐的魔術方塊,再也不知顏色正確的滋味。再過了一段時間,身上甚至還出現惱羞成怒小鬼進行"皮膚移植"留下的痕跡...

前幾天,跟小朋友逛市場路過十元商店,花了25元買了一個轉起來像快解體的魔術方塊給女兒玩。女兒胡亂轉了幾下不得要領,就沒興趣了,倒是大人認真起來...

前些日子看到報紙報導基測滿級分的李唐同學熱愛魔術方塊,苦練一年就達到12秒的佳績,讓中年人興起了大丈夫當如是的好強心理(要不得呀!),花了點心思在網路上找資料,搞懂解魔術方塊的原理,還很闊氣地去玩具反斗城買了官方版魔術方塊。按著網站上的詳細動畫圖解示範一個口令一個動作,薑! 薑! 薑! 薑~~~ 六面! 六面耶。原來,照著原理一步步實作,轉出六面並非遙不可及的事,至於速度,就端賴記憶與練習的加持。

我的下一階段目標,會開始將旋轉公式輸入大腦,練習用大腦而不是用電腦轉出六面來。對於記憶力日漸衰退的中年人來說,是種磨練也是考驗。但相信對日益嚴重的資訊焦慮併發注意力無法集中症狀,應具有一定療效才對。(謎之聲: 跟上回搞3D紙模同一個理由,你是嫌睡覺時間太多嗎?)

Posted 12 June 2008 02:23 AMJeffrey | 5 comment(s)
Filed under:
【茶包射手專欄】FTP: Netout :Connection reset by peer

早上接獲通報,一台主機的例行FTP作業失敗,檔案沒有正確上傳到Windows 2000的FTP Server。這個排程已經運作好長一段時間了,倒是第一次遇到此種狀況。

我先由FTP Log查起,看到了以下的記錄:
00:55:02 192.168.1.5 [62]USER anonymous 331
00:55:02 192.168.1.5 [62]PASS foo@boo.com 230
00:56:22 192.168.1.5 [62]created TheData.csv 426

查了一下,FTP Status Code 426 = Connection closed; transfer aborted. The command opens a data connection to perform an action, but that action is canceled, and the data connection is closed.。

(此時有段插曲,由於排程上傳失敗,同事重跑上傳作業,確認在FTP Server上有看到上傳檔案,有抓圖畫面為證;但待我檢查時,檔案卻不見蹤影)

我改以全手工上傳檔案,發現上傳這個707KB的檔案時,FTP Client會Hang住,一陣子後再彈出Netout :Connection reset by peer的錯誤訊息。有意思的是,在Hang住的期間,Server端可以看到並下載該檔案,上傳端收到錯誤後,檔案又彷彿被Rollback一般消失無蹤。(Dirty Read?) 這解釋了前述的插曲。

再做了一些測試,發現只有在上傳大檔案時會出錯。為了明確抓出會出錯的檔案大小,我用Mini C# Lab產生了一連串大小不同的txt檔案(這也算Mini C# Lab的經典應用情境),分別上傳測試,最後找出上傳703KB成功,704KB檔案失敗的臨界點,而今天早上失敗的上傳檔大小剛好是707KB。

D:\TEMP>ftp 192.168.1.9
Connected to 192.168.1.9.
220 MyFtp Microsoft FTP Service (Version 5.0).
User (192.168.1.9:(none)): ftp
331 Anonymous access allowed, send identity (e-mail name) as password.
Password:
230 Anonymous user logged in.
ftp> put data701.txt
200 PORT command successful.
150 Opening ASCII mode data connection for DATA701.txt.
226 Transfer complete.
ftp: 717824 bytes sent in 0.75Seconds 957.10Kbytes/sec.
ftp> put data702.txt
200 PORT command successful.
150 Opening ASCII mode data connection for DATA702.txt.
226 Transfer complete.
ftp: 718848 bytes sent in 0.70Seconds 1021.09Kbytes/sec.
ftp> put data703.txt
200 PORT command successful.
150 Opening ASCII mode data connection for DATA703.txt.
226 Transfer complete.
ftp: 719872 bytes sent in 0.69Seconds 1047.85Kbytes/sec.

ftp> put data704.txt
200 PORT command successful.
150 Opening ASCII mode data connection for DATA704.txt.
> Netout :Connection reset by peer
Connection closed by remote host.
ftp>

再深入Google了一下,發現比較可能的狀況是網路傳輸時TCP/IP時Window Size(Buffer)不足,雖然這種情況比較常發生於網路頻寬不足(本案中兩台機器在同一個LAN,FTP實測也有1MB/sec的水準)或Server端接收資料不及(本案中FTP Server CPU %幾乎永遠躺平),與我的實際情況並不相符,但我還是試了ftp -w:16384 192.168.1.9,將Window Size由預設4096放大四倍後,上傳超過704KB的檔案就也不再發生問題。

由此,應可推論本次的FTP連線錯誤是因為Window Size不足引起,但導致Windows Size不足的原因仍然是謎。我試了其他台的Windows 2000 FTP Server無此問題,查了問題FTP Server的Log,過去一年來也只零星發生不到十次426 Error;在有時間挖掘出真相前,我建議開發人員FTP配合加上Window Size參數因應這台古怪的機器。

KB-Install SQL 2000 Reporting Service on SQL 2005

大部分人安裝Reporting Service的經驗應該都是輕鬆愉快的"下一步、下一步"吧? 但我遇到的盡是一些RSConfigTool BugSSRS+SQL 2000 Reporting Service等刁鑽又詭異的情境,總與輕鬆愉快無緣。

這兩天幫同事要裝另一台SSRS + Reporting Service 2000的組合,本以為可以靠上回的經驗輕鬆過關,沒想到又是另一場苦難的開始。

上回安裝SSRS+SQL 2000 Reporting Service的情境,DB用的是SQL 2000,RptSvc2000是已經裝好的。這回的難題是,SQL 2000 Reporting Service的DB必須安裝在SQL 2005上...

SQL 2000 Reporting Service安裝時會檢查SQL Server版本是否吻合,就連Developer Edition的Reporting Service裝在SQL 2000 Enterprise Edition都過不了關,更甭說把SQL 2000 Reporting Service裝在SQL 2005了。

這回我想到的方法是手上有一組現成的ReportServer, ReportServerTempDB資料庫已裝在SQL 2000運轉中,打算將它Copy到SQL 2005上Attachment起來,並重新設定資料庫連線資訊,這個做法跟新增Web Farm主機差不多,理論上是可行的。而且,現成的ReportServer DB中已有一大堆報表,剛好也要在新環境中使用,此法還省去了重新部署報表的手續。

由於Reporting Service中有所謂的加密金鑰,必須與資料庫用的一致才能接上該資料庫,所以第一步是將金鑰匯出來:

C:\Program Files\Microsoft SQL Server\80\Tools\binn>rskeymgmt -e -f c:\rs2000.key -p keyPassword

接著在新主機上安裝SQL 2000 Reporting Service,但麻煩事來了...

第一,SQL 2000屬於另一個Domain,我發現在設定資料庫連線時,即使選擇用SQL帳號登入,系統還是會一直丟出"使用者'(null)'的登入失敗。原因: 未結合受信任的SQL Server連線。"。Google了一下,有人建議用RSSETUPACCOUNT指定帳號,但我測試的結果會變成丟出Domain\User認證失敗的訊息。後來想到一招鋸箭法,新主機開一個與另一Domain管理者級帳號密碼完全相同的帳號,改用該帳號執行安裝程式,透過"自動登入"的巧門,總算解決了這個棘手問題。

才剛過一關,第二個問題馬上就來了。Reporting Service的安裝程式允許你使用現成的ReportServer資料庫,主要是用於Web Farm新增Web主機的情境,但由於該資料庫已套用SP2換了版本,安裝程式會認為ReportServer資料庫的版次不對而無法直接使用。不得已,只好選擇另外新增ReportServer資料庫把Reporting Service裝起來,稍後再修改。

過了這兩關,後面的工作跟原先規劃的相去不遠,還算順利。

  1. 停止SQL 2000 Server
  2. 將ReportServer.mdf, ReportServer.ldf, ReportServerTempDB.mdf, ReportServerTempDB.ldf複製到SQL 2005
  3. SQL 2005 Attach這ReportServer, ReportServerTempDB資料庫
  4. 建立帳號rs_account,並給予存取ReportServer, ReportServerTempDB資料庫的db_owner權限
  5. 將新主機Reporting Service連線指向自身的SQL 2005
    C:\Program Files\Microsoft SQL Server\80\Tools\binn>rsconfig -c -s newHost -a sql -d reportserver -u rs_account -p password
    The command completed successfully
  6. 此時瀏覽http: //newHost/reports ,會發生以下錯誤
    尚未初始化報表伺服器安裝。如需詳細資訊,請查看文件。 (rsReportServerNotActivated) 取得線上說明
    -2147159550
  7. 我們需要安裝原先匯出的那把Key
    C:\Program Files\Microsoft SQL Server\80\Tools\binn>rskeymgmt -a -f d:\rs2000.key -p keyPassword
    Restarting the Report Server Windows service...
    Restarting IIS...
    The command completed successfully

再試一次,報表出現,搞定收工。

TIPS-解決ASP.NET日期格式不一致的問題

之前曾在介紹.NET DateTime Formatting時,建議過大家DateTime.ToString()最好能指定yyyy-MM-dd等格式,不要依賴Windows本身的國別設定,否則有可能發生換台機器甚至換個User結果就不同的困擾。

但如果網站專案是別人寫好的,硬是用了未指定格式的DateTime.ToString(),在中文版上跑得好好的,移到你的英文版Windows日期格式就出了問題,怎麼辦?

今天就遇到這種情況,跟同事研究出幾種解法:

  1. 如果只要處理單一Web Application,可以在web.config中加入<globalization culture="zh-TW' />(或需要的國別)
  2. 想一口氣解決一缸子Web Application的Culture設定,可以從C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\web.config 或 C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\config\machine.config下手,一樣是指定<globalizatoin> culture Attribute即可。
  3. 喜歡用GUI的人,可以用IIS管理員設定:
     

最後再提醒一次,ASP.NET不像Windows Form,很少會有配合"Windows環境"自動套用不同Culture的需求,若要配合使用者的偏好使用不同日期格式,也會靠User Profile機制來實現。所以不指定格式的DateTime.ToString()只會徒增部署及管理的困擾,請避免使用。

更多文章 下一頁 »

搜尋

Go

<June 2008>
SunMonTueWedThuFriSat
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

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

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication