跟我学ASP.NET MVC之六:SportsStrore添加产品目录导航
摘要:
上一篇文章,我建立了SportsStore应用程序的核心架构。现在我将使用这个架构向这个应用程序添加功能,你将开始看到这个基础架构的作用。我将添加重要的面向客户的简单功能,在这个过程中,你将看到MVC框架提供的额外功能。
如果客户能够根据目录导航产品,SportsStore应用程序可用性将更高。
- 改进ProductController控制器中的List方法,让他能够过滤在repository里的产品对象。
- 修改改进URL格式,修改routing策略。
- 在网站首页旁边创建一个目录列表,高亮显示当前页。
过滤产品列表
修改视图模型ProductsListViewModel,添加当前目录信息。
- using SportsStore.Domain.Entities;
- using System.Collections.Generic;
- namespace SportsStore.WebUI.Models
- {
- public class ProductsListViewModel
- {
- public IEnumerable<Product> Products { get; set; }
- public PagingInfo PagingInfo { get; set; }
- public string CurrentCategory { get; set; }
- }
- }
修改ProductController控制器的List方法,添加参数category,根据传入的category过滤产品。
- using SportsStore.Domain.Abstract;
- using SportsStore.WebUI.Models;
- using System.Web.Mvc;
- using System.Linq;
- namespace SportsStore.WebUI.Controllers
- {
- public class ProductController : Controller
- {
- private IProductRepository repository;
- public int PageSize = ;
- public ProductController(IProductRepository productRepository)
- {
- this.repository = productRepository;
- }
- public ViewResult List(string category, int page = )
- {
- ProductsListViewModel model = new ProductsListViewModel
- {
- Products = repository.Products.Where(p => string.IsNullOrEmpty(category) || p.Category == category)
- .OrderBy(p => p.ProductID).Skip((page - ) * PageSize).Take(PageSize),
- PagingInfo = new PagingInfo
- {
- CurrentPage = page,
- ItemsPerPage = PageSize,
- TotalItems = category == null ? repository.Products.Count() : repository.Products.Where(e => e.Category == category).Count()
- },
- CurrentCategory = category
- };
- return View(model);
- }
- }
- }
- 如果传入的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方法。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- using System.Web.Routing;
- namespace SportsStore
- {
- public class RouteConfig
- {
- public static void RegisterRoutes(RouteCollection routes)
- {
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
- routes.MapRoute(
- name: null,
- url: "",
- defaults: new { controller = "Product", action = "List", category = (string)null, page = }
- );
- routes.MapRoute(
- name: null,
- url: "Page{page}",
- defaults: new { controller = "Product", action = "List", category = (string)null },
- constraints: new { page = @"\d+" }
- );
- routes.MapRoute(
- name: null,
- url: "{category}",
- defaults: new { controller = "Product", action = "List", page = }
- );
- routes.MapRoute(
- name: null,
- url: "{category}/Page{page}",
- defaults: new { controller = "Product", action = "List" },
- constraints: new { page = @"\d+" }
- );
- routes.MapRoute(
- name: "Default",
- url: "{controller}/{action}/{id}",
- defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }
- );
- }
- }
- }
下面来解释添加的路由信息。
第一个路由函数:
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视图上生成链接字符串的方法调用。
- @model SportsStore.WebUI.Models.ProductsListViewModel
- @{
- ViewBag.Title = "Products";
- }
- @foreach (var p in Model.Products)
- {
- Html.RenderPartial("ProductSummary", p);
- }
- <div class="btn-group pull-right">
- @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x, category = Model.CurrentCategory }))
- </div>
Url.Action方法是向外产生链接最方便的方法。这里添加将category传入生成链接的代理方法中。
运行程序,改变浏览器地址栏上的URL,得到各路由URL页面结果。
创建目录导航菜单
首先创建MenuController控制器。
- using SportsStore.Domain.Abstract;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web.Mvc;
- namespace SportsStore.WebUI.Controllers
- {
- public class NavController : Controller
- {
- private IProductRepository repository;
- public NavController(IProductRepository productRepository)
- {
- repository = productRepository;
- }
- public PartialViewResult Menu(string category = null)
- {
- ViewBag.SelectedCategory = category;
- IEnumerable<string> categories = repository.Products.Select(x => x.Category).Distinct().OrderBy(x => x);
- return PartialView("Menu", categories);
- }
- }
- }
- 这个控制器返回PartialViewResult类型对象。PartialViewResult类跟之前使用的ViewResult类型都是继承自基类ViewResultBase。
- ViewBag动态类型属性SelectedCategory设置为当前目录字符串。
- 参数category将获取路由产生的URL上的目录字符串。
- categories变量返回Product下所有目录。
- 调用方法PartialView方法,返回PartialViewResult类型对象,传入的参数是视图名称和视图模型的变量。
然后创建Menu视图。
- @model IEnumerable<string>
- <div>
- @Html.RouteLink("Home", new { controller = "Product", action = "List" }, new { @class = "btn btn-block btn-default btn-lg" })
- @foreach (var link in Model)
- {
- @Html.RouteLink(link, new
- {
- controller = "Product",
- action = "List",
- category = link,
- page = 1
- }, new
- {
- @class = ("btn btn-block btn-default btn-lg") + (link == ViewBag.SelectedCategory ? " btn-primary" : "")
- })
- }
- </div>
这里调用Html扩展方法RouteLink,生成链接字符串。当然,你也可以使用ActionLink方法。
- 方法的第一个参数是链接显示的文本字符串。
- 第二个参数是动态数据类型,用来指定控制器,控制器方法以及方法传入的参数。
- 第三个参数也是动态数据类型,使用@class来指定链接的样式。这里使用bootstrap的样式,这里的设置顺序是:btn指定按钮样式,btn-block指定按钮呈现的外观占整行,btn-default指定按钮的皮肤颜色等,btn-lg指定按钮的大小。
- 如果是当前页,将添加btn-primary样式,将该按钮高亮显示。
最后,修改_Layout.cshtml文件,将Menu显示在页面上。
- <!DOCTYPE html>
- <html>
- <head>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <link href="~/Content/bootstrap.css" rel="stylesheet" />
- <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
- <title>@ViewBag.Title</title>
- </head>
- <body>
- <div class="navbar navbar-inverse" role="navigation">
- <a class="navbar-brand" href="#">SPORTS STORE</a>
- </div>
- <div class="row panel">
- <div class="col-xs-3">
- @Html.Action("Menu", "Nav")
- </div>
- <div class="col-xs-8">
- @RenderBody()
- </div>
- </div>
- </body>
- </html>
这里调用Html的扩展方法Action,传入控制器名字和方法名字,生成HTML字符串。它将Menu视图生成的字符串嵌入到div里面,生成导航栏。
注意这里不是调用RenderPartial方法,RenderPartial方法返回的void,它跟C#语句嵌套使用,在视图上嵌入视图。
运行程序,得到运行结果。
如果点击Soccer目录,将返回Category是Soccer的产品列表。并将Soccer这个按钮高亮显示。
跟我学ASP.NET MVC之六:SportsStrore添加产品目录导航的更多相关文章
- 跟我学ASP.NET MVC之五:SportsStrore开始
摘要: 这篇文章将介绍一个ASP.NET应用程序SportsStore的开发过程. 开始 创建解决方案 创建工程 在New ASP.NET Project - SportsStore窗口中,选择Emp ...
- 跟我学ASP.NET MVC之七:SportsStrore一个完整的购物车
摘要: SportsStore应用程序进展很顺利,但是我不能销售产品直到设计了一个购物车.在这篇文章里,我就将创建一个购物车. 在目录下的每个产品旁边添加一个添加到购物车按钮.点击这个按钮将显示客户到 ...
- 跟我学ASP.NET MVC之三:完整的ASP.NET MVC程序-PartyInvites
摘要: 在这篇文章中,我将在一个例子中实际地展示MVC. 场景 假设一个朋友决定举办一个新年晚会,她邀请我创建一个用来邀请朋友参加晚会的WEB程序.她提出了四个注意的需求: 一个首页展示这个晚会 一个 ...
- 跟我学ASP.NET MVC之二:第一个ASP.NET MVC程序
摘要: 本篇文章带你一步一步创建一个简单的ASP.NET MVC程序. 创建新ASP.NET MVC工程 点击“OK”按钮后,打开下面的窗口: 这里选择“Empty”模板以及“MVC”选项.这次不创 ...
- 跟我学ASP.NET MVC之一:开篇有益
摘要: ASP.NET MVC是微软的Web开发框架,结合了模型-视图-控制器(MVC)架构的有效性和整洁性,敏捷开发最前沿的思想和技术,以及现存的ASP.NET平台最好的部分.它是传统ASP.NET ...
- [转]我要学ASP.NET MVC 3.0(十二): MVC 3.0 使用自定义的Html控件
本文转自:http://www.cnblogs.com/lukun/archive/2011/08/05/2128693.html 概述 在ASP.NET MVC框架中已经封装了很多基于Html标 ...
- 跟我学ASP.NET MVC之十一:URL路由
摘要: 在MVC框架之前,ASP.NET假定在请求的URLs和服务器硬盘文件之间有直接的关系.服务器的职责是接收浏览器请求,从相应的文件发送输出. 这种方法只能工作于Web表单,每一个ASPX页面既是 ...
- ASP.NET MVC 5 系列 学习笔记 目录 (持续更新...)
前言: 记得当初培训的时候,学习的还是ASP.NET,现在回想一下,图片水印.统计人数.过滤器....HttpHandler是多么的经典! 不过后来接触到了MVC,便立马爱上了它.Model-View ...
- 给Asp.Net MVC及WebApi添加路由优先级
一.为什么需要路由优先级 大家都知道我们在Asp.Net MVC项目或WebApi项目中注册路由是没有优先级的,当项目比较大.或有多个区域.或多个Web项目.或采用插件式框架开发时,我们的路由注册很可 ...
随机推荐
- mybatis源码之MapperMethod
/** * @author Clinton Begin * @author Eduardo Macarron * @author Lasse Voss */ //这个类是整个代理机制的核心类,对Sql ...
- netlink组播的使用
Linux的netlink机制是非常好的Linux内核与应用层进行双向交互数据的方式.其常用的单播方式可以实现内核为服务端,应用层为客户端的通信方式.如果需要实现应用层为服务端,内核为客户端的通信方式 ...
- Java 8 Stream
1.关于Java8部分新特性介绍 Java8的新特性很多,在此就不一一介绍了,这里只说一下我自己在工作用用得比较多的几点: 1.1.Lambda表达式 Lambda允许把函数作为一个方法的参数(函数作 ...
- 如何在asp.net mvc 中使用Autofac 控制反转(Ioc)
前言 最近看了一些关于Ioc方面的开源项目,里面的类跳来转去,看的迷迷糊糊的.项目里根本不需要这么“复杂的”设计,只需简单完成Ico,达到解耦的目的,并且能高效的完成项目.于是参考autofac的官网 ...
- 多重影分身——C#中多线程的使用二(争抢共享资源)
只要服务器承受得了,我们可以开任意个线程同时工作以提高效率,然而 两个线程争抢资源可能导致数据混乱. 例如: public class MyFood { public static int Last ...
- Day6_内置函数
定义完一个有名函数,可以直接利用函数名+括号来执行,例如:func() 有名函数: def func(x,y,z=1): return x+y+z 匿名函数: lambda x,y,z=1:x+y+z ...
- 星云链开发dapp,赚取100nas(价值近万)
前几天星云链主网正式上线,现在只要成功提交一个dapp即可获得100nas,1个nas 75元人民币左右.编写合约只要会javascript就可以写.活动持续两个月左右.下面简单介绍一下流程 首先注册 ...
- SDL相关资料
SDL(Simple DirectMedia Layer)是一个自由的跨平台的多媒体开发包,适用于 游戏.游戏SDK.演示软件.模拟器.MPEG播放器和其他应用软件.目前支持windows,linux ...
- DDGScreenShot--iOS 图片处理--多图片拼接 (swift)
写在前面 最近总结了关于图片处理相关的内容,之前在二三四五工作的时候,也做过关于这方面的分享,图片的处理内容很多,会分很多模块来讲解. 今天简单讲多图片的拼接. 上代码 func composeIma ...
- Flask入门之开发简单登陆界面
涉及知识点: render_template() redirect():注意def的函数不要使用这个Python关键字 url_for():可以传参数给动态路由 动态路由 # Sample.py fr ...