赞
踩
在 ASP.NET MVC 应用程序中,所有传入的请求均由控制器处理,并将这些请求映射到控制器相应的方法上
控制器方法可能会返回一个视图,也可能执行其它类型的操作,例如重定向到另一个控制器方法上
如果使用 MVC 框架,最流行的创建 HTML 的方法是使用 ASP.NET MVC 的 Razor 视图引擎
为了使用 Razor 视图引擎,一个控制器方法将产生一个 ViewResult (实现IActionResult接口)对象,而一个 ViewResult 可以携带我们想要使用的 Razor 视图的名称。
即我们可以在控制器中组装数据,再将数据通过Model绑定或ViewBag、ViewData对象将组装的数据返传递给View,之后控制器将View(中的Html)返回给浏览器。
其过程如下:
控制器决定返回哪个视图、视图中的数据是什么样,而最终响应给浏览器的HTML代码是根据视图进行生成的。
创建一个视图
DeptController下有名为”Index“、”Add“的Action,他们均需要返回一个ViewResu则我们目录结构图下图所示:
在cshtml文件中我们可以直接使用Html代码进行编写,结构同Html结构
此时运行程序并访问Action就会加载刚才你写的视图页面
使用Razor布局解决视图公共部分
比如我们的系统使用如下图所示的圣杯布局
除登录页外所有页面面的header、left、right、footer部分都相同,只有center部分根据不同页面显示不同内容。
如果我们不使用Razor布局,也可以使用iframe的方式进行引入,但这种方式存在一些弊端,比如以下几种:
第一次打开页面是浏览器需要多次向服务器请求页面内容,存在一定开销
我们没有办法将其中某一页的地址发给其他人打开,如果直接打开center部分的页面则header、left、right、footer这些部分的内容不会显示(除非你使用URL重写或将center部分地址带入到)。
必须控制center部分的页面能被哪些域嵌入,否则可能存在xss攻击的风险,因为parent页可以取到iframe中的cookies信息并修改页面的html代码内容。
因此我们可以考虑在每个视图中单独呈现这些公共部分,但每个页手动编写存在工作量大、修改麻烦(一旦一个地方需要改动,可能每个视图都得修改)。
好在,mvc为我们提供了一套解决方案,即”Razor布局“。
我们在上文提到的Views目录下再新建一个"shared"目录,在"shared"目录新建一个视图布局,名为_Layout.cshtml
之后打开这个Razor布局文件,我们可以将html的公共部分写在这个文件里,然后每个页需要展示不同信息的地方(如center部分)写如下代码
然后我们再为控制器中的每个Action创建各自的视图,此时,请注意,因为公共部分已经写到了Razor布局文件,每个视图生成Html时都会有这些部分,因为、等标签是不需要在写的,我们只要在这些视图中写上要放在id为"mainFrame"的DIV中的内容即可
如Dept/Index的视图里面的代码:
当然我们需要在各个action的视图中标明他需要使用哪个公共布局,即在视图的最顶部加上以下代码:
利用Razor视图开始(ViewStart)批量配置布局
当有非常多视图都需要引入相同的布局时,我们可以按上面的方法在每个试图单独写Layout=”*****“,也可以使用Razor视图开始,在Razor视图开始中编写的引用在其作用域下所有的视图都会被加上相应的代码,引用其规定的Razor布局
Razor视图开始文件作用域在当前目录及其子目录的所有视图。
也就是说
现在我们在Viiews目录下创建一个Razor视图开始文件取名为”_ViewStart.cshtml“,文件中的全部代码如下
之后运行网站(去掉所有视图的Layout="*********"这些代码),你就会看到所有视图都引用了该布局。
视图引用的优先级(覆盖)
经过测试视图引用优先级规则如下:
说明:”>“号左边的引用方式优先级高于>“号右边的引用方式,即如果某一页需要单独引用不同的视图布局,则可以使用优先级更高的方式覆盖优先级低的方式。
在视图中使用C#代码
有时候,如果你需要在视图中进行值的调用或进行一些特殊的计算,需要让视图中能执行c#代码
视图中的特殊符号@就可以实现这个效果
@符号存在以下几种用法
代码体,单纯执行某些代码,不对页面内容进行修改,如需要在页面中执行一个当前页面访问量统计(当然最好可以通过控制器或接口来实现,这里只是提到具有这个用法,不推荐使用,否则会导致代码混乱不易维护)
在代码体中,每一行都需要用";“结束,代码区中,字母区分大小写。字符类型常量必须用”"括起来,
注释代码
使用 @注释内容@ 这种语法可以实现在视图中添加注释(当然更推荐用html的方式注释)。例:
在Razor中使用局部变量,进行上下文调用,也可以用来拼接字符串,比如页面中某个位置需要显示当前的时间(当然还是建议你用JS实现)
执行一些.netcore中自带的方法,如Url.Content(string path)方法能够实现自动将绝对地址转换为相对地址,如现有logo放在项目wwwroot/image目录下,如果直接写成"/image/logo.jpg",直接使用没有问题,如后期因部署方案调整,系统静态文件访问地址改为"/static/image/logo.jpg",但文件的物理地址还是不变,此时就必须跟着修改代码否则访问不到图片。但是如果使用Url.Content方法,则会根据静态文件配置自动修改成正确的图片的访问地址。
例:
其他更多方法我们后面还会学习到,这里不深究
控制显示内容,比如我们做一个随机抽签决定A或B下去拿外卖的小例子,取当前时间的毫秒数,如果当前毫秒为0或999,则显示“两个人一起去取餐”,否则如果毫秒数能被2整除则输出”A去取餐“,否则输入"B去取餐"。
Controller向视图传值的几种方式
使用ViewBag和ViewData可以实现控制器的Action向视图传值,比如我有一个视图布局,但是我需要根据不同的页面地址在浏览器中显示不同的标题。其行为和响应如下:
我们可以看出,我的标题中“——Jxmaker”部分是固定的,但是这部分之前的文字是根据访问不同页面动态显示的,此时,我又使用了Razor布局,该处的代码位于布局文件中,我在控制器中需要将这个值传给视图让他在相应位置出现,我们就可以使用ViewBag或ViewData,ViewBag和ViewData只在Action中有效。他俩其实类似,只是有点小区别,看下面
ViewBag和ViewData的区别
使用方法:
Controller中控制要显示的Title并把它传入ViewBag/ViewData:
在视图中显示传入的值
使用这种方式,控制器的Action中使用将实体对象当作View的参数传递给View,而View中绑定实体的类型,就可以直接使用@Model得到传来的值
例如,我现在有一个页面需要显示部门的列表,此时我肯定是需要在Action中将部门列表传给View,View负责进行展示
我们首先在项目创建一个Models目录,然后在该目录新建类,比如我们现在新建一个部门类
Action方法:
在View中,我们需要先绑定一下该视图接收到值的类型
然后我们就可以通过Model访问到传入的数据,比如我们遍历这个列表,并显示在表格中,比如我们要在视图中显示部门数量,我们就可以用如下代码:
视图中的Model就是你传入的那个对象,你可以在视图中调用这个Model中的函数、属性、字段。
@Html(HtmlHelper)基本包含了html中的表单控件和常用Html,简单地说就是你可以在页面上”.”出你所需要的html标签,@Html还自带了一些方法也是通过”.”来进行选择
@Html的用途很多,大家可以看这篇文章,我就不再讲了,后面用到自然就会(其实现在我都是前后端分离,服务端只管API返回,所以Razor页面也差不多忘光了):
https://www.cnblogs.com/wfy680/p/12213292.html
我们讲一个比较特殊的用法
方法作用:
根据模板返回当前Model实例的HTML代码。也就是说,@Html.DisplayForModel()这个位置最后会被根据模板和传入的Model生成的Html代码给覆盖掉。最常见的一种情况就是如以列表方式展示(如各部门)信息,并提供一些操作按钮可以针对每行(显示的部门)进行操作。
我们以部门列表页为例,在View中,写一个表格代码的html和样式,thead节点是表头,因为表头是固定的,所以可以直接写html代码,而tbody部分需要根据控制器传入的列表进行动态渲染,所以这部分我们就用“@Html.DisplayForModel();”语句,告诉.net引擎这里帮我根据模板生成一堆代码
接下来,需要创建模板。在项目的Views目录下创建一个DisplayTemplates目录,然后根据Model的类型名称(这里是DeptInfo),创建一个cshtml文件,如DeptInfo.cshtml。
在Model模板中,我们首先绑定传入的Model类型 :
然后像普通的页面那样写模板(.net引擎会自动给你进行循环,所以你只要管一行的模板就可以了,会自动根据你的列表有多少个对象,就会生成多少行这样的html,这样就可以实现一个列表的循环渲染)
此外还有一个常用的Html.DisplayFor方法也可以实现类似的功能,如果想知道怎么用可以自己去百度一下。
其他的什么生成Input、RadioButton等功能你们可以在用到的时候自行百度,这里就不说了,HtmlHelper的作用就是帮助我们快速生成一段Html代码。
在.net framework中,如果你想使用HtmlHelper生成一个超链接(链接预览),点击这个超链接会跳转到 news/preview页面,并通过get方式给该页面传入id=1的值,就可以使用如下代码:
.net core提供更加方便的taghelper,使我们写代码更简洁也更具易读性:
那么为什么在Asp.Net Core MVC中要使用TagHelper呢?我们结合路由来看一下,假设路由开始是“/{controller=Home}/{action=Index}/{id?}”后来因为需要改为“/page/{controller=Home}/{action=Index}/{id?}”,如果我们直接在Razor视图上写死:
那么你修改路由就需要修改各个超链接,容易出现遗漏,工作量也不小。
我们需要先在项目文件夹Views目录中创建一个Razor视图导入,取名为“_ViewImports.cshtml”
然后再这个导入文件里面添加如下代码
意思就是全局导入Microsoft.AspNetCore.Mvc.TagHelpers命名空间下的全部(*代表全部)TagHelper
这样所有的View都可以直接使用
如上面例子所述,如果我一个超链接到某个Controller下的Action,则我在A标签中可以使用asp-controller、asp-action两个属性,asp-controller的值为Controller的名称,asp-action的值就是Action的名称,则自动根据路由配置生成访问该Action的地址。
如果需要使用get方式进行传值,则可以使用“asp-route-参数名称”这种格式的属性,如asp-route-uid=“99999”,则生成的html将会变成:
比如刚才系统的部门列表每一行都提供一个“查看职员”超链接,该按钮被点击后将会请求Employee控制器下的名为“Index”的Action,该Action访问需要传入对应的部门Id(deptId),如果部门Id没有问题则会返回当前部门下所有职员列表。
代码如下:
假设我们现在需要修改网站的logo(网站logo地址在wwwroot/img/logo.jpg),我在服务器上修改后,客户访问网站由于浏览器缓存问题依然不会生效,看到的还是旧的logo图片。为了解决这一个问题,我们一般会在图片地址后面添加一个没有意义的参数,该参数给请求地址传递一个随机数,每次页面刷新时这串随机数都会改变,相当于访问了一张新图片,浏览器没进行缓存。
TagHelper为我们提供了一个更简易的方式,我们只要给img标签加上“asp-append-verison”属性,其值为true,则每次访问这个页面时图片地址后面会自动加入一个版本号,使用代码如下:
顾名思义,就是一个一个使用link标签引入外部css太麻烦了,我想要按规则批量引入某个目录下的css文件
直接上代码
asp-href-include属性值用来设置需要引入的文件规则,asp-href-exclude属性用来排除部分不引入的文件的规则
以上代码执行后效果除了all.min.css外,全部css目录下的文件都会被引入
使用environment标签可以实现在不同环境下向浏览器响应发送不同的Html代码
如,我在开发环境需要引入上述css目录下全部css(除all.min.css),而在生产环境或其他不属于开发的环境下直接引入压缩过后的 all.min.css,不引入其他css
1.给Model类配置每个属性的显示名称,不如刚才的DeptInfo,改成如下:
然后在DeptController里增加一个Add的Action,需要传入一个Model给视图
为这个Action添加视图,先绑定Model
然后写一个form标签,其提交地址可以使用asp-action指定
在form标签中可以用 asp-for指定输入框的名称和 input的name属性
全部代码:
然后在DeptController写一个接受表单post方式传值的action,命名为“Add”,该Action接收一个DeptInfo 类型的参数model
当我们使用Get方式访问(在浏览器中通过输入地址访问或点击超链接跳转),则会自动进入设置为[HttpGet]或不设置的Action,当我们使用Post方式,默认会去找具有[HttpPost]申明的Action。
最后生成的表单效果(文字是我输入进去的):
END
●NoSQL之Redis配置与优化
●Socket服务器与多客户端的长链接通信
●【干货】使用MVC框架开发网站
●免费的软件资源库,你一定要收藏好!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。