1. x86? x64? 傻傻分不清楚...

    雖然常在 x86 / x64 兩種模式下打轉,不過一不留神還真的會吃到虧... 最近平常下班跟工作都碰到 x64 的問題,因此這裡記一下心得,免的以後又吃到虧... 這篇又是無聊的碎碎唸 + 流水帳,沒耐心的人就直接跳過去吧 :D

     

    除非你的程式非得用 C/C++ 不可,否則想要平順的從 x86 跨到 x64 的環境,最簡單的方式還是用 .NET。不過別以為你用 .NET 然後編譯的 PLATFORM 選 ANY CPU 就可以高枕無憂,好戲現在才開始...。

     

    碎碎唸的內容太雜了,先列個摘要:

    1. 16 位元到 32 位元 v.s. 32 位元到 64 位元
    2. x64 + wow
    3. 同時使用 x86 only COM / x64 only COM

     

    過去從 16 位元模式轉到 32 位元模式的路我沒有經歷過,雖然我寫過 16 bits 的程式,不過大都是像俄羅斯方塊,或是貪吃蛇之流的小程式,寫爽的... 也沒怎麼在用,跟本沒有轉移的問題。DOS時代我一直撐著,沒怎麼在用 WIN 3.1,後來 IBM OS/2 出來我有認真的用了一下,直到 Win95 的年代才開始真正在用 Windows...

    不過 Windows 95 用了沒多久,實在受不了它的穩定性 (之前被 OS/2 慣壞了),就直接跳到 NT4 workstation,從此就一路一直用 NT 家族的作業系統 ( NT4、2000、XP... ),大部份時間都是窩在 32 位元的環境下作業。

     

    Microsoft 替 32 -> 64 鋪的路,跟 16 -> 32 不大一樣。16 -> 32 靠的是 v86 mode 來提供 16 位元的相容模式,在 windows 下則是以 wowexec 把所有的 16 位元成式集中在這個 process 下執行。不過到了 32 -> 64 的年代,提供相容環境的作法已經不一樣了,直接在 user mode 下提供相容的模式,唯一的限制是同一個 process 不能同時存在兩種模式的 code,要嘛 32 要嘛 64,一定要選邊站就是了。只要你不碰到 COM 這類 in-process 的程式,都不會有太大的問題。

    另外系統的目錄也開始分兩份...。安裝過 64 位元版的 windows 就知道,Program Files目錄變成兩個 ( Program Files / Program Files (x86) ),而 System32 目錄也變兩個了 ( System32 / SysWow64 ),其它像是 Registry 等也都有兩份...。

     

    談談我碰過的幾個案例,工作上碰到的例子很多,其實自己寫的都是 script / assembly,都不大需要跟平台榜在一起。不過寫過 ASP / VB 的都知道,拿掉 COM 元件的話,大概就什麼都不剩了... 只要你需要的 COM 元件有一個沒有提供 64 位元版,很抱歉... 你就要乖乖回到 32 位元模式...。像 JET / ODBC driver 就沒有 64 位元版...。不過 .NET 倒是得天獨厚,因為有類似 Java VM 的 CLR 擋在 .NET 及 OS 之間,因此絕大部份的 .NET 2.0 程式碼都可以自在的跨 x86 / x64 兩種模式執行,除了... 除了我碰到的情況之外 -_-。

     

    討厭的是這些自己寫的 .NET / SCRIPT 程式,沒有特別指定的話當然都會用原生的 64 位元模式執行,直到出錯你找半天找不到問題,無意之間才想到是 32/64 的鳥問題...,害我抓最久的就是 .NET 包裝的 SMTP 元件,CDO 沒有提供 64 位元版,但是 .NET 編譯成 ANY CPU 模式卻又沒有任何問題,直到執行時才給你 run time error ...。另一個例子是我自己在用的 WPF Image Codec... 因為我有用到 CANON 提供的 RAW CODEC,但是 CANON 遲遲不肯推出 64 位元版... Orz,我只好將就著點在 Vista x64 下跑 32 位元的版本。第一步就是重新 compile 自己寫的 Media Filer,通通編譯成 x86 platform。

     

    程式看起來跑的好好的,不過問題現在才開始。家裡大人常愛用相機拍 AVI 下來,原本的程式是叫用 Media Encoder 把 AVI 重新編碼程我要的規格。32位元下呼叫 CSCRIPT.exe, 然後再叫用 WMEnc.vbs 出來轉檔... 才發現問題大條了,怎麼找不到元件? @_@

     

    我一直以為 Microsoft 的東西,64位元版都會一次安裝兩種版本... 結果原來要個別去抓 32 / 64 位元的 Media Encoder 9 回來裝才能用... 好,硬碟就花下去,裝兩種就裝兩種...。執行過後又發現怪怪的,透過 media encoder components 啟動 media encoder 轉檔,怎麼轉完就停在 100% 不會自動關掉? 實在是搞不定,試了 64 位元版的沒問題,只好想辦法改用 64 位元版的 media encoder ...。

     

    它ㄨ的,問題一個接著一個來... 弄到這裡才發現,32 位元模式下的程式,沒辦法叫 64 位元版的 COM 元件來幫我做事,Orz... 如果換 64 位元的話,又用不到 Canon Raw Codec ...。最後沒辦法,只好程式大搬家,拆成幾個獨立的 .exe,各自用適合的版本運作... 以功能來說,這樣已經達成我的目的了。正好並行效果不大好的 Canon Raw Codec,在這樣的模式下還能吃掉四核CPU的80%運算能力,算是偷笑了... 這篇雜七雜八的 x64 / x86 大亂鬥就到這裡為止,謝謝觀賞 :D。

     

    image

    2008/07/23 .NET

  2. Canon Raw Codec 1.3 Released !

    不知為何突然想到要上網看看,有沒有新版的...,沒想到還真的有,嚇...

    不過都是無關痛癢的 update (對我來說啦),除了新機種的支援之外,更新說明裡沒有提到效能的增進,也沒提到 x64 的支援什麼時後才會有,嘖嘖...。

    主要的修正,一方面是增加 EOS Kiss X2/ EOS DIGITAL REBEL XSi/ EOS 450D DIGITAL 2 的支援 (大概是像當年 1.2 出來之前,G9 的 .CR2 都解不出來一樣的狀況吧),還有 "正式" 支援了 Vista SP1。舊的 1.2 我在 Vista SP1 也一直都用的好好的,不知道到底差在那?

    就睹它可能 "順便" 修正了一些小 BUG 吧,既然有新版的就來試看看。下載網址在這裡:

    http://www.microsoft.com/prophoto/downloads/tools.aspx

    OS 選單選了 "Windows Vista" 後才會出現,Canon RAW Codec 1.3,請享用 :D

     

    --

    [2008-07-12 補充]

    1.3 版的 CODEC 不知道什麼地方跟 1.2 版不大相容 @_@,裝了我的歸檔程式就跑不動了。更新說明裡有提到一段,說是新版的 CODEC 跟 Microsoft Pro Photo Tools 不相容,如果有使用這軟體的用戶請不要升級...

    還沒仔細去追原因,就還原回 1.2 了。上去看了一下版本還真有點亂 @_@,1.2版就有兩個,一個檔名是 RC120UPD_7L.EXE (古早的版本),這幾天又放了一份新的,檔名是 CRC120UPD_7L.EXE ...

    然後新的 1.3 版檔名是 RC130UPD_7L.EXE ....

    測試之後只有最古早的 RC120UPD_7L.EXE 我的歸檔程式可以用,另外兩份都不行... 加上跟 Microsoft Pro Photo Tools 不相容 (這是 MS 用 .NET 開發的小工具),所以有在用 .NET 3.0 + WPF 的人就不要更新了,以免出包 @_@

    2008/07/10 有的沒的

  3. 為什麼一堆推文的按鈕都不見了?

     

    image

    前兩天突然發現,怎麼一堆文章原本有推文數字的,怎麼都不見了?

     

    image

    網站有問題怎麼可以不追查個水落石出? 連到推推王找一下當時的推文... 耶? 還在啊,旁邊還有推文記錄...。

     

    image

    怪的是從推推王點回來看我的文章,Oops!

     

     

    越看越不對,把網址印出來比對一下才發現,我這邊的網址已經不一樣了!! 

    http://columns.chicken-house.net/post/FlickrProxy-1---Overview.aspx (推推王那邊的網址)

    http://columns.chicken-house.net/post/FlickrProxy-1-Overview.aspx (我這邊實際的網址)

     

     

    真妖獸,馬上聯想到前幾天升級 BE1.4 可能會有影響,就搬出 VSS 來比對一下,果然 1.3 跟 1.4 在自動產生 SLUG (SLUG 就是指 POST 網址後面那一串) 的規責有調整過:

    image

     

     

    嗯,肉眼看的出的調整,包括逗號被移掉,連續多個 -- 也會被替換成 - ,這個案例就是原網址的 "---" 換成 "-" 後就連不到了 :@

     

    本來想寫個程式修一下,後來想想跟本沒幾篇,就直接到推推王改掉了事,哈哈... 結案!

    2008/07/07 .NET BlogEngine.NET

  4. [BlogEngine Extension] PostViewCount 1.0

    這篇拖好久了,本來上禮拜要寫,結果正好碰到 BlogEngine 1.4 RELEASE,就一直拖到現在...。之前找到一個給 BlogEngine 用的 Counter Extension,以功能來說還不錯用,不過用久了就開始不滿足了。正好翻到這篇教學文章,算是官方文章了吧 (BlogEngine 作者之一寫的教學文)? 所以就動起自己寫的念頭。舊的其實沒什麼不好,不過缺了這幾項我想要的功能:

    1. 只有計 Total Count (謎: 不然你要 counter 記什麼?)
    2. 資料檔的結構及 I/O 的設計有點 Orz...
      1. 讀寫 XML 的 CODE 寫的很... Orz
      2. 沒有處理同時讀寫的問題 (後面寫的資料可能會蓋掉前面的,我的點閱率不知道少了幾百次 :D)
      3. 要有 CACHE 來加速處理速度

     

    既然要重寫,當然要寫個合用的. 底下是我對於新的 COUNTER 期望:

    1. 要能記流水帳。
      流水帳就是不只要記總數,我還要知道每次點閱的時間,來源 IP ... 等等
      ( darkthread 指示: 當你流量大的時後就不會去在意這個了... Orz, 真是一針見血... )
    2. 要處理多執行緒下讀寫資料檔的問題,這部份 Code 必需為 ThreadSafe。
    3. 妥善利用 CACHE,降低 (2) 的複雜度。
    4. COUNTER COMPACT
      配合 (1) 的需求,流水帳記錄太多的話也會造成問題,COUNTER要能適當的刪除舊的 HIT RECORD。

     

    決定好後就動工了! 既然問題都圍繞在 data storage 上,先來看看原來的檔案格式:

    原有的 ~/App_Data/PostViews.xml 片段:[copy code]
    <?xml version="1.0" encoding="utf-8" standalone="yes"?><posts>    <post id="b43ec49e-e9a2-4696-bcc7-2ba1667ecda9">781</post>    <post id="f1411c11-11ed-4f35-b383-0c6c8b2b963a">603</post>    <post id="e7b57492-652b-4247-bcd4-bc3ac2e56318">589</post>    <post id="7e2c2c88-240c-40ea-8477-2c96880adc8e">556</post>    <post id="0fda9c32-d294-4f09-85cd-41dab8e677cb">678</post>    ......</posts>
    
       1:  <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    
       2:  <posts>
    
       3:      <post id="b43ec49e-e9a2-4696-bcc7-2ba1667ecda9">781</post>
    
       4:      <post id="f1411c11-11ed-4f35-b383-0c6c8b2b963a">603</post>
    
       5:      <post id="e7b57492-652b-4247-bcd4-bc3ac2e56318">589</post>
    
       6:      <post id="7e2c2c88-240c-40ea-8477-2c96880adc8e">556</post>
    
       7:      <post id="0fda9c32-d294-4f09-85cd-41dab8e677cb">678</post>
    
       8:      ......
    
       9:  </posts>
    

     

    很普通的格式,配合我的需求,新的檔案結構我打算改成這樣:

    新的 ~/App_Code/counter/{post-id}.xml 檔的片段內容:[copy code]
    <?xml version="1.0" encoding="utf-8"?><counter base="8828">  <hit time="2008-06-29T12:42:51" referer="" remote-host="66.249.73.185" user-agent="Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" />  <hit time="2008-06-29T13:04:15" referer="http://www.google.com.tw/search?complete=1&amp;hl=zh-TW&amp;cr=countryTW&amp;rlz=1B3GGGL_zh-TWTW237TW238&amp;q=%E9%A6%99%E6%B8%AFg9&amp;start=30&amp;sa=N" remote-host="124.10.1.162" user-agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9) Gecko/2008052906 Firefox/3.0" />  <hit time="2008-06-29T13:04:20" referer="" remote-host="66.249.73.185" user-agent="Mediapartners-Google" />  ......</counter>
    
       1:  <?xml version="1.0" encoding="utf-8"?>
    
       2:  <counter base="8828">
    
       3:    <hit time="2008-06-29T12:42:51" referer="" remote-host="66.249.73.185" user-agent="Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" />
    
       4:    <hit time="2008-06-29T13:04:15" referer="http://www.google.com.tw/search?complete=1&amp;hl=zh-TW&amp;cr=countryTW&amp;rlz=1B3GGGL_zh-TWTW237TW238&amp;q=%E9%A6%99%E6%B8%AFg9&amp;start=30&amp;sa=N" remote-host="124.10.1.162" user-agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9) Gecko/2008052906 Firefox/3.0" />
    
       5:    <hit time="2008-06-29T13:04:20" referer="" remote-host="66.249.73.185" user-agent="Mediapartners-Google" />
    
       6:    ......
    
       7:  </counter>
    

     

    其中, /counter/@base 是給你作弊用的,這數字你填多少就是多少,然後再加上底下有幾筆 <hit /> 記錄,總數就出來了。很簡單的格式,而流水帳就是記在 <hit /> 這個 XML ELEMENT 的 ATTRIBUTES 上。目前記的有時間,IP,REFERRER 而以。等到網站人數暴增 (幻想嘛?),COMPACT的動作就免不了了,預留的 /counter/@base 就派上用場了。COUNTER 在必要時就能刪掉多餘的 <hit /> 記錄,再把刪掉的筆數加到 /counter/@base 上,讓最後點擊總數不變,又能控制記錄檔的大小。

     

    邏輯確定後就可以開始動工了,不過另外要解決技術問題,就是 ThreadSafe 的部份。這部份讓我煩惱了一下,因為在 File System 就提供了 FILE LOCK 的機制可以用,不過取得 LOCK 失敗是會引發 EXCEPTION,而不是像其它的 THREAD 控制機制會 WAIT。因此最後我決定 FILE LOCK 的機制做第二層保障 ,主要的 LOCK 機制還是自己來,用基本的 Monitor 來實作。要實做 LOCK 的前題,是要有明確的 LOCK "對像"。兩個 thread lock 同一個物件,後面 lock 的 thread 會被 block 暫停執行,直到前一個先 lock 同一個物件的 thread 釋放之後才會被喚醒,因此要先解決兩個同 ID 的 COUNTER 能拿到同一個物件,才能實作 LOCK 機制。這物件就好幾位合適的候選人,第一種方法是 COUNTER 本身,第二種方法則是替每個 counterID 產生一個無用的物件,就單純拿來 LOCK 用。

     

    要用 (1) 成本太高,一來就必需實作 Flyweight 這個 design pattern,這個設計模式並不難,只要實作 factory pattern再搭配個 Dictionary<string, Counter> 物件就可以搞定,但是我最後沒有選擇這個作法。因為最糟的情況下有可能會讓整個系統可能會用到的 counter 通通被放到這個 dictionary ,沒有被釋放回收的機會,因為沒有明確的時間點可以把這物件從 dictionary 移掉,移不掉的話永遠就會留著一個 object reference 指向這 COUNTER 物件,reference 只要存在,它就永遠不會被 GC 收掉...。不過這還是有解,只要用 WeakReference 就可以解決了,不過我只是要作個簡單的 Counter,搬出這一堆東西會不會太過頭了?

     

    因此我選擇了第二個方法。一樣用 flyweight pattern,只不過我放的是拿來 lock 的物件。我是直接 new object() 就拿來用了,物件很小我就不用耽心建立太多個又不能回收的問題...,而 counter 就讓它回歸最簡單的用法,需要就 new 一個出來,用完就丟著等著被回收。

     

    每次都是講的話比 CODE 還多,來看看程式碼:

     

    COUNTER 物件的 SYNC 機制[copy code]
            // 所有 COUNTER 用的 SYNC 物件 DICTIONARY        private static Dictionary<string, object> _counter_syncroot = new Dictionary<string, object>();        // 取得這個 COUNTER 用的 SYNC 物件        private object SyncRoot        {            get            {                return Counter._counter_syncroot[this._counterID];            }        }        private Counter(string counterID)        {            this._counterID = counterID;            //            //  建立 SYNC 物件 (如果沒有的話)            //            lock (Counter._counter_syncroot)            {                if (Counter._counter_syncroot.ContainsKey(this._counterID) == false)                {                    Counter._counter_syncroot.Add(this._counterID, new object());                }            }            //  略 ....        }        public void Hit()        {            lock (this.SyncRoot)            {                //                //  LOCK 後再開始更新檔案內容。 程式碼 略...                //            }        }
    
       1:  // 所有 COUNTER 用的 SYNC 物件 DICTIONARY
    
       2:  private static Dictionary<string, object> _counter_syncroot = new Dictionary<string, object>();
    
       3:  // 取得這個 COUNTER 用的 SYNC 物件
    
       4:  private object SyncRoot
    
       5:  {
    
       6:      get
    
       7:      {
    
       8:          return Counter._counter_syncroot[this._counterID];
    
       9:      }
    
      10:  }
    
      11:  private Counter(string counterID)
    
      12:  {
    
      13:      this._counterID = counterID;
    
      14:      //
    
      15:      //  建立 SYNC 物件 (如果沒有的話)
    
      16:      //
    
      17:      lock (Counter._counter_syncroot)
    
      18:      {
    
      19:          if (Counter._counter_syncroot.ContainsKey(this._counterID) == false)
    
      20:          {
    
      21:              Counter._counter_syncroot.Add(this._counterID, new object());
    
      22:          }
    
      23:      }
    
      24:      //  略 ....
    
      25:  }
    
      26:  public void Hit()
    
      27:  {
    
      28:      lock (this.SyncRoot)
    
      29:      {
    
      30:          //
    
      31:          //  LOCK 後再開始更新檔案內容。 程式碼 略...
    
      32:          //
    
      33:      }
    
      34:  }
    

     

    這問題解決掉後,剩下的就是單純把我要的邏輯實作出來,這部份我相信讀者的程度都不用我多講了,有需要的看 CODE 就看的懂。請直接下載最後面的程式碼就好。

     

    另外一個要提一下的是跟 BlogEngine 本身 Extension 相關的,這部份也花了點時間研究該怎麼寫。BlogEngine 的 Extension 寫法比較特別一點,一般這種外掛都是採 Provider 的方式實作 ( factory pattern 加上 abstract class ),先定義好這個 Provider 能作什麼事,然後每個寫 Extension 的人就自己繼承這類別來修改,再靠 Factory 動態的建立正確的 Extension 物件來使用。不過在這部份 BlogEngine 採用完全不同的作法來設計它的架構: Event Handler。

     

    Provider 依賴的是事先定義好的 ProviderBase (abstract class) 類別。這個類別定義了多少東西給底下的人覆寫,就決定了寫外掛的人能處理多少事。好處是簡單,架構清楚。缺點是能讓你擴充的功能,在 DESIGN TIME 就決定了,要多一個能 "擴充" 的地方,就得改 ProviderBase 類別定義,這很有可能會讓現有的 Extension 不能跑...。換成 EVENT 的方式就沒有跟程式碼綁的那麼緊了。多了新的功能,多定義一些事件就夠了。BlogEngine 就是採這種方式來實作它的 Extension .. 

     

    另外比較特別的是,BlogEngine 替每個 Extension 規劃好存放設定的地方。 1.3 版是所有的 Extension 共用一個設定檔, 1.4 則是有獨立的設定檔可以用。不過這些改變倒是沒有影響到它提供的 API。對於 API 來說,設定檔提供每個 Extension 一個像是 DataTable 那樣的 data storage, 讓你自訂欄位名,型別,然後能讓你一筆一筆的加進去,可以有多筆資料,而 BlogEngine Runtime 會負責幫你管理好這些設定。

     

    這部份帶入門就好,用法還是去查官方文件比較快。我簡單貼一下這部份 CODE 跟畫面上提供的設定頁面給大家看看:

    準備設定值的 SCHEMA 及載入目前的設定值[copy code]
        public PostViewCounter()	{        Post.Serving += new EventHandler<ServingEventArgs>(OnPostServing);        ExtensionSettings settings = new ExtensionSettings("PostViewCounter");        settings.AddParameter(            "MaxHitRecordCount",             "最多保留筆數:");        settings.AddParameter(            "HitRecordTTL",             "最長保留天數:");        settings.AddValues(new string[] { "500", "90" });        //settings.ShowAdd = false;        //settings.ShowDelete = false;        //settings.ShowEdit = true;        settings.IsScalar = true;        settings.Help = "設定 counter hit records 保留筆數及時間。只有在筆數限制內且沒有超過保留期限的記錄才會被留下來。";                ExtensionManager.ImportSettings(settings);        _settings = ExtensionManager.GetSettings("PostViewCounter");    }
    
       1:    public PostViewCounter()
    
       2:  {
    
       3:        Post.Serving += new EventHandler<ServingEventArgs>(OnPostServing);
    
       4:        ExtensionSettings settings = new ExtensionSettings("PostViewCounter");
    
       5:        settings.AddParameter(
    
       6:            "MaxHitRecordCount", 
    
       7:            "最多保留筆數:");
    
       8:        settings.AddParameter(
    
       9:            "HitRecordTTL", 
    
      10:            "最長保留天數:");
    
      11:        settings.AddValues(new string[] { "500", "90" });
    
      12:        //settings.ShowAdd = false;
    
      13:        //settings.ShowDelete = false;
    
      14:        //settings.ShowEdit = true;
    
      15:        settings.IsScalar = true;
    
      16:        settings.Help = "設定 counter hit records 保留筆數及時間。只有在筆數限制內且沒有超過保留期限的記錄才會被留下來。";
    
      17:        ExtensionManager.ImportSettings(settings);
    
      18:        _settings = ExtensionManager.GetSettings("PostViewCounter");
    
      19:    }
    

     

     

    對應的設定頁面:

    image

     

     

     

    最後講了半天,真正想自己動手寫的人應該不多吧 :D,只是想下載回去裝來用的人就不用聽我前面廢話一堆了,只要下載這檔案,放到 ~/App_Code/Extension 下,就安裝完成了... 咳咳,連安裝手冊都省了。檔案 COPY 好後就會在 Extension Manager 裡看到我寫的外掛,就可以開始用了。有任何意件歡迎留話給我 :D

     

    檔案下載: http://columns.chicken-house.net/wp-content/be-files/PostViewCounter.cs

    2008/07/06 .NET ASP.NET BlogEngine Extension BlogEngine.NET 作品集 技術隨筆

  5. [BlogEngine.NET] Widgets

    原本只是想找找有沒有 BlogEngine.NET Extension 存放自訂設定值的說明,無意間找到這個令人 Orz 的東西,BlogEngine.NET 專用的 Widgets ...

    Widgets 這名字到處都有人用,指的不外乎是能留在桌面或是網頁的 "小工具"。拜物件技術所賜,這種東西越來越好作了。當年還在用 ET 的時代,一篇報告要插張圖,就有一堆技巧得拿出來用... 先下好控制碼把位子空出來,列印... 然後再印張圖,貼上去..

    中間年代有些工具可以直接插圖的就不管了,真正有革命性的改變,是 WIN3.1 時代的 OLE (Object Linkage and Embedded) ,其實這也不是 Microsoft 先發展出來的,較早是 APPLE 的 OpenDoc ... 這些物件的技術開始可以讓兩種獨立的 AP,在同一份文件或是畫面上共同處理一樣的資料...。

    幹嘛扯這些? 因為我碩士論文就是弄這些五四三的物件導向技術,哈哈...。沒什麼,只是看到 BlogEngine Widget 這麼好寫,沒幾行 CODE 就搞定,那當年我的研究論文跟本是寫好玩的.. @_@

     

    http://rtur.net/blog/post/2008/03/24/BlogEngine-Widgets-Tutorial.aspx

    原本要找 Extension, 後來逛到這位強者的網站,它擺了一段很簡單的 CODE,就是之前研究過一陣子的 FlickrNet。它寫了一個簡單的 USER CONTROL,透過 FlickrNet 抓幾張圖回來,顯示在 User Control 的範圍內。

    另外他寫了另一個 User Control,用來編輯第一個 User Control 可能會用到的設定值,畫面上幾個 Text Box 也搞定了。

    然後,放到 BlogEngine.NET 的 ~/Widgets/ 目錄下就好了? 簡單到想打人...

     

    現在回頭來看看,這樣做出來的 widget 能幹嘛? 我現在用的版面,右側有一堆 "BOX",有 Google 的廣告,有 "安德魯是誰?",有最新回應...,沒錯,在 BlogEngine 1.4 之後,這些就變成真正的元件了。大概就像 Microsoft 的 Web Parts 一樣。網頁的主人可以很簡單的在畫面上拉一塊新的 "widget" 出來,直接用拖拉的方式放到喜歡的位子,按下 [EDIT],畫面就會切到編輯用的 User Control,OK就存檔...

    要做到這堆事,你只要會寫 USER CONTROL,照 BE 的規舉,繼承指定的 CLASS,把檔案放到指定的目錄就好了... Orz

     

    有時後東西弄的太簡單也很令人洩氣,尤其是 BLOG 剛搬完家,差不多要完工時 @_@,才發現 BlogEngine 在 2008/06/30 推出 1.4 版,主要就是加上 widget 的功能... 哈哈,那個小熊子應該比我更想哭吧 (H)

     

    不過事情倒還很順利,之前有作好準備,花了一兩個小時試一下就動工了,動啥工? 看看底下的版本... 已經搬到 1.4 版了 :D,唯一美中不足的是,過去花太多工夫在這個樣板上面,所以只好連樣板一起搬過來... 而這個樣版並不支援 Widget 的功能。看來又有得忙了...

    2008/07/02 BlogEngine.NET 技術隨筆 有的沒的