2008年10月29日 星期三

GrideView 加入自訂 Button 出錯

今天在 GrideView 裡加入自訂 Button ,在網頁執行時點選該 Button,就會出現下面錯誤。 雖然有人直覺的建議關閉 enableEventValidation,但在XSS攻擊盛行的當下,實在不是個
好方法。

------ Error Message -----

無效的回傳或回呼引數。已在組態中使用 <pages enableEventValidation="true"/>或在網頁中使用<%@ 
Page EnableEventValidation="true" %> 啟用事件驗證。基於安全性理由,這項功能驗證回傳或回呼引數是來自原本呈現它們的伺服器控制項。如果資料為有效並且是必需的,請使用 ClientScriptManager.RegisterForEventValidation 方法註冊回傳或回呼資料,以進行驗證。 


-------------------------

花了幾個小時後,發現原來是自己在 Page_Load(  ) 裡,不分是否為  IsPostBack 都去重新Bind( ) 那 GrideView,但我也的確需要在 Button 被觸發後,重新去 Bind( ) 過 GridView,在進退維谷之際,想到還有一個 OnPreRender( ) 可以用,所以我將 Bind( ) GridView 的動作搬到 OnPreRender( ) 之後,就正常了。真沒想到,一時的疏忽,竟衍生出這麼難找的 BUG。

PS:還好目前的專案有用VSS控管,所以在找錯誤時,可以放心的砍掉其他不相關的程式,才得以順利找到問題。待找出真正的問題點後,再將專案復原簽出就可以了。



另外,可以參考:
http://paladinprogram.blogspot.com/2010/08/imagebutton-repeaterdatalistgridview.html

2008年10月27日 星期一

__LASTFOCUS的漏洞

近來透過 watch files 掃描站台的安全性,發現會出現 __LASTFOCUS 的問題,在網路上也看到蠻多人也遇到同樣的狀況。

原來這是微軟 .Net 2.0 上的漏洞,需要在 Web AP 上更新修正檔來解決。

2008年10月21日 星期二

Remote Post



在一般的登入網頁,使用者必須輸入帳號密碼,再壓一個確認按鈕,來
進行登入動作。

上述這些行為,有沒有辦法可以不透過該系統而是用自己寫的一支程式
來自動完成動作?

以下就介紹 Remote Post 來完成我們的懶人計畫。

以前在寫ASP的時候,可以在 form 裡面選擇 Action ,也就是指定當
這個頁面被 submit 之後,要執行的程式是誰。可是在ASP.Net並沒有
提供這個方法讓我們直接使用。因為 XX.aspx  ,當他 submit 之後,
預設就是給 XX.aspx.cs 去執行。

所以,可以自行去創建一個新的 form ,並手動的去指定它的 Action 是誰。

[未完,詳細內容請看:詳細網址連結]

[參考網址]: Posting form data from ASP.NET page to another URL (建議下載作者原始檔回來練習一下,大有斬獲)

2008年10月16日 星期四

抓網路上的圖片

如果想要抓網路上的圖片下來,推薦一個不錯的類別:WebClient
下面範例,是將網路上的圖片抓下後,另存到 D 槽 的2.jpg


using System.Net;
using System.IO;

WebClient   oWebClient   =   new   WebClient();
oWebClient.DownloadFile( "http://bks4.books.google.com/book.jpg" , "d:\\2.jpg"); 
oWebClient.Dispose();

在 SQL 實作分頁效果




declare @pagesize nvarchar(20) 
declare @pageindex nvarchar(20)
set @pagesize='10' --每一頁呈現的資料筆數
set @pageindex='2' --要查詢的頁面索引(從0開始)

declare @sql nvarchar(2000)

-- 在 SQL 2005 提供了 ROW_NUMBER 函數,自動產生序號,如果是 SQL 2000,則需自行產生相類似的功能 (如註一)

select ROW_NUMBER() OVER(ORDER BY com_empno DESC) AS 'Row_Number',* 
into #tmp from common..comper 

set @sql='select Top '+@pagesize+' * from #tmp '
set @sql=@sql+'where Row_Number NOT IN ( '
set @sql=@sql+'select Top ('+@pagesize+'*'+@pageindex+')  Row_Number from #tmp )'

print @sql
exec (@sql)

select count(*) from common..comper 

drop table #tmp



-- 列印出 剛剛所執行的 SQL 語法

select Top 10 * from #tmp 
where 
Row_Number NOT IN 
( select Top (10*2)  Row_Number from #tmp )


#tmp 是我們自行整理過含有自動編號的資料集合
假如每個頁面要顯示10筆資料,一共有10個頁面,目前要顯示第3頁。
NOT IN (  )  這個括弧裡面所存的資料,是前2頁的資料, 
NOT IN (  )  正表示著要剔除前2頁的資料,
select To 10 ,則是剔除前2頁資料後,取最前面的10筆,也就會抓到我們所謂的第3頁資料。


會如此自討苦吃部是沒有原因的,當所要查詢的資料量很龐大時,不管是使用 DataGrid 還是 GridView,
都會直接將所查詢到的大量資料回傳到 Web AP,然後再將資料整理成USER所要看的HTML傳到USER的
瀏覽器。此時,除了等待之外,就是把頁面關掉,或上YAHOO新聞看看政經八卦了。

透過 SQL 自己實作分頁,可以大幅縮短使用者檢視大量查詢結果的時間,蠻有助益的。





註一: 
如果是在 SQL 2000,可以透過 IDENTITY(int,1,1) 來自動產生序號
select IDENTITY(int,1,1) AS 'Row_Number',* 
into #tmp from common..comper  ORDER BY com_empno DESC

在SP中接其他SP的回傳資料結果

一直都認為,在SP(Store Procedure)中若要去取得另一支SP的執行結果是件很困難的事。後來發現其實沒這麼難啦,只要事先建好一個暫存資料表,再把另一支 SP 的結果傳進暫存表即可。

以下是程式範例:

--建立暫存表
create table  #tmp(
com_cname nvarchar(20),
com_empno nvarchar(20),
com_empdept nvarchar(20),
com_empext nvarchar(20)
)

--將另一支SP (esp_comper_query ) 的執行結果存到暫存表
insert into #tmp
exec esp_comper_query '526278'

select * from #tmp

drop table #tmp

=====================
補充: 20090306
=====================
如果你採用這方式,但有另一支sp也是透過你寫的sp並傳回結果,則會出現
An INSERT EXEC statement cannot be nested.
所以要避免發生巢狀使用的方式。

2008年10月15日 星期三

取得 SP參數資料及型別

取得 SP 裡的輸入、輸出參數資料及型別。



關鍵字:

SP
Store Procedure 
SqlCommandBuilder.DeriveParameters
SqlParameter 

取得 DB 所有 SP 的名稱

SELECT name
FROM sysobjects
WHERE type = 'P' 

2008年10月8日 星期三

透過url去抓網頁資料回來

提供一段程式,可以透過 url 去將 url 所指定的網頁將網頁抓回並存成字串。
可以針對這回傳字串進行文字分析處理以取得我們想要的資訊。
#region Retrieves the HTML from the specified URL.
/// <summary>
/// Retrieves the HTML from the specified URL.
/// </summary>
/// <param name="pageUrl">URL of the web page to retrive HTML.</param>
/// <param name="timeoutSeconds">The timeout for the http request.</param>
/// <returns>Returns the retrived HTML.</returns>
public string GetPageHTML(string pageUrl, int timeoutSeconds)
{
 System.Net.WebResponse response = null;

 try
 {
     // Setup our Web request
     System.Net.WebRequest request = System.Net.WebRequest.Create(pageUrl);
     request.Timeout = timeoutSeconds * 1000;

     // Retrieve data from request
     response = request.GetResponse();

     System.IO.Stream streamReceive = response.GetResponseStream();
     System.Text.Encoding encoding = System.Text.Encoding.GetEncoding("utf-8");
     //System.Text.Encoding encoding = System.Text.Encoding.GetEncoding("big5");
     //System.IO.StreamReader streamRead = new System.IO.StreamReader(streamReceive, System.Text.Encoding.Default);
     System.IO.StreamReader streamRead = new System.IO.StreamReader(streamReceive, System.Text.Encoding.UTF8);



     // return the retrieved HTML
     return streamRead.ReadToEnd();
 }
 catch (Exception ex)
 {
     // Error occured grabbing data, return empty string.
     //MessageBox.Show(this, "An error occurred while retrived the HTML content. " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
     return "";
 }
 finally
 {
     // Check if exists, then close the response.
     if (response != null)
     {
         response.Close();
     }
 }
}
#endregion

// for test
protected void btnGet_Click(object sender, EventArgs e)
{
 string AA=GetPageHTML(txtURL.Text.Trim(), 100);
 txtResult.Text = AA;
}

關鍵字:
streamReceive
GetResponseStream
encoding
streamRead

參考:透過 HTML Agility Pack 抓網頁資料

Google Calendar 時區

最近在分析 Google Calendar 匯出 *.ics 時,發現裡面的時間,如:

DTSTART:20081006T230000Z

都跟實際的行事曆時間不同,事後發現,原來 Google 是使用 UTC 時間。而台灣的時區為 UTC+8,所以從Google所抓出的時間要加上8小時,才會是我們真正想要取得的時間。

註1:UTC+8 比協調世界時快8小時的時區

註2:協調世界時,又稱世界標準時間,簡稱UTC,從英文「Coordinated Universal Time」而來。

2008年10月7日 星期二

SQL語法 的 print

今天跟 lillian 找了一整天的 store procedure 與 EZ-Flower (真的一點都不Easy!),某一支 sp 特別奇怪,當單單執行這一支 sp 時,就沒問題,但透過別人來呼叫他,就會莫名的中斷程式執行,實在很火大。所以就在這支 sp 每一行都設了一個寫 Log 的指令。舉例來說,我一共設了10個寫 Log 的偵測點,如果這支 sp 正常完成執行,就會得到 10 個 Log 記錄,如果是出現在第6個 Log 之後就沒下文,可以推測實際上是在第6到第7個 log 之間發生了問題。我也是逼不得已才用這種笨方法的,無奈啊!


結果告訴我,程式竟然在 print 'xxxx' 出錯。原先在這支 sp ,充斥著古老前為了測試而留下來的 print 語法,沒想到今天卻成為兇手,但這結果真的很訝異。但在人證物證一應俱全的情況下,我也只能屈服了。真的是你,print。