2008 MVC (Modual View Controller) 架構介紹
http://msdn.microsoft.com/zh-tw/magazine/cc337884.aspx#S2
MVC至今已推廣三年,由MVC 發展至 MVC3
未來的發展實令人值得期待,開創Web高速的時代
本文探討:
|
本文使用技術: ASP.NET |
下載程式碼位址: MVCFramework2008_03.exe (189 KB)
Browse the Code Online
- 分離問題:不要將 UI 邏輯與基礎行為混在一起。
- 自動化單元測試:撰寫驗證程式碼行為是否合乎預期的自動化測試。
- 運用 HTTP 與 HTML -- 不要隱藏。
- 從頭到尾都內建可測試性。
- 幾乎可在每一點進行延伸。
- 讓您完全控制輸出。
using System;
using System.Web;
using System.Web.Mvc;
namespace HelloFromMVC.Controllers
{
public class HelloController : Controller
{
[ControllerAction]
public void Index()
{
...
}
}
}
[ControllerAction]
public void HiThere(string id)
{
ViewData["Name"] = id;
RenderView("HiThere");
}
namespace HelloFromMVC.Tests
{
[TestClass]
public class HelloControllerFixture
{
[TestMethod]
public void HiThereShouldRenderCorrectView()
{
TestableHelloController controller = new
TestableHelloController();
controller.HiThere("Chris");
Assert.AreEqual("Chris", controller.Name);
Assert.AreEqual("HiThere", controller.ViewName);
}
}
class TestableHelloController : HelloController
{
public string Name;
public string ViewName;
protected override void RenderView(
string viewName, string master, object data)
{
this.ViewName = viewName;
this.Name = (string)ViewData["Name"];
}
}
}
<html >
<head runat="server">
<title>Hi There!</title>
</head>
<body>
<div>
<h1>Hello, <%= ViewData["Name"] %></h1>
</div>
</body>
</html>
using System;
using System.Web;
using System.Web.Mvc;
namespace HelloFromMVC.Views.Hello
{
public partial class HiThere : ViewPage
{
}
}
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
// Change Url= to Url="[controller].mvc/[action]/[id]"
// to enable automatic support on IIS6
RouteTable.Routes.Add(new Route
{
Url = "[controller]/[action]/[id]",
Defaults = new { action = "Index", id = (string)null },
RouteHandler = typeof(MvcRouteHandler)
});
RouteTable.Routes.Add(new Route
{
Url = "Default.aspx",
Defaults = new {
controller = "Home",
action = "Index",
id = (string)null },
RouteHandler = typeof(MvcRouteHandler)
});
}
}
Url = "[controller]/[action]/[id]"
RouteTable.Routes.Add(new Route
{
Url = "[id]",
Defaults = new {
controller = "Hello",
action = "HiThere" },
RouteHandler = typeof(MvcRouteHandler)
});
- /[pagename] 顯示這個名稱的頁面。
- /[pagename]?version=n 顯示要求的頁面版本,0 = 目前版本、1 = 前一版...依此類推。
- /Edit/[pagename] 開啟該頁面的編輯畫面。
- /CreateNewVersion/[pagename] 張貼以便提交編輯結果的目標 URL。
public class WikiPageController : Controller
{
ISpaceRepository repository;
public ISpaceRepository Repository
{
get {
if (repository == null)
{
repository = new FileBasedSpaceRepository(
Request.MapPath("~/WikiPages"));
}
return repository;
}
set { repository = value; }
}
[ControllerAction]
public void ShowPage(string pageName, int? version)
{
WikiSpace space = new WikiSpace(Repository);
WikiPage page = space.GetPage(pageName);
RenderView("showpage",
new WikiPageViewData
{
Name = pageName,
Page = page,
Version = version ?? 0
});
}
}
public class WikiPageViewData {
public string Name { get; set; }
public WikiPage Page { get; set; }
public int Version { get; set; }
public WikiPageViewData() {
Version = 0;
}
public string NewVersionUrl {
get {
return string.Format("/CreateNewVersion/{0}", Name);
}
}
public string Body {
get { return Page.Versions[Version].Body; }
}
public string HtmlBody {
get { return Page.Versions[Version].BodyAsHtml(); }
}
public string Creator {
get { return Page.Versions[Version].Creator; }
}
public string Tags {
get { return string.Join(",", Page.Versions[Version].Tags); }
}
}
namespace MiniWiki.Views.WikiPage {
public partial class ShowPage : ViewPage<WikiPageViewData>
{
}
}
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
AutoEventWireup="true" CodeBehind="ShowPage.aspx.cs"
Inherits="MiniWiki.Views.WikiPage.ShowPage" %>
<asp:Content
ID="Content1"
ContentPlaceHolderID="MainContentPlaceHolder"
runat="server">
<h1><%= ViewData.Name %></h1>
<div id="content">
<%= ViewData.HtmlBody %>
</div>
</asp:Content>
namespace MiniWiki.Views.Layouts
{
public partial class Site :
System.Web.Mvc.ViewMasterPage<WikiPageViewData>
{
}
}
<%@ Master Language="C#"
AutoEventWireup="true"
CodeBehind="Site.master.cs"
Inherits="MiniWiki.Views.Layouts.Site" %>
<%@ Import Namespace="MiniWiki.Controllers" %>
<%@ Import Namespace="MiniWiki.DomainModel" %>
<%@ Import Namespace="System.Web.Mvc" %>
<html >
<head runat="server">
<title><%= ViewData.Name %></title>
<link href="http://../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="inner">
<div id="top">
<div id="header">
<h1><%= ViewData.Name %></h1>
</div>
<div id="menu">
<ul>
<li><a href="http://Home">Home</a></li>
<li>
<%= Html.ActionLink("Edit this page",
new { controller = "WikiPage",
action = "EditPage",
pageName = ViewData.Name })%>
</ul>
</div>
</div>
<div id="main">
<div id="revisions">
Revision history:
<ul>
<%
int i = 0;
foreach (WikiPageVersion version in ViewData.Page.Versions)
{ %>
<li>
<a href="http://<%= ViewData.Name %>?version=<%= i %>">
<%= version.CreatedOn %>
by
<%= version.Creator %>
</a>
</li>
<% ++i;
} %>
</ul>
</div>
<div id="maincontent">
<asp:ContentPlaceHolder
ID="MainContentPlaceHolder"
runat="server">
</asp:ContentPlaceHolder>
</div>
</div>
</div>
</body>
</html>
[ControllerAction]
public void EditPage(string pageName)
{
WikiSpace space = new WikiSpace(Repository);
WikiPage page = space.GetPage(pageName);
RenderView("editpage",
new WikiPageViewData {
Name = pageName,
Page = page });
}
<%@ Page Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
AutoEventWireup="true"
CodeBehind="EditPage.aspx.cs"
Inherits="MiniWiki.Views.WikiPage.EditPage" %>
<%@ Import Namespace="System.Web.Mvc" %>
<%@ Import Namespace="MiniWiki.Controllers" %>
<asp:Content ID="Content1"
ContentPlaceHolderID="MainContentPlaceHolder"
runat="server">
<form action="<%= Url.Action(
new { controller = "WikiPage",
action = "NewVersion",
pageName = ViewData.Name })%>" method=post>
<%
if (ViewContext.TempData.ContainsKey("errors"))
{
%>
<div id="errorlist">
<ul>
<%
foreach (string error in
(string[])ViewContext.TempData["errors"])
{
%>
<li><%= error%></li>
<% } %>
</ul>
</div>
<% } %>
Your name: <%= Html.TextBox("Creator",
ViewContext.TempData.ContainsKey("creator") ?
(string)ViewContext.TempData["creator"] :
ViewData.Creator)%>
<br />
Please enter your updates here:<br />
<%= Html.TextArea("Body", ViewContext.TempData.ContainsKey("body") ?
(string)ViewContext.TempData["body"] :
ViewData.Body, 30, 65)%>
<br />
Tags: <%= Html.TextBox(
"Tags", ViewContext.TempData.ContainsKey("tags") ?
(string)ViewContext.TempData["tags"] :
ViewData.Tags)%>
<br />
<%= Html.SubmitButton("SubmitAction", "OK")%>
<%= Html.SubmitButton("SubmitAction", "Cancel")%>
</form>
</asp:Content>
[ControllerAction]
public void NewVersion(string pageName) {
NewVersionPostData postData = new NewVersionPostData();
postData.UpdateFrom(Request.Form);
if (postData.SubmitAction == "OK") {
if (postData.Errors.Length == 0) {
WikiSpace space = new WikiSpace(Repository);
WikiPage page = space.GetPage(pageName);
WikiPageVersion newVersion = new WikiPageVersion(
postData.Body, postData.Creator, postData.TagList);
page.Add(newVersion);
} else {
TempData["creator"] = postData.Creator;
TempData["body"] = postData.Body;
TempData["tags"] = postData.Tags;
TempData["errors"] = postData.Errors;
RedirectToAction(new {
controller = "WikiPage",
action = "EditPage",
pageName = pageName });
return;
}
}
RedirectToAction(new {
controller = "WikiPage",
action = "ShowPage",
pageName = pageName });
}
public class WikiPageControllerFactory : IControllerFactory {
public IController CreateController(RequestContext context,
Type controllerType)
{
return new WikiPageController(
GetConfiguredRepository(context.HttpContext.Request));
}
private ISpaceRepository GetConfiguredRepository(IHttpRequest request)
{
return new FileBasedSpaceRepository(request.MapPath("~/WikiPages"));
}
}
ControllerBuilder.Current.SetControllerFactory( typeof(WikiPageController), typeof(WiliPageControllerFactory));
- OnPreAction、OnPostAction 及 OnError 可讓您在執行的每個動作上攔截泛型的前置與後置處理程序。OnError 則會提供整個控制器的錯誤處理機制。
- URL 路由到控制器但控制器並未實作路由中要求的動作時,就會呼叫 HandleUnknownAction。根據預設,這個方法會擲回例外狀況,不過您可以加以覆寫,以執行自己想要的任何動作。
- InvokeAction 這個方法會指出要呼叫的動作方法,並呼叫該方法。如果您想要自訂程序 (例如,免除 [ControllerAction] 屬性的需求),就是在這裡自訂。

留言功能已依作者設定調整顯示方式