標籤:style class blog code http tar
1. MVC模式
MVC模式是一種軟體架構模式。它把軟體系統分為三個部分:模型(Model),視圖(View)和控制器(Controller)。MVC模式最早由Trygve Reenskaug在1974年提出,是施樂帕羅奧多研究中心(Xerox PARC)在20世紀80年代為程式語言Smalltalk發 明的一種軟體設計模式。MVC模式的目的是實現一種動態程式設計,使後續對程式的修改和擴充簡化,並且使程式某一部分的重複利用成為可能。除此之外,此 模式通過對複雜度的簡化,使程式結構更加直觀。軟體系統通過對自身基本部份分離的同時也賦予了各個基本部分應有的功能。
模型(Model) “資料模型”(Model)用於封裝與應用程式的商務邏輯相關的資料以及對資料的處理方法。“模型”有對資料直接存取的權力,例如對資料庫的訪問。“模 型”不依賴“視圖”和“控制器”,也就是說,模型不關心它會被如何顯示或是如何被操作。但是模型中資料的變化一般會通過一種重新整理機制被公布。為了實現這種 機制,那些用於監視此模型的視圖必須事先在此模型上註冊,從而,視圖可以瞭解在資料模型上發生的改變.
視圖(View) 視圖層能夠實現資料有目的的顯示(理論上,這不是必需的)。在視圖中一般沒有程式上的邏輯。為了實現視圖上的重新整理功能,視圖需要訪問它監視的資料模型(Model),因此應該事先在被它監視的資料那裡註冊。
控制器(Controller) 控制器起到不同層面間的組織作用,用於控制應用程式的流程。它處理事件並作出響應。“事件”包括使用者的行為和資料模型上的改變。
在最初的JSP網頁中,像資料庫查詢語句這樣的資料層代碼和像HTML這樣的展示層代碼混在一起。經驗比較豐富的開發人員會將資料從展示層分離開來,但這通常不是很容易做到的,它需要精心地計劃和不斷的嘗試。MVC從根本上強制性地將它們分開。儘管構造MVC應用程式需要一些額外的工作,但是它帶給我們的好處是毋庸置疑的。
首先,多個視圖能共用一個模型。如今,同一個Web應用程式會提供多種使用者介面,例如使用者希望既能夠通過瀏覽器來收發電子郵件,還希望通過手機來訪問電子郵箱,這就要求Web網站同時能提供Internet介面和WAP介面。在MVC設計模式中,模型響應使用者請求並返迴響應資料,視圖負責格式化資料並把它們呈現給使用者,商務邏輯和展示層分離,同一個模型可以被不同的視圖重用,所以大大提高了代碼的可重用性。
其次,控制器是自包含(self-contained)指高獨立內聚的對象,與模型和視圖保持相對獨立,所以可以方便的改變應用程式的資料層和商務規則。例如,把資料庫從MySQL移植到Oracle,或者把RDBMS資料來源改變成LDAP資料來源,只需改變控制器即可。一旦正確地實現了控制器,不管資料來自資料庫還是LDAP伺服器,視圖都會正確地顯示它們。由於MVC模式的三個模組相互獨立,改變其中一個不會影響其他兩個,所以依據這種設計思想能構造良好的少互擾性的構件。
此外,控制器提高了應用程式的靈活性和可配置性。控制器可以用來串連不同的模型和視圖去完成使用者的需求,也可以構造應用程式提供強有力的手段。給定一些可重用的模型和視圖,控制器可以根據使用者的需求選擇適當的模型機型處理,然後選擇適當的的視圖將處理結果顯示給使用者。
2. Hello world 之 ASP.NET MVC 3
如果還沒有開發環境,先在這裡下載Visual Studio 2010和mvc3. 建立一個MVC3項目,選擇Razor模板引擎。VS已經建好了基本的目錄結構和兩個預設的頁面。
查看下檔案的代碼,可以看到Controllers中的類是處理一些邏輯過程,最終返回View用來產生頁面。Model中的代碼錶示的是資料和一些基 本的驗證規則,View通過Model中的資料來填充。運行下程式,可以看到一個基本的網站。MVC網站的運行過程是這樣的:
1. 當第一個請求從用戶端發起的時候,首先執行的是Global.asax中的Application_Start()方法來完成一些初始化工作,其中重要的一步是RegisterRoutes方法,這個方法指定了如何將url映射到具體的方法上,稍後詳解。
2. 根據第一步中指定的映射表產生一個RouteData對象,利用這個對象來建立一個RequestContext對象。
3. MvcRouteHandler建立一個MvcHandler,並將RequestContext對象傳給MvcHandler。
4. MvcHandler對象利用RequestContext對象確定一個IControllerFactory對象來建立Controller對象。
5. MvcHandler對象調用Controller對象的Execute()方法。
6. Controller的ControolerActionInvoker對象決定調用controller的哪個具體的action方法。
7. Action方法接受使用者參數,執行方法,返回一個Result類型的對象。
右擊Controller檔案夾,建立一空Controller,命名為HelloWorld,將代碼改為如下:
public class HelloWorldController : Controller
{
public string Index()
{
return "Hello world";
}
public string Hello()
{
return "Hello everyone";
}
public string Hello2(string name)
{
return "Hello to you " + name;
}
}
運行網站,在瀏覽器中分別訪問 /Helloworld,/Helloworld/hello,/HelloWorld/Hello?name=jack,可以看到相應的字串顯示。這 個例子展示了url是如何映射到具體的方法上的。通常,我們並不直接在Controller中返回字串,而是返回一個View,再建立一個 HelloController,不修改代碼,直接在瀏覽器中訪問/hello:
這是因為我們建立了Controller但沒建立相應的View,ASP.NET會按照一定的路徑去尋找View檔案。在Index方法上右擊,選擇建立View:
然後會彈出如下對話方塊:
在此填入View的名字,選擇視圖引擎,每一種視圖引擎支援一種視圖文法,MVC3支援多種模板文法,可以通過不同的視圖引擎來擴充實現。ASP.NET MVC早先使用的視圖引擎是和asp.net的webform一樣的。Razor引擎是MVC3新加入的引擎,還有一些開源的引擎可以用,例如NDjango就實現了類型Django的模板文法。在這個例子中選擇Razor引擎。最下面可以選擇一個MasterPage,這個和webform的主版頁面的概念是一樣的,使用預設的_viewstart頁面就可以。
在建立的視圖檔案中寫下一行html代碼:
@{
ViewBag.Title = "Index";
}
<h2>Hello My First View</h2>
運行網站,訪問/hello頁面:
其中ViewBag是一個dynamic類型的對象,可以用來在controller和頁面之間傳遞資料。將Controller的代碼改為:
public ActionResult Index()
{
ViewBag.Count = 4;
return View();
}
視圖頁面的代碼改為:
@{
ViewBag.Title = "Index";
}
<h2 >Hello My First View </h2 >
<ul >
@for (int i = 0; i < ViewBag.Count; i++)
{
<li >Hello @i </li >
}
</ul >
接下來來實現一個基本的增刪改的功能。假設我們要對電影的基本資料進行管理,首先需要定義一個Model類型,建立一個Model,代碼如下:
namespace HelloWorld.Models
{
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
}
public class MovieDBContext : DbContext
{
public DbSet<movie> Movies { get; set; }
}
}
接下來,我們建立一個Movie的Controller,使用EntityFramework來存取資料,如下配置:
點擊Add後,可以看到一個具備準系統的Controller已經建好。在View中,相應的CRUD頁面也已經有了。我們還需要配置下資料庫連接,在web.config中添加串連串的資訊:
此時資料庫和Movie表都還沒有,不過沒有關係,我們使用的 Entity Framework 4 的 Code First Development,它只需要一個平凡的類就可以了,EF會幫你完成建立資料庫和資料庫表的工作。運行網站,效果如下:
開啟SQL Sever,可以看到Movie表:
如果Model檔案發生了變化,例如添加了一個欄位:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
public string Rating { get; set; }
}
再運行下程式,就會發生錯誤:
錯誤訊息提示說資料庫在model建立之後已經發生了變化,要解決有兩種方案,一是調用Database.SetInitializer方法來自動重建 資料庫,二是手動修改資料庫表。第一種方法雖然簡單但是會導致已有的資料丟失,他會重建整個資料庫。但是在開發初期非常適合使用。在這裡先採用第一種方 案。具體方法是,在model中建立一個類繼承自DropCreateDatabaseIfModelChanges類。在其中可以加上可選的初始化資料的代碼,代碼如下:
using System;
using System.Collections.Generic;
using System.Data.Entity;
namespace HelloWorld.Models
{
public class MovieInitializer : DropCreateDatabaseIfModelChanges<moviedbcontext>
{
protected override void Seed(MovieDBContext context)
{
var movies = new List<movie> {
new Movie { Title = "When Harry Met Sally",
ReleaseDate=DateTime.Parse("1989-1-11"),
Genre="Romantic Comedy",
Rating="R",
Price=7.99M},
new Movie { Title = "Ghostbusters ",
ReleaseDate=DateTime.Parse("1984-3-13"),
Genre="Comedy",
Rating="R",
Price=8.99M},
};
movies.ForEach(d => context.Movies.Add(d));
}
}
}</moviedbcontext>
然後在Global.asax中將這個對象註冊下:
protected void Application_Start()
{
System.Data.Entity.Database.SetInitializer(new HelloWorld.Models.MovieInitializer());
//其餘不變
}
再運行下程式,有可能會遇到這個錯誤:
"This operation requires a connection to the ‘master‘ database. Unable to create a connection to the ‘master‘ database because the original database connection has been opened and credentials have been removed from the connection string. Supply an unopened connection."
我在這裡找到瞭解決方法。需要把連結字串中的Persist Security Info=true加上。然後程式就能正常運行了。運行之後,View頁面並不會自動跟著改變,需要手動修改。修改完成後,看一下編輯頁面:
這時候可以更新Rating欄位。編輯頁面還內建驗證功能,不過是英文的,下面我們會改進這個驗證功能。