快速导航
第六章 ASP.NET MVC辅助程序和扩展
前面我们提到了Web Forms利用服务器控件来完成工作,并且结果呈现为HTML,以供客户端上的浏览器使用。
然而,输出的HTML的完整结构并不由开发人员控制,除非不使用服务器控件,仅使用HTML控件有限的辅助功能。
6.1 MVC
MVC没有与Web Forms一样多的控件,没有<asp:TextBox />
这样的概念。在Web Forms中,页面文件和后台代码文件总是在一起,名字也一样,只不过一个是.aspx
文件一个为.aspx.cs
文件而已。解决方案管理器也把它们显示在一起,服务器控件通过ID都可以被后台代码调用,这是因为服务器控件其实是一个实例化的对象,自然其所有的属性都可以被调用。
MVC则不采用这样的方式,它每一块都是相互独立的,互相之间一无所知。Web Forms里的服务器控件不但用于生成返回给客户端的内容,还管理着从客户端接收的消息。这点跟MVC中架构的关注点分离思想相悖。ASP.NET MVC在默认情况下负责实现"模型-视图-控制器"的分离。
6.2 不同的方法
ASP.NET MVC不使用控件来管理信息的传递,而是使用模型的概念,如下图所示:
- 模型(Model)代表了数据底层的业务逻辑,它不关心视图究竟长什么样,只负责不同属性值的生成。
- 模型由控制器(Controller)负责填写,然后送入视图(View)。
- 视图将拿到的属性值分配给相应的界面元素。
让我们先看看这三部分代码,最后再讲解如何将它们拼起来:
模型Model
public class DemoModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
}
视图View
@model RentMyWrox.Models.DemoModel
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div>
@Html.DisplayFor(model => model.Property1)
</div>
<div>
@Html.DisplayFor(model => model.Property2)
</div>
<div>
@Html.DisplayFor(model => model.Property3)
</div>
</body>
</html>
控制器
public class DemoModelController : Controller
{
// GET: DemoModel/Details/{ID}
public ActionResult Details(int id)
{
DemoModel dm = new DemoModel()
{
Property1 = id.ToString(),
Property2 = $"Property2 {id}",
Property3 = $"Property3 {id}"
};
return View("DemoModelView", dm);
}
}
页面中的第一行用于定义视图要使用的模型:
@model RentMyWrox.Models.DemoModel
而第二种语法告诉Razor视图引擎,在页面上显示模型的属性Property1:
@Html.DisplayFor(model => model.Property1);
6.2.1 Razor语法
使用Razor语言时要注意:
- 代码通过@字符添加到页面里,这个字符告诉解析器,接下来的命令看作代码处理而非HTML元素。假如你需要在html上输出@字符,你可以像下面这么写:
@Html.Raw("@") //Raw方法返回的是IHtmlString对象
或者
@{
Response.Write("@"); // 这种方式会写在整个响应流前面
}
又或者
@{
HtmlString atString = new HtmlString("@");
string anotherAtString = "@";
}
@atString //因为HtmlString也实现IHtmlString接口
@anotherAtString //正常显示字符串
- 可以用@之后紧跟一对大括号代表代码块,代码不是只能有一行。
- 在代码块种,语句以分号结尾,跟C#一样的规则。
- 允许使用变量来存储值,与C#一样。
- 可以混合使用Razor代码与HTML标签,如下所示:
@{
for (int i = 0; i < 5; i++)
{
<div>@i</div>
<div>i</div>
}
}
Razor提供了不同的Display方法来在页面上显示数据,如下图所示:
虽然这部分称为View,但所有的处理仍然发生在服务端,也就是发送到客户端之前,要完成所有这些处理。
6.2.2 控制器
控制器决定使用什么模型,调用什么视图。控制器处理HTTP请求,如GET、PUT、POST或者DELETE。下面就是DemoModelController的内容,其中注释说明的是请求的类型和访问的Url:
public class DemoModelController : Controller
{
// GET: DemoModel
public ActionResult Index()
{
List<DemoModel> list = new List<DemoModel>();
for (int i = 0; i < 5; i++)
{
list.Add(new DemoModel
{
Property1 = i.ToString(),
Property2 = $"Property2 {i}",
Property3 = $"Property3 {i}"
}
);
}
return View("DemoModelList", list);
}
// GET: DemoModel/Details/{ID}
public ActionResult Details(int id)
{
DemoModel dm = new DemoModel()
{
Property1 = id.ToString(),
Property2 = $"Property2 {id}",
Property3 = $"Property3 {id}"
};
return View("DemoModelView", dm);
}
// GET: DemoModel/Create
public ActionResult Create()
{
return View(); // 需要填写的表单,用来创建新对象
}
// POST: DemoModel/Create
[HttpPost]
public ActionResult Create(DemoModel model)
{
return View(); // 用来确认某个新对象是否已经创建
}
// GET: DemoModel/Edit/5
public ActionResult Edit(int id)
{
return View(); // 需要填写的表单,用来编辑已创建的对象
}
// POST: DemoModel/Edit/5
[HttpPost]
public ActionResult Create(int id, DemoModel model)
{
return View(); // 用来保存对某个对象的修改
}
}
6.2.2.1 路由
注意模板中创建的App_Start文件夹以及其下的RouteConfig.cs文件。这个文件创建了Url地图,服务器通过地图,来判断请求的Url在哪个控制器上调用哪个方法,可以创建非常具体的路由,也可以使用模板。以下是RouteConfig.cs默认的代码:
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
var settings = new FriendlyUrlSettings();
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings);
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
}
}
注意最后一部分的MapRoute方法,其中的url属性标识了如何查找相应的Controller和处理方法。