目前分類:ASP.NET (11)

瀏覽方式: 標題列表 簡短摘要

最近在MVC上使用AjaxControlToolKit,稍微研究了一下$create()的用法,在這邊做個心得分享:

Note:在MVC上使用AjaxControlToolKit的方法可參考這裡

以下節錄自MSDN的說明:

image

 

我個人的理解如下:

type:元件的型別,可以從對應的 js 檔中找到,例如下圖

image

 

properties:替此元件加入屬性值,例如 id。

events:替此元件的事件加上 handler 。

references:這個很難看出它到底在幹嘛,還好這邊有比較清楚的說明。

element:實體的 DOM 物件。

 

 

最後,舉一個 FilteredTextBox 及 Calendar 的例子:

$create(
AjaxControlToolkit.FilteredTextBoxBehavior,
{
FilterType:AjaxControlToolkit.FilterTypes.Numbers,
id:
"filter1"
},
null,
null,
$get(
"TextBox1")
);

$create(
AjaxControlToolkit.CalendarBehavior,
{ id:
"calendar1" },
{
dateSelectionChanged:
function() {
alert(
"date changed");
}
},
null,
$get(
"TextBox1")
);

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

網友問了個問題:WCF 建立時,服務參考的網址是顯示主機名稱,但他想用 IP 取代主機名稱,這該怎麼做呢?其實還挺簡單的,在 IIS 設定一下就行了,下面用對照的方式來看:

 

設定前:

wcf-hostname

 

 

設定後:

wcf-ip

 

 

至於設定什麼呢……其實就是這個:

wcf-ip-instead-hostname

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

        之前發過一篇 SessionID重複 的問題。事隔多日,總算讓我找到好方法,可以透過修改機碼的方式來改變 IE 共用 SessionID 的行為。

        只要在 HKCU\Software\Microsoft\Internet Explorer\Main 底下新增一個名為 TabProcGrowth 的 DWORD 值,並將其值設為 0 即可。

REG-TabProcGrowth

 

        設定完成後,每個 IE 都會視同使用「新增工作階段」的方式來運作。也就不會有SessionID重複的情況發生了。

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

         最近在使用 Web Service 時發現了一個有趣的現象,只要按 F5 進偵錯模式時呼叫 Web Service,就常常會發生逾時的情況,但是不進偵錯模式的話又可以正常呼叫。

        雖然程式搬到 Server 上可以正常執行,但在開發時不能進偵錯模式實在很令人頭痛。為了解決這個問題,我把 Web Service 的 Request 交由 Fiddler 去發送,籍由這個工具來看 Request 的內容。程式碼大致上如下:

WebReference.Service1 service = new WebReference.Service1();
service.Proxy = new System.Net.WebProxy("127.0.0.1", 8888);

 

        接著呼叫 Web Service 提供的 WebMethod,Request 就會經由 Fiddler 發送出去。

 

        檢查了一下 Request 的內容,原來在偵錯模式下,HttpHeader 會多加下面這一段

fiddler-webservice-request

 

 

 

        Google之後,找到這篇,看來只要設定 Config,取消這一段自動加入的 Request Header 就行了。加入的 Config 區段如下:

<configuration> 
  <system.diagnostics> 
    <switches> 
       <add name="Remote.Disable" value="1" /> 
    </switches> 
  </system.diagnostics> 
</configuration> 

 

 

 

        可惜的是,手邊其實不止這一個 Web Service 站台,但只有呼叫這支會有這種問題,所以暫時也不知道確切發生的原因,看來只能等日後再慢慢研究、實驗了。

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

    今天寫 ASP.NET MVC 時,想抓目前的 RouteName 出來看,但 RouteCollection 好像在跟我唱反調一般,就是不讓我看到目前的 RouteName。

    心一橫,乾脆進 Source Code 去找看看,果然找到可以直接抓出來的辦法。原來 RouteCollection 是用一個 Dictionary 在儲存這些 RouteTable 的資訊。知道這點之後,要抓出來就不是什麼難事了。

public static string getRouteName() { 
    RouteData currentRoute = RouteTable.Routes.GetRouteData(
            new HttpContextWrapper(System.Web.HttpContext.Current));
 
 
    if (currentRoute == null) return null;
 
 
    FieldInfo field = typeof(RouteCollection).GetField(
        "_namedMap", 
        BindingFlags.Instance | BindingFlags.NonPublic); 
 
 
    Dictionary<string, RouteBase> namedMap =
        field.GetValue(RouteTable.Routes)
        as Dictionary<string, RouteBase>;
 
 
    return namedMap.First(
        route => { return route.Value == currentRoute.Route; }
    ).Key; 
}

 

    這樣一來,只要呼叫這個方法就可以知道目前所走的 RouteName 囉!

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

    這個錯誤的長相是這樣的

ControlCollection.Add

    因為字太長,所以標題就刪掉了一些。

 

    原因是當開發人員在aspx中寫了inline code,例如<%=…%>之後,ControlCollection集合就會變成唯讀的,所以不能使用ControlCollection類別中的Add()方法 or AddAt()方法。以下是測試的程式碼: 

<form id="form1" runat="server">
<div id="div1" runat="server">
    <%="readonly" %>
</div>
<div id="div2" runat="server">
</div>
</form>

 


protected void Page_Load(object sender, EventArgs e)
{
    try {
        div1.Controls.Add(new Button());
    } catch { Response.Write("div1不能加入控制項"); }
 
    try {
        div2.Controls.Add(new Button());
    } catch { Response.Write("div2不能加入控制項"); }
}

測試結果:

    div1不能動態加控制項進去,但div2可以。

解決辦法:

    1.不要動態加控制項 (廢話)

    2.不要用<%…%> (還是廢話)

    3.用其它容器處理。這個方法說穿了也是1跟2的變形。以上面的情況來說,會變成下面這樣

 


<form id="form1" runat="server">
<div id="div1" runat="server">
    <span id="span1" runat="server">
        <%="readonly"%>
    </span>
</div>
<div id="div2" runat="server">
</div>
</form>

 


protected void Page_Load(object sender, EventArgs e)
{
    try {
        div1.Controls.Add(new Button());
    } catch { Response.Write("div1不能加入控制項"); }
 
    try {
        div2.Controls.Add(new Button());
    } catch { Response.Write("div2不能加入控制項"); }
}

如此一來,div1.Controls就不再是唯讀集合,所以可以任意的呼叫Controls.Add()方法。

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

    最近把一些 .NET2.0 的專案從 x86 的 Server 搬到 x64 的 Server 上,一直都相安無事,直到今天才發現使用 Oledb 讀取 Excel 的時候會跳出「'Microsoft.Jet.Oledb.4.0' 未登錄於本機電腦上」的錯誤。

    印象中在論壇上看到過幾篇「x64 + Oledb」的討論,再回頭去翻了一下,原來還蠻容易解決的,只要把 AppPool 設為 32 位元模式就行了。

x32mode

 

    有論壇真好~~~

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

    今天同事遇到一個問題,使用者以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) 人氣()

今天某位網友在使用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) 人氣()

我的消息真的很不靈通,一直到前兩天才看到這個東西。突然想起之前有看到的這篇,於是自己動手寫看看。果然相當神奇。 原來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) 人氣()