今天同事遇到一個問題,使用者以IE8登入ASP.NET 1.1的網站後,在同一台電腦再另外開一個IE出來(不是用window.open()、也不是HyperLink),並登入同一個網站,結果會發現兩個視窗所使用的SessionID竟然的相同的。

    用Fiddler去觀察的結果如下:
1.開第一個IE,並連到網站,此時Request的內容不包含ASP.NET_SessionId
2.登入後,任何的PostBack都會包含ASP.NET_SessionId=krjo4r55my1gdc55kqlfgdic
3.再另外開一個IE,並連到網站,此時Request已經包含ASP.NET_SessionId=krjo4r55my1gdc55kqlfgdic

    我一直以為,開一個新的瀏覽器視窗出來,就會擁有跟其它瀏覽器不一樣的SessionID。結果今天這個事情完全推翻掉我的認知。還好有google到這篇,再加上台灣有個高手眾多的論壇,總算是解決掉我的疑惑。

    解法就是開啟視窗的時候加上nomerge的參數,或是直接按「檔案」--「新增工作階段」來開啟新視窗。本來想找看看有沒有透過修改registry的做法,不過天不從人願,找不到就是找不到。

 

    不過呢……我還是覺得獨立視窗擁有各自的SessionID會比較好一點。

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

    這次得獎其實還挺意外的,我想這要感謝Lolota大大這麼給面子,願意把這個獎項給我。

 

    Lolota大,真的很感謝您,謝謝。

 

    老實說,我以前一直是個不學好的死小孩。二專被退學之後就到海軍去了,職業軍人當了五年半,因為受到船上一位直屬士官長影響,開始對程式語言產生興趣。後來退伍之後就到桃園退輔會去上程式語言的課程。然後2007年3月的時候找到第一份工作,接著就開始了寫程式的日子。

    一直到現在,我自己的能力仍然不是很好。開發經驗不比別人多,也不是科班出身,甚至很多技術是我不熟、不會的(看我的部落格就知道了)。不過,透過MSDN論壇,卻可以讓我得到許多有用的資訊,進而吸收,變成自己的知識。甚至點部落上的許多好文章也是在加入論壇之後才發現的。

    MSDN論壇真的是很好的一個地方,不管是提問者或回答者,在一來一往的交流中都可以得到成長的機會,開拓自己的視野。我想,要走的路還很長,今後還是會繼續在論壇上活動,因為這是一個可以從許多優秀開發人員身上學習的好機會。

    感謝MSDN論壇、感謝各位論壇上的前輩,謝謝。

AnferneeHardaway 發表在 痞客邦 留言(1) 人氣()

    今天參加MSDN聯合版聚,拿到這個獎,還跟許多高手見面。老實說,真的很開心。不過突然要我上去講心得,還真的不知道該講什麼,最後竟然講了一句……祝大家新年快樂~~~真夠糗的了。

    現場來了幾位論壇上常見到的高手:91、坎尼、hunterpo0323、小朱、Bill、Lolota、Joe、Ricoisme、Alex。能跟這些高手本人面對面真的很令我興奮,其實還蠻想跟他們聊聊天的,可惜會後還有點事情,殘念~~

DSC08778

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

    一直不是很了解.pdb檔(Program Database file),只知道它是用來偵錯的,但倒是從來沒有研究過裡面到底記載了什麼資訊。一直到今天有網友在偵錯時碰到問題,我才開始研究這個神奇的檔案。google了一下,找到這篇,原來pdb檔記錄了下面這些資訊:

1.source code file name
2.行號資訊
3.local variable name

而dll中則是記錄了這個pdb檔的位置,所以當我們按下F5進行偵錯時,會先到dll去找pdb的位置,然後再讀取pdb檔,接著依照pdb的記錄去找source code,然後就是我們看到的偵錯畫面。

除了dll內記錄的pdb檔位置之外,偵錯時還會去兩個地方找看看有沒有pdb可供載入,一個是專案的執行目錄,另一個則是vs的偵錯設定

pdb-location2

 

三個地方的先後順序應該是這樣的

1.執行目錄
2.ddl內記載的目錄
3.偵錯設定中的目錄

另外,也可以手動從「模組視窗」中手動載入

pdb-location5

 

但如果vs載入了pdb檔,但卻找不到pdb記錄的source code file,則vs會直接跳一個視窗叫你告訴它檔案在哪裡。

pdb-location4

 

最後,如果pdb載入了,也順利找到了原始檔,但原始檔卻被編輯過,那偵錯時就會讓人覺得怪怪的,這是因為原始程式碼檔案已經跟dll不符合的關係

 

 

不過讓我覺得很奇怪的是,即使我是在Release模式下去編譯,仍然會產出pdb檔,而且dll內也照樣記錄著pdb檔的位置。

用dumpbin看到的資訊

pdb-location3

 

 

查到這裡,大致上對pdb有了初步的認識,唯一覺得可惜的是沒辦法看到pdb檔的實際內容。唉,殘念!!

 

[2010/4/18] 補上對 pdb 檔的內容的新發現

 

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

今天某位網友在使用Menu控制項時碰到一個例外訊息:

Can't select a disabled or unselectable menu item
(無法選取停用的或無法選取的功能表項目)

 

案發現場大概是這樣的:這位朋友在MenuItemClick的時候,把選取到的MenuItem.Selectable設為false,然後再選另一個MenuItem,這個時候就會拋出這個例外了。

由於之前用TreeView的時候有遇過某個Node的Value重複,而浪費了許多時間在Debug的經驗。所以直覺就認為:MenuItem的Value有重複。經過測試後,的確,MenuItem的Value只要重複就會造成這種錯誤。

<asp:Menu ID="Menu1" runat="server" onmenuitemclick="Menu1_MenuItemClick">
    <Items>
        <asp:MenuItem Text="新增項目1" Value="1"></asp:MenuItem>
        <asp:MenuItem Text="新增項目1" Value="1"></asp:MenuItem>
        <asp:MenuItem Text="新增項目2" Value="2"></asp:MenuItem>
    </Items>
</asp:Menu>

 


protected void Menu1_MenuItemClick(object sender, MenuEventArgs e) {
    e.Item.Selectable = false;
}

 

只要這樣寫,點個幾下就會跳錯誤了。 

menu-selectable_false

 

 

 

 

 

不過這位朋友似乎不認為這是主因,於是我又追了一下。這才發現原來還有另一個情況會報錯,就是在程式碼裡面新增MenuItem。簡化之後的程式碼大致上如下: 


<asp:Menu ID="Menu1" runat="server" onmenuitemclick="Menu1_MenuItemClick">
    
</asp:Menu>

 


protected void Page_Load(object sender, EventArgs e) {
    if (!IsPostBack) {
        Menu1.Items.Add(new MenuItem("新項目1", "1"));
        Menu1.Items.Add(new MenuItem("新項目2", "2"));
        Menu1.Items.Add(new MenuItem("新項目3", "3"));
    }
}
 
protected void Menu1_MenuItemClick(object sender, MenuEventArgs e) {
    e.Item.Selectable = false;
}

 這樣寫即使MenuItem的Value沒重複也一樣會跳錯誤

 

 

 

會錯誤的原因是在於時間點,因為PageLoad是在LoadViewState之後,而Menu控制項會在LoadViewState的時候重新建立子節點(包括SelectedItem),所以此時如果已經有某一個節點已經被設為Selectable = false的話,就會出現這個錯誤訊息。

 

解決方式還蠻簡單的,直接設定e.Item.Selected = false就行了。 


protected void Menu1_MenuItemClick(object sender, MenuEventArgs e) {
    e.Item.Selectable = false;
    e.Item.Selected = false;
}

 

 

 

[結論] 

使用Menu控制項時,得注意以下二點: 

1.Value不要重複
2.如果程式內會設定Selectable的話,得連同Selected一起設定

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

一直以來,我對SqlDataSource存有相當大的疑惑。

 

每次用DataGrid或GridView做分頁的時候,總是會在SQL語法上多下一點功夫,想辦法只抓出少量的資料筆數。後來VS2005推出了SqlDataSource,可以在不寫程式的情況下就做到分頁的功能。直覺就是:這麼方便?!難道它會自己產生分頁的SQL語法?

今天總算找到時間研究了一下SqlDataSource的程式碼,果然有效能上的缺點。

 

首先我在aspx上放了一個GridView跟一個SqlDataSource,後端程式則完全不寫。

<form id="form1" runat="server">
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" DataSourceID="SqlDataSource1"></asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString="<%$ ConnectionStrings:MyConnectionString %>" 
    ProviderName="<%$ ConnectionStrings:MyConnectionString.ProviderName %>" 
    SelectCommand="SELECT Seq FROM Test"></asp:SqlDataSource>        
</form>

 

直接就有了分頁的功能。 

SqlDataSource_Performance

 

 

 

同時我打開Sql Profiler來觀察

SqlDataSource_Performance1

 

可以看得出來,每次換頁時都會執行一次查詢,而且是全部筆數都抓出來。果然,方便的代價就是付出效能成本。

 

 

[結論]

SqlDataSource在不設定EnableCaching的情況下,每次查詢都會老老實實的把資料全部抓出來,使用時不得不慎!

 

AnferneeHardaway 發表在 痞客邦 留言(1) 人氣()

同事問了一個問題:

      假如有兩個物件(A和B),這兩個物件分屬不同類別,且大多數的屬性都一樣,但彼此沒有繼承關係,也不能修改原始類別的程式碼。要如何快速將物件A的屬性值全部複製給物件B??

思考了一下,由於功力不深,所以只想得出PropertyInfo類別。

 

首先定義ClassA及ClassB

public class ClassA {
    public string Str1 { get; set; }
    public string Str2 { get; set; }
    public string Str3 { get; set; }
    public string Str4 { get; set; }
    public string Str5 { get; set; }
    public string Str6 { get; set; }
    public string Str7 { get; set; }
    public string Str8 { get; set; }
    public string Str9 { get; set; }
    public string Str10 { get; set; }
    public string Str11 { get; set; }
    public string Str12 { get; set; }
    public string Str13 { get; set; }
    public string Str14 { get; set; }
    public string Str15 { get; set; }
    public string Str16 { get; set; }
    public string Str17 { get; set; }
    public string Str18 { get; set; }
    public string Str19 { get; set; }
    public string Str20 { get; set; }
    public string Str21 { get; set; }
    public string Str22 { get; set; }
    public string Str23 { get; set; }
    public string Str24 { get; set; }
    public string Str25 { get; set; }
    public string Str26 { get; set; }
    public string Str27 { get; set; }
    public string Str28 { get; set; }
    public string Str29 { get; set; }
    public string Str30 { get; set; }
    public string Str31 { get; set; }
    public string Str32 { get; set; }
    public string Str33 { get; set; }
    public string Str34 { get; set; }
    public string Str35 { get; set; }
    public string Str36 { get; set; }
    public string Str37 { get; set; }
    public string Str38 { get; set; }
    public string Str39 { get; set; }
    public string Str40 { get; set; }
    public string Str41 { get; set; }
    public string Str42 { get; set; }
    public string Str43 { get; set; }
    public string Str44 { get; set; }
    public string Str45 { get; set; }
    public string Str46 { get; set; }
    public string Str47 { get; set; }
    public string Str48 { get; set; }
    public string Str49 { get; set; }
    public string Str50 { get; set; }
    public string Str51 { get; set; }
    public string Str52 { get; set; }
    public string Str53 { get; set; }
    public string Str54 { get; set; }
    public string Str55 { get; set; }
    public string Str56 { get; set; }
    public string Str57 { get; set; }
    public string Str58 { get; set; }
    public string Str59 { get; set; }
    public string Str60 { get; set; }
    public string Str61 { get; set; }
    public string Str62 { get; set; }
    public string Str63 { get; set; }
    public string Str64 { get; set; }
    public string Str65 { get; set; }
    public string Str66 { get; set; }
    public string Str67 { get; set; }
    public string Str68 { get; set; }
    public string Str69 { get; set; }
    public string Str70 { get; set; }
    public string Str71 { get; set; }
    public string Str72 { get; set; }
    public string Str73 { get; set; }
    public string Str74 { get; set; }
    public string Str75 { get; set; }
    public string Str76 { get; set; }
    public string Str77 { get; set; }
    public string Str78 { get; set; }
    public string Str79 { get; set; }
    public string Str80 { get; set; }
    public string Str81 { get; set; }
    public string Str82 { get; set; }
    public string Str83 { get; set; }
    public string Str84 { get; set; }
    public string Str85 { get; set; }
    public string Str86 { get; set; }
    public string Str87 { get; set; }
    public string Str88 { get; set; }
    public string Str89 { get; set; }
    public string Str90 { get; set; }
    public string Str91 { get; set; }
    public string Str92 { get; set; }
    public string Str93 { get; set; }
    public string Str94 { get; set; }
    public string Str95 { get; set; }
    public string Str96 { get; set; }
    public string Str97 { get; set; }
    public string Str98 { get; set; }
    public string Str99 { get; set; }
    public string Str100 { get; set; }
}
 
public class ClassB {
    public string Str1 { get; set; }
    public string Str2 { get; set; }
    public string Str3 { get; set; }
    public string Str4 { get; set; }
    public string Str5 { get; set; }
    public string Str6 { get; set; }
    public string Str7 { get; set; }
    public string Str8 { get; set; }
    public string Str9 { get; set; }
    public string Str10 { get; set; }
    public string Str11 { get; set; }
    public string Str12 { get; set; }
    public string Str13 { get; set; }
    public string Str14 { get; set; }
    public string Str15 { get; set; }
    public string Str16 { get; set; }
    public string Str17 { get; set; }
    public string Str18 { get; set; }
    public string Str19 { get; set; }
    public string Str20 { get; set; }
    public string Str21 { get; set; }
    public string Str22 { get; set; }
    public string Str23 { get; set; }
    public string Str24 { get; set; }
    public string Str25 { get; set; }
    public string Str26 { get; set; }
    public string Str27 { get; set; }
    public string Str28 { get; set; }
    public string Str29 { get; set; }
    public string Str30 { get; set; }
    public string Str31 { get; set; }
    public string Str32 { get; set; }
    public string Str33 { get; set; }
    public string Str34 { get; set; }
    public string Str35 { get; set; }
    public string Str36 { get; set; }
    public string Str37 { get; set; }
    public string Str38 { get; set; }
    public string Str39 { get; set; }
    public string Str40 { get; set; }
    public string Str41 { get; set; }
    public string Str42 { get; set; }
    public string Str43 { get; set; }
    public string Str44 { get; set; }
    public string Str45 { get; set; }
    public string Str46 { get; set; }
    public string Str47 { get; set; }
    public string Str48 { get; set; }
    public string Str49 { get; set; }
    public string Str50 { get; set; }
    public string Str51 { get; set; }
    public string Str52 { get; set; }
    public string Str53 { get; set; }
    public string Str54 { get; set; }
    public string Str55 { get; set; }
    public string Str56 { get; set; }
    public string Str57 { get; set; }
    public string Str58 { get; set; }
    public string Str59 { get; set; }
    public string Str60 { get; set; }
    public string Str61 { get; set; }
    public string Str62 { get; set; }
    public string Str63 { get; set; }
    public string Str64 { get; set; }
    public string Str65 { get; set; }
    public string Str66 { get; set; }
    public string Str67 { get; set; }
    public string Str68 { get; set; }
    public string Str69 { get; set; }
    public string Str70 { get; set; }
    public string Str71 { get; set; }
    public string Str72 { get; set; }
    public string Str73 { get; set; }
    public string Str74 { get; set; }
    public string Str75 { get; set; }
    public string Str76 { get; set; }
    public string Str77 { get; set; }
    public string Str78 { get; set; }
    public string Str79 { get; set; }
    public string Str80 { get; set; }
    public string Str81 { get; set; }
    public string Str82 { get; set; }
    public string Str83 { get; set; }
    public string Str84 { get; set; }
    public string Str85 { get; set; }
    public string Str86 { get; set; }
    public string Str87 { get; set; }
    public string Str88 { get; set; }
    public string Str89 { get; set; }
    public string Str90 { get; set; }
 
    public int Str91 { get; set; }
    public int Str92 { get; set; }
    public int Str93 { get; set; }
    public int Str94 { get; set; }
    public int Str95 { get; set; }
    public int Str96 { get; set; }
    public int Str97 { get; set; }
    public int Str98 { get; set; }
    public int Str99 { get; set; }
    public int Str100 { get; set; }
}

 

 

 

接著產生物件A、物件B


ClassA a = new ClassA() {
            Str1 = "Str1",
            Str2 = "Str2",
            Str3 = "Str3",
            Str4 = "Str4",
            Str5 = "Str5",
            Str6 = "Str6",
            Str7 = "Str7",
            Str8 = "Str8",
            Str9 = "Str9",
            Str10 = "Str10",
            Str11 = "Str11",
            Str12 = "Str12",
            Str13 = "Str13",
            Str14 = "Str14",
            Str15 = "Str15",
            Str16 = "Str16",
            Str17 = "Str17",
            Str18 = "Str18",
            Str19 = "Str19",
            Str20 = "Str20",
            Str21 = "Str21",
            Str22 = "Str22",
            Str23 = "Str23",
            Str24 = "Str24",
            Str25 = "Str25",
            Str26 = "Str26",
            Str27 = "Str27",
            Str28 = "Str28",
            Str29 = "Str29",
            Str30 = "Str30",
            Str31 = "Str31",
            Str32 = "Str32",
            Str33 = "Str33",
            Str34 = "Str34",
            Str35 = "Str35",
            Str36 = "Str36",
            Str37 = "Str37",
            Str38 = "Str38",
            Str39 = "Str39",
            Str40 = "Str40",
            Str41 = "Str41",
            Str42 = "Str42",
            Str43 = "Str43",
            Str44 = "Str44",
            Str45 = "Str45",
            Str46 = "Str46",
            Str47 = "Str47",
            Str48 = "Str48",
            Str49 = "Str49",
            Str50 = "Str50",
            Str51 = "Str51",
            Str52 = "Str52",
            Str53 = "Str53",
            Str54 = "Str54",
            Str55 = "Str55",
            Str56 = "Str56",
            Str57 = "Str57",
            Str58 = "Str58",
            Str59 = "Str59",
            Str60 = "Str60",
            Str61 = "Str61",
            Str62 = "Str62",
            Str63 = "Str63",
            Str64 = "Str64",
            Str65 = "Str65",
            Str66 = "Str66",
            Str67 = "Str67",
            Str68 = "Str68",
            Str69 = "Str69",
            Str70 = "Str70",
            Str71 = "Str71",
            Str72 = "Str72",
            Str73 = "Str73",
            Str74 = "Str74",
            Str75 = "Str75",
            Str76 = "Str76",
            Str77 = "Str77",
            Str78 = "Str78",
            Str79 = "Str79",
            Str80 = "Str80",
            Str81 = "Str81",
            Str82 = "Str82",
            Str83 = "Str83",
            Str84 = "Str84",
            Str85 = "Str85",
            Str86 = "Str86",
            Str87 = "Str87",
            Str88 = "Str88",
            Str89 = "Str89",
            Str90 = "Str90",
            Str91 = "Str91",
            Str92 = "Str92",
            Str93 = "Str93",
            Str94 = "Str94",
            Str95 = "Str95",
            Str96 = "Str96",
            Str97 = "Str97",
            Str98 = "Str98",
            Str99 = "Str99",
            Str100 = "Str100"
        };
 
        ClassB b = new ClassB();

 

 

 

最後就是複製的動作了


Type typeB = typeof(ClassB);
PropertyInfo[] propertiesA = typeof(ClassA).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo infoA in propertiesA) {
    string name = infoA.Name;
    PropertyInfo infoB = typeB.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
    if (infoB != null && infoA.PropertyType == infoB.PropertyType) {
        infoB.SetValue(b, infoA.GetValue(a, null), null);
    }
}

 

 

 

結果

Copy_Properties

 

其實Reflection命名空間還蠻神奇的,它甚至連物件內的private變數也能進行修改。只是一直沒時間好好研究它......

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

我的消息真的很不靈通,一直到前兩天才看到這個東西。突然想起之前有看到的這篇,於是自己動手寫看看。果然相當神奇。 原來ajax也能做出上一頁、下一頁的效果。本著好奇的心態追了一下,原來是利用網址的hash做到這種效果。

為方便理解,我這裡用html來實做

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <input type="text" id="text1" />
    <input type="button" value="addHash" onclick="add();" />
</body>
</html>

 


<script type="text/javascript">
    function add(){
        var hash = location.hash;
        if(hash.indexOf("#") > -1)
            location.hash = hash + "&t=" + document.getElementById("text1").value;
        else
            location.hash = "#t=" + document.getElementById("text1").value;
    }
</script>

 

如此一來,每次按下按鈕時,就會多出一個HistoryPoint。至於偵測使用者按下「上一頁」、「下一頁」的動作,則是利用setInterval(),不斷的檢查url。

 

不過在IE7或IE6上就沒這麼順利了,需要再加一個iframe,利用document.open()、document.close()的方式讓IE去加HistoryPoint。

 

[參考資料]

http://www.mikage.to/jquery/jquery_history.html
http://msdn.microsoft.com/zh-tw/ee460838.aspx
http://www.netmag.com.tw/member/netmag_article/N081108201.pdf

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

«123