2014年5月20日 星期二

ASP.NET Web Form 對應優先設計 (Mapping-First Design) 第三彈 - 被遺忘者

PM 常說 先求有 再求好

PG 就說 no problem!

於是三兩下搞定了 CRUD 交給 USER

然後立馬被玩壞

因為 USER 總是能夠超越極限 在 TextBox 裡面塞入無限的可能性

顯而易見 我們需要類似這種東東 防止 USER 的無限加速器全開

或許反射性的就想到工具箱裡面的好碰友...

but that was out of fashion





既然前面兩彈 大費周章的 弄了一個 values mapping system

又在每彈結尾留可有可無的伏筆

自然就是要在上面搞些花招

已達更加無腦的境界





首先從 Map 發想

我希望這樣子來使用欄位驗證

這裡由於驗證可能是複數 所以使用 ICollection

然後陣列可以當作 ICollection 的實體





再來就是 中二到不行的 抽象類 Judgement





之所以不想命名成 validation 之類的 只是因為不想跟 其他欄位驗證的類別混淆

並非因為這個傢伙

或這個傢伙





審判的細節 靠子類實作

至於實作的細節 平常怎麼幹 就怎麼幹囉

隨便貼一個





觸發審判的方式也沒什麼特別

就在 Buster 裡面挖個方法 觸發的時機 高興怎樣就怎樣囉

這邊是在 Buster 放個 IsAllInnocent 屬性 取得該屬性時 會觸發驗證

該死的 Click 事件 獲得了 欄位驗證 並且避免了 重度脂肪肝

Great Success





標題梗 again

2014年5月4日 星期日

ASP.NET Web Form 對應優先設計 (Mapping-First Design) 第二彈 - 百變星君

第一彈 之後 現在再來玩些變化

因為世上無可能有網頁 全部都只用 TextBox 的

在 CheckBox RadioButton DropDownList 參上之前 先來看看 先前第一彈 留下了什麼伏筆




1. 神手會失誤 庸手會失憶

每次都必須宣告 ValueMapBuster 變數 然後在 Page_Load 裡面 SetUpValueMaps Mapping 機制才會奏效

但是 神仙打鼓有時錯 每次都要 Key 這些固定 CODE 實在讓人 KEY 肚藍

所以我們需要 把這些給西 封裝起來 放到基底類裡面

再靠抽象方法 約束後人 必須實作 SetUpValueMaps





2. 噁心的 人形蜈蚣 代碼

什麼是 人形蜈蚣 代碼?

something like...

or like...

咦 好像沒什麼不對呀?

這樣寫的確 沒有任何錯誤 程式依舊能跑

但是這是一個造成 難以維護的 壞味道

如果哪天 條件增加 減少了 勢必要到處去修改這些蜈蚣

況且 這麼多的判斷式 如果只是為了 "其中一種狀況" 發生的時候該做什麼 "對應的事" 的話

其他的 判斷式 在這裡就顯得有點擋路

所以我們需要 善用多型

首先把原本的 ValueMap<T> 變成抽象類


GetValue 和 SetValue 則依靠 抽象方法實作 GetDefaultValue 和 SetDefaultValue 的細節 (就是原本蜈蚣的部分)


再來就是 "多型" 的部分 原先 Mapping 的時候 需要考慮各種控制項的可能

現在則是每種控制項 增加一個獨立的類別 並且繼承 ValueMap<T> 來實作細節

這裡 又會遇到一項設計上的考量 有時候 某個值不見得只靠一種控制項 就能表現

最顯而易見的就是 RadioButton

一群的 RadioButton 實際上只對應某個欄位的列舉值

所以分成 單體 跟 群組 兩種類型的 Map 來應付

單體

TextBoxMap:預設 Map Text 屬性


DropDownListMap:預設 Map SelectedValue 屬性


CheckBoxMap:預設 Map Checked 屬性


HiddenFieldMap:預設 Map Value 屬性


群組

GroupMap:由於是複數控制項表示一欄位值 所以必須要 自行設定 OnGetValue 跟 OnSetValue


CheckGroupMap:專門處裡 RadioButton 或 CheckBox 群組 預設 Map Checked 屬性





上面改了一堆 實際上究竟如何呢? 馬上來把之前的一堆 TextBox 改成 百變星君

首先改 UI 恕我不貼 HTML -.-...


再來當然是...超超超長 Map

呼...好累...然後呢?

什麼然後? * w * ??? 沒有然後了呀

沒錯 Mapping-First 在 Map 完了之後 大半就完成了

除了 SQL 多了些欄位之外 Click 事件內的 Code 無須更動



難道這是傳中的 Two-Way Data Binding!! (誤)




咦?如果我 TextBox 亂打 不合型別會怎樣?

呵呵呵 當然是會壞掉呀 因為現在還沒 實作欄位驗證

敬待 下回分曉 ˊ_>ˋ




Déjà vu?????????????




標題梗:

2014年4月29日 星期二

ASP.NET Web Form 對應優先設計 (Mapping-First Design) 第一彈 - 提線木偶

如果你沒聽過什麼 對應優先設計 (Mapping-First Design) 的話

先別急著 估狗 偽基 因為...

這名詞 是我掰的 :P





It was long long ago...

那個時代 還沒有 ASP.NET MVC (或者有只是無人問津)

拉控項 Click 事件 寫 CODE 天經地義

一個 Click 事件 幾千行 CODE 家常便飯





過了一陣子 開始流行 3-tier n-tier

主要把 程式分成 表現層 邏輯層 資料存取層 封裝起來 降低耦合程度 增加可維護性

但是老實說 控制項 跟這些架構什麼的 相性 很差

很多時候 要額外寫一堆轉換的代碼

像是...

參數接控制項屬性

string name = TextBox1.Text;

控制項屬性接參數

TextBox1.Text = name;

當然 "絕不會" 只有一點點參數 跟 固定種類的控制項

當 TextBox CheckBox RadioButton DropDownList 參在一起做成撒尿牛丸

資料庫欄位 跟你玩 85度C ( c = column )

這時候...

真嗣表示:這時候,只要笑就可以了





但是這煩惱其實沒有困擾多久 因為後來 ASP.NET MVC 出現了

Model-First~

Model Binding~

ORM~

各種風騷技術

一開始自然覺得很硬 各種約束 奔放不起來

但是玩久了之後 發現就那麼回事而已

招式套路 基本會用上的就那幾招

控制項 神馬的 不用鳥他 潮爽der~

View 自由發揮就好了





因緣際會之下 又回來玩了一下 Web Form

之前的問題又回來困擾著我

但是意外發現 .NET 4.5 Web Form 竟然也吃 Model Binding 跟 Routing

傳說中的 瘟疫同化???





但是 4.0 或 之前的 專案 仍然無解 (誰也不敢貿然升等)

於是就想 那就自幹吧 寫個小元件來搞定他

試過很多奇奇怪怪的方式 最後都覺得不好

感覺上就是 寫了一些 偽 Model Binding 的類別

要搞 Model 何不直接用 MVC?

要搞 Model Binding 何不直接用 .NET 寫好的?

搞這些花招 又不能直接輸出到頁面上 就算真的可以直接輸出到頁面上的話 控制項又要幹嘛?

取值 轉物件 運算 塞值回去 繞一圈 這樣真的比較有意義?

想了許久...還是沒有滿意的做法





直到某天我看到小溪裡的小魚逆流而上

我頓時領悟到 根本不需要 Model 呀

寫多了 MVC 習慣用 MVC 來思考 自然怎樣都像在抄 MVC

回歸本質來想想 問題跟需求到底是什麼

首先 邏輯層 資料存取層 這兩層 沒什麼大困擾

不管是 Web Form 還是 MVC 都只是一些 物件導向的把戲

頂多差在 資料存取

Web Form 通常用 ADO.NET 搞

MVC 通常用 ORM 搞

問題還是在 表現層

MVC 靠 Model Binding 進 controller 的時候 就有現成的 Model

然後 資料存取也能沿用這些 Model 一氣呵成

但是 ADO.NET 在操作的時候 並沒有一定要使用 具體型別(Model)的要求

SqlParameter 只要給他 名稱 跟 值 就能用了 (保險點再給個 SqlDbType)

把 input 轉成 POCO 再給各層使用 在 web form 裡面的意義並不大 尤其只用 ADO.NET 來資料存取

(Plain-old CLR Object) 永續儲存無知物件 <= 中譯超有梗

只要想辦法處裡 "對應" 就好了

設法紀錄 控制項 跟 資料庫欄位的對應關係 之後就可以依靠對應關係來交流





不靠 Model 屬性名稱來做對應的時候...

Dictionary<TKey, TValue> 是你的好基友

Value 用 object 就好了 但是重點是 Key 該用什麼?

string 怕打錯 int 怕太抽象...(這些都是魔術化參數)

別忘了我們的 好碰友 列舉!! (列舉又能變 string 又能變 int)

先標記好欄位名稱當 KEY

然後老梗 拉控制項 先全用 TextBox 試水溫

再來 設計一個 ValueMap 物件 用來記錄 Key 跟 控制項 的對應關係

還有最主要的 GetlValue SetValue 方法

這邊稍微解釋一下

Func<T> OnGetValue 跟 Action<T> OnSetValue 是用來處理自定義的 取/設 值 的方式

否則預設的情況下 取/設 值 針對慣用的屬性

TextBox.Text

DropDownList.SelectedValue

RadioButton.Checked

CheckBox.Checked





有了 ValueMap 之外 還需要一個專們來操作 ValueMap 集合的 物件

這裡的 Buster 是指終結者 :p

然後就是來使用它

SetUpValueMaps 可以使用 partial class 的方式 包在另一頁 會乾淨一些 當然 見仁見智

最後就剩 Click 事件裡的東東啦

通常各家都有祖傳私釀的 SqlHelper 來玩 ADO.NET 或者用 enterprise library 也 OK

因為 參數吃 DataRow 跟 SqlParameter 要怎麼變出來 都無所謂

現在只剩兩行...

實際功能 DEMO 則不值一提 就是 查詢 / 更新 顯示在 TextBox 上面

但是樸素的外表又豈能看出 Click 事件 裡面竟然不需要碰到 噁心的控制項 這種美麗內在呢?





咦?如果我 TextBox 亂打 不合型別會怎樣?

呵呵呵 當然是會壞掉呀 因為現在還沒 實作欄位驗證

敬待 下回分曉 ˊ_>ˋ





標題梗: