免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
ASP.NET MVC4 IN ACTION學(xué)習(xí)筆記

ASP.NET MVC4 IN ACTION –View Models

--這是本書(shū)的第二部分,前三波是第一部分,這波的知識(shí)真的很重要

--在這一波博客里,我會(huì)加入一些vs2010的編程技巧,這是在別人那里學(xué)不到的

--我會(huì)加入一些自己總結(jié)的EF方面技巧,這是這本書(shū)中暫時(shí)還沒(méi)看到的

--內(nèi)容我已經(jīng)不打算按書(shū)中原汁原味的講,因?yàn)檫@波開(kāi)始,你將要真正的掌握MVC

--每個(gè)細(xì)節(jié)我都會(huì)抓的很細(xì),講書(shū)中省略的很多東西,但后期我可能不會(huì)這樣去做了,因?yàn)橐岣咝?/span>

--所以學(xué)習(xí)本系列MVC博客的人,可能不能跳著學(xué)習(xí)了,因?yàn)槲抑v過(guò)的就不會(huì)去再講了

原著:ASP.NET MVC 4 IN ACTION

本人能力有限,盡量將書(shū)中的知識(shí)濃縮去講,仔細(xì)學(xué)過(guò)后,然后你再學(xué)習(xí)其他語(yǔ)言的MVC框架也就大同小異了

本次覆蓋知識(shí)點(diǎn):

  • 1. 用代碼呈現(xiàn)用戶界面(UI/User Interface)(Representing UI concepts in code)
  • 2. 定義一個(gè)頁(yè)面使用的model(presentation model 或者上波我們提到的view model) (Defining the presentation model)
  • 3. 顯示用戶輸入的數(shù)據(jù) (Representing user input)
  • 4. 在復(fù)雜的場(chǎng)景中使用 (Scaling to complex scenarios)

 

     茗洋芳竹飛機(jī)票:第一波  第二波  第三波

 

    備注:controller action指controller中的action(也就是你們經(jīng)常寫的方法而已)

            controller actions指controller中全部actions

            action名字加action表示 某某名字的action,例如有個(gè)叫Index的action,我就會(huì)這樣表示

            Index action.知道了嗎?這方便我寫博客,也更方便理解

            view model指頁(yè)面(view)中用到model,我上篇博客說(shuō)的視圖模型就是view model

            action method指 返回值是ActionResult那個(gè)方法,比如Index那個(gè)action方法

            user interface,用戶接口(UI的全稱),你可以意會(huì)理解成頁(yè)面,也就是要跟用戶交互的東西,比如我們給用提供一個(gè)頁(yè)面,讓用戶錄入數(shù)據(jù),這就是一個(gè)interface,一個(gè)接口,你暫且在這里就是view,就是頁(yè)面

            business logic,商業(yè)邏輯,類似于數(shù)據(jù)訪問(wèn)層中業(yè)務(wù)實(shí)現(xiàn)的邏輯

            domain,你可以理解數(shù)據(jù)訪問(wèn)層

            domain model,數(shù)據(jù)訪問(wèn)層要使用到的model

            以后我想直接寫英文了,好方便理解,在第二波的博客里我是吃過(guò)苦了,文章讀起來(lái)好拗口

    關(guān)于本書(shū)的第一部分(前三波內(nèi)容)講了很多點(diǎn)到即止的知識(shí),大致地概括了一下框架的某些部分。

     現(xiàn)在我們要更深入的研究這些細(xì)枝末節(jié)

     在本章我們將要討論這個(gè)model,怎樣為ASP.NET MVC框架特意地去設(shè)計(jì)一些更好結(jié)構(gòu)的model。我們還要研究一下Model-View-Controller模式,model通常是很難理解的,因?yàn)閙odel在很多地方用到的,說(shuō)實(shí)話,view model,domain model,頁(yè)面上的Model對(duì)象,@model等等。

     model中定義了很多字段,例如Student這個(gè)model定義了Name,id,classname,我們可以想象一下Student是個(gè)圓,這個(gè)大圓里面有很多小圓

假如程序運(yùn)行了,會(huì)給程序一塊內(nèi)存用來(lái)存數(shù)據(jù),Student這個(gè)圓可以理解為一整塊,一個(gè)整體,然后細(xì)分Name一塊,Class一塊,Id一塊,我感覺(jué)這就是數(shù)據(jù)結(jié)構(gòu)了,不知道對(duì)不對(duì)。如果圓更多,是不是可以抽象理解成一個(gè)煤球形狀的數(shù)據(jù)結(jié)構(gòu),如果數(shù)據(jù)是這樣分布的,這里隨便說(shuō)著玩的,我是這樣理解的。

干嘛說(shuō)這些,因?yàn)檫@些數(shù)據(jù)都有意義,比如Name代表學(xué)生姓名,那么在view中我就可以直接model.Name就可以輸出學(xué)生名字了。上一波我們也講到了關(guān)于 view model要設(shè)計(jì)的更有意義和技巧,比如顯示用戶名 和 這個(gè)用戶所發(fā)的所有comment數(shù),view model中就2個(gè)字段,但是如果我們用domain model,那么顯示不太方便。所以上面說(shuō)要特意地去設(shè)計(jì)view model。

我感覺(jué)這句話挺好的:

When you work with object-oriented languages (such as C#), you create  classes that define this representation. You can create your representation so that when you use it you’re working in a more natural language that allows you to talk about the concepts represented by the software instead of using programming language constructs like Booleans, strings, and integers.

當(dāng)你在使用面向?qū)ο蟮恼Z(yǔ)言,比如C#,你定義了一個(gè)類,這個(gè)類定義了頁(yè)面上該怎么顯示,你可以創(chuàng)建你的表現(xiàn)形式,不需要再使用domain model(它里面可能含有很多boolean類型,string類型,int類型結(jié)構(gòu)的數(shù)據(jù)),用更少的代碼就可以表達(dá)出你想要顯示的數(shù)據(jù)的形式,table顯示或者div顯示等等

一句話,domain model能滿足view顯示,你就顯示,你覺(jué)得不方便,你可以新建一個(gè)model,我們稱為 view model(或者presentation model),這個(gè)view model用來(lái)在頁(yè)面更容易顯示數(shù)據(jù)

通過(guò)本章,有些顯示數(shù)據(jù)的問(wèn)題你可以使用view model去簡(jiǎn)化在頁(yè)面上呈現(xiàn)的邏輯,我們將要看一下view models和input models(把數(shù)據(jù)從view傳遞給controller,相當(dāng)于添加數(shù)據(jù)等等)

 

5.1 什么是view model

          view model的目的很直接--它就是一個(gè)model,在一個(gè)view里面,為了方便操作數(shù)據(jù)而特意設(shè)計(jì)的一個(gè)model ,感覺(jué)如果還不懂,需要到項(xiàng)目中去意會(huì)了。

         在本節(jié)中,我們做一個(gè)簡(jiǎn)單的online store(在線商店)例子來(lái)講解view model怎么工作的。了解一下,把view model傳遞給view時(shí)候的時(shí)候,domain model和view model傳遞的區(qū)別,最后我們看一下,input models是如何把view上的數(shù)據(jù)傳遞給controller的。

 

 

5.1.1 Online Store例子

            準(zhǔn)備工作(書(shū)中沒(méi)有,我大致寫下讓你復(fù)習(xí)一下)

          

新建項(xiàng)目

           

默認(rèn),也添加測(cè)試模版,單擊

          

添加EntityFramework.SqlServerCompact

           

正在安裝…

 

在Models文件夾中新建一個(gè)StoreOnlineContext類

修改這個(gè)類,讓它繼承DbContext,按Shift+Alt+F10快速導(dǎo)入命名空間

添加一個(gè)構(gòu)造函數(shù),參數(shù),是我們的數(shù)據(jù)庫(kù)名字

接下來(lái),我順便教大家快捷方式吧,寫代碼就要快才好,下次我就不寫了

直接在這個(gè)類繼續(xù)編寫,寫下如下代碼

 

將光標(biāo)置入 Customer中去,按下Ctrl+Shift+F10,然后回車鍵,可以快速生成對(duì)應(yīng)名稱的類

同理我們繼續(xù),完成后的樣子

然后我們?nèi)サ?那個(gè)ServiceLevel的DbSet

接下來(lái)我們向?qū)嶓w類中添加代碼

Customer.cs

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel.DataAnnotations;
   4:  using System.Linq;
   5:  using System.Text;
   6:   
   7:  namespace OnlineStore.Models
   8:  {
   9:      public class Customer
  10:      {
  11:          [Key]
  12:          public int ID { get; set; }
  13:          public int Number { get; set; }
  14:          public string FirstName { get; set; }
  15:          public string LastName { get; set; }
  16:          public bool Active { get; set; }
  17:          public ServiceLevel ServiceLevel { get; set; }
  18:          public ICollection<Order> Orders { get; set; }
  19:      }
  20:  }

 

ServiceLevel.cs

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:   
   6:  namespace OnlineStore.Models
   7:  {
   8:      public enum ServiceLevel
   9:      {
  10:          Standard,
  11:          Premier 
  12:      }
  13:  }

 

Order.cs

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel.DataAnnotations;
   4:  using System.Linq;
   5:  using System.Text;
   6:   
   7:  namespace OnlineStore.Models
   8:  {
   9:      public class Order
  10:      {
  11:          [Key]
  12:          public int ID { get; set; }
  13:          public DateTime Date { get; set; }
  14:          public ICollection<Product> Product { get; set; }
  15:          public decimal TotalAmount { get; set; }
  16:      }
  17:  }

 

Product.cs

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel.DataAnnotations;
   4:  using System.Linq;
   5:  using System.Text;
   6:   
   7:  namespace OnlineStore.Models
   8:  {
   9:      public class Product
  10:      {
  11:          [Key]
  12:          public int ID { get; set; }
  13:          public string Name { get; set; }
  14:          public decimal Cost { get; set; }
  15:      }
  16:  }

 

接下來(lái)我們打開(kāi)HomeController  添加一個(gè)新的action,添加好后,我們便來(lái)添加好對(duì)應(yīng)的試圖

   1:    StoreOnlineContext _db = new StoreOnlineContext();
   2:   
   3:          public ActionResult Create()
   4:          {
   5:              //添加測(cè)試數(shù)據(jù)
   6:              //1.添加產(chǎn)品
   7:              Product pro1 = new Product
   8:              {
   9:                  ID=1,
  10:                  Name = "大話設(shè)計(jì)模式",
  11:                  Cost = 39.98M
  12:              };
  13:              Product pro2 = new Product
  14:              {
  15:                  ID = 2,
  16:                  Name = "  WCF服務(wù)編程:.NET開(kāi)發(fā)者決戰(zhàn)SOA的制勝利劍(第3版) [平裝]",
  17:                  Cost = 88.5M
  18:              };
  19:              Product pro3 = new Product
  20:              {
  21:                  ID = 3,
  22:                  Name = "  WCF全面解析(套裝上下冊(cè))",
  23:                  Cost = 126M
  24:              };
  25:              ICollection<Product> pros = new List<Product> { pro1,pro2,pro3};
  26:              //2.添加訂單
  27:              Order order = new Order();
  28:              order.ID = 1;
  29:              order.Date = DateTime.Now;
  30:              order.Product = pros;
  31:              order.TotalAmount = 254.48M;
  32:              //3.添加客戶
  33:              Customer customer = new Customer();
  34:              customer.FirstName = "楊";
  35:              customer.LastName = "洋";
  36:              customer.Number = 10000;
  37:              customer.ServiceLevel = ServiceLevel.Standard;
  38:              customer.Active = true;
  39:              ICollection<Order> orders = new List<Order> { order };
  40:              customer.Orders = orders;
  41:              _db.Customers.Add(customer);
  42:              _db.SaveChanges();
  43:              return Content("添加成功!");
  44:          }

對(duì)應(yīng)的Create頁(yè)面

接下來(lái)按下F5運(yùn)行,默認(rèn)只有 localhost:端口號(hào),顯示的Home中的Index action的內(nèi)容

修改瀏覽器地址欄:localhost:你的端口號(hào)/Home/Create,過(guò)一會(huì),會(huì)顯示添加成功

關(guān)閉窗口,關(guān)掉調(diào)試,我們就會(huì)發(fā)現(xiàn)生成了一個(gè)sdf文件,這個(gè)是我們第一波博客里面說(shuō)的SqlServer Compact

如果沒(méi)發(fā)現(xiàn),請(qǐng)點(diǎn)擊顯示全部文件,或者刷新一下解決方案資源管理器

右鍵該數(shù)據(jù)庫(kù),將它包含到項(xiàng)目中去,我們右鍵打開(kāi)該文件,就會(huì)發(fā)現(xiàn)生成的表文件了

到這里,我們的數(shù)據(jù)基本初始化完成了,數(shù)據(jù)雖然少,但是我們主要是體現(xiàn)的編程思想,下面開(kāi)始吧!

我們現(xiàn)在有一個(gè)這樣的需求:

這個(gè)系統(tǒng)的管理員,想要總結(jié)Customer的 名字,在線狀態(tài),等級(jí)狀態(tài),Order數(shù)量,最近的訂單時(shí)間

一種方案是:我們用domain model完成,將數(shù)據(jù)處理后放到頁(yè)面展示。我們從數(shù)據(jù)庫(kù)中取出Customers,然后把它傳給view,在view里面,我們循環(huán)這個(gè)customer集合,然后構(gòu)造個(gè)table展示,在最后一列(最近訂單日期),在view中又要遍歷Customers中的Orders集合,處理一下,然后找出最近的訂單日期。

這種方法會(huì)感覺(jué)在view上很復(fù)雜,秉著盡可能地設(shè)計(jì)可維護(hù)性好的程序的理念,這種方法就要放棄----復(fù)雜的循環(huán)和計(jì)算應(yīng)該在更高級(jí)的一層去處理,view要做的事情就是展示處理后的結(jié)果。(這里我又添加了一條數(shù)據(jù),但是這次我把Id手動(dòng)賦值給去掉了,因?yàn)閿?shù)據(jù)庫(kù)中我給Id那個(gè)屬性上面加了Key特性,說(shuō)明它是個(gè)主鍵,自動(dòng)增長(zhǎng)列,ICollection會(huì)自動(dòng)理解為外鍵)

我們創(chuàng)建一個(gè)view model來(lái)解決這個(gè)問(wèn)題。

5.1.2 創(chuàng)建一個(gè)View Model

         在Customer Summary頁(yè)面上使用一個(gè)view model是很正確的。我們這樣設(shè)計(jì)我們?cè)贛odels文件中添加一個(gè)CustomerSummary.cs文件)

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:   
   6:  namespace OnlineStore.Models
   7:  {
   8:      public class CustomerSummary
   9:      {
  10:          public string Name { get; set; }
  11:          public string Active { get; set; }
  12:          public string ServiceLevel { get; set; }
  13:          public string OrderCount { get; set; }
  14:          public string MostRecentOrderDate { get; set; }
  15:      }
  16:  }

這里面的結(jié)構(gòu)很簡(jiǎn)單,都是string類型的。對(duì)的,我們所要做的就是在頁(yè)面上顯示文本(text)。這樣看起來(lái),簡(jiǎn)單直接,很容易見(jiàn)看懂了,不是嗎?presentation  model設(shè)計(jì)理念,就是在一個(gè)view里面,presentation model的設(shè)計(jì),要將view要呈現(xiàn)的model的難度降到最低。

這里我解釋一下:presentation  model、view model、domain model的區(qū)別:

presentation  model是頁(yè)面上最終要使用的一類model的總稱,可以是view model,也可以是domain model(當(dāng)然,domain model顯示的數(shù)據(jù)比較簡(jiǎn)單,已經(jīng)不需要在專門去設(shè)計(jì)一個(gè)view model了,它也可以充當(dāng)presentation  model)。view model是為了方便view顯示數(shù)據(jù)而有意,有技巧的而設(shè)計(jì)的model。

打個(gè)比方:presentation 對(duì)應(yīng)  一場(chǎng)展覽晚會(huì),model對(duì)應(yīng)服裝,平時(shí)domain風(fēng)格的model也可以去參加這場(chǎng)晚會(huì),有時(shí)場(chǎng)合合適,但是有時(shí)不適合,在晚會(huì)里會(huì)遇到很多坎坷,所以我們有必要去換一個(gè)風(fēng)格的服裝,比如view風(fēng)格的model,它也可以去參加這場(chǎng)晚會(huì),而且精心設(shè)計(jì)的,我相信view風(fēng)格的在presentation 表現(xiàn)上更出色。所以我會(huì)去選擇view model

不知道你們有沒(méi)有聽(tīng)懂?(哎,這三個(gè)英文單詞的區(qū)別,我是搞懂了,不知道,你有沒(méi)有搞懂?)

5.1.3 把數(shù)據(jù)傳到 Presentation Model

     在我們的應(yīng)用程序中,我們等下會(huì)建立presentation model,這個(gè)model結(jié)構(gòu)和domain model的結(jié)構(gòu)有時(shí)幾乎一模一樣的,你可能會(huì)懷疑,有必要再建立一個(gè)model嗎?用domain model不就夠了嗎,寫兩個(gè)model不麻煩嗎?通常如果你用Entity framework框架生成的實(shí)體已經(jīng)夠做domain model了,但有時(shí)你真的不能怕麻煩,而不去再建立presentation model,寧愿你把ef中生成的實(shí)體,你拷貝過(guò)去都行,都隨便了,只要有都行,我們真正要在頁(yè)面上使用的model都是presentation model,這樣比如 domain model 滿足不了頁(yè)面要顯示的額外數(shù)據(jù),我們就可以在presentation model中拓展要顯示的屬性就行了,view中使用@model關(guān)鍵字 聲明一個(gè)強(qiáng)類型的視圖的時(shí)候,只能是一個(gè)model,假如一個(gè)頁(yè)面要顯示的數(shù)據(jù)來(lái)自兩個(gè)model怎么辦?view中@model只能使用一次,所以你就只能把要顯示的所有內(nèi)容封裝到一個(gè)model中去,而這些數(shù)據(jù)都來(lái)自domain model中的,有的在domain層,可能都是要通過(guò)邏輯計(jì)算后才能得到的結(jié)果,比如 用戶名 發(fā)帖數(shù) 最近訪問(wèn)時(shí)間,這個(gè)發(fā)帖數(shù)使用通過(guò)計(jì)算得到的,除非你數(shù)據(jù)庫(kù)設(shè)計(jì)時(shí),就一張表,字段就這個(gè)3個(gè),那無(wú)所謂了,隨便了,而view中就只是要顯示這3個(gè)字段,所以我們可以建立一個(gè)presentation model,里面就這3個(gè)字段,全string型的,方便顯示了不是嗎?而view中@model 關(guān)鍵字引入的model就是presentation model類型的,就行了.所有復(fù)雜的問(wèn)題都解決了.

每次都要寫presentation model的確很煩,不過(guò)不用擔(dān)心,這個(gè)問(wèn)題,已經(jīng)有人考慮了,我們可以使用AutoMapper工具幫我們對(duì)presentation model和domain model的相互映射,因?yàn)榧偃?domain model中有很多屬性要賦值到presentation model中去,一行一行寫代碼確實(shí)很煩,所以使用AutoMapper就能很快幫我們解決,一行代碼就行了.(我會(huì)在第11章講)

(這段內(nèi)容都是我自己加的,這一波開(kāi)始,我發(fā)現(xiàn)書(shū)中把看書(shū)者的地位已經(jīng)放在你已經(jīng)做過(guò)ASP.NET MVC項(xiàng)目了,內(nèi)容簡(jiǎn)寫了好多)

后期你寫項(xiàng)目的時(shí)候,就應(yīng)該能感受到方便了.我們把要顯示的數(shù)據(jù)使用Presentation model思想封裝的那么好,頁(yè)面上很容易就顯示數(shù)據(jù)了,所以我們就能把開(kāi)發(fā)的重點(diǎn)放在HTML和css樣式,布局前端上面去了,難道不是嗎?

這樣做,反而使的程序更容易測(cè)試,維護(hù),開(kāi)發(fā).寫到這里,我想到一個(gè)想法,團(tuán)隊(duì)開(kāi)發(fā)中,我們可以先寫好Presentation model,domain model直接利用工具生成,寫好后,后臺(tái)程序員直接經(jīng)過(guò)邏輯,將結(jié)果封裝成presentation model去就行了.前端只要Model點(diǎn)屬性不就夠了,真的很簡(jiǎn)單.

在controller中創(chuàng)建presentation model是不好的,因?yàn)閏ontroller負(fù)責(zé)的職責(zé)已經(jīng)很多了,它要決定哪個(gè)view被呈現(xiàn),還有很多其他的工作,所以不要給controller添麻煩了,把這個(gè)model提取出去,新建一個(gè)類也可以

我們新建一個(gè)CustomerSummaryController

代碼:

   1:  using OnlineStore.Models;
   2:  using System;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using System.Web;
   6:  using System.Web.Mvc;
   7:   
   8:  namespace OnlineStore.Controllers
   9:  {
  10:      public class CustomerSummaryController : Controller
  11:      {
  12:          //
  13:          // GET: /CustomerSummary/
  14:          StoreOnlineContext _db = new StoreOnlineContext();
  15:          public ActionResult Index()
  16:          {
  17:              IEnumerable<CustomerSummary> model = from o in _db.Customers.ToList<Customer>()
  18:                      select new CustomerSummary
  19:                      {
  20:                          Name = o.FirstName + o.LastName,
  21:                          Active = o.Active? "是" : "否",
  22:                          ServiceLevel =  Enum.GetName(typeof(ServiceLevel), o.ServiceLevel).ToString(),
  23:                          OrderCount = o.Orders == null ? "0" : o.Orders.Count().ToString(),
  24:                          MostRecentOrderDate=(from sub in o.Orders
  25:                                                                orderby sub.Date descending
  26:                                                                select sub).Count()>0?(from sub in o.Orders
  27:                                                                orderby sub.Date descending
  28:                                                                select sub).FirstOrDefault().Date.ToString("yyyy年MM月dd日"):"還沒(méi)有訂單"
  29:                      };
  30:              return View(model);
  31:          }

在這里,你發(fā)現(xiàn)了,我_db.Customers.ToList<Customer>()

本來(lái)是linq  to entity操作,被我轉(zhuǎn)成了linq to object操作,因?yàn)槲以趌inq to entity遇到一個(gè)問(wèn)題,就是ToString的問(wèn)題,linq to entity不支持ToString,不信你可以試試

在這個(gè)方法中,我們返回的是一個(gè) View(對(duì)象),這個(gè)對(duì)象還是一個(gè)集合

 

5.1.4 ViewData.Model

Controller和View都共享一個(gè)名叫ViewData.ViewData(鍵值對(duì)形式的一個(gè)很正常的集合),類型叫ViewDataDictionary的一個(gè)object

在上個(gè)代碼中,我們最后使用了return View(model),這個(gè)ViewData.Model就會(huì)自動(dòng)的被賦值了,這里被賦值了一個(gè)IEnumerable<CustomerSummary>類型的集合,這個(gè)對(duì)象在view被呈現(xiàn)之前,就已經(jīng)全部準(zhǔn)備好了,所以你在view中就可以使用這個(gè)對(duì)象,并使用它里面的值了.這個(gè)Model屬性是強(qiáng)類型的,所以我們的view知道怎樣去預(yù)測(cè),開(kāi)發(fā)者就可以在vs中就會(huì)有智能提示,得到這個(gè)好處.這些內(nèi)部的工作,大部分的Razor視圖引擎都會(huì)幫我們做好了,我們使用@model關(guān)鍵字

@model IEnumerable<OnlineStore.Models.CustomerSummary>

接著上面的那個(gè)action,我們添加對(duì)應(yīng)的視圖,代碼如下:

   1:  @{
   2:      ViewBag.Title = "Index";
   3:  }
   4:  @model IEnumerable<OnlineStore.Models.CustomerSummary>
   5:  <style>
   6:       td,th{ height:30px; text-align:center;width:20%}
   7:       table td,th{ border:  #0094ff  solid  1px ;}
   8:      table {width:100%;}
   9:  </style>
  10:  <h2>Custommer Summary</h2>
  11:  <table>
  12:      <tr>
  13:          <th>Name</th>
  14:          <th>Active?</th>
  15:          <th>Service Level</th>
  16:          <th>Order Count</th>
  17:          <th>Most Recent Order Date</th>
  18:      </tr>
  19:      @foreach (var summary in Model)
  20:              {
  21:          <tr>
  22:              <td>@summary.Name</td>
  23:              <td>@summary.Active</td>
  24:   
  25:              <td>@summary.ServiceLevel</td>
  26:   
  27:              <td>@summary.OrderCount</td>
  28:              <td>@summary.MostRecentOrderDate</td>
  29:          </tr> 
  30:              }
  31:  </table>

估計(jì)你也看懂了,怎么去使用了.

5.2 表現(xiàn)層的用戶輸入(user input)

就像我們精心設(shè)計(jì)一個(gè)presentation model來(lái)呈現(xiàn)數(shù)據(jù)一樣,我們也要精心設(shè)計(jì)一個(gè)model來(lái)獲得用戶輸入的數(shù)據(jù).在view里,我們使用很厲害的presentation model使工作變得很簡(jiǎn)單,當(dāng)然一個(gè)很厲害的input model也可以在解決獲得用戶輸入的數(shù)據(jù)后添加到數(shù)據(jù)庫(kù)里這個(gè)問(wèn)題上變得很簡(jiǎn)單.以前在ASP.NET里面我們都是通過(guò)request請(qǐng)求上key獲得對(duì)應(yīng)的view來(lái)獲得數(shù)據(jù)然后來(lái)處理的。這里我們使用input model

5.2.1 設(shè)計(jì)model

我們新建一個(gè)類

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:   
   6:  namespace OnlineStore.Models
   7:  {
   8:      public class NewCustomerInput 
   9:            { 
  10:                 public string FirstName { get; set; }                  
  11:                 public string LastName { get; set; }                                                
  12:                 public bool Active { get; set; } 
  13:            }
  14:  }

這個(gè)model主要接受用戶輸入的數(shù)據(jù),跟view都是一一對(duì)應(yīng)的

5.2.2 設(shè)計(jì)model

接下來(lái)我們?cè)贑ustomerSummaryController中添加一個(gè)action

   1:        public ViewResult Save(NewCustomerInput input)
   2:          {
   3:              return View(input);
   4:          } 

添加完NewCustomerInput,F5運(yùn)行下程序,然后我們?cè)儆益ISave名稱,添加對(duì)應(yīng)的view

選中后,我們點(diǎn)確定

當(dāng)然我們可以不選擇模型類,自己添加對(duì)應(yīng)的view后,自己手動(dòng)加代碼,這里只是列出一個(gè)技巧

在這個(gè)Save action中,我們傳了一個(gè)NewCustomerInput類型對(duì)象的參數(shù),這個(gè)值就會(huì)被ASP.NET MVC中的DefaultModelBinder相互綁定,view中就可以把值封裝好后傳過(guò)來(lái),在ASP.NET MVC默認(rèn)是這樣定義的.

我們添加好view后,我們就成功把一個(gè)view變成一個(gè)強(qiáng)類型的view,ViewPage<T>,其中T已經(jīng)被指定為NewCustomerInput對(duì)象了,也就意味著,ViewData.Model對(duì)象已經(jīng)是NewCustomerInput類型的了。然后我們?cè)诰脑O(shè)計(jì)一個(gè)form(表單)就可以完成了.

   1:  @model OnlineStore.Models.NewCustomerInput
   2:   
   3:  @{
   4:      ViewBag.Title = "Save";
   5:  }
   6:  <div>
   7:      <form action="@Url.Action("Save")" method="post">
   8:          <fieldset>
   9:              <div>
  10:                  @Html.LabelFor(x => x.FirstName)
  11:                  @Html.TextBoxFor(x => x.FirstName)
  12:              </div>
  13:              <div>
  14:                  @Html.LabelFor(x => x.LastName)
  15:                  @Html.TextBoxFor(x => x.LastName)
  16:              </div>
  17:              <div>
  18:                  @Html.LabelFor(x => x.Active)
  19:                  @Html.CheckBoxFor(x => x.Active)
  20:              </div>
  21:              <div>
  22:                  <button name="save">
  23:                      保存</button>
  24:              </div>
  25:          </fieldset>
  26:      </form>
  27:  </div>

指定了這個(gè)表單post到哪個(gè)action去處理,這里指定了Save

還有我們使用了lambda表達(dá)式,綁定NewCustomerInput中的屬性

例如,@Html.TextBoxFor(x=> x.LastName)等同于代碼

<input type="text" name="LastName" />

你寫這行代碼和C#風(fēng)格的綁定效果都是一樣的.

  Lambda在重構(gòu)(refactoring)中的幫助

   不要小看view中的lambda表達(dá)式,它們?cè)谀銓懘a的時(shí)候就在編譯,所以你改了action,這個(gè)代碼就會(huì)在編譯的時(shí)候報(bào)錯(cuò),所以在你的view中寫代碼時(shí)候,對(duì)比下你視圖中引用的類,還有返回string的方法--你只有在運(yùn)行的時(shí)候會(huì)發(fā)現(xiàn)這些錯(cuò)誤.

   在refactoring中當(dāng)然還有其他的強(qiáng)類型視圖數(shù)據(jù)引用助手,我們可以使用JetBrains ReSharper(www.jetbrains.com/resharper),它將幫助你重構(gòu)代碼,所有的視圖都可以使用它,一個(gè)很強(qiáng)大的工具

 

再使用強(qiáng)類型助手之前,我們還是依靠 magic(魔力的)strings,編程者們要手動(dòng)地去確保它們和input form一致,使用強(qiáng)類型助手,就像上面view中的代碼,ASP.NET MVC已經(jīng)為我們處理了,所以把input model中的屬性改名了,也不會(huì)在屏幕上顯示錯(cuò)誤,程序順利運(yùn)行,但是打開(kāi)錯(cuò)誤的頁(yè)面,還是會(huì)顯示綁定錯(cuò)誤的.

這里FirstName后我故意添加了一個(gè)s

按下F5的時(shí)候,程序可以運(yùn)行,無(wú)影響,但是指定到使用頁(yè)面的時(shí)候,就會(huì)顯示這個(gè)綁定的錯(cuò)誤.就是這個(gè)效果

5.2.3 處理提交的input model

在上面那個(gè)view中,我們post到Save action,ASP.NET MVC提供了一個(gè)很簡(jiǎn)單的方式,把HTTP請(qǐng)求轉(zhuǎn)換成一個(gè)model,這個(gè)過(guò)程我們叫model binding,第十章我們會(huì)仔細(xì)去講,我們看一下這個(gè)action

接下來(lái)我們新添一個(gè)ActionResult Save2,上面那個(gè)action返回的是ViewResult

修改對(duì)應(yīng)的view中post請(qǐng)求的action,為Save2

按下F5運(yùn)行項(xiàng)目,輸入新地址

然后輸入http://localhost:<你的port>/CustomerSummary/Index

我們?cè)傩薷南耂ave2 action,return 新的action---Index,這樣添加成功后,就會(huì)跳轉(zhuǎn)到Index action,而Index action返回的是一個(gè)view,也就是Customer Summary列表

小提示:修改view中的代碼的時(shí)候,修改好后,保存,不必重新運(yùn)行項(xiàng)目,直接刷新瀏覽器就可以立即看到刷新后的效果

如果程序的服務(wù)器沒(méi)有關(guān),但是vs中的代碼已經(jīng)停止運(yùn)行了,此時(shí)修改view中的代碼,然后保存,也不必重新運(yùn)行項(xiàng)目,直接刷新瀏覽器就可以立即看到刷新后的效果.就等同于修改一個(gè)html一樣,很方便,但是修改后臺(tái)的代碼,就不行了,就必須要重新運(yùn)行項(xiàng)目.

許多view不會(huì)去顯示或者一個(gè)input forms,而是整合很多elements(網(wǎng)頁(yè)上一級(jí)一級(jí)的節(jié)點(diǎn)),來(lái)達(dá)到一個(gè)富客戶端的體驗(yàn).在一下節(jié)里,我么將會(huì)應(yīng)用這些我們?cè)诒静ɡ镆呀?jīng)學(xué)到的concept(概念或者思想),來(lái)實(shí)現(xiàn)一個(gè)更復(fù)雜的view

 

5.3 更復(fù)雜的model,display和input并存

在這一節(jié)里面,我們將構(gòu)造一個(gè)view model,既顯示數(shù)據(jù),也把input model中最后修改的active狀態(tài)數(shù)據(jù)發(fā)送到服務(wù)器上,做修改工作

5.3.1 設(shè)計(jì)展示和Input都存在的model

我們新建一個(gè)CustomerSummary2類

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:   
   6:  namespace OnlineStore.Models
   7:  {
   8:      public class CustomerSummary2
   9:      {
  10:              public string Name { get; set; }
  11:              public string ServiceLevel { get; set; }
  12:              public string OrderCount { get; set; }
  13:              public string MostRecentOrderDate { get; set; }
  14:            public CustomerSummaryInput inputs { get; set; }
  15:          public class CustomerSummaryInput {
  16:              public int Number { get; set; }
  17:              public bool Active { get; set; }
  18:          }
  19:      }
  20:  }

 

這里我們?cè)谝粋€(gè)類中嵌套另一個(gè)類,之后,在user interface上,在顯示的時(shí)候,input elements就會(huì)被嵌套,把CustomerSummaryInput這個(gè)Input model寫在這里面,方便以后的維護(hù),因?yàn)樗瓦@一個(gè)view在一起顯示,在其他view中也沒(méi)有用到啊

注意在CustomerSummaryInput中的Number屬性--它是每一個(gè)customer中的編號(hào)(Id),現(xiàn)在我們凍結(jié)叫楊洋的這個(gè)customer

5.3.2 讓Input Model開(kāi)始工作

我們?cè)傩陆ㄒ粋€(gè)action,MoreSave action,Save3 action

   1:    public ViewResult MoreSave()
   2:          {
   3:              IEnumerable<CustomerSummary2> model = from o in _db.Customers.ToList<Customer>()
   4:                                                   select new CustomerSummary2
   5:                                                   {
   6:                                                       Name = o.FirstName + o.LastName,
   7:                                                       ServiceLevel = Enum.GetName(typeof(ServiceLevel), o.ServiceLevel).ToString(),
   8:                                                       OrderCount = o.Orders == null ? "0" : o.Orders.Count().ToString(),
   9:                                                       MostRecentOrderDate = (from sub in o.Orders
  10:                                                                              orderby sub.Date descending
  11:                                                                              select sub).Count() > 0 ? (from sub in o.Orders
  12:                                                                                                         orderby sub.Date descending
  13:                                                                                                         select sub).FirstOrDefault().Date.ToString("yyyy年MM月dd日") : "還沒(méi)有訂單",
  14:                                                       inputs=new CustomerSummary2.CustomerSummaryInput{
  15:                                                        Active=o.Active,
  16:                                                        Number=o.Number
  17:                                                       }
  18:                                                   };
  19:              return View(model);
  20:          }
  21:   
  22:          [HttpPost]
  23:          public ActionResult Save3(List<CustomerSummary2.CustomerSummaryInput> input)
  24:          {
  25:              foreach (var item in input)
  26:              {
  27:                  Customer cus = _db.Customers.Where(x => x.Number == item.Number).FirstOrDefault();
  28:                  cus.Active = item.Active;
  29:                  _db.SaveChanges();
  30:              }
  31:              return RedirectToAction("MoreSave");
  32:          }

 

我們添加對(duì)應(yīng)的視圖:

   1:  @model IEnumerable<OnlineStore.Models.CustomerSummary2>
   2:  @{
   3:      ViewBag.Title = "MoreSave";
   4:  }
   5:  <style>
   6:      td, th {
   7:          height: 30px;
   8:          text-align: center;
   9:          width: 20%;
  10:      }
  11:   
  12:      table td, th {
  13:          border: #0094ff solid 1px;
  14:      }
  15:   
  16:      table {
  17:          width: 100%;
  18:      }
  19:  </style>
  20:  <h2>Custommer Summary</h2>
  21:  <form action="@Url.Action("Save3")" method="post">
  22:      <table>
  23:          <tr>
  24:              <th>Name</th>
  25:              <th>Service Level</th>
  26:              <th>Order Count</th>
  27:              <th>Most Recent Order Date</th>
  28:              <th>Active?</th>
  29:          </tr>
  30:          @foreach (var summary in Model)
  31:          {
  32:              <tr>
  33:                  <td>@summary.Name</td>
  34:                  <td>@summary.ServiceLevel</td>
  35:   
  36:                  <td>@summary.OrderCount</td>
  37:                  <td>@summary.MostRecentOrderDate</td>
  38:                  <td>
  39:                      <input type="checkbox" name="Active" checked="@summary.inputs.Active"/>
  40:                      <input type="hidden" name="Number" value="@summary.inputs.Number" />
  41:                  </td>
  42:              </tr> 
  43:          }
  44:      </table>
  45:      <div>
  46:          <button name="save">
  47:              修改Active</button>
  48:      </div>
  49:  </form>

按下F5運(yùn)行,就可以看到一個(gè)列表的效果,Active列已經(jīng)自動(dòng)幫我們勾選上了

接下來(lái)修改active,關(guān)于這個(gè),這里的Save3沒(méi)有成功實(shí)現(xiàn),還有問(wèn)題,如果讓我實(shí)現(xiàn)這個(gè)功能,我不會(huì)采用嵌入類的形式的,我自己試著用嵌入類的方式去寫了,但是沒(méi)有成功,你們能幫我解決嗎?

在這一波教程里面,書(shū)里面省略了很多的代碼,而且都簡(jiǎn)化了,博客寫到這里,還有點(diǎn)可惜,因?yàn)榘研薷暮蟮臓顟B(tài)保存回去,還沒(méi)有完成.

這一波的代碼我就不上傳了,手寫練習(xí)吧,如果你有利用嵌入類完成了最后的這個(gè)效果,你能告訴我思路嗎?

 

在下一波的教程里,我們主要講Validation ,驗(yàn)證,再下下一波里,我們主要講AJAX方面的,這兩波內(nèi)容都很多,也都是很重要的部分

關(guān)于ASP.NET MVC4 IN ACTION系列目錄地址已經(jīng)生成:點(diǎn)擊查看目錄

 

 

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
使用MVP模式重構(gòu)代碼
萬(wàn)能 Activity 重構(gòu)篇(Android)
架構(gòu)之路(八)從CurrentUser說(shuō)起
有監(jiān)督預(yù)訓(xùn)練!文本生成又一探索!
初探MVP(ModelViewPresenter)設(shè)計(jì)模式
前端面試 vue 部分 (1)——談?wù)勀銓?duì) MVVM 的理解
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服