1.按照MusicStore-1步骤创建mvc项目,并初始化数据库
2.修改HomeController
using Chapter8.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Chapter8.Controllers
{public class HomeController : Controller{private MusicStoreEntities storeDB = new MusicStoreEntities();// GET: Homepublic ActionResult Index(){var albums = GetTopSellingAlbums(2);return View(albums);}private List<Album> GetTopSellingAlbums(int count){return storeDB.Albums.OrderByDescending(s => s.OrderDetails.Count).Take(count).ToList();}}
}
3修改index.cshtml
@{ViewBag.Title = "Home Page";
}<div class="jumbotron"><h1>MVC Music Store</h1><img src="~/Images/home-showcase.png" />
</div><ul class="row list-unstyled" id="album-list">@foreach (var album in Model){<li class="col-lg-2 col-md-2 col-sm-2 col-xs-4 container"><a href="@Url.Action("Details", "Store", new { id = album.AlbumId })"><img alt="@album.Title" src="@Url.Content( @album.AlbumArtUrl)" /><h4>@album.Title</h4></a></li>}
</ul>@section Scripts {<script src="~/Scripts/App/MusicScripts.js"></script>
}
4.在Scripts目录下新建App目录,并在其下面新增MusicScripts.js
$(function () {$("#album-list img").mouseover(function () {$(this).animate({ height: '+=25', width: '+=25' }).animate({ height: '-=25', width: '-=25' });});
});
5.运行程序,此时应能看到

6.通过nuget引入ajax,并添加到index的scripts节中,再视图里面添加查看打折信息的超链接,以及显示用的div
@{ViewBag.Title = "Home Page";
}<div class="jumbotron"><h1>MVC Music Store</h1><img src="~/Images/home-showcase.png" />
</div><ul class="row list-unstyled" id="album-list">@foreach (var album in Model){<li class="col-lg-2 col-md-2 col-sm-2 col-xs-4 container"><a href="@Url.Action("Details", "Store", new { id = album.AlbumId })"><img alt="@album.Title" src="@Url.Content( @album.AlbumArtUrl)" /><h4>@album.Title</h4></a></li>}
</ul><div id="dailydeal">@Ajax.ActionLink("Click here to see today's special","DailyDeal",null,new AjaxOptions
{UpdateTargetId = "dailydeal",InsertionMode = InsertionMode.Replace,HttpMethod= "GET"
},
new { @class = "btn btn-primary" })
</div>@section Scripts {<script src="~/Scripts/App/MusicScripts.js"></script><script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
}
7 在HomeController里面增加处理DailyDeal()方法,处理打折信息请求
using Chapter8.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Chapter8.Controllers
{public class HomeController : Controller{private MusicStoreEntities storeDB = new MusicStoreEntities();// GET: Homepublic ActionResult Index(){var albums = GetTopSellingAlbums(2);return View(albums);}private List<Album> GetTopSellingAlbums(int count){return storeDB.Albums.OrderByDescending(s => s.OrderDetails.Count).Take(count).ToList();}public ActionResult DailyDeal(){var album = GetDailyDeal();return PartialView("_DailyDeal", album);}private object GetDailyDeal(){var album = storeDB.Albums.OrderBy(a => System.Guid.NewGuid()).First();album.Price *=0.5m;return album;}}
}
8 在Views/Home下新建分部视图
@model Chapter8.Models.Album<div class="panel panel-primary"><div class="panel-heading"><h3>Your Daily Deal: @Model.Title</h3></div><div class="panel-body"><p><img alt="@Model.Title" src="@Url.Content(Model.AlbumArtUrl)" /></p><div id="album-details"><p><em>Artist:</em>@Model.Artist.Name</p><p><em>Price:</em>@string.Format("{0:F}", Model.Price)</p>@Html.ActionLink("Add to cart","AddToCart","ShoppingCart",new { id=Model.AlbumId},new { @class="btn btn-primary"})</div></div>
</div>
9 运行,点击Index下面的获取打折信息的超链接,就会在当前页面显示打折信息

10.在Index视图上增加搜索框来搜索Artist,以及用于显示搜索结果的div
@{ViewBag.Title = "Home Page";
}<div class="jumbotron"><h1>MVC Music Store</h1><img src="~/Images/home-showcase.png" />
</div><div class="panel panel-default"><div class="panel-heading">Artist Search</div><div class="panel-body">@using(Ajax.BeginForm("ArtistSearch","Home",new AjaxOptions{InsertionMode= InsertionMode.Replace,HttpMethod="GET",OnFailure="searchFailed",LoadingElementId="ajax-loader",UpdateTargetId="searchresults"})){<input type="text" name="q" /><input type="submit" value="search" /><img id="ajax-loader" src="@Url.Content("~/Images/ajax-loader.gif")" style="display:none"/>}<div id="searchresults"></div></div>
</div><ul class="row list-unstyled" id="album-list">@foreach (var album in Model){<li class="col-lg-2 col-md-2 col-sm-2 col-xs-4 container"><a href="@Url.Action("Details", "Store", new { id = album.AlbumId })"><img alt="@album.Title" src="@Url.Content( @album.AlbumArtUrl)" /><h4>@album.Title</h4></a></li>}
</ul><div id="dailydeal">@Ajax.ActionLink("Click here to see today's special","DailyDeal",null,new AjaxOptions
{UpdateTargetId = "dailydeal",InsertionMode = InsertionMode.Replace,HttpMethod= "GET"
},
new { @class = "btn btn-primary" })
</div>@section Scripts {<script src="~/Scripts/App/MusicScripts.js"></script><script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
}
11在HomeController里面增加ArtistSearch方法来处理请求
using Chapter8.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Chapter8.Controllers
{public class HomeController : Controller{private MusicStoreEntities storeDB = new MusicStoreEntities();// GET: Homepublic ActionResult Index(){var albums = GetTopSellingAlbums(2);return View(albums);}private List<Album> GetTopSellingAlbums(int count){return storeDB.Albums.OrderByDescending(s => s.OrderDetails.Count).Take(count).ToList();}public ActionResult DailyDeal(){var album = GetDailyDeal();return PartialView("_DailyDeal", album);}private object GetDailyDeal(){var album = storeDB.Albums.OrderBy(a => System.Guid.NewGuid()).First();album.Price *=0.5m;return album;}public ActionResult ArtistSearch(string q){var artists = GetArtist(q);return PartialView(artists);}private List<Artist> GetArtist(string searchstring){return storeDB.Artists.Where(a => a.Name.Contains(searchstring)).ToList();}}
}
12在Views/Home下面添加分部视图ArtistSearch.cshtml用于显示搜索结果
@model IEnumerable<Chapter8.Models.Artist><div id="searchResults"><ul>@foreach (var item in Model){<li>@item.Name</li>}</ul></div>
13.在项目中添加MaxWordsAttribute
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Chapter8
{public class MaxWordsAttribute : ValidationAttribute,IClientValidatable{public MaxWordsAttribute(int wordCount): base("Too many words in {0}"){WordCount = wordCount;}public int WordCount { get; set; }protected override ValidationResult IsValid(object value,ValidationContext validationContext){if (value != null){var wordCount = value.ToString().Split(' ').Length;if (wordCount > WordCount){return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));}}return ValidationResult.Success;}public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context){var rule = new ModelClientValidationRule();rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());rule.ValidationParameters.Add("wordcount", WordCount);rule.ValidationType = "maxwords";yield return rule;}}
}
14.在Album的Title属性上添加MaxWords特性,增加特性后只会产生对应data-属性,验证要靠添加自定义JS来实现
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;namespace MvcMusicStore.Models
{public class Album {[ScaffoldColumn(false)]public int AlbumId { get; set; }public int GenreId { get; set; }public int ArtistId { get; set; }[Required][StringLength(160, MinimumLength = 2)][MaxWords(10)]public string Title { get; set; }[Required][Range(0.01, 100.00)][DataType(DataType.Currency)]public decimal Price { get; set; }[DisplayName("Album Art URL")][StringLength(1024)]public string AlbumArtUrl { get; set; }public virtual Genre Genre { get; set; }public virtual Artist Artist { get; set; }public virtual List<OrderDetail> OrderDetails { get; set; }}
}
15 基于Album模型类和MusicStoreEntities数据上下文新建AlbumsController控制器,并自动产生视图
16 通过nuget添加jquery,validation插件
17 在Scripts/App目录下新建CustomValidators.js
$.validator.unobtrusive.adapters.addSingleVal("maxwords", "wordcount");$.validator.addMethod("maxwords", function (value, element, maxwords) {if (value) {if (value.split(' ').length > maxwords) {return false;}}return true;
});
18在Views/Albums/Create.cshtml中添加jquery.validator和CustomValidators的引用
@model Chapter8.Models.Album@{ViewBag.Title = "Create";Layout = "~/Views/Shared/_Layout.cshtml";
}<h2>Create</h2>@using (Html.BeginForm())
{@Html.AntiForgeryToken()<div class="form-horizontal"><h4>Album</h4><hr />@Html.ValidationSummary(true, "", new { @class = "text-danger" })<div class="form-group">@Html.LabelFor(model => model.GenreId, "GenreId", htmlAttributes: new { @class = "control-label col-md-2" })<div class="col-md-10">@Html.DropDownList("GenreId", null, htmlAttributes: new { @class = "form-control" })@Html.ValidationMessageFor(model => model.GenreId, "", new { @class = "text-danger" })</div></div><div class="form-group">@Html.LabelFor(model => model.ArtistId, "ArtistId", htmlAttributes: new { @class = "control-label col-md-2" })<div class="col-md-10">@Html.DropDownList("ArtistId", null, htmlAttributes: new { @class = "form-control" })@Html.ValidationMessageFor(model => model.ArtistId, "", new { @class = "text-danger" })</div></div><div class="form-group">@Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })<div class="col-md-10">@Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })@Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })</div></div><div class="form-group">@Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })<div class="col-md-10">@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })</div></div><div class="form-group">@Html.LabelFor(model => model.AlbumArtUrl, htmlAttributes: new { @class = "control-label col-md-2" })<div class="col-md-10">@Html.EditorFor(model => model.AlbumArtUrl, new { htmlAttributes = new { @class = "form-control" } })@Html.ValidationMessageFor(model => model.AlbumArtUrl, "", new { @class = "text-danger" })</div></div><div class="form-group"><div class="col-md-offset-2 col-md-10"><input type="submit" value="Create" class="btn btn-default" /></div></div></div>
}<div>@Html.ActionLink("Back to List", "Index")
</div>@section Scripts {<script src="~/Scripts/jquery.validate.js"></script><script src="~/Scripts/jquery.validate.unobtrusive.js"></script><script src="~/Scripts/App/CustomValidators.js"></script>
}
18.运行,访问Albums/Create页面,当TiTle的长度(以空格隔开)大于设定长度,提示错误信息

19.通过nuget添加jquery.ui
20.修改MusicScripts.js
$(function () {$("#album-list img").mouseover(function () {//$(this).animate({ height: '+=25', width: '+=25' })// .animate({ height: '-=25', width: '-=25' });//$(this).effect("bounce");$(this).effect("bounce", { time: 3, distance: 40 });});});
21 在index视图里面添加jquery.ui的引用
@{ViewBag.Title = "Home Page";
}<div class="jumbotron"><h1>MVC Music Store</h1><img src="~/Images/home-showcase.png" />
</div><div class="panel panel-default"><div class="panel-heading">Artist Search</div><div class="panel-body">@using (Ajax.BeginForm("ArtistSearch", "Home",new AjaxOptions{InsertionMode = InsertionMode.Replace,HttpMethod = "GET",OnFailure = "searchFailed",LoadingElementId = "ajax-loader",UpdateTargetId = "searchresults"})){<input type="text" name="q" /><input type="submit" value="search" /><img id="ajax-loader" src="@Url.Content("~/Images/ajax-loader.gif")" style="display:none" />}<div id="searchresults"></div></div>
</div><ul class="row list-unstyled" id="album-list">@foreach (var album in Model){<li class="col-lg-2 col-md-2 col-sm-2 col-xs-4 container"><a href="@Url.Action("Details", "Store", new { id = album.AlbumId })"><img alt="@album.Title" src="@Url.Content( @album.AlbumArtUrl)" /><h4>@album.Title</h4></a></li>}
</ul><div id="dailydeal">@Ajax.ActionLink("Click here to see today's special","DailyDeal",null,new AjaxOptions
{UpdateTargetId = "dailydeal",InsertionMode = InsertionMode.Replace,HttpMethod= "GET"
},
new { @class = "btn btn-primary" })
</div>@section Scripts {<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script><script src="~/Scripts/jquery-ui-1.12.1.js"></script><script src="~/Scripts/App/MusicScripts.js"></script>}
22.运行,鼠标放到Album上面可以看到上下跳动的效果
24 在index视图上增加搜索框属性<input type="text" name="q" data-autocomplete-source="@Url.Action("QuickSearch","Home")" />
@{ViewBag.Title = "Home Page";
}<div class="jumbotron"><h1>MVC Music Store</h1><img src="~/Images/home-showcase.png" />
</div><div class="panel panel-default"><div class="panel-heading">Artist Search</div><div class="panel-body">@using (Ajax.BeginForm("ArtistSearch", "Home",new AjaxOptions{InsertionMode = InsertionMode.Replace,HttpMethod = "GET",OnFailure = "searchFailed",LoadingElementId = "ajax-loader",UpdateTargetId = "searchresults"})){<input type="text" name="q" data-autocomplete-source="@Url.Action("QuickSearch","Home")" /><input type="submit" value="search" /><img id="ajax-loader" src="@Url.Content("~/Images/ajax-loader.gif")" style="display:none" />}<div id="searchresults"></div></div>
</div><ul class="row list-unstyled" id="album-list">@foreach (var album in Model){<li class="col-lg-2 col-md-2 col-sm-2 col-xs-4 container"><a href="@Url.Action("Details", "Store", new { id = album.AlbumId })"><img alt="@album.Title" src="@Url.Content( @album.AlbumArtUrl)" /><h4>@album.Title</h4></a></li>}
</ul><div id="dailydeal">@Ajax.ActionLink("Click here to see today's special","DailyDeal",null,new AjaxOptions
{UpdateTargetId = "dailydeal",InsertionMode = InsertionMode.Replace,HttpMethod= "GET"
},
new { @class = "btn btn-primary" })
</div>@section Scripts {<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script><script src="~/Scripts/jquery-ui-1.12.1.js"></script><script src="~/Scripts/App/MusicScripts.js"></script>}
25 在HomeController里面增加QuickSearch方法
using Chapter8.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Chapter8.Controllers
{public class HomeController : Controller{private MusicStoreEntities storeDB = new MusicStoreEntities();// GET: Homepublic ActionResult Index(){var albums = GetTopSellingAlbums(2);return View(albums);}private List<Album> GetTopSellingAlbums(int count){return storeDB.Albums.OrderByDescending(s => s.OrderDetails.Count).Take(count).ToList();}public ActionResult DailyDeal(){var album = GetDailyDeal();return PartialView("_DailyDeal", album);}private object GetDailyDeal(){var album = storeDB.Albums.OrderBy(a => System.Guid.NewGuid()).First();album.Price *=0.5m;return album;}public ActionResult ArtistSearch(string q){var artists = GetArtist(q);return PartialView(artists);}private List<Artist> GetArtist(string searchstring){return storeDB.Artists.Where(a => a.Name.Contains(searchstring)).ToList();}public ActionResult QuickSearch(string term){var artists = GetArtists(term).Select(a => new { value = a.Name });return Json(artists, JsonRequestBehavior.AllowGet);}private List<Artist> GetArtists(string searchstring){return storeDB.Artists.Where(a => a.Name.Contains(searchstring)).ToList();}}
}
26.在MusicStore.js中添加js代码
$(function () {$("#album-list img").mouseover(function () {//$(this).animate({ height: '+=25', width: '+=25' })// .animate({ height: '-=25', width: '-=25' });//$(this).effect("bounce");$(this).effect("bounce", { time: 3, distance: 40 });});$("input[data-autocomplete-source]").each(function () {var target = $(this);target.autocomplete({ source: target.attr("data-autocomplete-source") });});});
27 运行,当在搜索框输入a时候,会自动弹出相关项目,从而实现自动完成功能















