ASP.NET MVC 開(kāi)發(fā)實(shí)例(一)
近幾年前端發(fā)展很快,大有不需要后端之趨勢(shì)。node.js+webpack我現(xiàn)在也有在觀望學(xué)習(xí)中,的確,很酷。但是我并沒(méi)有進(jìn)行產(chǎn)品開(kāi)發(fā),因?yàn)檫@種東西一投入,說(shuō)不定馬上就有一個(gè)更酷的框架出來(lái)。學(xué)習(xí)框架和你做投資一樣,都需要成本。新框架帶來(lái)了一些新技術(shù),也帶來(lái)了新問(wèn)題。但由于是開(kāi)源的關(guān)系,所有的問(wèn)題都很快得到解決。同時(shí),需求不同也就造就今天框架盛行的局面。沒(méi)有完美的架構(gòu),只有適合的架構(gòu),如果你想要有一個(gè)完全匹配你需求的框架,那么就自己寫(xiě)一個(gè)。很多有實(shí)力的公司就是這么做的。
其實(shí),我更樂(lè)意做的事,就是 在原有的技術(shù)上,兼容現(xiàn)在流行的MV*前端框架,以達(dá)到迅速開(kāi)發(fā)的目的,如果產(chǎn)品頁(yè)需要SEO,那么回到C#,用傳統(tǒng)的后端對(duì)頁(yè)面進(jìn)行渲染。要做到數(shù)據(jù)靈活綁定,游刃有余。
我希望這一系列的教材,是從ASP.NET MVC入門(mén)開(kāi)始,再開(kāi)發(fā)一套小型的商城網(wǎng)站,最后寫(xiě)一套屬于自己的MVC架構(gòu)出來(lái)。這是一個(gè)上十萬(wàn)字的大工程,不過(guò)如果能在業(yè)余時(shí)間做出來(lái),我會(huì)很佩服我自己的。準(zhǔn)備了兩套入門(mén)方案,一套建立Empty模板,為注冊(cè)會(huì)員代碼。一套為自動(dòng)生成代碼的留言板方案,然后修改。以此來(lái)增強(qiáng)入門(mén)體驗(yàn)。
從現(xiàn)在開(kāi)始吧,打開(kāi)Visual Studio 2015,先來(lái)做個(gè)例子。
下面是一個(gè)用戶管理的實(shí)例,這個(gè)實(shí)例沒(méi)有關(guān)聯(lián)到任何數(shù)據(jù)庫(kù),當(dāng)然也不會(huì)有Identity,下面這個(gè)實(shí)例只是讓你基本的了解一下MVC的基本操作概念。(本例子參考了《精通ASP.NET MVC5》,書(shū)中第二章:第一個(gè)MVC應(yīng)用程序。)
新建項(xiàng)目,在已安裝-模板里面選擇Web,創(chuàng)建一個(gè)ASP.NET Web 應(yīng)用程序,如下圖。本例命名為alexzeng,當(dāng)然你可以改為你喜歡的任何名字,不違背命名規(guī)則就可以。

在彈出來(lái)的新建ASP.NET 項(xiàng)目里面選擇一個(gè)Empty模板,為以下添加文件夾和核心引用點(diǎn)擊MVC。

然后在解決方案資源管理器的窗口里面,找到Controllers,右擊新建一個(gè)新的控制器,如下圖,選擇MVC 5控制器-空。命名為HomeController.cs 。

默認(rèn)代碼如下:
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace alexzengnet.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
}
}
現(xiàn)在我們還運(yùn)行不了這個(gè)網(wǎng)站,稍微改一下代碼:
public string Index()
{
return "<h1>歡迎光臨</h1>";
}
按一下F5,可以開(kāi)始瀏覽到網(wǎng)站了,一個(gè)基于ASP.NET框架的網(wǎng)站基本成立了。
再把代碼恢復(fù)成默認(rèn)的樣子,對(duì)著Index右擊鼠標(biāo),新建視圖,在彈出來(lái)的窗口,按默認(rèn)值即可。

將代碼修改成下面的樣子,運(yùn)行一下,是不是和剛才一樣
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h1>歡迎光臨!</h1>
</div>
</body>
</html>
回到HomeController.cs,我們給代碼添加一點(diǎn)動(dòng)態(tài),在這里我們使用的是ViewBag。
將數(shù)據(jù)傳給視圖的一種方式是使用了ViewBag, ViewBag是一個(gè)動(dòng)態(tài)的對(duì)象,可以賦予它任何屬性。
下面的例子就是演示如何使用ViewBag。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace alexzengnet.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
int hour = DateTime.Now.Hour;
ViewBag.SayHi=hour<12?"早上好":"下午好";
return View();
}
}
}
再打開(kāi)視圖文件:Index.cshtml,修改一下代碼:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h1>歡迎光臨!</h1>
<p>@ViewBag.SayHi</p>
@Html.ActionLink("注冊(cè)會(huì)員","REG")
</div>
</body>
</html>
運(yùn)行一下試試,它會(huì)根據(jù)你當(dāng)前的時(shí)間顯示上午好還是下午好,這是一個(gè)最簡(jiǎn)單的MVC程序。下面我們將繼續(xù)完善它,我們會(huì)結(jié)合流行的Bootstrap ,做一個(gè)簡(jiǎn)單的注冊(cè)會(huì)員程序。
現(xiàn)在,首先我們先來(lái)安裝Bootstrap
打開(kāi)工具菜單,點(diǎn)擊NuGet程序包管理器里面的程序包管理器控制臺(tái)。它是一個(gè)PowerShell的運(yùn)行環(huán)境,在控制臺(tái)里面輸入(注意,區(qū)分大小寫(xiě)):
Install-Package -version 3.0.0 bootstrap
完成了安裝程序后會(huì)有提示:已將“bootstrap 3.0.0”成功安裝到 alexzengnet。
我在制作網(wǎng)頁(yè)的時(shí)候,通常是先做PS文件,然后通過(guò)PS做成html,最后將html分拆成我所需要的cshtml。下面就是加載了bootstrap 的注冊(cè)頁(yè)面。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<meta charset="utf-8" />
<link href="Content/bootstrap.min.css" rel="stylesheet">
<script src="Scripts/jquery-1.9.0.min.js"></script>
<script src="Scripts/jquery-1.9.0.min.js"></script>
<style>
body {
padding-top:50px;
color:#FFF; background:#444;
}
div {margin:5px auto;}
h1 {
color: #fff;
}
#content{
width:100%;
min-height:600px;
background:#444;
padding-top:20px;
color:#FFF;
}
.register{
padding: 20px;
font-weight:700;
border:#FFF solid 1px;
-moz-border-radius: 10px; /* Gecko browsers */
-webkit-border-radius: 10px; /* Webkit browsers */
border-radius:10px; /* W3C syntax */
}
.col-sm-3{
line-height:48px;
}
</style>
</head>
<body>
<div id="content">
<div class="container">
<form>
<div class="row">
<h1 class="col-md-6 col-md-offset-3 col-xs-10 col-xs-offset-1 page_title ">注冊(cè)</h1>
</div>
<div class="col-md-6 col-md-offset-3 col-xs-10 col-xs-offset-1 register">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">用戶名:</label>
<div class="col-sm-8">
<div class="input-group">
<input type="text" class="form-control" name="username" placeholder="請(qǐng)輸入用戶名">
<div class="input-group-addon">
<span class="glyphicon glyphicon-user"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">密碼:</label>
<div class="col-sm-8">
<div class="input-group">
<input type="password" class="form-control" name="password" placeholder="請(qǐng)輸入密碼(六位以上)">
<div class="input-group-addon">
<span class="glyphicon glyphicon-lock"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="chkpwd" class="col-sm-3 control-label">確認(rèn)密碼:</label>
<div class="col-sm-8">
<div class="input-group">
<input type="password" class="form-control" name="chkpwd" placeholder="請(qǐng)確認(rèn)密碼">
<div class="input-group-addon">
<span class="glyphicon glyphicon-exclamation-sign"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="email" class="col-sm-3 control-label">郵箱:</label>
<div class="col-sm-8">
<div class="input-group">
<input type="text" class="form-control" name="email" placeholder="請(qǐng)輸入有效郵箱">
<div class="input-group-addon">
<span class="glyphicon glyphicon-envelope"></span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3 col-md-offset-3 col-xs-12">
<button type="reset" class="btn btn-default btn-block">
<b>清空</b>
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
<div class="col-md-3 col-xs-12">
<button type="submit" class="btn btn-info btn-block">
<b>提交</b>
<span class="glyphicon glyphicon-arrow-right"></span>
</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
運(yùn)行測(cè)試,基本成功。
接著我們來(lái)設(shè)計(jì)一個(gè)數(shù)據(jù)模型類(lèi):命名為User.cs。在解決系統(tǒng)方案資源管理器窗口的Models右擊,新建項(xiàng),類(lèi),名稱(chēng)User.cs。
下面是該類(lèi)代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace alexzengnet.Models
{
public class User
{
public int Id { get; set; }
public string Name{ get; set; }
public string PassWord { get; set; }
public string phone { get; set; }
public string email { get; set; }
}
}
然后Ctrl+Shift+B,生成解決方案。也就是將這個(gè)類(lèi)進(jìn)行編譯。
打開(kāi)HomeController.cs,在Index下面加入以下代碼
public ActionResult REG()
{
return View();
}
右擊REG,添加視圖,這時(shí)候需要的強(qiáng)類(lèi)型視圖,所以跟上面添加index視圖略有不同。設(shè)置如下圖:

然后稍微寫(xiě)一些代碼進(jìn)去,測(cè)試一下:
@model alexzengnet.Models.User
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>REG</title>
</head>
<body>
<div>
@using (Html.BeginForm())
{
<p>Name:@Html.TextBoxFor(x=>x.Name)</p>
<p>Password:@Html.PasswordFor(x => x.PassWord)</p>
<p>Phone:@Html.TextBoxFor(x => x.phone)</p>
<input type="submit" value="submit" />
}
</div>
</body>
</html>
運(yùn)行了以后,基本能夠滿足我的要求,現(xiàn)在我對(duì)它進(jìn)行樣式化,將我們剛剛做的加載了bootstrap的html頁(yè)面復(fù)制到這邊來(lái),注意代碼的變化,如下所示:
@model alexzengnet.Models.User
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<meta charset="utf-8" />
<link href="~/Content/bootstrap.min.css" rel="stylesheet">
<script src="~/Scripts/jquery-1.9.0.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<style>
body {
padding-top: 50px;
color: #FFF;
background: #444;
}
div {
margin: 5px auto;
}
h1 {
color: #fff;
}
#content {
width: 100%;
min-height: 600px;
background: #444;
padding-top: 20px;
color: #FFF;
}
.register {
padding: 20px;
font-weight: 700;
border: #FFF solid 1px;
-moz-border-radius: 10px; /* Gecko browsers */
-webkit-border-radius: 10px; /* Webkit browsers */
border-radius: 10px; /* W3C syntax */
}
.col-sm-3 {
line-height: 48px;
}
</style>
</head>
<body>
<div id="content">
<div class="container">
@using (Html.BeginForm())
{
<div class="row">
<h1 class="col-md-6 col-md-offset-3 col-xs-10 col-xs-offset-1 page_title ">注冊(cè)</h1>
</div>
<div class="col-md-6 col-md-offset-3 col-xs-10 col-xs-offset-1 register">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">用戶名:</label>
<div class="col-sm-8">
<div class="input-group">
@Html.TextBoxFor(x => x.Name, new { @class= "form-control", @placeholder = "請(qǐng)輸入有效用戶名" })
<div class="input-group-addon">
<span class="glyphicon glyphicon-user"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">密碼:</label>
<div class="col-sm-8">
<div class="input-group">
@Html.PasswordFor(x => x.PassWord, new { @class = "form-control", @placeholder = "請(qǐng)輸入有效密碼" })
<div class="input-group-addon">
<span class="glyphicon glyphicon-lock"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="chkpwd" class="col-sm-3 control-label">電話:</label>
<div class="col-sm-8">
<div class="input-group">
@Html.TextBoxFor(x => x.phone, new { @class = "form-control" , @placeholder= "請(qǐng)輸入有效電話" })
<div class="input-group-addon">
<span class="glyphicon glyphicon-phone"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="email" class="col-sm-3 control-label">郵箱:</label>
<div class="col-sm-8">
<div class="input-group">
@Html.TextBoxFor(x => x.email, new { @class = "form-control", @placeholder = "請(qǐng)輸入有效郵箱" })
<div class="input-group-addon">
<span class="glyphicon glyphicon-envelope"></span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3 col-md-offset-3 col-xs-12">
<button type="reset" class="btn btn-default btn-block">
<b>清空</b>
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
<div class="col-md-3 col-xs-12">
<button type="submit" class="btn btn-info btn-block">
<b>注冊(cè)</b>
<span class="glyphicon glyphicon-arrow-right"></span>
</button>
</div>
</div>
}
</div>
</div>
</body>
</html>
運(yùn)行之后,感覺(jué)不錯(cuò),如下圖:

這時(shí)我們點(diǎn)擊注冊(cè),將不會(huì)有任何反應(yīng),下面我們就來(lái)研究一下如何寫(xiě)注冊(cè)的代碼。
第一步,先來(lái)設(shè)置啟動(dòng)URL,點(diǎn)擊項(xiàng)目菜單,選擇本項(xiàng)目的屬性,如本例就是alexzengnet屬性。在面板中選擇Web,特定頁(yè),不用填寫(xiě)任何值即可。如下圖。

第二步,我們來(lái)修改一下HomeController.cs文件,讓它響應(yīng)http的GET,POST。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using alexzengnet.Models;
namespace alexzengnet.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
int hour = DateTime.Now.Hour;
ViewBag.SayHi=hour<12?"早上好":"下午好";
return View();
}
[HttpGet]
public ActionResult REG()
{
return View();
}
[HttpPost]
public ActionResult REG(User user)
{
return View("Thank", user);
}
}
}
這里的意思就是如果MVC獲取到user數(shù)據(jù),那么將使用post請(qǐng)求。使用post將查找并渲染“Thank”視圖。
第三步,創(chuàng)建Thank視圖。右擊HomeController.cs文件,添加一個(gè)強(qiáng)類(lèi)型菜單視圖。如下圖:

修改一下新建的Thank.cshtml,代碼如下:
@model alexzengnet.Models.User
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Thank</title>
</head>
<body>
<div>
<h1>多謝注冊(cè)本站,@Model.Name</h1>
</div>
</body>
</html>
測(cè)試一下成功,但對(duì)于會(huì)員注冊(cè),我們往往需要增加一些輸入驗(yàn)證,以防止用戶一些無(wú)效的輸入:
第一步打開(kāi)User.cs,增加驗(yàn)證規(guī)則聲明,在這個(gè)命名空間里面using System.ComponentModel.DataAnnotations; 做驗(yàn)證,下面是代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace alexzengnet.Models
{
public class User
{
public int Id { get; set; }
[Required(ErrorMessage ="請(qǐng)輸入用戶名。")]
public string Name{ get; set; }
[Required(ErrorMessage = "請(qǐng)輸入密碼。")]
public string PassWord { get; set; }
[Required(ErrorMessage = "請(qǐng)輸入電話。")]
public string phone { get; set; }
[Required(ErrorMessage = "請(qǐng)輸入Email。")]
[RegularExpression(".+\\@.+\\..+", ErrorMessage ="請(qǐng)輸入正確的Email地址")]
public string email { get; set; }
}
}
第二步修改reg.cshtml文件,在需要提示錯(cuò)誤的地方加上@Html.ValidationSummary() 以下省略掉不必要的代碼,示例如下:
@using (Html.BeginForm())
{
<div class="row">
<h1 class="col-md-6 col-md-offset-3 col-xs-10 col-xs-offset-1 page_title ">注冊(cè)</h1>
</div>
<div class="col-md-6 col-md-offset-3 col-xs-10 col-xs-offset-1 register">
<div class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<strong>@Html.ValidationSummary()</strong>
</div>
......
}
第三步修改HomeController.cs文件,做一個(gè)判斷,如果發(fā)生錯(cuò)誤提示,就不查找并渲染文件。
[HttpPost]
public ActionResult REG(User user)
{
if (ModelState.IsValid) {
return View("Thank", user);
}
else {
return View();
}
}
測(cè)試完成!
這一個(gè)例子并沒(méi)有寫(xiě)入數(shù)據(jù)庫(kù),它通過(guò)一個(gè)全空的MVC,一步一步的往里面填充代碼,熟悉一下視圖、控制器、MODEL之間的關(guān)聯(lián),對(duì)MVC有了一個(gè)初步的了解。
下一個(gè)例子我們會(huì)用一個(gè)簡(jiǎn)單的留言板作為例子,你將看到用極簡(jiǎn)單的代碼將自動(dòng)生成留言板,并寫(xiě)入數(shù)據(jù)庫(kù),還有了修改、刪除等操作數(shù)據(jù)庫(kù)功能。然后我們?cè)賹?duì)其進(jìn)行修改,以滿足我們的設(shè)計(jì)需求。