前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >ASP.NET MVC5高级编程——(2)MVC模式的视图与Razor引擎

ASP.NET MVC5高级编程——(2)MVC模式的视图与Razor引擎

作者头像
浩Coding
发布于 2019-07-03 02:57:47
发布于 2019-07-03 02:57:47
3.7K00
代码可运行
举报
文章被收录于专栏:浩Coding浩Coding
运行总次数:0
代码可运行

视图的作用:

1 ,视图职责是向用户提供界面,当控制器针对被请求的URL执行完合适的逻辑后,就将要显示的内容委托给视图。

2 ,视图本身不会被直接访问,浏览器不能直接指向一个视图并渲染他,相反,视图总是被控制器渲染!因为控制器为他提供了要渲染的数据!

3 ,常见的情况是控制器需要向视图提供一些信息,所以会传递一个数据转移对象,叫做模型(此处模型指的是数据容器,就是类似于Javabean),而视图将这个模型转换为一种适合显示给用户的格式。

MVC框架请求流程图:

WebFrom请求的是aspx页面,而MVC请求的是Action。

WebFrom页面逻辑的控制都在和页面绑定的.cs文件,而MVC页面逻辑的控制都在Action。

MVC是表现模式,而三层是架构模式。如图所示:

Razor引擎和ASPX引擎(MVC5已经不支持)的区别:

Razor引擎(视图文件后缀名为.cshtml):

ASPX引擎 (视图文件后缀名为.aspx):

ASPX引擎也称为Web Form视图引擎,使用 ASP.NET Web Form 的“<%……%>” 标签语法,维持了与旧版MVC应用程序的兼容性。

Razor引擎由.NET MVC3 版本引入,语法简单而雅致,最明显的变化是用“@”替代“<%……%>”。创建项目时,两种视图引擎只能选其一。

1.1理解视图约定

当创建一个项目模版时,可以注意到,项目以一种非常具体的方式包含了一个结构化的Views目录。在每一个控制器的View文件夹中,每一个操作方法都有一个同名的视图文件与其对应。这就提供了视图与操作方法关联的基础。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 public ActionResult Index()
2 {
3      return View();  
4 }

视图选择逻辑在/Views/ControllerName目录(这里就是去掉Controller后缀的控制器名)下查找与操作方法同名的视图。此处选择的是/Views/Home/Index.cshtml

与ASP.NET MVC中的大部分方法一样,这一约定是可以重写的。想让Index操作方法渲染一个不同的视图,可以向其提供一个不同的视图名称,代码如下:

1 public ActionResult Index() 2 { 3 return View("NotIndex"); 4 }

对于上面的编码,操作方法依然在/Views/Home目录中查找视图,但选择的不再是Index.cshtml,而是NotIndex.cshtml。

如果需要制定完全位于不同目录结构中的视图,注意,此时需要在路径前面加上个~,而且必须带上拓展名哦!

编码如下:

1 public ActionResult Index() 2 { 3 return View("~/Views/Example/Index.cshtml"); 4 }

1.2 强类型视图

假设需要编写一个显示Album实例列表的视图,一种方法是将专辑添加到ViewBag中,然后在视图中进行迭代。

1 public ActionResult List() 2 { 3 var albums = new List<Album>(); 4 for (int i = 0; i < 10; i++) 5 { 6 albums.Add(new Album { Title = "Product" + i }); 7 } 8 ViewBag.Albums = albums; 9 return View(); 10 }

然后,再在视图中迭代显示,如下代码:

1 <ul> 2 @foreach (Album a in (ViewBag.Albums as IEnumerable<Album>)) 3 { 4 <li>@a.Tilte</li> 5 } 6 </ul>

强类型视图既能获得dynamic的简洁语法,又能获得强类型和编译时检查的好处(比如正确的输入属性和方法名称)。强类型视图允许设置视图的模型类型。因此可以从控制器向视图传递一个在两端都是强类型的模型对象,从而获得智能感知、编译器检查等好处。

在Controller方法中,可以通过向重载的View方法中传递模型实例来指定模型,代码如下:

1 public ActionResult List() 2 { 3 var Musics = new List<MusicModels>(); 4 for (int i = 0; i < 10; i++) 5 { 6 Musics.Add(new MusicModels { MusicName = "MusicName" + i.ToString() }); 7 } 8 returnView(Musics); 9 }下一步是告知视图哪种类型的模型正在使用@model声明。但要注意这里需要输入模型类型的完全限定类型名(名称空间和类型名称),如下所示:1 @model IEnumerable<MvcMusicStore.Models.MusicModels> 2 <ul> 3 @foreach(MvcMusicStore.Models.MusicModels music in Model) 4 <li>@music.SingerName</li> 5 </ul>如果不想输入模型类型的完全限定类型名,可使用@using关键字,如下所示:1 @using MvcMusicStore.Models 2 @model IEnumerable<MusicModels> 3 <ul> 4 @foreach(MusicModels music in Model) 5 <li>@music.SingerName</li> 6 </ul>

对于在视图中经常使用的名称空间,好的方法是在Views目录下的web.config文件中声明

<add namespace="MvcMusicStore.Models">

1.3 理解ViewBag、ViewData和ViewDataDictionary

之前介绍了使用ViewBag从控制器向视图传递信息,然后介绍了传递强类型模型。现实中,这些都是通过ViewDataDictionary传递的。

从技术的角度看,数据从控制器传送到视图是通过一个名为ViewData的ViewDataDictionary(这是一个特殊的字典类)。我们可以使用标准的字典语法设置或读取其中的值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ViewData["CurrentTime"] = DateTime.Now;

尽管这种语法现在也能用,但是MVC3提供了更简单的语法,可以利用C#4的dynamic关键字。ViewBag是ViewData的动态封装器。这样我们就可以按照下面的方式来设置值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ViewBag.CurrentTime = DateTime.Now;

ViewBag.CurrentTime和ViewData["CurrentTime"] 起到了等同的作用。

一般来说,大部分代码使用ViewBag(传递少量简单类型数据),而不是ViewData,这两种语法并不存在技术上的差异,仅仅是因为ViewBag相对于字典语法而言看上去好看。

注意,ViewBag和ViewData的差异:

  • 只有当要访问的关键字是一个有效的C#标识符时,ViewBag才起作用。例如,如果在ViewData["Key With Spaces"]中存放一个值,那么就不用使用ViewBag访问,因为无法通过编译。
  • 动态值不能作为一个参数传递给扩展方法,因为C#编译器为了选择正确的扩展方法,在编译时必须知道每一个参数的真正类型。

2.视图模型

先写一个新的方法到HomeCOntroller控制器中,Edit:

public ActionResult Edit() { return View(); }

在操作方法上右击 --> “添加视图”

  • View name:当从一个操作方法的上下文中打开这个对话框时,视图的名称默认被填充为操作方法的名称。视图的名称是必须有的。
  • Template:一旦选择一个模型类型,就可以选择一个基架模版。这些模版利用Visual Studio模版系统来生成基于选择模型类型的视图。
  • 引用脚本库:这个选项用来指示要创建的视图是否应该包含指向JavaScript库(如果对视图有意义的话)的引用。默认情况下,_Layout.cshtml文件既不引用jQuery Validation库,也不引用Unobtrusive jQuery Validation库,只引用主jQuery库。

当创建一个包含数据条目表单的视图(如Edit视图或者Create视图)时,选择这个选项会添加对jqueryval捆绑的脚本引用。如果要实现客户端验证,那么这些库就是必须的。除这种情况外,完全可以忽略这个复选框。

  • 创建一个分部视图:选择这个意味着要创建的视图不是一个完整的视图,因此,Layout选项是不可选用的。生成的部分视图除了在其顶部没有<html>标签和<head>标签外,很像一个常规的视图。
  • 使用布局页:这个选项决定了要创建的视图是否引用布局,还是成为一个完全独立的视图。如果选择使用默认的布局,就没必要指定一个布局了,因为在_ViewStart.cshtml文件中已经指定了布局。这个选项是用来重写默认布局文件的。

2.2 Razor视图引擎

ASP.NET MVC中提供了两种不同的视图引擎:较新的Razor视图引擎和较早的WebForms视图引擎。

Razor中的核心转换字符是(@),这个单一字符用作标记-代码的转换字符,有时也反过来用作代码-标记的转换字符

这里一共有两种基本类型的转换:代码表达式和代码块。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<h1>Listing @items.Length items.</h1>

表达式@items.Length是作为隐式表达式来求解的,然后输出表达式的值3。这里不需要指出代码表达式的结束位置。

但是Razor自动从代码转回标记的能力,也带来了二义性的问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 @{
2     string rootNamespace = "MyApp";
3 }
4 <span>@rootNamespace.Models</span>

这个示例想要的输出结果是: <span>MyApp.Models</span> ,然而实际会出现错误,提示string没有Models属性,此时需要通过圆括号解决:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 @{
2     string rootNamespace = "MyApp";
3 }
4 <span>@(rootNamespace).Models</span>

这样可以告诉Razor,.Models是字面量文本,而不是代码表达式的一部分。

对于电子邮件地址时的情况,Razor可以辨别出邮件的模式,进而不处理这种形式的表达式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<span>support@megacorp.com</span>

但是如果确实想将这种形式的字符串作为一个表达式,也需要合理用圆括号:

对于

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<li>Item_@item.Length</li>

期望的输出结果是<li>Item_3</li>,但是Razor会将其按照字符串进行打印。

处理的方法是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<li>Item_@(item.Length)</li>

有时也需要使用@符号来进行转义,@@就是为了显示@这个字符:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 <p>2  You should follow3  @@aspnet4 </p>

3.Razor语法示例

常见用途下的Razor语法;

  • 隐式代码表达式

代码表达式将被计算并将值写入到响应中,这就是视图中显示值的一般原理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<span>@model.Message</span>
  • 显示代码表达式

代码表达式的值将被计算并写入到响应中,这就是在视图中显示值的一般原理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<span>1 + 2 = @(1 +2 )</span>
  • 无编码代码表达式

有些情况下,需要显式的渲染一些不应该采用HTML编码的值,这时可以采用Html.Raw方法来保证该值不被编码(指的是应该被razor引擎解释,而不是被浏览器当成HTML语言)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<span>@Html.Raw(model.Message)</span>
  • 代码块

不像代码表达式先求的表达式的值,然后再输出到响应,代码块是简单地执行代码部分

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 @{
2    int x = 123;
3    string y = "because."
4 }
  • 文本和标记相结合

这个例子显示了在Razor中混用文本和标记的概念,具体如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 @foreach (var item in items)
2 {
3    <span>Item @item.Name.</span>
4 }
  • 混合代码和纯文本

Razor查找标签的开始位置以确定何时将代码转换为标记。然而,有时可能想在一个代码块之后立即输出纯文本。例如,在下面的这个例子中就是展示如何在一个条件语句块中显示纯文本

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 @if (showMessage)
2 {
3    <text>this is plain text</text>
4 }

或者

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 @if (showMessage)
2 {
3    @:this is plain text.
4 }

第一种使用<text>标签,这样只是把标签内容写入到响应中,而标签本身则不写入。第二种方式使用一种特殊的语法,实现代码到纯文本的转换,但是这种方法每次只能作用于一行文本。

  • 转义代码分隔符

使用“@@”来编码“@”以达到显示“@”的目的。此外,时钟都可以选择使用HTML编码来实现。

Razor:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
the asp.net twitter handle is &#64;aspnet

或者

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
the asp.net twitter handle is @@aspnet
  • 代码注释@**@
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1@*2 代码块3*@

4.布局

Razor的布局有助于使应用程序的多个视图保持一致的外观。可以使用布局为网站定义公共模版(或只是其中的一部分)。公共模版包含一个或多个占位符,应用程序中的其他视图为它们提供内容。从某些角度看,布局很像视图的抽象基类。

我们新建一个布局,右键--》添加--》MVC布局页:

如下则是一个简单的布局SiteLayout.cshtml:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <title>@ViewBag.Title</title>
 5     </head>
 6     <body>
 7         <h1>@ViewBag.Title</h1>
 8         <div>@RenderBody()</div>
 9         <footer>@RenderSection("Footer")</footer>
10     </body>
11 </html>

占位符就相当于使用了一个变量,而变量定义下面视图中!

对应视图的代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1 @{
2    Layout = "~Views/Shared/SiteLayout.cshtml";
        //上面这句话的意思是,这个视图,应用于SiteLayout.cshtml这个布局,
        //即:这个视图定义的变量,谁使用这个变量,这个变量的内容就显示到哪里,
 3     ViewBag.Title = "The Index";
4 }
5
6 <p>this is the main content!</p>
7
8 @section Footer{
9     this is the <strong>footer</strong>.
10 }

而这个视图通过layout属性来指定布局,当渲染这个视图时候,它的HTML内容将被放在SiteLayout.cshtml的<div></div>中,最终SiteLayout.cshtml的HTML内容应该是下面这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 <html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>The Index</title>
</head>
<body>
    <div>
       this is the main content!
     </div>
</body>
</html>

总之就是,布局使用了视图的变量

5.ViewStart

在创建一个默认的ASP.NET MVC项目后,会在Views目录下自动添加一个_ViewStart.cshtml文件,它指定了一个默认布局

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 @{
2    Layout = "~/Views/Shared/_Layout.cshtml"
3 }

如果多个视图都使用都使用同一个布局,就会产生冗余。_ViewStart.cshtml中的代码先于任何视图运行,所以一个视图可以重写Layout属性的默认值,从而重新选择了一个不同的布局。如果一组视图拥有共同的设置,那么_ViewStart.cshtml中的代码可以用来对共同的视图进行统一配置。如果有视图需要覆盖统一的设置,只需要修改对应的属性值即可。

6.指定部分视图

除了返回视图之外,操作方法也可以通过PartialView方法以PartialViewResult的形式返回部分视图:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 public class HomeController : HomeController
2 {
3     public ActionResult Message()
4     {
5         ViewBag.Message = "this is a partial view.";
6         return  PartialView();
7     }
8 }

这种情形下,渲染的是视图Message.cshtml,但是如果布局是由_ViewStart.cshtml页面指定(而不是直接在视图中)的,将无法渲染布局。

除了不能指定布局之外,部分视图看起来和正常视图没有分别:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<h2>@ViewBag.Message</h2>

在使用Ajax技术进行更新时,部分视图是很有用的。示例使用jQuery将一个部分视图的内容加载到一个使用了Ajax调用的当前视图中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1 <div id="result"></div>
2 @section scripts{
3 <script type="text/javascript">
4 $(function(){
5 $('#result').load('/home/message');
6 });
7 </script>
8 }

其中@section语法为布局中定义的一个节指定了内容。

视图引擎的用途非常具体且有限,目的是获取从控制器传递给它们的数据,并生成 经过格式化输出的,通常是HTML格式。(看不懂就留着,后面会详细解释这个坑)

本系列文章所有实例代码GitEE地址:

https://gitee.com/jahero/mvc

参考文章:

https://www.cnblogs.com/imstrive/p/6480118.html

https://www.cnblogs.com/imstrive/p/6510726.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浩Coding 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Flask框架(五)之SQLAlchemy
SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
GH
2020/03/19
3K0
SQLAlchemy
SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
小小咸鱼YwY
2020/06/19
3.2K0
Flask使用SQLAlchemy连接mysql
表操作 models.py from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column from sqlalchemy import Integer,String,Text,Date,DateTime from sqlalchemy import create_engine Base = declarative_base() class Users(Base): __tablenam
人生不如戏
2018/06/21
1.7K0
SQLAlchemy SQLAlchemy
SQLAlchemy 1.1.SQLAlchemy介绍 SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。 安装 pip install sqlalchemy 组成部分 Engine,框架的引擎 Connection Pooling ,数据库连接池 Dialect,选择连接数据库的DB API种类 Schema/Types,架构和类型 SQL Exprr
zhang_derek
2018/05/30
2.3K0
SQLALchemy的其他常用操作
使用连接池的两种方式 第一种方式: 直接从SessionFactory里获取,此时如果需要开启多个进程,那么创建连接池的代码一定要放在循环里面 不然的话每个进程都是用一个session了 from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from models import Student,Course,Student2Course engine = create_engine( "my
人生不如戏
2018/07/05
7870
Python操作MySQL(二) ORM
SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
py3study
2020/01/06
1.5K0
Python操作MySQL(二) ORM
pymysql
pymsql是python中操作的MYsql的模块,其使用方法和MySQLdb几乎相同
Wyc
2018/09/11
4.2K0
pymysql
python_day11のPython操
pymysql是Python中操作MySQL的模块,其使用方法和python2.7的MySQLdb几乎相同。
py3study
2020/01/13
4730
STM32 通过外部时钟输入模式测量频率,串口打印
使用了stm32f103zet6 通过外部时钟输入模式进行频率采集,在100khz以上误差在10hz左右
用户4585225
2020/12/17
2.2K0
python ORM框架SQLAlchemy
SQLAlchemy是一个基于Python的ORM框架。该框架是建立在DB-API之上,使用关系对象映射进行数据库操作。
用户5760343
2022/05/14
7660
ORM框架SQLAlchemy
原文链接:https://www.cnblogs.com/mengqingjian/articles/8521512.html
菲宇
2019/09/23
1.2K0
ORM框架SQLAlchemy
Python SQLAlchemy入门教程
本文将以Mysql举例,介绍sqlalchemy的基本用法。其中,Python版本为2.7,sqlalchemy版本为1.1.6。
oYabea
2020/09/07
3.3K0
Python操作SQLAlchemy
SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
菲宇
2019/06/13
8620
Python操作SQLAlchemy
SQLAlchemy总结+
Review: 一、Mysql 操作 创建一个test库 create database test; 授权一个用户 grant all privileges on *.* to 'asd'@'%' identified by 'awerfsdf123'; 创建表 create table student(id int not null); 查询 select * from tabel_name where 条件1 and 条件2 增加 insert into table_name (id, name
老七Linux
2018/05/31
2.3K0
Python 学习笔记 - SQLAlc
例1. 获取主机1的所有用户,原理和1对多的一样,通过relationship快速定位到对应的表
py3study
2020/01/15
3260
Python 学习笔记 - SQLAlc
Python ORM - pymysql&sqlalchemy
Python3主要是面向对象的编码风格,访问数据库也可以使用ORM框架来实现面向对象,本文介绍pymysql和sqlalchemy 安装组件 pip3 install pymysql pip3 install sqlalchemy 定义数据对象 user表结构 CREATE TABLE `user` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(64) NOT NULL, `age` int DEFAULT NULL, `del
十毛
2021/01/21
7470
盘点Flask与数据库的交互插件--Flask-Sqlalchemy
在我们做web开发的时候,经常需要用到与数据库交互,因为我们的数据通常都是保存在数据库中的,如果有人需要访问,就必须与数据库访问,所以今天我们介绍一个Flask中与数据库交互的插件---Flask-Sqlalchemy。
Python进阶者
2021/08/20
2.5K0
使用Python操作MySQL和Oracle数据库
前面两篇文章已经说过将数据存储到SQLite和本地文件中,如果还没有来得及看,可点击如下快速链接:
JiekeXu之路
2019/08/15
2.9K0
Python 数据库操作 SQLAlchemy
在运行过程中所有的的数据都存储在内存 (RAM) 中,「RAM 是易失性存储器,系统掉电后 RAM 中的所有数据将全部丢失」。在大多数情况下我们希望程序运行中产生的数据能够长久的保存,此时我们就需要将数据保存到磁盘上,无论是保存到本地磁盘,还是通过网络保存到服务器上,最终都会将数据写入磁盘文件。将数据保存在磁盘中我们需要面对一个数据格式的问题,此时就需要引入数据库操作。
keinYe
2019/08/01
1.6K0
SQLAlchemy学习-9.一对多和多对一关系
前言 一对多和多对一关系 一对多关系 一对多关系表设计,一个Parent类关联多个Child类 from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship # 拼接配置dialect + driver://username:pa
上海-悠悠
2022/08/26
3.3K0
SQLAlchemy学习-9.一对多和多对一关系
相关推荐
Flask框架(五)之SQLAlchemy
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文