精通 ASP.NET MVC 4 学习笔记(一)

这里记录着从 P132 到 P192 的内容。水分很足,大部分是书上的代码,我只加了一些基于我自己的理解的能帮助初学者看懂的注释,并且把书中的部分内容做了一些的拓展。

建立数据层

设置 DI 容器

/// <summary>/// 设置 DI 容器/// </summary>/// <seealso cref="System.Web.Mvc.DefaultControllerFactory" />public class NinjectControllerFactory : DefaultControllerFactory{private IKernel ninjectKernel;//添加依赖绑定规则private void AddBindings(){//put bindings here//将所有对 IProductsRepository 接口的实现替换为对 EFProductRepository 类的实现!!!ninjectKernel.Bind<IProductsRepository>().To<EFProductRepository>();}//必要的public NinjectControllerFactory(){ninjectKernel = new StandardKernel();AddBindings();}protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType){return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);}}

这个NinjectControllerFactory是一个继承于DefaultControllerFactory的自定义的依赖性解释器,这样,我们的就可以手动的控制查找控制器的方式。这里,我们把所有对 IProductsRepository 接口的实现替换为对 EFProductRepository 类的实现。
然后,在我们的应用中的 Global.asax.cs 文件中的Application_Start方法里面注册一下自定义的依懒性解析器:

ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());

现在,我们接着看看与IProductsRepository相关的东西,首先是这个这个接口的内容:

/// <summary>
/// 通过存储库模式实现持久化逻辑与域模型实体的分离。
/// </summary>
public interface IProductsRepository
{IQueryable<Product> Products { get; }
}

Products 属性存着来自数据库的 Product 表内容。

使用 EF 连接到数据库

然后我们再看看EFProductRepository的内容。

/// <summary>
/// 通过实现 IProductsRepository 接口实现的存储库类。
/// </summary>
/// <seealso cref="SportsStore.Domain.Abstract.IProductsRepository" />
public class EFProductRepository : IProductsRepository
{/// <summary>/// 用来定义从实体对象到数据库的映射。/// </summary>private EFDbContext context = new EFDbContext();public IQueryable<Product> Products{get { return context.Products; }}
}

这就是存储库类,他实现了IProductsRepository接口,而且用了一个EFDbContext实例,便于 Entity Framework 接收数据库的数据,然后通过Products属性以只读的方式访问数据库实体。

然后让我们看看EFDbContext的内容:

public class EFDbContext : DbContext
{/// <summary>/// 表示用 Product 模型类型来表示 Products 表中的每一行。/// </summary>/// <value>/// Products 表中所有行的集合。/// </value>public DbSet<Product> Products { get; set; }
}

它继承于DbContext,定义了从实体对象到数据库的映射。除此之外,他还提供了如下的服务:

  • 跟踪已经检索到的实体对象,如果再次查询该对象,就直接从对象上下文中提取它。
  • 保存实体的状态信息。可以获得已添加、修改和删除对象的信息。
  • 更新对象上下文中的实体,把改变的内容写入底层的存储器中。

然后他还有一个DataSet属性,DataSet表示上下文中给定类型的所有实体的集合或可从数据库中查询的给定类型的所有实体的集合,基本上就是一个存在于内存的数据库,其中包含了所有表、关系和约束。

仅仅是这么做是不够的,我们还需要告诉 Entity Framework 如何连接到数据库,我们要在 Web.config 文件中添加一条连接字符串,就像在 WebForms 网站中做的一样:

<connectionStrings><add name="EFDbContext" connectionString="Data Source=DESKTOP-M31J37E;Initial Catalog=SportsStore;Integrated Security=True" providerName="System.Data.SqlClient" /></connectionStrings>

添加控制器

ProductController

首先是书中最先添加的 ProductController

public class ProductController : Controller{private IProductsRepository repository;public int PageSize = 4;public ProductController(IProductsRepository productReposotory){this.repository = productReposotory;}/// <summary>/// 显示指定目录、指定页面的商品。/// </summary>/// <param name="category">The category.</param>/// <param name="page">The page.</param>/// <returns>返回一个 ProductsListViewModel 模型的视图</returns>public ViewResult List(string category, int page = 1){ProductsListViewModel model = new ProductsListViewModel{Products = repository.Products.Where(p => category == null || p.Category == category).OrderBy(p => p.ProductID).Skip((page - 1) * PageSize).Take(PageSize),PagingInformation = 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);}}

这里需要关注的是这个控制器的构造函数,他需要一个商品存储库类型的参数,这个参数将由我们之前设置的 DI 容器自动注入,也就是一个被映射有数据库内容的EFProductRepository对象,这样,我们的控制器就可以获取到数据库的内容了。
然后List方法中,创建了一个ProductsListViewModel,其中包含了要被显示出来的商品的集合、页面的分页信息跟当前显示的分类信息。下面是这个视图模型的具体内容:

public class ProductsListViewModel{public IEnumerable<Product> Products { get; set; }public PagingInfo PagingInformation { get; set; }public string CurrentCategory { get; set; }}

由于这个模型与业务中的域模型并没有什么关系,所以他被定义在 WebUI.cs 中。

接下来是NavController,用来给用户提供一个分类显示商品的方法,在页面中的体现就是导航栏。
为了实现这个功能,我们使用了 MVC 框架中的“子动作”,这依赖于一个叫做“RenderAction”的Html辅助器的方法,他可以让用户在当前视图中包含任意一个动作方法的输出(不是以iframe的形式)。
下面是这个控制器的内容:

public class NavController : Controller{private IProductsRepository respository;public NavController(IProductsRepository repo){respository = repo;}public PartialViewResult Menu(string category = null){ViewBag.SelectedCategory = category;IEnumerable<string> categories = respository.Products.Select(x => x.Category).Distinct().OrderBy(x => x);return PartialView(categories);}}

这个控制器的构造函数也是跟ProductController.List的构造函数一样,由 DI 来为他们注入参数。
Menu方法返回一个分部视图,这样可以让视图片段跨视图重用,有助于减少重复,分部视图在渲染的时候只是生成 HTML 片段。

为了能够完整的把 MVC 的思想体现出来,接下来将会介绍与上面两个控制器相关的视图。

视图

List

@model SportsStore.WebUI.Models.ProductsListViewModel@{ViewBag.Title = "Products";
}@foreach (var p in Model.Products)
{Html.RenderPartial("ProductSummary", p);
}<div class="pager">@Html.PageLinks(Model.PagingInformation, x => Url.Action("List", new { page = x, category = Model.CurrentCategory }))
</div>

这是一个强类型的视图,与List方法使用一致的模型。
首先我们需要关注的是第9行的代码,这里使用了RenderPartialHTML辅助器,它会直接将内容写入当前页面,不返回任何值。在这里,我们使用了参数为(视图名,模型)的重载。其中ProductSummary是一个分部视图,其中的内容暂且按下不表。

另一个需要关注的地方是第13行我们自定义的Html辅助器,他的内容如下:

public static class PagingHelpers{/// <summary>/// Build "a" tag to navigate from page to others./// </summary>/// <param name="html">The HTML Helper.</param>/// <param name="pageInfo">The page information.</param>/// <param name="pageUrl">The delegate that can create page URL for paging.</param>/// <returns>The Html string.</returns>public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pageInfo, Func<int, string> pageUrl){StringBuilder result = new StringBuilder();for (int i = 1; i <= pageInfo.TotalPages; i++){TagBuilder tag = new TagBuilder("a");tag.MergeAttribute("href", pageUrl(i));tag.InnerHtml = i.ToString();if (i == pageInfo.CurrentPage){tag.AddCssClass("selected");}result.Append(tag.ToString());}return MvcHtmlString.Create(result.ToString());}}

PageLinks是一个拓展方法,他接受一个页面信息参数跟一个用来生成 Url 的函数参数用来生成 HTML 代码。这个函数参数调用的是Url.Action方法,他可以根据动作方法与数据模型生成指定的 Url 。

这是与NavController.Menu方法相关的视图,他的内容如下:

@model IEnumerable<string>@Html.ActionLink("Home", "List", "Product")@foreach (var link in Model)
{@Html.RouteLink(link, new
{controller = "Product",action = "List",category = link,page = 1
},new { @class = link == ViewBag.SelectedCategory ? "selected" : null }
)
}

这也是一个强类型视图,不过在创建这个视图的时候,VS2015并不能让我直接从弹出的对话框里面指定我想要的模型,所以我是先创建空模型的视图,然后手动在源码里面添加模型的。这个模型里面包含着所有分类的名称,然后使用RouteLink方法生成对应的a标签,其中,第一个参数是a标签的内容,第二个参数是包含有路由信息的属性,通过检查对象的属性,利用反射检索参数。该对象通常是使用对象初始值设定项语法创建的。第三个参数是一个包含要添加给标签属性的对象,在这里,我们使用@class来给标签元素添加一个 class 。

路由

至此,我们的网站已经有了最基本的功能,但是,页面的 url 却很不美观,这里,我们就需要修改 RouteConfig.cs 里面的内容来产生美观的 url 。修改后的内容如下:

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 = 1 });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 = 1 });routes.MapRoute(name: null,url: "{category}/Page{page}",defaults: new { Controller = "Product", action = "List" },constraints: new { page = @"\d+" }//约束);routes.MapRoute(null, "{controller}/{action}");}}

这里面,主要需要注意的是 MapRoute 方法的调用。路由的是按照他定义的顺序来运用的,如果改变这种顺序会出现奇怪的效果。
现在我来解释一下这个方法的几个参数的含义:

  • name:表示路由的名称,目前我感觉木啥卵用
  • url:表示路由的格式,大括号内的内容是用来匹配实际 url 的
  • defaults:一个包含了控制器,动作方法的对象,动作方法参数的对象
  • constrains:用来约束上面查询字符串的正则表达式

具体是如何实现的,等我去研究一下。。。

转载于:https://www.cnblogs.com/JacZhu/p/5324544.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/430701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python之 tkinter中菜单栏快速学习(菜单栏,弹出菜单等)

python之tkinter中菜单栏的快速学习 本文主要讲述菜单栏的一些应用&#xff0c;附上代码&#xff0c;供大家学习。 import tkinter#导入tkinter库 toptkinter.Tk()#创建一个主窗口 top.geometry(400x80000)#指定主窗口大小 top.wm_title(Menu菜单功能的实现) #设置标题名称 ma…

如何命令行远程连接centos_如何使用windows远程控制centOS桌面

如何远程控制centOS桌面? 如何使用windows远程控制centOS桌面?1.查看本机是否有安装vnc(centOS5默认有安装vnc)rpm -q vnc vnc-server如果显示结果为&#xff1a;package vnc is not installedvnc-server-4.1.2-14.e15_3.1那恭喜你&#xff0c;机器上已经安装了vnc&#xff0…

【大数据】Hadoop入门预告版

背景 当今世界&#xff0c;大数据无处不在&#xff0c;它影响到了我们的工作、生活和学习&#xff0c;并将继续施加更大的影响。 大数据用于描述这样的数据组&#xff0c;其规模超出了日常软件在可容忍期限内获取、管理和加工数据的能力。一些网络技术领先的公司持续地投资于昂…

Python ——告白小程序,添加微信号(快来设置你的freestyle吧)

朋友过生日&#xff0c;然后就在搜一些小程序&#xff0c;哈哈哈O(∩_∩)O哈哈~ 然后就搜到了一些表白的小程序&#xff0c; 然后再自己改了改&#xff0c;增加了一个添加微信的功能。然后加载了背景音乐&#xff0c;啦啦啦啦啦&#xff0c;赶紧告白起来吧 图片和音乐可以根据自…

airpodspro窃听模式_AirPods Pro实时收听怎么关闭? AirPods Pro实时收听的使用方法

苹果全新AirPods Pro增加了许多新功能。首先,是控制播放。苹果在AirPods Pro中放弃了敲击手势,并用杆上的力传感器取代了它。控制音乐或视频只需要简单的短按即可。一次按压即可播放或暂停当前播放。两次按压将跳至下一曲目,而三次挤压则向后移动。可以通过按压任一AirPods …

UML基础知识点

UML : unified Modeling Language 统一建模语言1.对系统问题进行分析和建模2.非专利的第三代建模和规约语言3.UML是一种开放的方法、用于说明、可视化、构建、编写一个正在开发的、面向对象的、软件密集系统的开放方法4.UML集成了Booch、OMT和面向对象软件工程的概念面向对…

如何实现listbox选项,然后双击鼠标实现选项的删除

如何实现双击鼠标左键然后删除列表框中的选项呢&#xff1f; 只需要两步&#xff1a; 第一步&#xff0c;建立listbox控件与鼠标事件的绑定并给一个跳转函数; 如本例中的listbox控件&#xff0c;绑定事件<Double-Button-1>&#xff0c;其含义是指双击鼠标左键&#xf…

因变量 方差膨胀系数_请问如何计算潜变量的方差膨胀因子(VIF)?

这里提供一个 Python 实现的方法和原理趣分析方差膨胀因子是非常经典缓解多元共线性的方法&#xff0c;原理简单&#xff0c;实现优雅&#xff0c;效果拔群。源代码源数据可私聊俺获取&#xff0c;每天固定时间查看和回复。原理趣析多重线性回归模型的主要假设之一是我们的预测…

下拉到底部加载更多

var p1; active_list();function active_list() {$.ajax({type: "GET",url: "{:U(User/glodLogList_data)}",data: {page:p},dataType: "json",success: function(data){if(datanull){$("#add_more").html(没有更多了);$("#add_m…

Print() 语句以及数字赋值语句 中if-else的使用

#print语句以及num里面if else 的变态语句 x10 num110 if x>8 else 20 #如果中间语句成立为True,则执行输出左边语句&#xff1b;否则为False 则输出右边语句 print(num1) num110 if x>15else 20 #如果中间语句成立为True,则执行输出左边语句&#xff1b;否则为False 则输…

幻世机器人_2014年科幻动作《幻世追踪/启动机械码》BD中英双字幕

◎译  名 幻世追踪/启动机械码(台)◎片  名 Vice◎年  代 2015◎国  家 美国◎类  别 动作/科幻/惊悚/冒险◎语  言 英语◎字  幕 中英双字幕◎IMDB评分 4.0/10 from 3,848 users◎文件格式 BD-RMVB◎视频尺寸 1280 x 720◎文件大小 1CD◎片  长 96…

单链表逆置

单链表的逆置问题&#xff0c;常常遇到&#xff0c;今天总结如下&#xff1a; 方法&#xff1a;头插法&#xff1a; 图示&#xff1a; 代码&#xff1a; //翻转单链表 ListNode* Revers(ListNode* pHead) {ListNode* newhead NULL;ListNode* cur pHead;while(cur){ListNode* …

if-else多级嵌套,输入3/4/5个数寻找最大值(太多了容易乱!!!)

哎呀呀&#xff0c;心累啊&#xff0c;玩这个多级嵌套&#xff0c;眼花~ 多级嵌套有序3个数&#xff08;找最大值&#xff09; a,b,ceval(input("a,b,c")) if a>b:pass #a (a,b)if a>c:print("max",a)if b>c:print(b,c)else:print(c,b)else:p…

页面 接收跳转数据_【实战案例】在线教育渠道落地页数据分析

商业数智化工作坊“ 与多位来自高校的专家学者与业界导师共同探索商业数字化、智能化发展趋势、技术及实践培养数字思维&#xff0c;掌握数智化工具&#xff0c;实现管理能力跃迁”1背景与目标通过对跟渠道落地页数据的分析&#xff0c;优化用户路径&#xff0c;提高各环节的转…

竞态条件和临界区

1. 临界区和竞态条件&#xff1a; 临界区&#xff1a;访问和操作共享数据的代码段&#xff1b; 竞态条件&#xff1a;当有多个线程同时进入临界区时&#xff0c;执行结果取决于线程的执行顺序&#xff1b; 如下述代码&#xff0c;当多个线程同时调用func函数&#xff0c;对共享…

MATLAB程序实现经纬度转换成平面坐标

近期搜了下经纬度坐标转换成直角坐标的程序和原理啥的&#xff0c;哎&#xff0c;真难啊&#xff0c;其实道理都懂吧&#xff0c;下面直接贴代码&#xff0c; 主要是加了个for循环而言&#xff0c;优化输出效果。 %%%MATLAB程序实现经纬度转换成平面尔坐标&#xff1a; M_PI3…

ANSYS2020R2与Solidworks2019进行关联,但2019安装完后打开出现无法获得下列许可SOLIDWORKS Standard.使用许可文件不支持此版本(-21,126,0)

本身想将ANSYS2020R2与Solidworks进行关联&#xff0c;本身电脑上安装了2016版本&#xff0c;但是使用ANSYS2020R2软件&#xff0c;无法关联上。又没找到相应方法去解决&#xff0c;估计是版本问题无法关联上吧&#xff0c;所以就重新下个高点的版本试试。在网上下载相关软件&a…

jquerymobile使用技巧

1&#xff09;ajax开关&#xff08;默认jquery以ajax方式加载页面&#xff09; $.mobile.ajaxEnabled false; 2&#xff09;不编译指定标签 $.mobile.page.prototype.options.keepNative"input"; 3&#xff09;开启dom缓存 $.mobile.page.prototype.options.domCach…

git 使用writer_GitHub - Vpredictor/WriterFly: [QT/C++] 写作天下,为作家创造世界而生,执云作笔,诉尽平生意。...

写作天下简介为作家们创造世界而诞生&#xff0c;执云作笔&#xff0c;诉尽平生意。集简约UI与人性化AI于一体的码字工具&#xff0c;无论是小说、作文、日记、报告&#xff0c;都能轻松驾驭。QQ交流群&#xff1a;705849222特点已有功能&#xff1a;自由的目录&#xff1a;自动…

《Linux内核》课本读书笔记 第三章

转载于:https://www.cnblogs.com/bushifudongjing/p/5339017.html