一、MVC簡單入門
1.1、MVC概念
視圖(View)
代表用戶交互界面,對於Web應用來說,可以概括為HTML界面,但有可能為XHTML、XML和Applet。
模型(Model)
表示用戶對其數據的操作的一個封轉。可以分為視圖模型(view model)和領域模型(domain models),視圖模型就是在視圖與控制器之間傳輸數據的一個封轉,而領域模型就是業務邏輯,后台數據模型等的一個集合。是我們學的3層中的BLL,DAL,Models的集合
控制器(Controller)
控制器可以理解為從用戶接收請求,將模型與視圖匹配在一起,共同完成用戶的請求。
1.2、ASP.NET MVC 原理
當在瀏覽器中輸入一個URL,進入了Route系統,路由系統得到URL各個片段的值,並交給MVC處理,MVC依據URL的信息知道請求的Action,接着就對模型進行一系列的處理,然后呈現視圖。
MVC對控制器與View有一定的限制,但對模型沒有任何的限制。
控制器必須實現IController接口或者繼承Controller類,控制器類中的公有方法稱之為Action Method。
1.3、MVC項目結構及含義
1.4、MVC命名習慣
在MVC項目中有2種習慣
a、建議你如何組織項目中的一些文件,比如js文件放在Scripts文件夾下,像這種習慣,你完全可以不遵循,這些文件夾和文件刪除並不影響MVC框架本身。
b、另外一種,有個專門的術語:”Convention over configuration”,意思就是說如果你遵循了這個習慣就不需要進行額外的配置或編碼(特別是控制器與視圖)。這種習慣就盡量遵循,如果違反,在MVC中就需要做許多的事情。
主要有3個方面:
a、控制器命名習慣:控制器類必須以Controller結尾,但引用這個控制器的時候可以省略掉Controller,如果想改變這種行為,需要自己實現IControllerFactory接口,默認是通過DefaultControllerFactory來執行這個控制器的查找的。
b、視圖命名習慣:視圖或者分部視圖應該放在/Views/Controllername文件夾下面,比如一個控制器為Demo 那么這個控制器的所有視圖應該放在/Views/Demo/下面,默認情況下,每一個Action Method對應一個視圖,盡
量讓視圖名字與Action名字一樣,這樣在Action中就可以直接return View();而放在Shared文件夾下面的視圖所有的控制器都可以使用
c、布局命名習慣:布局文件都以下划線開頭,並放置在shared文件夾下面,在MVC 3中默認每個視圖都會用到_layout.cshtml布局,可以在_viewstart.cshtml看到這個設置
1.5、ASP.NET MVC優缺點
優點:
A、具有多個視圖對應一個模型的能力。
B、由於一個應用被分離為三層,因此有時改變其中的一層就能滿足應用的改變。一個應用的業務流程或者業務規則的改變只需改動MVC的模型層。
C、它還有利於軟件工程化管理。由於不同的層各司其職,每一層不同的應用具有某些相同的特征,有利於通過工程化、工具化產生管理程序代碼。
缺點:
A、增加了系統結構和實現的復雜性。
B、視圖與控制器間的過於緊密的連接。
C、視圖對模型數據的低效率訪問。
1.6、創建第一個MVC應用程序
創建第一個MVC應用程序之前,首先說明一下我的電腦使用配置環境:VS2013與SQLSever2012。
1、首先打開VS2013,新建一個MVC4項目。
2、點擊確定后會彈出如下圖界面。
3、點擊確定后會自動生成如下默認項目結構。
4、在Controller文件夾上右鍵添加一個控制器。
5、點擊添加按鈕后,生成HomeController類,默認生成Index()方法如下:
6、現在Controller控制器已經創建好了,下面來創建一個View視圖了,添加添加視圖兩種方式:方式一:在控制器里的Index()方法里右鍵添加視圖,方式二:在View文件夾上右鍵添加一個與HomeController控制器名稱相同的文件夾如:Home文件夾,在該文件夾上右鍵添加一個與Index()方法同名的視圖。這里選擇選擇方式一創建方法如下所示:
7、最終添加視圖后的界面,開始運行瀏覽查看結果。
到這里我們的第一個MVC程序Hello World就完成了,是不是感覺很簡單。那么接下來就來學習寫一個關於Asp.Net MVC的增刪改查的簡單測試案例吧。已經學習過Asp.Net的同學可以先思考一下如何用MVC實現一個增刪改查的的功能。沒有學習過的同學可以思考下邏輯三層與MVC中Model的聯系,下面這個簡單測試案例將讓你對MVC概念的理解的更明白些。
1.7、實現一個關於Asp.Net MVC的增刪改查的簡單測試案例
測試案例增刪改查效果圖如下:
1、首先准備數據庫數據。
use master go create database Demo go use Demo go create table Product ( ID int primary key identity(1,1), Name nvarchar(20), Price decimal ) go insert into Product values('電腦墊',22),('鼠標',55),('鍵盤',22),('網線',32),('U盤',100),('咖啡',55),('書籍',99),('牛奶',5) go
2、打開VS2013創建一個名為MvcFristDemo的MVC4項目,創建步驟與上面一致,這里步驟不再詳細介紹,最終項目創建完成截圖如下。
這里需要說明一下添加視圖的步驟與上面Hello World示例有所區別:因為要用到Model模型,所以在添加視圖的時候需要選中如下圖中的創建強類型視圖 模型選擇Product模型。
3、步驟一:ProductController控制器代碼如下。
1 using MvcFirstDemo.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 MvcFirstDemo.Controllers 9 { 10 public class ProductController : Controller 11 { 12 public ActionResult List() 13 { 14 List<Product> result = new ProductBll().Select(); 15 return View(result); 16 } 17 18 19 public ActionResult Add() 20 { 21 return View(); 22 } 23 [HttpPost] 24 public ActionResult Add(Product p) 25 { 26 bool result = new ProductBll().Insert(p); 27 return RedirectToAction("List"); 28 } 29 30 public ViewResult Update(int id) 31 { 32 Product p = new ProductBll().GetProductById(id); 33 return View(p); 34 } 35 [HttpPost] 36 public ActionResult Update(Product p) 37 { 38 bool result = new ProductBll().Update(p); 39 return RedirectToAction("List"); 40 } 41 42 public ActionResult Delete(int id) 43 { 44 bool result = new ProductBll().Delete(id); 45 return RedirectToAction("List"); 46 } 47 } 48 }
4、步驟二:Model文件夾中的三個類代碼如下。
Product.cs代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 namespace MvcFirstDemo.Models 7 { 8 public class Product 9 { 10 public int ID { get; set; } 11 public string Name { get; set; } 12 public decimal Price { get; set; } 13 } 14 }
ProductBll.cs代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 namespace MvcFirstDemo.Models 7 { 8 public class ProductBll 9 { 10 ProductDal dal = new ProductDal(); 11 public List<Product> Select() 12 { 13 return dal.Select(); 14 } 15 public Product GetProductById(int id) 16 { 17 return dal.GetProductById(id); 18 } 19 public bool Update(Product p) 20 { 21 return dal.Update(p); 22 } 23 24 public bool Insert(Product p) 25 { 26 return dal.Insert(p); 27 } 28 29 public bool Delete(int id) 30 { 31 return dal.Delete(id); 32 } 35 } 36 }
ProductDal.cs代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Data.SqlClient; 4 using System.Linq; 5 using System.Web; 6 7 namespace MvcFirstDemo.Models 8 { 9 public class ProductDal 10 { 11 string connStr = @"server=PC-201511211346\MSSQLSERVER2;database=Demo;uid=sa;pwd=123456;"; 12 public List<Product> Select() 13 { 14 using (SqlConnection conn = new SqlConnection(connStr)) 15 { 16 conn.Open(); 17 string SQL = "select * from Product"; 18 SqlCommand cmd = new SqlCommand(SQL, conn); 19 using (SqlDataReader sdr = cmd.ExecuteReader()) 20 { 21 List<Product> list = new List<Product>(); 22 Product obj = null; 23 while (sdr.Read()) 24 { 25 obj = new Product 26 { 27 ID = Convert.ToInt32(sdr["ID"]), 28 Name = sdr["Name"].ToString(), 29 Price = Convert.ToDecimal(sdr["Price"]) 30 }; 31 list.Add(obj); 32 } 33 return list; 34 } 35 } 36 } 37 38 public bool Insert(Product p) 39 { 40 using (SqlConnection conn = new SqlConnection(connStr)) 41 { 42 conn.Open(); 43 string SQL = "insert into Product values(@Name,@Price)"; 44 SqlCommand cmd = new SqlCommand(SQL, conn); 45 cmd.Parameters.AddWithValue("Name", p.Name); 46 cmd.Parameters.AddWithValue("Price", p.Price); 47 return cmd.ExecuteNonQuery() > 0 ? true : false; 48 } 49 } 50 51 public bool Update(Product p) 52 { 53 using (SqlConnection conn = new SqlConnection(connStr)) 54 { 55 conn.Open(); 56 string SQL = "update Product set Name=@Name,Price=@Price where ID=@ID"; 57 SqlCommand cmd = new SqlCommand(SQL, conn); 58 cmd.Parameters.AddWithValue("@ID", p.ID); 59 cmd.Parameters.AddWithValue("@Name", p.Name); 60 cmd.Parameters.AddWithValue("@Price", p.Price); 61 62 return cmd.ExecuteNonQuery() > 0 ? true : false; 63 } 64 } 65 66 public bool Delete(int id) 67 { 68 using (SqlConnection conn = new SqlConnection(connStr)) 69 { 70 conn.Open(); 71 string SQL = "delete from Product where ID=@ID"; 72 SqlCommand cmd = new SqlCommand(SQL, conn); 73 cmd.Parameters.AddWithValue("@ID", id); 74 return cmd.ExecuteNonQuery() > 0 ? true : false; 75 } 76 } 77 78 internal Product GetProductById(int id) 79 { 80 using (SqlConnection conn = new SqlConnection(connStr)) 81 { 82 conn.Open(); 83 string SQL = "select * from Product where ID=@ID"; 84 SqlCommand cmd = new SqlCommand(SQL, conn); 85 cmd.Parameters.AddWithValue("@ID", id); 86 using (SqlDataReader sdr = cmd.ExecuteReader()) 87 { 88 Product obj = null; 89 while (sdr.Read()) 90 { 91 obj = new Product 92 { 93 ID = Convert.ToInt32(sdr["ID"]), 94 Name = sdr["Name"].ToString(), 95 Price = Convert.ToDecimal(sdr["Price"]) 96 }; 97 } 98 return obj; 99 } 100 } 101 } 102 } 103 }
5、步驟三:View文件夾中三個視圖代碼如下。
這里需要說明一下的是對List.aspx頁面中圖一中默認生成代碼改成圖二中代碼,修改成紅色部分代碼:<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<List<MvcFirstDemo.Models.Product>>" %>
為什么要這樣修改呢?因為我們在ProductDal.cs類中的Select()方法返回的是list<Product>集合 ,而在List.aspx頁面中foreach需要遍歷一個List<Product>集合綁定顯示列表。如果你不做修改,運行程序后會出現如下圖所示錯誤。
List.aspx頁面代碼如下:
1 <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<List<MvcFirstDemo.Models.Product>>" %> 2 3 <!DOCTYPE html> 4 5 <html> 6 <head runat="server"> 7 <meta name="viewport" content="width=device-width" /> 8 <title>List</title> 9 </head> 10 <body> 11 <div> 12 <table cellspacing="1" border="1"> 13 <tr> 14 <td>產品ID</td> 15 <td>產品名稱</td> 16 <td>產品價格</td> 17 <td>操作 <a href="Product/Add">增加</a></td> 18 </tr> 19 <% 20 foreach (var item in Model) 21 { 22 %> 23 <tr> 24 <td><%=item.ID %></td> 25 <td><%=item.Name %></td> 26 <td><%=item.Price %></td> 27 <td> 28 <a href="/Product/Update?id=<%=item.ID %>">修改</a> 29 <a href="/Product/Delete?id=<%=item.ID %>">刪除</a> 30 </td> 31 </tr> 32 <% 33 } 34 %> 35 </table> 36 </div> 37 </body> 38 </html>
Add.aspx頁面代碼如下:
1 <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MvcFirstDemo.Models.Product>" %> 2 3 <!DOCTYPE html> 4 5 <html> 6 <head runat="server"> 7 <meta name="viewport" content="width=device-width" /> 8 <title>Add</title> 9 </head> 10 <body> 11 <div> 12 <form action="/Product/Add" method="post"> 13 <input type="text" name="Name" value=" " /> 14 <input type="text" name="Price" value=" " /> 15 <input type="submit" name="submit" value="增加" /> 16 </form> 17 </div> 18 </body> 19 </html>
Update.aspx頁面代碼如下:
1 <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MvcFirstDemo.Models.Product>" %> 2 3 <!DOCTYPE html> 4 5 <html> 6 <head runat="server"> 7 <meta name="viewport" content="width=device-width" /> 8 <title>Update</title> 9 </head> 10 <body> 11 <div> 12 <form action="/Product/Update" method="post"> 13 <input type="hidden" name="ID" value="<%=Model.ID%>" /> 14 <input type="text" name="Name" value="<%=Model.Name %>" /> 15 <input type="text" name="Price" value="<%=Model.Price %>" /> 16 <input type="submit" name="submit" value="修改" /> 17 </form> 18 </div> 19 </body> 20 </html>
二、初學者常見的幾個錯誤總結。
2.1、錯誤一
解決辦法:此錯誤解決方式有三個,方式一:在圖二中Update(int id)方法修改成可以為null的方法Update(int? id),方式二:給圖二中Update(int id)方法參數添加一個默認值如:Update(int id=0)即可。方式三:把圖二中的參數名dd改成與圖一中傳遞的參數名id一樣的名字即可解決為null問題獲得數據。
2.2、錯誤二
解決辦法:在如下圖中方法重載代碼處,其中一個方法添加一個特性如[HttpPost]、[HttpPut]、[HttpPatch],即可解決此問題,至於添加哪個特性需要依據你發起請求的方法而決定。
2.3、錯誤三
解決辦法:此問題的解決辦法在上面步驟三中已做解釋說明,這里不再重復解釋。
2.4、錯誤四
解決辦法:把下圖中的傳遞表單數據的參數名字改成與Product模型類里的字段名一樣即可獲得表單傳遞過來的數據。
2.4、錯誤五
解決辦法:查看頁面代碼發現瀏覽器請求的頁面路徑並沒有錯誤,但是運行又確實報錯,找不到請求URL指定路徑的頁面,這該怎么辦呢?我們冷靜分析一下,這里其實牽涉到了一個知識點,就是你對MVC原理的理解,在前面1.2、Asp.Net MVC的原理節中已經講到MVC的原理,所以這里我們只需要做如下圖所示修改即可解決此問題。
三、示例下載
Github下載地址:https://github.com/SeeYouBug2/MvcFirstDemo.git
總結:在本文章中,主要是對理解ASP.NET MVC的相關概念做了個簡單介紹,以及通過一個MVC增刪改查簡單測試案例幫助初學者加深對MVC模式的理解,最后還總結了初學者幾個常見的錯誤,讓初學者少走點彎路。