ASP.NET MVC5(一)创建项目

作者 Zhendong Ho 日期 2021-02-24
ASP.NET MVC5(一)创建项目

准备:Visual Studio 2013版本以上

创建新的ASP.NET MVC项目

打开VS,创建新项目,搜索模板ASP.NET Web应用程序(.NET Framework),项目名称设置为PartyInvites,框架选择.NET Framework4.5.1以上

选择空模板并勾选MVC,点击创建。

添加控制器

在MVC中,输入请求是由控制器来处理的。控制器继承于框架内置的控制器基类System.Web.Mvc.Controller

控制器中的每一个public方法都是一个动作方法,可以通过URL调用它来执行一个动作。

右键Controllers文件夹,添加控制器,选择MVC5控制器 - 空,输入控制器名称为HomeController

using System.Web.Mvc;

namespace PartyInvites.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
}

理解路由

MVC程序使用路由系统决定如何将URL映射到控制器和动作上。

以下任一个URL,都会被引向HomeController上的Index动作

  • /
  • /Home
  • /Home/Index

注意:HomeController和Index动作方法是MVC约定的默认起点。如果不遵循这种约定,则需要修改路由RouteConfig.cs文件

渲染Web页面

创建并渲染视图

从一个动作方法返回一个ViewResult对象时,是在指示MVC渲染一个视图。调用不带参数的View方法,是渲染该动作的默认视图。

右键HomeController的Index动作方法,点击添加视图,选择MVC5视图,视图名称为Index,模板选择Empty(不具有模型)创建为分部视图使用布局页复选框处于未选状态。

Index视图代码如下。

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
</div>
</body>
</html>

注意

  1. @{ Layout = null; },这是一个将由Razor视图引擎进行解释的表达式,Razor引擎处理视图内容并生成发送给浏览器的HTML。
  2. 控制器的Index方法返回了一个ViewResult,MVC框架渲染了一个视图返回了它所产生的HTML
  3. 除了字符串ViewResult对象,动作方法也可以返回其他结果。如RedirectResultHttpUnauthorizedResult,统称为动作结果

添加动态输出

在MVC中,控制器构造一些数据并将其传递给视图,而视图则负责把它渲染成HTML。

将数据从控制器传递给视图使用ViewBag对象,它是Controller基类的一个成员。

ViewBag动态对象,可以赋值任意属性,并在随后渲染的视图中使用。

在HomeController的Index动作方法使用ViewBag对象。

public ViewResult Index()
{
int hour = DateTime.Now.Hour;
ViewBag.Greeting = hour < 12 ? "Good Morning" : "Good Afternoon";
return View();
}

在Indexl视图中通过Razor表达式获取ViewBag属性。

@ViewBag.Greeting

注意:Web页面从服务器到浏览器的呈现过程分为三步

第一步,渲染(服务器完成)。通过视图引擎对视图文件进行解释,将视图文件中的代码转换为HTML标记。

第二步,传递。将渲染后的HTML标记传递给客户端的浏览器。

第三步,呈现(浏览器完成)。浏览器接收到HTML后对其进行处理并呈现为Web页面。

创建一个简单的数据录入应用程序

场景

假设一个朋友决定举行一个“新年除夕晚会”,需要创建一个Web应用程序,以便让受邀人进行电子邮件回复(RSVP)。

添加模型类

模型是定义应用程序主题的实现对象、过程以及规则的表示,通常称为域模型

右键Models文件夹,添加类GuestResponse.cs,代码如下。

public class GuestResponse
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public bool? WillAttend { get; set; }
}

链接动作方法

创建动作方法

Html.ActionLink是一个HTML的辅助器方法

ActionLink有两个参数,第一个是该链接的显式文本,第二个是用户单击该链接时要执行的动作

@Html.ActionLink("RSVP Now", "RsvpForm")

注意:MVC框架附带了一组内置的辅助器方法,它们可以方便地用来渲染HTML的链接、文本框、复选框、选择框以及其他种类的内容。

这时候需要在HomeController添加RsvpForm动作方法

public ViewResult RsvpForm()
{
return View();
}

添加强类型视图

接着为RsvpForm动作方法添加强类型视图。强类型视图渲染一个特定的域类型,以便更好使用该类型的方法。

右键HomeController的RsvpForm动作方法,点击添加视图,选择MVC5视图,视图名称为RsvpForm,模板选择Empty,模型类选择GuestResponse (PartyInvites.Models)视图选项中的复选框处于未选状态。

@model PartyInvites.Models.GuestResponse

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>RsvpForm</title>
</head>
<body>
<div>
</div>
</body>
</html>

注意@model表达式指示了该强类型视图的域模型。可以将常规视图修改成强类型视图,只需在代码中添加或去除@model指示符即可。

建立表单

扩建RsvpForm视图的内容,制作成编辑GuestResponse对象的HTML表单。

@model PartyInvites.Models.GuestResponse

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>RsvpForm</title>
</head>
<body>
@using (Html.BeginForm())
{
<p>Your name: @Html.TextBoxFor(x => x.Name)</p>
<p>Your email: @Html.TextBoxFor(x => x.Email)</p>
<p>Your phone: @Html.TextBoxFor(x => x.Phone)</p>
<p>
Will you attend?
@Html.DropDownListFor(x => x.WillAttend, new[] {
new SelectListItem() { Text = "Yes, I'll be there",
Value = bool.TrueString },
new SelectListItem() { Text = "No, I can't come",
Value = bool.FalseString }
}, "Choose an option")
</p>
<input type="submit" value="Submit RSVP" />
}
</body>
</html>

注意

  1. TextBoxFor辅助器方法会生成一个input元素的HTML,type参数设置为textidname标签属性设置为域类型的属性名
  2. HTML辅助器方法能够用lambda表达式读取@model表达式中指定类型的属性名称。
  3. 替代运用lambda表达式的另一种方法,Html.TextBox(“Email”)
  4. Html.BeginForm辅助器方法,生成一个HTML表单元素的form标签。封装在using语句中,可以在超出范围时自动关闭form标签

设置启动URL

可在VS设置一个固定的启动URL。右键项目,属性,Web,启动操作,特定页。

处理表单

为了接收并处理表单所递交的数据,在HomeController添加第二个RsvpForm动作方法。一个方法使用HttpGet注解,另一个方法使用HttpPost注解,来响应不同的请求。

[HttpGet]
public ViewResult RsvpForm()
{
return View();
}

[HttpPost]
public ViewResult RsvpForm(GuestResponse guestResponse)
{
return View("Thanks", guestResponse);
}

使用模型绑定

第一个重载的RsvpForm动作方法渲染名称为RsvpForm的视图

第二个重载的RsvpForm方法给定GuestResponse参数,它通过模型绑定解析输入数据,并将HTTP请求中的键值来填充域模型的属性。这一过程与使用HTML辅助器的方法是相反的

渲染其他视图

第二个重载的RsvpForm方法告诉MVC渲染名称为Thanks的视图,并对该视图传递GuestResponse对象

创建Thanks强类型视图,右键HomeController的任一方法,点击添加视图,选择MVC5视图,视图名称为Thanks,模板选择Empty。模型类选择GuestResponse (PartyInvites.Models)视图选项中的复选框处于未选状态。

@model PartyInvites.Models.GuestResponse

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Thanks</title>
</head>
<body>
<div>
<h1>Thank you, @Model.Name!</h1>
@if (Model.WillAttend == true)
{
@:It's great that you're coming. The drinks are already in the fridge!
}
else
{
@:Sorry to hear that you can't make it, but thanks for letting us know.
}
</div>
</body>
</html>

添加验证

通过System.ComponentModel.DataAnnotations命名空间中的注解属性进行验证规则声明,并修改GuestResponse模型类代码如下。

using System.ComponentModel.DataAnnotations;

namespace PartyInvites.Models
{
public class GuestResponse
{
[Required(ErrorMessage = "Please enter your name")]
public string Name { get; set; }

[Required(ErrorMessage = "Please enter your email address")]
[RegularExpression(".+\\@.+\\..+", ErrorMessage = "Please enter a valid email address")]
public string Email { get; set; }

[Required(ErrorMessage = "Please enter your phone number")]
public string Phone { get; set; }

[Required(ErrorMessage = "Please specify whether you'll attend")]
public bool? WillAttend { get; set; }
}
}

在控制器类中使用ModelState.IsValid属性检查表单验证错误。

[HttpPost]
public ViewResult RsvpForm(GuestResponse guestResponse)
{
if (ModelState.IsValid)
{
// 给晚会的组织者发送电子邮件
return View("Thanks", guestResponse);
}
else
{
// 有验证错误
return View();
}
}

如果没有验证错误,便让MVC渲染Thanks视图。如果验证错误,则调用不带参数的View方法重新渲染RsvpForm视图,直到GuestResponse的所有验证通过,用户才会看到Thanks视图。

在有错误时,需要给用户提示。做法是,在RsvpForm视图中使用Html.ValidationSummary辅助器方法。

@using (Html.BeginForm())
{
@Html.ValidationSummary()
...
}

高亮显示无效字段

当发生验证错误时,辅助器方法给input元素添加一个值为input-validation-errorclass标签属性,可以创建样式表并设置该class的CSS样式。

右键项目,添加Content文件夹,在Content文件夹中添加样式表Styles.css

.field-validation-error {
color: #f00;
}

.field-validation-valid {
display: none;
}

.input-validation-error {
border: 1px solid #f00;
background-color: #fee;
}

.validation-summary-errors {
font-weight: bold;
color: #f00;
}

.validation-summary-valid {
display: none;
}

在RsvpForm视图中添加Link元素。

<link href="~/Content/Styles.css" rel="stylesheet" />

设置内容样式

使用Nuget安装Bootstrap

打开包管理控制台,输入命令:Install-Package -version 3.0.0 bootstrap

设置Index视图

在Index视图中添加Bootstrap

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
<title>Index</title>
<style>
.btn a {
color: white;
text-decoration: none;
}

body {
background-color: #F1F1F1;
}
</style>
</head>
<body>
<div class="text-center">
<h2>We're going to have an exciting party!</h2>
<h3>And you are invited</h3>
<div class="btn btn-success">
@Html.ActionLink("RSVP Now", "RsvpForm")
</div>
</div>
</body>
</html>

设置RsvpForm视图

在RsvpForm视图中添加Bootstrap。

@model PartyInvites.Models.GuestResponse

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
<link href="~/Content/Styles.css" rel="stylesheet" />
<title>RsvpForm</title>
</head>
<body>
<div class="panel panel-success">
<div class="panel-heading text-center">
<h4>RSVP</h4>
</div>
<div class="panel-body">
@using (Html.BeginForm())
{
@Html.ValidationSummary()
<div class="form-group">
<label>Your name:</label>
@Html.TextBoxFor(x => x.Name, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Your email:</label>
@Html.TextBoxFor(x => x.Email, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Your phone:</label>
@Html.TextBoxFor(x => x.Phone, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Will you attend?</label>
@Html.DropDownListFor(x => x.WillAttend, new[] {
new SelectListItem() { Text = "Yes, I'll be there",
Value = bool.TrueString },
new SelectListItem() { Text = "No, I can't come",
Value = bool.FalseString }
}, "Choose an option", new { @class = "form-control" })
</div>
<div class="text-center">
<input class="btn btn-success" type="submit" value="Submit RSVP" />
</div>
}
</div>
</div>
</body>
</html>

注意Html.TextBoxFor(x => x.Name, new { @class = “form-control” }),使用了C#的匿名类型创建对象,在TextBoxFor辅助器生成的元素上,将class属性设置为form-control

设置Thanks视图

在Thanks视图中添加Bootstrap。

@model PartyInvites.Models.GuestResponse

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Thanks</title>
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
<style>
body {
background-color: #F1F1F1;
}
</style>
</head>
<body>
<div class="text-center">
<h1>Thank you, @Model.Name!</h1>
<div class="lead">
@if (Model.WillAttend == true)
{
@:It's great that you're coming. The drinks are already in the fridge!
}
else
{
@:Sorry to hear that you can't make it, but thanks for letting us know.
}
</div>
</div>
</body>
</html>

完成示例

Thanks视图中使用WebMail辅助器方法,在渲染Thanks视图时发送邮件。

<body>
@{
try
{
WebMail.SmtpServer = "smtp.example.com";
WebMail.SmtpPort = 587;
WebMail.EnableSsl = true;
WebMail.UserName = "mySmtpUsername";
WebMail.Password = "mySmtpPassword";
WebMail.From = "rsvps@example.com";
WebMail.Send("party-host@example.com",
"RSVP Notification",
Model.Name + "is" + ((Model.WillAttend ?? false) ? "" : "not") + "attending");
}
catch (Exception)
{
@:<b>Sorry - we could't send the email to confirm your RSVP.</b>
}
}
...
</body>