2008年5月28日

Safari的強勢推廣

Safari目前市占率約為5%,而蘋果公司3月開始透過iTunes的自動更新大力推廣Safari。這種強勢推廣已有一些效果,根據Net Applications統計,Safari在視窗電腦的市占率3月時成長200%。

這邊的關鍵字是:強勢推廣。嗯,強勢推廣...

2008年5月23日

DataBinding的問題

從昨天傍晚遇到這個問題,弄了一整夜找不出原因。先把問題記下來,將來再研究為何...

ArticleEntryEditor繼承了DataList,做了一點小修改。

ArticleEntryEditor的EditItemTemplate,用了一個UserControl:ArticleEditorItem

在ArticleEditorItem中,接受一個Item的欄位,型別為ContentItem。用DataBind的<%# Container.DataItem %>之後,ArticleEditorItem 中的 DropDownList 都不會抓到正確的值。應該說,在指定完畢之後,就立刻不見了(回復到選單的第一個值)。可是其他的WebControl不會受到影響。

如果是在OnItemDataBound中,去指定ArticleEditorItem.Item的值,就不會有這個問題。

這個問題應該不是第一次遇到,只是沒有像這次一樣繞路要花很多時間。記下來將來研究。

2008年5月11日

IPrincipal vs Session Identity Persistence 的思考

為了家總的案子,終於把這一段給弄清楚了...

簡單講IPrincipal的架構:HttpContext.User就是一個IPrincipal,IPrincipal負責標示Role(有個IsInRole的method要實現),也就是負責授權。IPrincipal下面有一個Identity,可以存真正獲得這個Principal的Identity(:IIdentity)。

每次的HttpRequest, Asp.Net都會自動幫我們把IPrincipal與IIdentity處理出來。標準狀況下(使用Forms Authentication,且使用FormsAuthentication.SetAuthCookie的情況下),每個Request獲得的User是一個GenericPrincipal,Identity則是一個FormsIdentity。這往往不是我們要的,所以,我們有兩種作法:

1. 在系統拿到IPrincipal與IIdentity的時候,自己根據取得的IIdentity.Name去把我們要的類別代換。比如我有CDLPrincipal:IPrincipal, CDLIdentity:IIdentity,在Authentication_End的時候,執行

string currentUserId=HttpContext.User.Identity.Name;
HttpContext.Current.User=new CDLPrincipal(currentUserId);

這裡的new CDLPrincipal,基本上就是從Identity Store裡,取出我們要的CDLPrincipal,以及附贈的CDLIdentity。也就是說,在這個過程裡面,HttpContext.Current.User發生了兩次指定的工作:一次是系統做的,一次是我們做的。

2. 如果要只想做一次這個動作,只能我們自己寫Authentication Module。在這種時候,我們要用authentication cookie把所有IPrincipal的內容Serialize(並Encrypt)成一個string,然後指定cookie name,傳給browser。這也是Msdn的標準作法,SetAuthCookie只是這個作法的一個簡易版。這種作法的問題很多,主要authentication cookie這下子可能變得很長,影響頻寬。

第一種作法,可以用HttpModule解決或是用Page_Init,第二種方式就一定是用HttpModule處理。

另外,這跟使用Session比起來有何好處?老實說,除了可以Impersonate之外,我看不出任何好處。但多了一個Auth. Cookie,在頻寬上是有影響的。session的偽冒問題,IPrincipal的作法同樣透過cookie,也不可避免。

這是個值得進一步思考的問題。

2008年5月8日

Inversion of Control 與 DI 的分別

最近突然沒有什麼事,花了一點時間把 Inversion of Control 與 Dependency Injection 的議題搞清楚。

Martin Fowler雖然很久以前就說明了 IoC 是什麼,而 DI 又是什麼,但是網路上的文章還是很多人弄錯,有必要說明一下。這邊的解釋沒有任何新意,完全是別人(多半是 Martin Fowler)已經說明過的。

從前,我們寫command line程式時,會要求使用者按照我們的規定輸入資料。比如:先輸入座號、再輸入分數,如此重複五十次完成一個班級的分數輸入作業。然後,用另外一個命令,顯示所有輸入的內容;萬一有錯,再執行一個命令,這個命令會要求我們輸入一筆座號,再輸入分數,僅修改該座號的分數。這樣的執行步驟,都是我們事先決定的,使用者必須按照順序一個一個來;好一點的程式設計者,會提供一些方式讓人中途離開這個流程(比如ctrl-c)。我們的程式寫起來,就是一個接一個的執行一個個指令,這是以前的作法。這樣的程式,寫起來如下:



for i=1 to 50
print "請輸入座號" : input no
print "請輸入分數" : input score
writeSql "insert score(no, score) values(@1, @2)", no, score
next


進入視窗年代後(是,我說的是 Macintosh 的 Window),程式就不是這樣寫了。基本上我們叫出一個可操作的視窗,然後系統進入一個無窮迴圈(其實不是無窮迴圈,不過先這樣想好了)。使用者透過滑鼠操作,點選座號的文字控制項,輸入座號;再點選分數的文字控制項,輸入分數,再點選送出,完成一個操作。在這種寫作程式的方式下,我們的程式比較像是這樣的模式:


var txtNo:TextInput;
var txtScore:TextInput;
var btnSave:Button;
public function initialize():void{
txtNo=new TextInput();
addChild(txtNo);
txtNo.x=10; txtNo.y=50;
txtNo.addEventListener(focusOut, checkTxtNo);

txtScore=new TextInput();
addChild(txtScore);
txtScore.x=10; txtScore.y=90;
txtScore.addEventListener(focusOut, checkTxtScore);

btnSave=new Button();
addChild(btnSave);
btnSave.x=10; btnSave.y=130; btnSave.label="儲存";
btnSave.addEventListener(click, saveScore);
}

private function checkTxtNo(evt:Event):void{
...
}

...


我們寫的程式,只有在使用者做出對應的動作時,才會被系統呼叫,處理該處理的事情,而不再掌管主要的流程。這種程式寫作方式,也就是把程式執行流程的控制權從程式設計者轉移到背後的框架,所以這種程式的架構方式,我們稱為 Inversion of Control。在這種程式的撰寫中,最常用到的就是Template Pattern。

IoC,還可以說明另一個程式庫特性:所有的 Framework,都是 IoC 的,也就是單獨看你寫完的程式碼而沒有該程式庫的背景知識,我們會無法確定執行的流程。不符合以上條件的,就是 Library。所以,Flex是一個 Framework,pureMVC 是 Framework,as3core 則是 Library。另外許多程式庫,雖宣稱是 Framework,但在這樣的標準下,很快就可以判定其實他們應該是 Library,比如個人最近在研究的 AsWing。

這樣的判定有何用處嗎?有,當你需要快速瞭解一個framework時。把framework中,屬於Library的部分先略過,直接切進核心的執行流程(這裡常出現的關鍵字是:life cycle),你就可以很快的掌握該怎麼使用該framework。

以上就是個人關於 Inversion of Control 的瞭解。至於 Dependency Injection,網路上的說明資料就太多了,不需要我再多做說明。倒是有一點可以提:

Inversion of Control Containers and the Dependency Injection pattern 這邊提到兩種decoupling的作法,第一種就是Dependency Injection,第二種是Service Locator。DI 由Java界率先發難,推廣得很好沒問題,但 Service Locator 呢?有人在用嗎?答案是有,而且正是 .Net Framework 的標準作法,只是改名叫做 Provider。

2008年5月6日

Page Inherited Abstract 不能在 VS 2003 中以Design View觀看

這句話的意思是:如果你自己定義了一個繼承自Page的Abstract class,那任何以這個Abstract class延伸的出來的頁面,就不能在Visual Studio 2003中以Design View檢視。

也就是說:

public abstract class BasePage : System.Web.UI.Page {
}

public class adm_user_list : BasePage{
}


其中 adm_user_list是 adm_user_list.aspx的code behind。在這種情況下,adm_user_list.aspx就無法在 Visual studio 2003 下以 Design view 觀看。嘗試這件事情的時候,會得到Type Abstract的錯誤訊息。

也許這本來就是應該的(沒有時間去查清楚Design time support的相關限制),但我還是覺得很奇怪。對所有其他有design time support的server control,當然不應該有abstract的可能,但Page是一個很奇怪的例外。就以上例來說,adm_user_list.aspx已經是BasePage的一個實作子類別,不是一個Abstract Type。而且,就算沒有code behind,所有的.aspx都會由掛在IIS的ISAPI(也就是ASP.NET_xxxxx.dll)先行產生一個class(這裡的例子,會產生ASP.adm_user_list_aspx這個class)。這樣還給我Type Abstract,就會讓人有點三條線的感覺....