Webform和MVC,為什么MVC更好一些?

jopen 10年前發布 | 22K 次閱讀 Webform .NET開發

前言

如果你看了最近微軟的議程,你會發現他們現在的焦點除了MVC,還是MVC。問題在于為什么微軟如此熱衷于丟棄傳統的APS.NET Webform而轉向ASP.NET MVC?本文就主要來討論這個問題。

ASP.NET Webform 后臺代碼(behind code)—— 福音與詛咒

如果你密切關注過ASP.NET Webform技術,你會發現它更接近可視化設計,換句話說,開發者只需要從設計面板中拖拽控件即可完成UI,接著在behind code中實現邏輯代碼即可完成最后的Web頁面功能。

Webform和MVC,為什么MVC更好一些?

所以換句話說,當你從設計面板中拖拽一個按鈕時,在后臺代碼中就會生成一個button對象,你只需要在按鈕的點擊事件中實現事件響應代碼即可。

public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Developers write code here
        }

    protected void Button1_Click(object sender, EventArgs e)
    {
        // Developers write code here
    }
}</pre> <p>當我們在頁面中拖拽一些UI元素時,雙擊它們即可在后臺代碼中生成一系列事件響應代碼,這些邏輯代碼都在ASPX.CS文件中。</p>

Webform和MVC,為什么MVC更好一些?

這個后臺代碼文件是ASP.NET Webform的關鍵,你可以在這個文件中應用.NET的所以特性,包括事件、委托、HTTP協議以及session等等。

但是這種behind code模式有5個問題,下面我們將一一講述這5個問題,并用MVC的設計思想來分別解決這些問題。

問題1:基于視圖的方案來解決基于行為的需求

我們的網站最終是由用戶使用的,用戶訪問網站肯定會有特定的目的,網站要做的就是通過讓用戶的交互行為來完成其想要的目的。比如當用戶訪問一個購物網站時,也許他的交互行為會是這樣的:

  • 購買產品
  • 打印發票

這些交互行為是通過按鈕點擊、右鍵點擊和瀏覽器URL實現的。由于這些交互都是基于HTTP協議的,所以如果我們能將這些交互行為映射到具體的一些方法上,那么整個架構將會變得簡單很多。

但是微軟做不到這樣,因為它要實現可視化網頁編程,所以他們最終選擇了基于視圖的解決方案。

Webform和MVC,為什么MVC更好一些?

從上圖可以看出,整個請求過程看上去很奇怪:

  • 用戶發起一個HTTP請求,比如HTTP POST / GET
  • IIS服務器將請求映射到視圖
  • 視圖調用頁面的生命周期,通過事件驅動,調用合適的交互方法
  • 最后將交互的結果展現給終端用戶

因為微軟一開始就選擇了基于視圖的設計方案,所以架構本身很難向基于用戶交互的設計思想靠攏。換句話說,當用戶發出“購買”請求時,先是訪問了視圖 頁面“Shopping.aspx”,后臺邏輯代碼在“Shopping.aspx.cs”中,頁面生命周期中會將頁面的計算結果返回給用戶。

Webform和MVC,為什么MVC更好一些?

如果利用MVC的思想,都是基于用戶交互行為的話,那么請求流程將會是如下所示:

Webform和MVC,為什么MVC更好一些?

問題2:壞架構的副作用 —— 緊耦合

當你選擇了一個錯誤的架構以后,未來將會出現很多難以解決的副作用,在ASP.NET Webform中就出現了這個問題。盡管behind code后臺代碼被分離到不同的文件中,但是ASPX.CS文件和ASPX文件卻緊密的聯系在一起,這將導致系統的耦合度很高,并且很難解耦和,這是一個 很頭疼的問題。

Webform和MVC,為什么MVC更好一些?

簡單地說,我們很難將Customer.aspx.cs和CustomerDetailed.aspx簡單地剝離開,后臺代碼已經緊緊地將其捆在一 起,而且也很難復用。如果我們可以將請求先通過action,而不同過視圖view,action得到的數據再由控制器決定由哪個view展示,那么請求 的流程將會是這樣的:

Webform和MVC,為什么MVC更好一些?

所以我們可以很方便地控制最終結果是由移動頁面展示還是正常頁面展示,如下代碼:

public ActionResult Index(string DeviceType)
{
           if (viewType == "Mobile")
            {
                return View("MobileView");
            }
            else
            {
                return View("NormalView");
            }
}

問題3:HTML不是唯一的返回類型

由于視圖view和后臺代碼behind code緊密耦合在一起,所以默認的返回類型就固定了,都是HTML類型。如果你想改變類型就必須設置Content-type和調用Response.End方法。

如果我們創建一個Action,返回的類型由Action中指定,系統就可以在同一個action中根據不同條件輸出不同的返回類型。代碼如下:

public ActionResult Index(string viewType)
{
            if (viewType == "JSON")
            {
                return Json(new Customer(), JsonRequestBehavior.AllowGet);
            }
            else
            {
                return View("DisplayCustomer", new Customer());
            }
}

問題4:視圖和數據的靈活組合

Webform是視圖優先的架構,所以視圖決定了展現的數據,所以視圖的擴展性就很差,如果遇到復雜的數據結構,這種方式就顯得力不從心了。

但是如果是行為優先的架構的話,當我們觸發action時,action可以根據不同的請求選擇不同的數據模型和視圖結構,如下圖:

Webform和MVC,為什么MVC更好一些?

在MVC中,你可以在不同的view中選擇相同的數據模型,比如下面的代碼,customerdata數據既可以綁定在DetailCustomer視圖中,也可以綁定在Customer視圖中。

public ActionResult Index(string ViewName,Customer customerdata)
{
            if (ViewName == "Detailed")
            {
return View("DetailCustomer",customerdata);
            }
            else
            {
                return View("Customer",customerdata);
            }
}

這在Webform中實現起來是非常麻煩的。

問題5、將behind code當做普通的類來進行單元測試

behind code后臺代碼在Webform中是一個非常龐大的類,并且不能簡單地實例化。要知道Webform是繼承于Page類的,Page類不能直接實例化,因為它有太多的依賴項了。

public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        public void Button1_Click(object sender, EventArgs e)
        {
            Session["SomeSession"] = "Is this set";
        }
    }

你為什么想要實例化Page類呢?其中一個原因就是可以方便單元測試。比如我要測試一個按鈕點擊事件,用來檢查Session是否設置成功。在Webform中的代碼看起來不是那么舒服:

[TestMethod]
public void TestMethod1()
{
            WebApplication22.WebForm1 obj = new WebApplication22.WebForm1();

            obj.Button1_Click(this, new EventArgs());
}

并且運行時還會拋出一個異常:

Webform和MVC,為什么MVC更好一些?

在MVC中,這個類變成了一個普通類,我們可以在測試工程中將它實例化,并對類里面的屬性方法、Session、viewbag 、 tempdata等進行單元測試。

public class HomeController : Controller // ? this class is simple 
{
        public ActionResult Index()
        {
            Session["SomeSession"] = "Is this set";
            return View("SomeView");
        }
}

所以是否選擇MVC解決方案?

Webform和MVC,為什么MVC更好一些?

從Webform架構切換到MVC架構,你需要做以下幾件事情:

  • 將behind code中的代碼轉移到controller類中,并將原來的方法轉換成action方法。
  • 中間層用數據模型和邏輯接口代替。
  • 視圖view只用來展現數據和頁面布局。
  • DAL層和其他層沒有什么變化,因為它和behind code關系不大。

Webform和MVC,為什么MVC更好一些?

所以MVC架構中,用戶的請求分為下面3個步驟:

  • 終端用戶發送請求,路由器將請求路由到合適的Controller,Controller是邏輯實體和行為action的集合。
  • Controller將請求映射到特定的Action。
  • action有兩個任務,第一是獲取合適的數據,第二是將這些數據和視圖view綁定起來。action創建數據模型,并將數據模型連接到指定view,輸出最終的相應結果。

譯文鏈接:http://原網站已經失效/article/webforms-vs-mvc.html
英文原文:Webforms vs MVC and Why MVC is better ?
翻譯作者:碼農網 – 小峰

     本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
     轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
     本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!