2017年2月20日 星期一

the DevOps journey (1) - 敏捷開發不相信時程預測?

這一篇,我們來討論敏捷開發中怎麼看待時程預估,以及迭代開發的重要性…

到底專案時程能不能預測?

這是一個常常困擾初踏入敏捷開發領域的新手的問題。

你一定聽到過有人說(甚至,其實上一篇推薦的Martin Fowler的文章中也提到過),敏捷開發不太相信可以進行準確的時程預測,我特別用『預測』這個字,而非預估。中文很有意思,這兩個字很接近,但有那麼一點點的不同。

前面提到過,既然真實世界裡面的需求根本不可能固定,開發人員的素質(每個人每天的產出)也不太可能統一,那我們幾乎已經宣告無法掌握軟體開發專案中,最重要的兩個變因,那這樣怎麼可能精準的預測出開發時程呢?

Martin Fowler在早期的文章中,幾乎是直接告訴你,預測是不可能的。

但這件事情非常弔詭,大概所有開發人員都明白,在需求不確定的狀況下,要精準的預測專案時程、計算出人天數,是幾近不可能的事情。但好笑有趣的地方就在於,幾乎所有的軟體專案的業務或PM,都會要求你在專案起始前,在一切模糊的前提下,估出人天數以便於報價

壓在合約裡面的驗收日期和報價耶!? 難到不需要更詳細的資訊以便於精細計算嗎?

這是繼上一篇提到的軟體開發迷思之後,另一個超級經典、行之有年、卻嚴重違反常識/常理的軟體開發迷思。同樣的問題又來了,難道從來沒有人覺得哪裡怪怪的嗎? 我相信有,但你會碰到各種壓力,告訴你整個業界都是這樣幹的,你區區一個程式設計師想改變這個慣例? 不可能。

因此,開發人員只能習慣性的在時程預估裡面保留一些buffer,業務/PM報價時再加一些Buffer,然後客戶的採購砍一些作為折扣,done,成交。後面就看彼此的運氣了…

不能預估,怎麼辦?

這篇文章一開始的那張圖很貼切,它描繪出了理想狀況與真實世界之間的差異,上一篇說過,兩個軟體專案的需求不可能完全一樣,因為完全一樣你就根本不需要新的專案,買個套裝軟體或直接copy一份即可。因此,我們知道每一個軟體專案都是新的開始,既然是新的開始,沒做過的事情要預估時間,這本來就是一種賭博

這也是軟體開發和工程專案差異很大的地方,傳統的工程專案施工較容易預估人天,因為施工方法固定,需求固定,常常只是在可以控制變因的狀況下,重新做一次而已,但軟體開發不是,每一個專案都是一場新的冒險。

我常開玩笑的跟業務說,你真要我這樣報價,乾脆就隨便猜一個數字,你讓我在模糊的狀況下進行時程和成本的預測,估出來的金額,跟你用猜的其實也差不了多少。需求越模糊,我猜(給出)的範圍就越大(例如,150萬~300萬之間,這是我的預估,你在中間隨便選一個數字報價吧)。另外,越有經驗的開發人員,因為考慮的越多,估出來的時程就可能越保守(這某種程度上解釋了,為何同一個需求,新手估出來的金額往往比較低)。

不過,在台灣軟體專案的報價現在已經變成一種藝術,而非可以討論的科學方法,如果可以,我們當然希望能夠採用time-materials的報價,但往往甲方很難接受,如何解決? 在這邊我們先跳過這個議題,(如果有興趣可以私下問我),我們回過頭來談談,如果開發時程不能預估,那專案管理該怎麼進行? 答案就在迭代…

用迭代開發解決問題

敏捷開發中的迭代行為,簡單的說就是把一整個開發循環,切成一個一個迭代(iteration),如果採用Scrum(迭代開發法的一種),那每一個迭代(Scrum稱為Sprint)都需要產出一個潛在可交付產品增量(Potentially Shippable Product Increment ),這個字很有趣,注意『潛在可交付產品增量』並非半成品,也不一定就是一個大產品的一小部分功能,更不是一個功能的某一部分(例如先做該功能的UI、或是先完成該功能的後端API)。

很多新手分不出什麼是潛在可交付產品增量,常常跟prototype甚至半成品搞混。然而,潛在可交付產品增量根本就是迭代開發的重點,每一個迭代的最主要目標(甚至接近是唯一目的),就是產出正確的潛在可交付產品增量

潛在可交付產品增量不是半成品、不是雛形、不是部分功能,而是一個可提供客戶價值(Value)的最小成果,搭配MVP的概念更容易理解,我們參考底下這張很經典的圖:

常有人誤會這張圖所要表達的意思。以為MVP(Minimum Viable Product)是說,客戶要一台車,你就先給他一個滑板應付一下…不,不是這個意思。

MVP是最小可行性產品,不管是軟體專案或是軟體產品開發,只要面對需求可能常常改變、無法控制,那採用迭代開發與潛在可交付產品增量(或MVP概念),都是一個非常好的技巧。

上圖中MVP的意思是,客戶本質上要的是一個交通/運輸工具(這是Value),但往往腦袋裡直覺就會想到是一台車,卻又說不清楚是什麼車?

『車』這個需求描述很空泛,是雙門? 四門? 多少馬力? 幾輪? 甚麼顏色? 傳統瀑布式專案中的系統分析(SA),往往企圖在一開始就想把所有的細節談定,並且要求客戶,一旦定下來,你就不能改

然而,現在這種『一旦定下來,你就不能改』的要求,客戶越來越不能接受,因為市場瞬息萬變,不是客戶故意找你麻煩想變,是客戶的客戶(或市場)逼著客戶變。

因此,敏捷開發和MVP鼓勵你不去先談『車』的細節(features),而是先專注在你的目的,我們知道客戶要的是一個交通/運輸工具,OK,我們就在每一個迭代(也許2周、也許4周)中,一邊開發,一邊持續釐清需求,逐漸為客戶打造出符合他心裡期待的『交通/運輸工具』。

因此,第一個版本是滑板,它不很完美,但能帶著客戶從A點到B點,是一個堪用的交通/運輸工具,它有Value(注意,這很重要),雖然確實還有很大的改善空間。不過,由於客戶看到了實體,客戶的腦袋開始更清楚的知道自己要的是甚麼,以及(特別是)不要的是甚麼。我們的開發團隊每一週持續跟客戶溝通,持續調整對需求的認知、持續蒐集更新需求、持續開發、持續改善,每一段時間都產出一個更貼近客戶要求的成果(但別忘記,每一次產出的成果,都要能夠運輸,都要有Value),直到達成客戶心中100%的預期 -- 這才是迭代開發,這才是潛在可交付產品增量。

這才是迭代開發、潛在可交付產品增量,與MVP(最小可行性產品)的意義。

好,你現在可以回頭對照上圖MVP的上半段,傳統的瀑布式開發則會先蒐集好詳細且完整的需求,然後先產生出輪子(不能運輸、沒有Value)、接著產生出底盤(不能運輸、沒有Value),過了很久很久以後(也許半年也許一年),才產生出一台(工程師心裡認為)完美的車子。然而,這時拿給客戶(客戶第一次看到),有很大的機會,客戶會跟你說:『他不能用』,因為他心裡想的車子和你做的不盡然相同,更有可能,他的想法改變了,或是他的客戶的想法改變了…你沒有機會持續修正,沒有機會持續調整,因為你的開發團隊只看規格書,被要求要stick to the plan。

經過幾年的敏捷開發專案,你會發現,需求是不可能在一開始就釐清的,即便一開始就真的讓你釐清(代價很高,多半要花費很多人力),隨著專案的進行,客戶端人員的異動、市場的改變,需求也會一直在變,往往半年後,一開始談的需求現在已經不同了(前面花時間釐清的需求,撰寫的規格書,全浪費了)。現在你知道,強調sitck on the plan的傳統計畫導向式開發,不具備這時代需要的隨時改變、隨時調整的特性。

從這邊,你會開始看到迭代開發,與傳統計畫導向開發,兩者在本質上有著很大很大的差別。

這樣的開發方法怎麼解決時程問題?

好,我們終究要回頭面對預估的問題,前面提到過,預測精確的時程幾乎不可能,因為大多數的軟體開發根本就是一場冒險,由於所有的事情都是新的,以前沒做過,就算預估也是猜測。加上,客戶的需求無法固定,專案中可能會遭遇哪些問題你也無法預測,所以,精確的預測哪一天會完成根本不可能。

但這不代表我們無法『預估』。

當你用上面提到的這樣的『MVP』、『潛在可交付產品增量』、以及『迭代』的概念進行軟體開發,你就會發現,雖然無法預測哪一天完成,但每一次交付產出的時候(也許每隔兩周、也許每隔一個月),你和客戶雙方都會更清楚的知道,距離雙方的理想目標還有多遠,雙方認知的差距還有多大,每一個迭代都會靠近最終成果更近一點,都會縮小彼此的認知落差,每一個迭代的預估也都會越來越貼近真正的結案時間。

也就是說,我們不能在專案尚未開始進行前,就預測出專案需要的精準人力或完成時間,但我們可以隨著專案的進行,依照前面的經驗和花費過的時間(P),來推估後面還需要花多少時間(E)…

上面這張圖很貼切,我們在專案開始點(B),因為還沒開始做,想要去預估專案完成所需要花費的人力和時程是非常非常困難的,估不准是理所當然。但,我們透過迭代開發、陸續蒐集需求、持續與客戶確認、持續產出潛在可交付產品增量、持續調整更正需求…經過了一段時間,到了今天(T),這時,過去花費的時間(P)就成為一個依據,透過這個依據,我們可以更合理的推估出,還需要多少時間(E)。

因此,我們得到一個結論:

專案開始前幾乎無法精準預估時程,但隨著專案的進行,我們得到的資訊(需求、已花費時間P)越來越多,我們預估的(E)就會越來越準確,只要我們持續修正這個預估

理解嗎? 我再舉一個例子你應該會更容易掌握。

你一定用過GPS。

以前剛出來的導航系統很笨,你輸入給它你要去的目的地(F),以及開始位置(B),它幫你計算出最佳路徑,然後就叫你依照這個最佳路徑走,不管這個路徑中的路況是否有問題,可能出了車禍導致交通堵塞,也可能前面正在施工根本無法通行….但,以前的導航只會叫你照著這個路徑走(stick to the plan),因為它認為這是計算過後的最佳路徑。

但,最近幾年的導航系統都很聰明,還可以連上網,它在幫你計算出最佳路徑之後,還會隨時觀察交通狀況(例如Google導航會有即時路況),當它發現前面路段似乎有嚴重塞車時,可以立即重新計算出新的路徑,讓你用更短的時間抵達,這就是自適應性,也就是應變能力。而傳統的導航則是計畫驅動式導航,如同過去的瀑布式開發,一旦SA團隊把規格書開好,就拍拍屁股閃人進入下一個專案了,至於開發過程中發生什麼問題?很抱歉,不關我的事(保重,我在另一個案子了)。

以前的軟體開發大多是是計劃導向,我們要求大家遵循計劃,制定計劃的人並不在乎你知不知道目標,也不在乎你要不要隨時依照路況去應變。

之所以過去可以行之多年,是因為早年路況良好、變數不大、不會常常塞車。但,現在時代不同了,現在路況變幻莫測、瞬息萬變,不能夠再依靠以前的計畫導向,而必須強調目標導向,強調自適應性(提升團隊的應變能力)。

這是敏捷開發和計畫驅動開發最大最大的差異,至於時程預估,你會發現,現在Google導航的預計到達時間幾乎都非常準,且你越靠近目的地,算出來的結果就越準。是了,它會參考先前的行車資訊與路況持續修正,和過去舊版的導航只依照目的地剩餘公里數和平均速度來推估,有著很大的不同,沒錯,這是敏捷導航是也。

最後,分享一張最近從FB上看到的圖:

(引用的原始出處為https://www.facebook.com/jaceju/posts/1291860560895634)

如果你覺得這有點怪怪的,為何依舊接受計畫導向的專案管理?

------
這一篇,我們釐清了迭代的重要概念,接著,後面我們會陸續介紹該如何做? 用甚麼工具來做?

------------------------------
本系列文章索引位於 http://studyhost.blogspot.tw/2017/02/the-devops-journey-index.html

2017年2月19日 星期日

the DevOps journey (0) - 敏捷開發真和每個開發人員有關?

#不想看廢話,直接按這裡跳到重點

這年頭大多數人已經沒有耐心,已經很難看完一整篇長篇大論,因為這樣,這幾年我們寫blog的時候,幾乎都零零碎碎,這使得許多學員面對知識的掌握,也變得片片斷斷。

如果可以,我希望能夠把我們這幾年面對軟體開發方法,以及ALM/DevOps的一些經驗,有條理一點的整理出來,如果你有興趣,不妨嘗試慢慢的看看,如果實在已經不習慣看長篇文章,也可以挑有興趣的重點來讀。

開始一段新的旅程

這一系列的標題中有個字眼『journey』,第一次看到這個字…是在一場研討會,我忘了是TechEd還是Build,印象中研討會的主題是Metro Style App(現在應該不多人還記得這個名字了吧?),主講人用journey這個字眼來描述學習一種技術的過程,我覺得真TxD的太貼切了…

不知道你有沒有發現,最近五年,軟體開發的潮流根本就是一場journey,而且非常像是我最愛的影集Star Trek Voyager中的旅程。你該怎麼形容這段旅程呢? 圖乎其來? 充滿意外? 不僅如此,大夥摸著石頭過河…似乎根本沒人能告訴你往哪個方向才是對的,你也不知道怎麼走才會到終點…這差不多就是這部影集當中的旅程。

若用來描述最近五年軟體開發技術的發展,根本是整個貼切到不行,而且從Web、前端、行動裝置、開發方法、框架…幾乎都逃不過這場journey魔咒,所有的技術都是在途(on the road),一點都沒有發展成熟的跡象…

當然,如果旅程總是只為了看到終點倒也世俗了些,旅程的過程中還是有很多意外的小驚喜,以及足以令人回味的點滴,不管是你早已遺忘的Metro Style Application,或是充斥各種消耗型框架的所謂前端開發技術,又或者是我們要討論的這個主題 – ALM/DevOps。

關於開發方法的重要性

身為一個以寫程式起家的開發人員,就一個軟體開發人員的生命週期來看,我算是到了很老的時候,才願意承認軟體專案/產品的開發過程中,最重要的可能不是開發技術,而是開發方法。

技術能力的強度,是進入軟體(專案/產品)開發領域的入場券,它就是一塊敲門磚,技術能力的強度,決定了你敲門的力道。然而一但當門打開,你開始了一個專案,進入了一個團隊,參與了一個產品的研發,技術能力對成果的影響力,可能就開始慢慢式微了。請注意,個人技術能力可能會影響開發團隊產出的品質和數量,然而開發團隊產出的品質和數量卻很可能跟軟體專案的『成果』沒有絕對的正相關。

什麼意思? 我們看過太多技術能力很強的個人或團隊,但經手的專案或產品開發依舊是失敗的很徹底的。例子很多,不好一個一個舉。你可以盡其所能地回憶你自己參與過的專案,你應該會發現,團隊的技術能力決定了你能不能做某個案子(或產品),但開發方法和團隊的素養,則決定了案子做得好不好,能不能順利結案。

由於軟體開發與一般工程營造迥異的特性,使得軟體開發這件事情,並不單單的工程行為,也是創作行為…這導致,追求技術的極致,其實對軟體專案沒有絕對的幫助,技術能力一旦到了某一個點之後,對於整體專案的幫助就迅速下滑…

像是上面這張圖,技術能力到一個臨界點之後,再怎麼提升,對於軟體專案的價值與效益其實影響開始遞減。

怎麼觀察? 如果你身為PM或Team Leader,當你開始慢慢發現,手上專案所發生的問題/瓶頸,大多跟技術無關,而是跟時程、溝通、預估…等非技術因素有關的時候,就表示,你的團隊可以在技術能力提升上稍稍休息,而該開始補強一下開發方法和專案管理能力。

總的來說,我接觸到的年輕團隊,大多都是技術能力遠勝於專案管理能力,至於開發方法,則往往都還有很多的成長的空間。

正在糾結?到底要不要踏入敏捷開發?

如果要談論開發方法,這幾年你不可能避開『敏捷開發(Agile Development)』,相較於傳統的瀑布式開發,敏捷開發在意的是自適應性(Self-Adaptive這個字硬翻很怪,我覺得你可以把這個字想成『應變能力』),而傳統的瀑布式開發,在意的是『計畫導向』,簡單一句話,就是要你『stick to the plan』。

上課時,我會推薦學員一定要看Martin Fowler的這篇文章: http://martinfowler.com/articles/newMethodology.html

如果你需要中文翻譯,他位於:
http://www.jianshu.com/p/e042ed1d79b0

我假設你已經讀完了,我要說,這篇文章非常經典,字字珠璣,他解釋了為何這個時代的軟體專案,應該採用敏捷開發。

我覺得只需要扼要說明,請一邊參考底下這張圖。

最早期(1960年代),軟體開發是毫無章法,雜亂無章的情況,迫使技術團隊覺得應該要有一些制度,因此借鏡了傳統的工程營造之類的專案管理概念,一段時間的演進之後,建構了像是CMMI之類的軟體專案管理方式,但後來(最近10年)許多人慢慢發現,似乎並不可行…

不可行的原因出自於幾點:

  1. 傳統的專案管理和工程方法試圖把人當作可替換的資源,但軟體開發並非全然是施工(Implementation),還有創作的成分(而且非常高),每一個程式設計師的產能可能天差地遠完全不一樣,把開發人員視為可替換的資源根本是個錯誤的假設。
  2. 傳統計畫導向的開發方法相信,設計(Design)和實施(Implement)可以分離,甚至,設計需要比較高階的人力,而實施只要muscle就好。但敏捷開發認為,設計和實施無法分離,每一個開發動作都同時包含了設計和實施的成分在。
  3. 我們幾乎永遠不可能有確定的需求。因為完全一樣的程式碼(需求)你根本不用重寫,只需要copy一分(或買套裝軟體)就好,所以,每一個軟體專案幾乎肯定都是獨特的。再加上現今市場變化快速,需求的固定幾乎已經不可能。
  4. 從不確定的需求,衍生出,準確的預估幾乎是不可能實現的。因此,軟體開發沒有stick to the plan這回事。(那要怎麼辦呢? 後面再說)

因為上面這幾個與傳統工程之間的核心差異,導致軟體開發用工程方法、SOP、甘特圖來管理、期待他跟其他的工程施工一樣順利,似乎非常的不切實際。

除非你的需求永不變動、除非你每一個開發人員的產能完全相同,除非你有無窮盡的開發人員可以替換,否則,傳統的工程管理方法根本無法進行軟體開發的專案管理。

不知道你是否曾經好奇過,其實我們早已用工程方法(甘特圖、要徑法、CMMI、SOP…等)來管理軟體開發很多很多年,如果,這個方法是錯的,難道從來沒有人懷疑過? 難道從來沒人覺得工程方法怪怪的?

有,但很抱歉,過去,設計出這些管理方法的人,很可能自己根本都不寫程式。就像設計員工管理制度的HR/Manager,本身可能根本不是一般員工,這些制度的受益者/設計者,從來都不是制度的使用者…也因此,身為程式設計師的你,如果夠敏感,很可能早就覺得哪裡怪怪的,但,你無法改變,因為制度的設計者不是你。

一個新方法

然而,敏捷開發法的出現,和過去工程方法誕生的方式完全不同,敏捷開發的概念是由有實務開發經驗的開發人員所設計,這跟過去建構工程方法的管理階層,自己從來沒下來搬過磚塊的狀況有著很大的差別。

敏捷開發法的設計者認為,你不能把程式設計師看做資源,軟體開發的團隊,也根本不是傳統的施工團隊。如果真要比較,軟體開發團隊比較像是一組球隊(team),團隊中的成員每一個都有自己獨特的角色和任務,人人不可或缺,無法輕易替代。每一個球員的產值也大不相同,高低之間可能相差數十倍,無法相提並論或替換。

這是一個認知上的巨大差異,一旦當你把軟體開發團隊,從傳統工程(例如營造)的施工團隊,轉變成球場上的團隊,你會發現你的思維將會瞬間轉換。你將不再相信傳統的專案管理方法,你帶領團隊的方式也會大不相同。

DevOps/ALM/Agile與軟體專案管理

一旦你用一個全新的眼光看待軟體開發,你對於軟體開發的方式,採用的專案管理工具、做法,都將會跟以前有所不同。

也因此,我們這篇先談敏捷開發,然後接著,我們要來看,在這個思維底下,如何管理軟體專案,如何管理軟體生命週期,如何透過工具來實現DevOps…

如果你要惡補你的敏捷開發概念,請參考底下這本書:
http://www.books.com.tw/products/0010691328

下一篇,我們談時程預估與迭代的概念。

------------------------------
本系列文章索引位於 http://studyhost.blogspot.tw/2017/02/the-devops-journey-index.html

2017年2月2日 星期四

asp.net Web開發框架 (8) - 使用krajee進行非同步檔案上傳

這一篇介紹Bootstrap File Input這個套件,之所以會被歸類到asp.net Web開發框架系列,是因為整個套件和我們採用asp.net走SPA架構(不管是用WebForms或WebAPI)都非常的速配。

檔案上傳範例

首先我們有一個範例位於Github,如果你想要測試,下載這個範例後,基本上已經擁有所有你需要的檔案。請使用Visual Studio運行index.html這個檔案(對,沒錯,是pure html5),執行起來的畫面像是底下這樣:

這個套件精彩的地方是上傳預覽畫面,你會看到上圖中,它除了支援中文、多檔上傳、非同步上傳,還支援圖片預覽、Mp3檔案甚至可以撥放,會不會太誇張了點? 是的,人家就是支援…更不用說UI的部分很有誠意的原生支援正體中文(包含zh-TW的多國語言js)這也是我們使用此套件的原因之一。

如何使用

整個套件的使用可以完全採用AJAX方式(當然也支援傳統的submit/postback),搭配我們的SPA架構非常之合拍,也因此,你在運行該範例的時候,會發現只需要執行index.html即可(當然伺服器端接收檔案的部分還是需要Server Code,這我們後面介紹ReceieveFile.aspx的時候再說明)。

如果你看index.html,會發現程式碼如下:

我們先看55行的部分,這是定義一個Input標記,其中的multiple意味著支援多檔上傳,data-show-preview="true"則是支援顯示預覽視窗。當然這些設定都可以在後面透過js來更動。

而66行javaScript所呼叫到32行的setupFileUploadBox(),就是進行相關的設定,其中language: 'zh-TW' 指定了多語UI採用中文(請留意這也是我們在19行引用了locales/zh-TW.js的原因),而後面幾個參數應該不需要太多解釋,showUpload是顯示上傳按鈕,uploadAsync說明了採用非同步上傳,maxFileCount指定了檔案上傳上限。

比較重要的是uploadUrl,這個參數指定了非同步檔案上傳的接收位置,由於這個範例採用WebForms,因此我們指定ReceieveFile.aspx,這部分我們待會後面介紹。(我覺得熟悉WebAPI的開發人員可以輕易的把ReceieveFile.aspx這隻改成WebAPI,因此我暫時就不動手改了)

先看上面程式碼43行的on後面定義的幾個事件hook:

fileuploaded事件發生在所有檔案上傳完成之後(嚴格說起來是伺服器端回應之後),而filepreupload事件則發生在所有檔案上傳之前,如果你還需要hook其他事件,可以參考該套件的官網說明(這套件的事件方法支援都算相當完整)

我們在fileuploaded這段程式碼當中,也只是把上傳完成之後,伺服器端傳來的檔案路徑(URL)給顯示出來而已…

伺服器端如何接收檔案,如何把特定訊息往前端送? 這個我們待會下面介紹,先看看該套件需要引用哪些css與js (我都整理在Content/bootstrap-fileinput資料夾下):
上圖是所有你需要引用的檔案,基本只有四個,如果你需要更多的功能(例如檔案排序…),則可能需要引用更多,其中1,3是與CSS相關,2是核心的js,4則是多國語言(中文需要的js)。

撰寫伺服器端接收檔案的C#程式碼

前端的code非常簡單,接著我們就要來看看後端接收檔案的程式碼如何撰寫。這個套件基本上走非常標準的http post把檔案往後端送,如果你採用非同步檔案上傳,則檔案是被一個一個往後端送的,也就是說,如果你上傳五個檔案,後端接收檔案的API會被呼叫五次。

後端接收檔案的API可以用WebAPI或是單純的apsx頁面撰寫,我們先看.aspx的版本:

你會發現這其實是一個很簡單的WebForm aspx,我們可以在PageLoad當中透過Request.Files接收到檔案,沒什麼特別的。這個範例刻意用aspx來撰寫,其實當然也可以用WebAPI,但在行為上其實都一樣。

由於多檔上傳時,前端的套件是把檔案一次一個往後端送,因此如果你同時上傳五個檔案,其實這個 ReceieveFile.aspx.cs 的Page_Load會被呼叫五次,因此,其實理論上 Request.Files.Count 在正常狀況下只會是1。

後面36-41行就是把取得的檔案儲存。然後43-46行回應一個很標準的JSON給前端。

這邊請特別留意,該套件要求,你撰寫的接收檔案的API(嚴格說起來不該稱之為API,應該叫做Backend Service),必須回應JSON,即便你啥也不想傳給前端,都必須回應一個空的{ }。

你會看到我們new了一個13-19行定義的customResponse物件,其實裡面也只有一個URL屬性,你可以自己加上其他的屬性,如果需要的話。不過最少,也應該回應一個檔案上傳到後端之後的id或URL,範例中我們選擇回應URL,因此你會看到我們在44行組出被上傳檔案的URL,然後在46行回傳給前端。

就這樣,其他的code全是例外處理。

整個範例的source code在: https://github.com/isdaviddong/KrajeeFileUploadExample
該套件的官網: http://plugins.krajee.com/file-input

整個套件採BSD 3-Clause License,這年頭好心人真多…
--------------------------------------------
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。