ASP.NET MVC 最好的视图引擎Razor语法使用速成指南
liuian 2024-12-02 22:22 21 浏览
在ASP.NET Core MVC应用程序中,视图引擎(view engine)负责处理发送给客户端的内容。MVC框架中默认的视图引擎称为Razor,用来为HTML文件添加注释说明并将这些动态内容插入发送给浏览器的输出中。
本章将介绍一个用于快速解读Razor语法的工具,这样当你看到它的时候,就可以马上将其识别出来。本章不会非常详细地介绍Razor的内容,把本章看作Razor语法的速成指南即可。随着本书其他章节介绍MVC的其他功能,我们再慢慢深入介绍。关于在具体语境中如何理解Razor,参见表5-1。
表5-1 在具体语境中理解Razor
问题 | 答案 |
它是什么? | Razor是负责将数据合并到HTML文档中的视图引擎 |
它有什么作用? | 动态生成内容的能力对编写Web应用程序是必不可少的,Razor提供了可以使C#语句轻松地与ASP.NET Core MVC的其他部分协同工作的能力 |
怎样使用? | 将Razor表达式添加到视图文件的静态HTML中,Razor表达式可协助生成客户端请求的响应 |
有哪些容易出现的问题或限制? | Razor表达式可以包含几乎所有的C#语句,并且很难决定逻辑应该属于视图还是控制器,从而削弱MVC关注点分离的核心理念 |
有其他的做法吗? | 可以编写自己的视图引擎。也有一些第三方的视图引擎可以使用,但它们往往在特定情况下可行,不提供长期支持 |
表5-2列出了本章要完成的操作。
表5-2 本章要完成的操作
操作 | 解决方法 | 代码清单 |
访问视图模型 | 使用@model表达式定义模型类型,使用@Model表达式访问模型对象 | 代码清单5-5、代码清单5-14、代码清单5-17 |
使用类型名称而不限定它们的命名空间 | 创建视图导入文件 | 代码清单5-6和代码清单5-7 |
定义多视图共享的内容 | 使用布局 | 代码清单5-8~代码清单5-10 |
定义默认布局 | 使用视图启动文件 | 代码清单5-11~代码清单5-13 |
将数据从控制器传递到视图模型之外的其他视图 | 使用视图包 | 代码清单5-15和代码清单5-16 |
有选择地生成内容 | 使用Razor条件表达式 | 代码清单5-18和代码清单5-19 |
为数组和集合中的每个元素生成内容 | 使用Razor的foreach表达式 | 代码清单5-20和代码清单5-21 |
5.1 准备示例项目
为了演示Razor是怎样工作的,首先创建一个ASP.NET Core Web Application(.NET Core)项目并取名为Razor,就像之前的章节描述的那样。接下来,在Startup.cs文件中启用了MVC的默认配置,如代码清单5-1所示。
代码清单5-1 在Razor文件夹下的Startup.cs文件中启用MVC的默认配置
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Razor {
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
//app.Run(async (context) => {
// await context.Response.WriteAsync("Hello World!");
//});
app.UseMvcWithDefaultRoute();
}
}
}
5.1.1 定义模型
接下来,创建模型文件夹Models,并在其中添加名为Product.cs的类文件,用于定义代码清单5-2中的简单模型类。
代码清单5-2 Models文件夹下的Product.cs文件的内容
namespace Razor.Models {
public class Product {
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { set; get; }
}
}
5.1.2 创建控制器
Startup.cs文件中的配置如下:默认情况下,MVC将请求发送到名为Home的控制器。创建Controllers文件夹,并在其中添加名为HomeController.cs的类文件,用于定义代码清单5-3中的简单控制器。
代码清单5-3 Controllers文件夹下的HomeController.cs文件的内容
using Microsoft.AspNetCore.Mvc;
using Razor.Models;
namespace Razor.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
Product myProduct = new Product {
ProductID = 1,
Name = "Kayak",
Description = "A boat for one person",
Category = "Watersports",
Price = 275M
};
return View(myProduct);
}
}
}
以上控制器定义了一个名为Index的操作方法来创建和填充Product对象的属性。将Product对象传递给View方法,以便渲染视图时将其用作模型。在调用View方法时,并不指定视图文件的名称,这样操作方法便会使用默认视图。
5.1.3 创建视图
为了给 Index 操作方法创建默认视图,创建Views/Home文件夹,在其中添加MVC视图页面文件Index.cshtml,其中的内容如代码清单5-4所示。
代码清单5-4 Views/Home文件夹下的Index.cshtml文件的内容
@model Razor.Models.Product
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
Content will go here
</body>
</html>
后面将介绍Razor视图的其他部分,并演示其中一些内容的不同作用。在学习Razor的时候,请记住一点,视图的存在是为了向用户表达模型的一个或多个方面。也就是说,可利用从一个或多个对象中检索到的数据来生成HTML 页面文件。如果你仍记得我们始终试图建立可以发送到客户端的HTML页面,那么就会觉得Razor所做的一切都是有意义的。如果运行示例应用程序,你将看到图5-1所示的输出。
图5-1 示例应用程序的输出
5.2 使用模型对象
让我们从Index.cshtml视图文件的第一行开始。
...
@model Razor.Models.Product
...
Razor表达式以@字符开头。在本例中,@model表达式声明了将从操作方法传递到视图的模型对象的类型。这样就可以通过@model来访问视图模型对象的方法、字段和属性,代码清单5-5显示了对Index视图所做的简单补充。
代码清单5-5 在Views/Home文件夹下的Index.cshtml文件中引用视图模型对象的属性
@model Razor.Models.Product
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
@Model.Name
</body>
</html>
注 意
这里使用@model声明视图模型对象的类型,而使用@Model访问Name属性。
如果运行应用程序,你将看到图5-2所示的输出。
图5-2 在视图中读取属性的输出
使用@model表达式指定类型的视图称为强制类型视图(strongly typed view)。当键入@model和句点时,Visual Studio便会弹出@model表达式成员可以使用的名称建议,如图5-3所示。
图5-3 Visual Studio基于@model表达式为成员名称提供建议
Visual Studio对成员名称的可视化建议有助于避免在Razor中出现错误。根据个人意愿,可以忽略这些建议,Visual Studio将高亮显示成员名称有问题,以便进行更正,就像使用常规的C#类文件一样。图5-4列举了一个示例,开发人员在其中试图引用@Model.NotARealProperty。Visual Studio已意识到开发人员在模型类型中指定的Product类没有这样的属性,因而在编辑器中高亮显示错误。
图5-4 Visual Studio为@Model表达式报告错误
使用视图导入
当在Index.cshtml文件的开头定义模型对象时,必须导入包含模型类的命名空间,如下所示:
...
@model Razor.Models.Product
...
默认情况下,在强制类型的Razor视图中引用的所有类型都必须使用命名空间进行限定。当模型对象有唯一的引用类型时,这不是什么大问题;但是当需要编写更复杂的Razor表达式时,就会使视图的可读性变差。
可以通过在项目中添加视图导入文件来指定要搜索类型的命名空间集合。视图导入文件放在Views文件夹中,并命名为_ViewImports.cshtml。
注 意
Views文件夹中名称以下画线(_)开头的文件不会返回给用户,从而将想要呈现的视图文件和支持它们的文件区分开。视图导入文件和布局模板(稍后介绍)是以下画线为前缀的。
要创建视图导入文件,请在解决方案资源管理器(Solution Explorer)中右击Views文件夹,从弹出菜单中选择Add→New Item,然后从ASP.NET类别中选择MVC View Imports Page模板,如图5-5所示。
图5-5 创建视图导入文件
Visual Studio会自动将文件的名称设置为_ViewImports. cshtml,单击Add按钮以创建该文件。代码清单5-6展示了添加完表达式之后的视图。
代码清单5-6 Views文件夹下的_ViewImports.cshtml文件的内容
@using Razor.Models
Razor视图中用来搜索类的命名空间由@ using表达式指定,后面跟着相应的命名空间。在代码清单5-6中,已为Razor.Models命名空间添加了一项,其中包含了示例应用程序的模型类。
现在,Razor.Models命名空间就包含在视图导入文件中了,可以从Index.cshtml文件中移除命名空间,如代码清单5-7所示。
代码清单5-7 在Views/Home文件夹下的Index.cshtml文件中不使用命名空间引用模型类
@model Product
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
@Model.Name
</body>
</html>
提 示
还可以将@using表达式添加到单个视图文件中,这将允许在单个视图中使用没有命名空间的类型。
5.3 使用布局
Index.cshtml视图文件中还有另外一个重要的Razor表达式:
...
@{
Layout = null;
}
...
这是一个Razor代码块,允许在视图中包含C#语句。Razor代码块以@“{”开始,以“}”结束,里面包含的语句将在呈现视图时执行。
以上Razor代码块将Layout属性的值设置为null。Razor视图被编译为MVC应用程序中的C#类,并且用基类定义了Layout属性。第21章将介绍具体的工作方式。将Layout属性设置为null的效果就是告诉MVC视图是自包含的,并将渲染客户端所需的所有内容。
自包含的视图对于简单的示例应用程序表现比较好,但是一个真正的项目可以有几十个视图,有些视图将共享内容。在视图中复制共享内容又很难管理,尤其是当需要进行更改并且必须跟踪所有需要更改的视图时。
当一个模板包含公共的内容并且可以应用于一个或多个视图时,比较好的方法就是使用Razor布局。对布局进行更改时,更改将自动影响使用布局的所有视图。
5.3.1 创建布局
布局通常由多个控制器使用的视图共享,并存储在Views/Shared文件夹中,这是在查找文件时Razor会自动查看的位置之一。为了创建布局,先创建Views/Shared文件夹,右击后从弹出菜单中选择Add→New Item。从ASP.NET类别中选择MVC View Layout Page模板,并将文件名设置为_BasicLayout.cshtml,如图5-6所示。单击Add按钮创建这个文件(与视图导入文件一样,布局文件的名称也以下画线开头)。
代码清单5-8显示了由Visual Studio创建的_BasicLayout.cshtml文件的初始内容。
代码清单5-8 Views/Shared文件夹下的_BasicLayout.cshtml文件中的初始内容
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@RenderBody()
</div>
</body>
</html>
图5-6 创建布局
布局是一种特殊的视图形式,代码中已高亮显示@表达式。@RenderBody方法的调用会将操作方法定义的视图内容插入布局标记中。
...
<div>
@RenderBody()
</div>
...
布局中的另一个Razor表达式会查找名为ViewBag.Title的属性,以便设置title元素的内容。
...
<title>@ViewBag.Title</title>
...
ViewBag允许在应用程序中传递数据值,本例中是指在视图和布局之间传递。在将布局应用于视图时,你将看到这是如何工作的。
布局中的HTML元素将应用于任何使用它们的视图,并且提供了一个用于定义公共内容的模板。在代码清单5-9中,在布局中添加了一些简单的标记,这样模板效果就很明显了。
代码清单5-9 在Views/Shared文件夹下的_BasicLayout.cshtml文件中添加内容
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<style>
#mainDiv {
padding: 20px;
border: solid medium black;
font-size: 20pt
}
</style>
</head>
<body>
<h1>Product Information</h1>
<div id="mainDiv">
@RenderBody()
</div>
</body>
</html>
这里添加了标头元素以及一些CSS来为包含@RenderBody表达式的div元素的内容设置样式,这样就可以清楚地知道哪些内容来自布局,哪些内容来自视图。
5.3.2 使用布局
要将布局应用于视图,我们需要设置Layout属性的值,并移除现在由布局提供的HTML,如代码清单5-10所示的html、head和body元素。
代码清单5-10 在Views/Home文件夹下的Index.cshtml文件中应用布局
@model Product
@{
Layout = "_BasicLayout";
ViewBag.Title = "Product Name";
}
Product Name: @Model.Name
Layout属性将指定用于视图的布局文件,但不使用.cshtml文件扩展名。Razor将在/Views/Home和Views/Shared文件夹中查找指定的布局文件。
上面还设置了ViewBag.Title属性。在渲染视图的时候,布局会使用该属性设置title元素的内容。
即使是非常简单的应用,视图的这种转换也是非常激动人心的。布局包含了任何HTML响应所需的所有结构,这使得视图只需要关注向用户呈现数据的动态内容就可以了。当MVC处理Index.cshtml文件时,将应用布局来创建统一的HTML响应,如图5-7所示。
图5-7 为视图使用布局后的效果
5.3.3 应用视图启动文件
另一个需要交代的地方,就是必须为将要使用的每个视图指定布局文件。因此,如果需要重命名布局文件,就必须找到引用布局文件的每个视图并进行更改,这非常容易出错。最重要的是,这与MVC应用程序的易维护宗旨背道而驰。
这个问题可以通过使用视图启动文件(view start file)来解决。在渲染视图的时候,MVC将查找一个名为_ViewStart.cshtml的文件。这个文件的内容将被视为包含在视图文件本身中,我们可以使用这个功能自动设置Layout属性的值。
要创建视图启动文件,请右击Views文件夹,从弹出菜单中选择Add→New Item,然后从ASP.NET类别中选择MVC View Start Page模板,如图5-8所示。
Visual Studio会自动将文件的名称设置为_ViewStart.cshtml,单击Add按钮,Visual Studio为这个文件创建的初始内容如代码清单5-11所示。
图5-8 创建视图启动文件
代码清单5-11 Views文件夹下的_ViewStart.cshtml文件的初始内容
@{
Layout = "_Layout";
}
为了将布局应用于应用程序中的所有视图,更改分配给Layout属性的值,如代码清单5-12所示。
代码清单5-12 在Views文件夹下的_ViewStart.cshtml文件中应用默认视图
@{
Layout = "_BasicLayout";
}
因为视图启动文件包含Layout属性的值,所以可以从Index.cshtml文件中删除相应的表达式,如代码清单5-13所示。
代码清单5-13 更新Views/Home文件夹下的Index.cshtml文件以体现视图启动文件的使用
@model Product
@{
ViewBag.Title = "Product Name";
}
Product Name: @Model.Name
不必指定要使用的视图启动文件。MVC将自动定位视图启动文件并使用里面的内容。视图启动文件中定义的值优先,这样就可以方便地重写视图启动文件。
还可以使用多个视图启动文件为应用程序的不同部分设置默认值。Razor会查找离正在处理的视图最近的视图启动文件,这意味着可以通过在Views/Home或Views/Shared文件夹中添加视图启动文件来覆盖默认设置。
警 告
务必了解从视图启动文件中省略Layout属性与将Layout属性设置为null之间的区别。如果视图是自包含的,并且不希望使用布局,可将Layout属性设置为nulll。如果省略Layout属性,MVC将认为需要布局,并且应该使用已在视图启动文件中找到的值。
5.4 使用Razor表达式
至此,我们已经了解了视图和布局的基本知识,接下来介绍Razor支持的各种不同类型的表达式,以及如何使用它们来创建视图内容。在优秀的MVC应用程序中,操作方法和视图的角色之间存在着明确的差异,如表5-3所示。
表5-3 操作方法和视图的角色差异
内容 | 可以做什么 | 不能做什么 |
操作方法 | 将视图模型对象传递到视图 | 将格式化数据传递到视图 |
视图 | 使用视图模型对象向用户显示内容 | 修改视图模型对象 |
为了充分发挥MVC的优势,我们需要尊重并保证应用程序不同部分之间的分离。正如你将看到的,Razor可以为我们做很多工作,包括使用C#语句,但是不能使用Razor执行业务逻辑或以任何方式操作域模型对象。
作为一个简单的示例,代码清单5-14显示了一种在Index.cshtml文件中添加表达式的方式。
以上回答摘自刚刚上架的《精通http://ASP.NET Core MVC (第7版)》全书694页,作者:[美] 亚当·弗里曼(Adam Freeman) 著,郝冠军,孙臻,闫小迪,张淯易 译
1.畅销书升级版,详细介绍了http://ASP.NET Core MVC的架构、功能和应用,讲述了开发可扩展的Web应用程序的工具和技术。
2.结合具体实例和代码,展示了http://ASP.NET Core MVC的方方面面,揭示了如何用http://ASP.NET Core MV构建Web应用程序。
3.第7版新增了大量内容:
- Visual Studio、C#、Entity Framework、.NET Core 2的功能;
- 配置应用程序和元包的方法;
- Visual Studio Code的用法和在非Windows平台上使用.NET Core的方法。
通过阅读本书,你可以实现以下目标:
- 透彻理解http://ASP.NET Core MVC框架;
- 理解MVC和测试驱动的开发的原理;
- 学会在日常工作中应用http://ASP.NET Core MVC的功能;
- 明白如何为单页应用程序创建REST风格的Web服务;
- 基于已有的MVC知识快速搭建新的编程模型。
相关推荐
- GANs为何引爆机器学习?这篇基于TensorFlow的实例教程为你解惑!
-
「机器人圈导览」:生成对抗网络无疑是机器学习领域近三年来最火爆的研究领域,相关论文层出不求,各种领域的应用层出不穷。那么,GAN到底如何实践?本文编译自Medium,该文作者以一朵玫瑰花为例,详细阐...
- 高丽大学等机构联合发布StarGAN:可自定义表情和面部特征
-
原文来源:arXiv、GitHub作者:YunjeyChoi、MinjeChoi、MunyoungKim、Jung-WooHa、SungKim、JaegulChoo「雷克世界」编译:嗯~...
- TensorFlow和PyTorch相继发布最新版,有何变化
-
原文来源:GitHub「机器人圈」编译:嗯~阿童木呀、多啦A亮Tensorflow主要特征和改进在Tensorflow库中添加封装评估量。所添加的评估量列表如下:1.深度神经网络分类器(DNNCl...
- 「2022 年」崔庆才 Python3 爬虫教程 - 深度学习识别滑动验证码缺口
-
上一节我们使用OpenCV识别了图形验证码躯壳欧。这时候就有朋友可能会说了,现在深度学习不是对图像识别很准吗?那深度学习可以用在识别滑动验证码缺口位置吗?当然也是可以的,本节我们就来了解下使用深度...
- 20K star!搞定 LLM 微调的开源利器
-
LLM(大语言模型)微调一直都是老大难问题,不仅因为微调需要大量的计算资源,而且微调的方法也很多,要去尝试每种方法的效果,需要安装大量的第三方库和依赖,甚至要接入一些框架,可能在还没开始微调就已经因为...
- 大模型DeepSeek本地部署后如何进行自定义调整?
-
1.理解模型架构a)查看深度求索官方文档或提供的源代码文件,了解模型的结构、输入输出格式以及支持的功能。模型是否为预训练权重?如果是,可以在预训练的基础上进行微调(Fine-tuning)。是否需要...
- 因配置不当,约5000个AI模型与数据集在公网暴露
-
除了可访问机器学习模型外,暴露的数据还可能包括训练数据集、超参数,甚至是用于构建模型的原始数据。前情回顾·人工智能安全动态向ChatGPT植入恶意“长期记忆”,持续窃取用户输入数据多模态大语言模型的致...
- 基于pytorch的深度学习人员重识别
-
基于pytorch的深度学习人员重识别Torchreid是一个库。基于pytorch的深度学习人员重识别。特点:支持多GPU训练支持图像的人员重识别与视频的人员重识别端到端的训练与评估简单的re...
- DeepSeek本地部署:轻松训练你的AI模型
-
引言:为什么选择本地部署?在AI技术飞速发展的今天,越来越多的企业和个人希望将AI技术应用于实际场景中。然而,对于一些对数据隐私和计算资源有特殊需求的用户来说,云端部署可能并不是最佳选择。此时,本地部...
- 谷歌今天又开源了,这次是Sketch-RNN
-
前不久,谷歌公布了一项最新技术,可以教机器画画。今天,谷歌开源了代码。在我们研究其代码之前,首先先按要求设置Magenta环境。(https://github.com/tensorflow/magen...
- Tensorflow 使用预训练模型训练的完整流程
-
前面已经介绍了深度学习框架Tensorflow的图像的标注和训练数据的准备工作,本文介绍一下使用预训练模型完成训练并导出训练的模型。1.选择预训练模型1.1下载预训练模型首先需要在Tensorf...
- 30天大模型调优学习计划(30分钟训练大模型)
-
30天大模型调优学习计划,结合Unsloth和Lora进行大模型微调,掌握大模型基础知识和调优方法,熟练应用。第1周:基础入门目标:了解大模型基础并熟悉Unsloth等工具的基本使用。Day1:大模...
- python爬取喜马拉雅音频,json参数解析
-
一.抓包分析json,获取加密方式1.抓包获取音频界面f12打开抓包工具,播放一个(非vip)视频,点击“媒体”单击打开可以复制URL,发现就是我们要的音频。复制“CKwRIJEEXn-cABa0Tg...
- 五、JSONPath使用(Python)(json数据python)
-
1.安装方法pipinstalljsonpath2.jsonpath与Xpath下面表格是jsonpath语法与Xpath的完整概述和比较。Xpathjsonpath概述/$根节点.@当前节点...
- Python网络爬虫的时候json=就是让你少写个json.dumps()
-
大家好,我是皮皮。一、前言前几天在Python白银交流群【空翼】问了一个Python网络爬虫的问题,提问截图如下:登录请求地址是这个:二、实现过程这里【甯同学】给了一个提示,如下所示:估计很多小伙伴和...
- 一周热门
-
-
Python实现人事自动打卡,再也不会被批评
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
python使用fitz模块提取pdf中的图片
-
《人人译客》如何规划你的移动电商网站(2)
-
Jupyterhub安装教程 jupyter怎么安装包
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- table.render (33)
- uniapp textarea (33)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- react-admin (33)
- vscode切换git分支 (35)
- vscode美化代码 (33)
- python bytes转16进制 (35)