摘要:

上一篇文章,我建立了SportsStore应用程序的核心架构。现在我将使用这个架构向这个应用程序添加功能,你将开始看到这个基础架构的作用。我将添加重要的面向客户的简单功能,在这个过程中,你将看到MVC框架提供的额外功能。

如果客户能够根据目录导航产品,SportsStore应用程序可用性将更高。

  • 改进ProductController控制器中的List方法,让他能够过滤在repository里的产品对象。
  • 修改改进URL格式,修改routing策略。
  • 在网站首页旁边创建一个目录列表,高亮显示当前页。

过滤产品列表

修改视图模型ProductsListViewModel,添加当前目录信息。

  1. using SportsStore.Domain.Entities;
  2. using System.Collections.Generic;
  3.  
  4. namespace SportsStore.WebUI.Models
  5. {
  6. public class ProductsListViewModel
  7. {
  8. public IEnumerable<Product> Products { get; set; }
  9. public PagingInfo PagingInfo { get; set; }
  10. public string CurrentCategory { get; set; }
  11. }
  12. }

修改ProductController控制器的List方法,添加参数category,根据传入的category过滤产品。

  1. using SportsStore.Domain.Abstract;
  2. using SportsStore.WebUI.Models;
  3. using System.Web.Mvc;
  4. using System.Linq;
  5.  
  6. namespace SportsStore.WebUI.Controllers
  7. {
  8. public class ProductController : Controller
  9. {
  10. private IProductRepository repository;
  11.  
  12. public int PageSize = ;
  13.  
  14. public ProductController(IProductRepository productRepository)
  15. {
  16. this.repository = productRepository;
  17. }
  18.  
  19. public ViewResult List(string category, int page = )
  20. {
  21. ProductsListViewModel model = new ProductsListViewModel
  22. {
  23. Products = repository.Products.Where(p => string.IsNullOrEmpty(category) || p.Category == category)
  24. .OrderBy(p => p.ProductID).Skip((page - ) * PageSize).Take(PageSize),
  25. PagingInfo = new PagingInfo
  26. {
  27. CurrentPage = page,
  28. ItemsPerPage = PageSize,
  29. TotalItems = category == null ? repository.Products.Count() : repository.Products.Where(e => e.Category == category).Count()
  30. },
  31. CurrentCategory = category
  32. };
  33. return View(model);
  34. }
  35. }
  36. }
  • 如果传入的category是空字符串,则返回所有产品列表。否则根据linq的where条件获取category下的产品列表。
  • 如果传入的category是空字符串,则返回所有产品数量。否则根据linq的where条件获取category下的产品数量。
  • 将category赋值给视图模型对象的CurrentCategory属性。

执行程序,如果将浏览器地址栏修改成下面的形式:

http://localhost:17596/?category=Soccer

将返回category是Soccer的产品列表。

很明显,用户将不会自己使用URL导航产品目录,但是你可以看到,一旦基础架构做好了,一个小的改动在一个MVC框架的应用程序起到了大的作用。

修改定义URL格式

没有人想看到或者使用丑陋的像/?category=Soccer一样的URL。为了改进这个,我将修改路由格式,创建更适合我和客户的生成URL的方法。

修改RouteConfig.cs文件的RegisterRoutes方法。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Mvc;
  6. using System.Web.Routing;
  7.  
  8. namespace SportsStore
  9. {
  10. public class RouteConfig
  11. {
  12. public static void RegisterRoutes(RouteCollection routes)
  13. {
  14. routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  15.  
  16. routes.MapRoute(
  17. name: null,
  18. url: "",
  19. defaults: new { controller = "Product", action = "List", category = (string)null, page = }
  20. );
  21. routes.MapRoute(
  22. name: null,
  23. url: "Page{page}",
  24. defaults: new { controller = "Product", action = "List", category = (string)null },
  25. constraints: new { page = @"\d+" }
  26. );
  27. routes.MapRoute(
  28. name: null,
  29. url: "{category}",
  30. defaults: new { controller = "Product", action = "List", page = }
  31. );
  32. routes.MapRoute(
  33. name: null,
  34. url: "{category}/Page{page}",
  35. defaults: new { controller = "Product", action = "List" },
  36. constraints: new { page = @"\d+" }
  37. );

  38. routes.MapRoute(
  39. name: "Default",
  40. url: "{controller}/{action}/{id}",
  41. defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }
  42. );
  43. }
  44. }
  45. }

下面来解释添加的路由信息。

第一个路由函数:

url: "":表示这个是默认路由。defaults设置参数默认值,将category的空字符串设置为默认值,page的默认值是1。这样,如果访问URL:http://localhost:17596/,category为空字符串,page值为1。

第二个路由函数:

url: "Page{page}":表示路由的URL格式是/Page{page}。defaults设置参数category的默认值为空字符串。这样,如果访问URL:http://localhost:17596/Page2,category为空字符串,page值为传入的值2。

第三个路由函数:

url: "{category}":表示路由的URL格式是/{category}。defaults设置参数page的默认值为1。这样,如果访问URL:http://localhost:17596/Soccer,category为字符串Soccer,page值为默认值1。

第四个路由函数:

url: "{category}/Page{page}":表示路由的URL格式是/{category}/Page{page}。defaults不用设置参数默认值。这样,如果访问URL:http://localhost:17596/Soccer/Page2,category为字符串Soccer,page值为传入的值2。

MVC使用ASP.NET路由系统来处理客户端到来的请求,但是它还用来向外生成符合URL定义格式的URL字符串,嵌入到Web页面上。于是,我可以保证应用程序的所有的URL都是一致的。

定义好路由表后,需要修改List视图上生成链接字符串的方法调用。

  1. @model SportsStore.WebUI.Models.ProductsListViewModel
  2.  
  3. @{
  4. ViewBag.Title = "Products";
  5. }
  6.  
  7. @foreach (var p in Model.Products)
  8. {
  9. Html.RenderPartial("ProductSummary", p);
  10. }
  11. <div class="btn-group pull-right">
  12. @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x, category = Model.CurrentCategory }))
  13. </div>

Url.Action方法是向外产生链接最方便的方法。这里添加将category传入生成链接的代理方法中。

运行程序,改变浏览器地址栏上的URL,得到各路由URL页面结果。

创建目录导航菜单

首先创建MenuController控制器。

  1. using SportsStore.Domain.Abstract;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web.Mvc;
  5.  
  6. namespace SportsStore.WebUI.Controllers
  7. {
  8. public class NavController : Controller
  9. {
  10. private IProductRepository repository;
  11.  
  12. public NavController(IProductRepository productRepository)
  13. {
  14. repository = productRepository;
  15. }
  16.  
  17. public PartialViewResult Menu(string category = null)
  18. {
  19. ViewBag.SelectedCategory = category;
  20. IEnumerable<string> categories = repository.Products.Select(x => x.Category).Distinct().OrderBy(x => x);
  21. return PartialView("Menu", categories);
  22. }
  23. }
  24. }
  • 这个控制器返回PartialViewResult类型对象。PartialViewResult类跟之前使用的ViewResult类型都是继承自基类ViewResultBase。
  • ViewBag动态类型属性SelectedCategory设置为当前目录字符串。
  • 参数category将获取路由产生的URL上的目录字符串。
  • categories变量返回Product下所有目录。
  • 调用方法PartialView方法,返回PartialViewResult类型对象,传入的参数是视图名称和视图模型的变量。

然后创建Menu视图。

  1. @model IEnumerable<string>
  2.  
  3. <div>
  4. @Html.RouteLink("Home", new { controller = "Product", action = "List" }, new { @class = "btn btn-block btn-default btn-lg" })
  5. @foreach (var link in Model)
  6. {
  7. @Html.RouteLink(link, new
  8. {
  9. controller = "Product",
  10. action = "List",
  11. category = link,
  12. page = 1
  13. }, new
  14. {
  15. @class = ("btn btn-block btn-default btn-lg") + (link == ViewBag.SelectedCategory ? " btn-primary" : "")
  16. })
  17. }
  18. </div>

这里调用Html扩展方法RouteLink,生成链接字符串。当然,你也可以使用ActionLink方法。

  • 方法的第一个参数是链接显示的文本字符串。
  • 第二个参数是动态数据类型,用来指定控制器,控制器方法以及方法传入的参数。
  • 第三个参数也是动态数据类型,使用@class来指定链接的样式。这里使用bootstrap的样式,这里的设置顺序是:btn指定按钮样式,btn-block指定按钮呈现的外观占整行,btn-default指定按钮的皮肤颜色等,btn-lg指定按钮的大小。
  • 如果是当前页,将添加btn-primary样式,将该按钮高亮显示。

最后,修改_Layout.cshtml文件,将Menu显示在页面上。

  1. <!DOCTYPE html>
  2.  
  3. <html>
  4. <head>
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <link href="~/Content/bootstrap.css" rel="stylesheet" />
  7. <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
  8. <title>@ViewBag.Title</title>
  9. </head>
  10. <body>
  11. <div class="navbar navbar-inverse" role="navigation">
  12. <a class="navbar-brand" href="#">SPORTS STORE</a>
  13. </div>
  14. <div class="row panel">
  15. <div class="col-xs-3">
  16. @Html.Action("Menu", "Nav")
  17. </div>
  18. <div class="col-xs-8">
  19. @RenderBody()
  20. </div>
  21. </div>
  22. </body>
  23. </html>

这里调用Html的扩展方法Action,传入控制器名字和方法名字,生成HTML字符串。它将Menu视图生成的字符串嵌入到div里面,生成导航栏。

注意这里不是调用RenderPartial方法,RenderPartial方法返回的void,它跟C#语句嵌套使用,在视图上嵌入视图。

运行程序,得到运行结果。

如果点击Soccer目录,将返回Category是Soccer的产品列表。并将Soccer这个按钮高亮显示。

跟我学ASP.NET MVC之六:SportsStrore添加产品目录导航的更多相关文章

  1. 跟我学ASP.NET MVC之五:SportsStrore开始

    摘要: 这篇文章将介绍一个ASP.NET应用程序SportsStore的开发过程. 开始 创建解决方案 创建工程 在New ASP.NET Project - SportsStore窗口中,选择Emp ...

  2. 跟我学ASP.NET MVC之七:SportsStrore一个完整的购物车

    摘要: SportsStore应用程序进展很顺利,但是我不能销售产品直到设计了一个购物车.在这篇文章里,我就将创建一个购物车. 在目录下的每个产品旁边添加一个添加到购物车按钮.点击这个按钮将显示客户到 ...

  3. 跟我学ASP.NET MVC之三:完整的ASP.NET MVC程序-PartyInvites

    摘要: 在这篇文章中,我将在一个例子中实际地展示MVC. 场景 假设一个朋友决定举办一个新年晚会,她邀请我创建一个用来邀请朋友参加晚会的WEB程序.她提出了四个注意的需求: 一个首页展示这个晚会 一个 ...

  4. 跟我学ASP.NET MVC之二:第一个ASP.NET MVC程序

    摘要: 本篇文章带你一步一步创建一个简单的ASP.NET MVC程序.  创建新ASP.NET MVC工程 点击“OK”按钮后,打开下面的窗口: 这里选择“Empty”模板以及“MVC”选项.这次不创 ...

  5. 跟我学ASP.NET MVC之一:开篇有益

    摘要: ASP.NET MVC是微软的Web开发框架,结合了模型-视图-控制器(MVC)架构的有效性和整洁性,敏捷开发最前沿的思想和技术,以及现存的ASP.NET平台最好的部分.它是传统ASP.NET ...

  6. [转]我要学ASP.NET MVC 3.0(十二): MVC 3.0 使用自定义的Html控件

    本文转自:http://www.cnblogs.com/lukun/archive/2011/08/05/2128693.html 概述   在ASP.NET MVC框架中已经封装了很多基于Html标 ...

  7. 跟我学ASP.NET MVC之十一:URL路由

    摘要: 在MVC框架之前,ASP.NET假定在请求的URLs和服务器硬盘文件之间有直接的关系.服务器的职责是接收浏览器请求,从相应的文件发送输出. 这种方法只能工作于Web表单,每一个ASPX页面既是 ...

  8. ASP.NET MVC 5 系列 学习笔记 目录 (持续更新...)

    前言: 记得当初培训的时候,学习的还是ASP.NET,现在回想一下,图片水印.统计人数.过滤器....HttpHandler是多么的经典! 不过后来接触到了MVC,便立马爱上了它.Model-View ...

  9. 给Asp.Net MVC及WebApi添加路由优先级

    一.为什么需要路由优先级 大家都知道我们在Asp.Net MVC项目或WebApi项目中注册路由是没有优先级的,当项目比较大.或有多个区域.或多个Web项目.或采用插件式框架开发时,我们的路由注册很可 ...

随机推荐

  1. mybatis源码之MapperMethod

    /** * @author Clinton Begin * @author Eduardo Macarron * @author Lasse Voss */ //这个类是整个代理机制的核心类,对Sql ...

  2. netlink组播的使用

    Linux的netlink机制是非常好的Linux内核与应用层进行双向交互数据的方式.其常用的单播方式可以实现内核为服务端,应用层为客户端的通信方式.如果需要实现应用层为服务端,内核为客户端的通信方式 ...

  3. Java 8 Stream

    1.关于Java8部分新特性介绍 Java8的新特性很多,在此就不一一介绍了,这里只说一下我自己在工作用用得比较多的几点: 1.1.Lambda表达式 Lambda允许把函数作为一个方法的参数(函数作 ...

  4. 如何在asp.net mvc 中使用Autofac 控制反转(Ioc)

    前言 最近看了一些关于Ioc方面的开源项目,里面的类跳来转去,看的迷迷糊糊的.项目里根本不需要这么“复杂的”设计,只需简单完成Ico,达到解耦的目的,并且能高效的完成项目.于是参考autofac的官网 ...

  5. 多重影分身——C#中多线程的使用二(争抢共享资源)

    只要服务器承受得了,我们可以开任意个线程同时工作以提高效率,然而 两个线程争抢资源可能导致数据混乱. 例如: public class MyFood { public static int Last ...

  6. Day6_内置函数

    定义完一个有名函数,可以直接利用函数名+括号来执行,例如:func() 有名函数: def func(x,y,z=1): return x+y+z 匿名函数: lambda x,y,z=1:x+y+z ...

  7. 星云链开发dapp,赚取100nas(价值近万)

    前几天星云链主网正式上线,现在只要成功提交一个dapp即可获得100nas,1个nas 75元人民币左右.编写合约只要会javascript就可以写.活动持续两个月左右.下面简单介绍一下流程 首先注册 ...

  8. SDL相关资料

    SDL(Simple DirectMedia Layer)是一个自由的跨平台的多媒体开发包,适用于 游戏.游戏SDK.演示软件.模拟器.MPEG播放器和其他应用软件.目前支持windows,linux ...

  9. DDGScreenShot--iOS 图片处理--多图片拼接 (swift)

    写在前面 最近总结了关于图片处理相关的内容,之前在二三四五工作的时候,也做过关于这方面的分享,图片的处理内容很多,会分很多模块来讲解. 今天简单讲多图片的拼接. 上代码 func composeIma ...

  10. Flask入门之开发简单登陆界面

    涉及知识点: render_template() redirect():注意def的函数不要使用这个Python关键字 url_for():可以传参数给动态路由 动态路由 # Sample.py fr ...