在《避開WebForm天坑,擁抱ASP.Net MVC吧》這篇博客中我講到了ASP.net WebForm因爲一些先天的「誘導犯罪」的缺陷,如今用ASP.net MVC的公司愈來愈多。可是根據那篇文章末尾的"ASP.net MVC的免費網絡公開課"調查表的統計,咱們發現有一大半的人尚未使用過ASP.Net MVC,而沒用過ASP.net MVC的人中居然有不少人人是由於感受ASP.Net 難、沒時間學。調查表分析數據以下:html
初看ASP.net確實難:複雜的路由機制、 ViewData/ViewBag/TempData、過濾器、Razor、Layout、XXXHelper、驗證、WebAPI、依賴注入、單元測試……光看這一堆概念頭就暈了,「仍是拖控件簡單」。前端
其實學習一個新的框架,只要搞清他的原理就會「豁然開朗」,再看其餘的東西就不會感受恐懼了。程序員
這篇文章我將會帶着你們搞明白什麼叫MVC模式,而且帶着你們用你們熟悉的Asp.Net WebForm實現MVC!數據庫
對!你沒聽錯!緩存
用Asp.Net WebForm實現MVC!安全
再次感覺一下ASP.net WebForm吧。服務器
假設有一個Person對象的集合,咱們要在網頁中以html渲染,那麼要以下編寫網絡
<table> <asp:Repeater ID="Repeater1" runat="server"> <ItemTemplate><tr><td><%#Eval("Name") %></td><td><%#Eval("Age") %></td></tr></ItemTemplate> </asp:Repeater> </table>
C#代碼:架構
if(!IsPostBack) { List<Person> list = new List<Person>(); list.Add(new Person { Name = "rupeng", Age = 8 }); list.Add(new Person { Name = "qq", Age = 18 }); Repeater1.DataSource = list; Repeater1.DataBind(); }
這樣作的缺點是C#代碼中訪問了apsx中的控件Repeater1,也就是在aspx中必需要有一個Repeater類型、Id爲Repeater1的控件,這樣aspx就和C#代碼耦合在了一塊兒。麻煩在哪兒呢?併發
1)若是aspx有兩個地方都要用list了,那麼就要寫兩組DataSource=list;DataBind();
2)若是aspx中忽然不想要Repeater了,把Repeater1刪掉C#代碼就會報錯
3)Aspx中突然不想用Repeater進行數據的顯示了,想換別的控件,那麼C#代碼也要改
再好比,在ASP.Net WebForm中,實現加法計算器會以下實現:
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> +<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="=" /> <asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
protected void Button1_Click(object sender, EventArgs e) { int i1 = Convert.ToInt32(TextBox1.Text); int i2 = Convert.ToInt32(TextBox2.Text); int i3 = i1 + i2; TextBox3.Text = i3.ToString(); }
後臺的C#代碼和aspx的耦合要求aspx視圖中必須有三個名字各爲TextBox一、TextBox二、TextBox3的TextBox類型的服務器控件。若是我想把計算的結果從TextBox改爲span就不行。前端設計人員看到TextBox絕對沒有input親切,前端人員對input 的把控能力會被TextBox更好。另外沒必要再說WebForm引入的ViewState、頁面生命週期、ClientID等使人做嘔的問題。
有同窗會說了:你有病嗎,開發時候aspx怎麼可能老是變來變去,即便aspx變了,你C#代碼也就變唄,有什麼大不了的?
若是說系統小的話可能無所謂,對於比較複雜的系統,若是aspx和C#這樣緊密的耦合,維護還會特別麻煩。並且若是實現像一些CMS系統那樣能夠動態修改模板文件的話就是存在着「C#沒法預測、沒法強制要求aspx到底怎麼寫」的問題。
這還僅僅是展現一個集合的問題,若是要展現複雜的扁平化數據或者須要從用戶輸入中獲取數據,用這種方式更災難。
那麼MVC思想怎麼解決呢?邏輯代碼(Controller)不直接和頁面視圖(View)進行交互,他們之間用Model(數據模型)做爲溝通的通道。當須要展現數據的時候由Controller收集到數據(Model),而後把數據交給View去展現;當Controller須要讀取View中用戶輸入內容的時候,框架會把View中的數據映射到Model中,而後Controller讀取Model中的數據進行後續的邏輯處理。這樣就把邏輯代碼(俗稱C#代碼)和視圖(俗稱頁面)進行解耦了。
光說概念沒用,仍是先看代碼把。下面使用MVC模式改造的「顯示Person集合」:
View視圖PersonsView.aspx
<%@ Page Language="C#"%> <%@ Import Namespace="System.Collections.Generic" %> <%@ Import Namespace="WebApplication1" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body> <table> <% var persons = (List<Person>)Context.Items["persons"]; foreach(var person in persons) { %> <tr><td><%=person.Name %></td><td><%=person.Age %></td></tr> <% } %> </table> </body> </html>
注意,我把aspx相關的兩個自動生成的.cs文件刪掉了,而且把<%@Page%>標籤的AutoEventWireup、CodeBehind、Inherits等幾個屬性也都幹掉了,這樣aspx就變成了一個純粹的「模板引擎」
做爲Controller的Index.ashx的代碼以下:
public void ProcessRequest(HttpContext context) { List<Person> list = new List<Person>(); list.Add(new Person { Name="rupeng",Age=8}); list.Add(new Person { Name = "qq", Age = 18 }); context.Items["persons"] = list; context.Server.Transfer("PersonsView.aspx"); }
這裏借鑑了JSP中「request.getRequestDispatcher("index.jsp").forward(request,response)」同樣的思路。
context.Server.Transfer是在服務器內部把請求處理權轉交給"PersonsView.aspx"處理。HttpContext中的Items的生命週期是整個請求響應,這樣咱們在通常處理程序中把數據放到context.Items中,而後在"PersonsView.aspx"中就能夠能夠經過Context.Items["persons"]拿到這個數據從而進行數據的展現。
爲何把數據放到HttpContext.Items中呢。因爲Transfer僅僅是服務器內部處理權的轉接,可是仍然是在一個請求中的,因此放到Context.items是最好的。若是放到Session、Application等中會有併發的問題。
這樣Controller(通常處理程序)和View(aspx)之間只要維持一個「要傳遞一個名字爲persons類型的List<Person>」這樣一個弱耦合關係便可,至於aspx用不用這個persons、用幾回persons、怎麼用persons,你Controller都不用管。
按照一樣方法改造加法計算器
下面是視圖AddView.aspx的代碼
<%@ Page Language="C#"%> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <%dynamic viewBag = Context.Items["ViewBag"]; %> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>加法計算器</title> </head> <body> <form id="form1"> <input type="hidden" name="action" value="addSubmit" /> <input type="text" name="i1" value="<%=viewBag.i1 %>" />+<input type="text" name="i2" value="<%=viewBag.i2%>" /> <input type="submit" value="=" /><input type="text" value="<%=viewBag.i3 %>" /> </form> </body> </html>
而AddHandler.ashx的主體代碼以下:
public void ProcessRequest(HttpContext context) { string action = context.Request["action"]; dynamic viewBag = new System.Dynamic.ExpandoObject(); if(string.IsNullOrEmpty(action)) { viewBag.i1 = ""; viewBag.i2 = ""; viewBag.i3 = ""; } else if(action=="addSubmit") { int i1 = Convert.ToInt32(context.Request["i1"]); int i2 = Convert.ToInt32(context.Request["i2"]); int i3 = i1 + i2; viewBag.i1 = i1; viewBag.i2 = i2; viewBag.i3 = i3; } context.Items["ViewBag"] = viewBag; context.Server.Transfer("AddView.aspx"); }
因爲View和Controller之間傳遞的數據比較複雜、比較多,爲了簡化開發,這樣用了dynamic 動態類型。熟悉ASP.Net MVC的同窗是否是感受這個和ASP.net MVC中的ViewBag殊途同歸呢。
在這個加法計算器中若是我想把結算結果用span顯示,那麼只要把<input type="text" name="i3" value="<%=viewBag.i3%>" />改爲<span><%=viewBag.i3%></span>就能夠了。美工也容易介入頁面美化。
若是我想把頁面的Title從「加法計算器」改爲「3和5相加的結果」,那麼只要這樣改就能夠:<title><%=viewBag.i1 %>和<%=viewBag.i2 %>相加的結果</title> 這樣model裏的數據我aspx想用幾回用幾回,想怎麼用就怎麼用。有沒有感受到和WebForm不同的地方呢?
因此只要思想一想通了,其實實現MVC模式不必定要用ASP.net MVC,我見過不少項目都是本身搞的MVC機制。
固然既然ASP.net MVC已經這麼優秀了,通常狀況不必像我這樣從新本身發明一個輪子用。
這裏給你們講ASPX實現MVC只是用你們熟悉的東西讓你們明白原理,工程項目應用仍是直接用ASP.Net MVC吧。
如鵬網.Net培訓班正在報名,有網絡的地方就能夠參加如鵬網的學習,學完就能高薪就業,點擊此處瞭解
三年前只要懂「三層架構」就能夠說「精通分層架構」;如今則須要懂IOC(AutoFac等)、CodeFirst、lambda、DTO等才值錢;
三年前只要會SQLServer就能夠說本身「精通數據庫開發」;如今則需還須要掌握MySQL等開源數據庫才能說是「.Net開源」時代的程序員;
三年前只要會進行用戶上傳內容的安全性處理便可;如今則須要熟悉雲存儲、CDN等才能在雲計算時代遊刃有餘;
三年前只要掌握Lucene.Net就會說本身「熟悉站內搜索引擎開發」;如今你們都用ElasticSearch了,你還用Lucene.Net就太老土了;
三年前發郵件仍是用SmtpClient;如今作大型網站發郵件必須用雲郵件引擎;
三年前緩存就是Context.Cache;如今則是Redis、Memcached的天下;
如鵬網再次引領.Net社區技術潮流!點擊此處瞭解如鵬網.Net最新課程