【asp.net core 系列】3 视图以及视图与控制器
0.前言
在之前的几篇中,我们大概介绍了如何创建一个asp.net core mvc项目以及http请求如何被路由转交给对应的执行单元。这一篇我们将介绍一下控制器与视图直接的关系。
1. 视图
这里的视图不是数据库里的视图,是一种展示技术。在asp.net core mvc项目中视图是指以cshtml做扩展名的文件,通常在Views文件夹。
那么现在我们进到之前创建的测试项目 MvcWeb的Views目录下,如果小伙伴们没有做修改的话,能看到如下的目录结构:
├── Home
│ ├── Index.cshtml
│ └── Privacy.cshtml
├── Shared
│ ├── Error.cshtml
│ ├── _Layout.cshtml
│ └── _ValidationScriptsPartial.cshtml
├── _ViewImports.cshtml
└── _ViewStart.cshtml
在Views根目录下,有两个文件分别是:_ViewImports.cshtml
、 _ViewStart.cshtml
两个文件(注意,有个前置下划线)。
1.1 在视图中引用命名空间
我们知道,在cshtml文件中,虽然极大的减少了服务器代码,但是有时候无法避免的使用一些C#代码。那么就会产生一个问题,很多类都有自己的命名空间,如果我们在某个或某几个或某些视图中需要访问这些类和方法,那么一个视图一个视图的写引用有点不太现实,因为这太繁琐了。
所以asp.net core mvc 设置了在名为_ViewImports.cshtml的文件中添加引用,则在Views下所有视图中都生效。那么,先来看看这个文件里有啥吧:
@using MvcWeb
@using MvcWeb.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
可以看到,这里引用了项目的命名空间和项目下Modes命名空间的所有内容。因为我们之前创建的测试项目名称就是 MvcWeb。
最后一行是一个 cshtml标记引用,第一个星号表示当前项目的所有TagHelper实现都引用,后面的表示引入aps.net core mvc内置的TagHelper。
关于 TagHelper,这篇就先不介绍了。
1.2 ViewsStart
_ViewStart.cshtml
作用从名字中可见一二,这个文件用来配置一些在视图刚开始加载时的一些配置内容。先看一下,默认的里面是什么吧:
@{
Layout = "_Layout";
}
先做个介绍,@符号后面用一对大括号包裹,里面是C# 代码。也就是说 Layout = "_Layout"
,这行的意思是给某个名为Layout的属性设置值为_Layout
。
那么,Layout的属性是哪里的呢?
对于asp.net core mvc而言,一个视图也是一个类只不过这个类是动态生成的,不是一个由程序员编写出来的类,但是这个类继承自:
namespace Microsoft.AspNetCore.Mvc.Razor
{
public abstract class RazorPageBase : IRazorPage
{
}
}
Layout正好是这个类的一个属性,表示视图是否使用了某个布局页。所以上面的代码表示,Views里的新建视图,默认是使用名为_Layout
的视图作为布局页。
当然,这个页面不只有这个作用,小伙伴们可以自己尝试下哦。
1.3 视图检索
在上一节中,我们指定了一个布局页的名称。布局页也是视图中的一种,但我们也只指定了名称,但没有指定路径。asp.net core是如何发现这个名称的视图呢?
asp.net core 会按照以下顺序查找对应的视图文件:
- Views/[ControllerName]/[ViewName].cshtml
- Views/Shared/[ViewName].cshtml
所以,_Layout
也会按照这个顺序查找,为了避免不必要的混淆,我们只在Shared目录下写了_Layout.cshtml
。这也是通常的做法,该文件表示一个全局的布局页。
2. 控制器与视图的关系
在上一篇《【asp.net core 系列】2 控制器与路由的恩怨情仇》中,我们介绍了三种创建控制器的方法,并且最后推荐使用名字以Controller结尾并继承Controller类的写法。我将在这里为大家再次讲解为什么推荐这样写:
- 以Controller结尾,可以很明确的告诉其他人或者未来的自己这是一个控制器,不是别的类
- 继承Controller,是因为Controller类为我们提供了控制器用到的属性和方法
嗯,暂时就这两点。别看少,但是这很重要。
2.1 使用视图
在之前介绍的时候,有提到过当我们访问一个URL的时候,路由会自动为我们寻找到对应的可执行代码单元。但是,没有进一步内容的介绍。当我们寻找到对应的可执行代码单元也就是Action之后,Action进行一系列的处理,会对这个请求做出响应。有一种响应就是返回一个展示页面,也就是View。
那么,如何返回一个View呢?
创建一个控制器,名为ViewDemoController
,并添加一个方法Index
,返回类型为IActionResult
:
using Microsoft.AspNetCore.Mvc;
namespace MvcWeb.Controllers
{
public class ViewDemoController:Controller
{
public IActionResult Index()
{
return View();
}
}
}
其中 View() 表示返回一个View,这View的名称是 Index,在ViewDemo控制器下。所以,它的路径应该是:
Views/ViewDemo/Index.cshtml
在对应目录创建该文件,然后在文件里随便写一些内容,之后启动项目(项目的端口在第一部分就已经修改过了):
http://localhost:5006
然后访问:
http://localhost:5006/ViewDemo/
应该是类似的页面。
IActionResult 是一个接口,表示是一个Action的处理结果,在这里可以理解为固定写法。
2.2 指定视图
在控制器里,View 方法表示使用一个视图进行渲染,默认是使用方法同名的视图。当然,既然是默认的,那就一定有不默认的时候。对的,View方法提供了几个重载版本,这些重载版本里有一个名字为viewName
的参数,这个参数就是用来指定视图名称的。
那么,我们可以指定哪些视图名称:
- 同一个控制器文件夹下的其他视图
- Shared 文件夹下的视图
这两种都是不用携带路径的视图名,可以省略文件扩展名(cshtml)。
当然,还可以指定其他路径下的视图文件,如:
Views/Home/About.cshtml
表示从根目录下查找到这个视图,这种写法必须指定扩展名../Manage/Index
表示在Manage控制器目录下的Index
2.3 给视图传递数据
之前介绍了如何使用视图、如何指定视图名称,但是还缺最关键的一步,那就是如何给视图传递数据。
通常情况下,Action方法中给视图传递数据,只有这三种是推荐的:
- 使用ViewData
- 使用ViewDataAttribute
- 使用ViewBag
- 使用ViewModel
Controller类有一个属性是 ViewData,它的声明如下:
public ViewDataDictionary ViewData { get; set; }
可以看到这是一个字典型的属性,所以给它赋值是这样使用的:
public IActionResult Index()
{
ViewData["Title"] = "ViewDemo";
return View();
}
ViewBag也是 Controller类的一个属性,它的声明如下:
public dynamic ViewBag { get; }
可以看到这是一个动态类,实际上ViewBag里的数据与ViewData是互通的,换句话说就是ViewBag是对ViewData的一次封装,两者并没有实际上的区别。赋值使用:
public IActionResult Index()
{
ViewBag.Name = "小李";
return View();
}
而ViewDataAttribute则与上两个,不太一样,这个属性标注给控制器的属性上,asp.net core mvc就会把这个属性的值填充给ViewData,键值就是属性名:
[ViewData]
public string AttributeTest{get;set;}
与 ViewData["AttributeTest"]
效果一致。
在View方法的一些重载版本里,需要一个名为 model的参数,类型是object。这个参数就是一个ViewModel。使用:
在MvcWeb/Models 下添加一个类:
namespace MvcWeb.Models
{
public class ViewModelTestModel
{
public string Name{get;set;}
public int Age{get;set;}
}
}
回到刚刚的Index方法里,创建一个ViewModelTestModel实例,并传给View方法:
public IActionResult Index()
{
ViewData["Title"] = "ViewDemo";
ViewBag.Name = "小李";
var model = new ViewModelTestModel
{
Name = "测试实例",
Age = 1
};
return View(model);
}
2.4 在视图中使用
在上一小节中,我们分别使用ViewData和ViewBag以及ViewModel给视图传递了三个数据,那么如何在视图中获取这三个数据呢?
<h2>@ViewData["Title"]</h2>
<!--实际会显示 <h2>ViewDemo</h2>-->
与字典一样,@起头,表示后面跟着一个属性或者一段C#表达式,并将表达式的结果输出到页面上。
ViewBag的访问与ViewData类似,只不过ViewBag是动态对象,可以认为它的类型并没有发生改变,继续按照之前的类型进行使用:
<h4>@ViewBag.Name</h4>
对于ViewModel的使用,View内置了一个dynamic的Model属性,在不做特殊处理的情况下,我们在页面上使用@Model
会得到一个dynamic对象(如果传了ViewModel的话)。虽然也能用,但是这不太友好。
这时候,就需要我们在视图的开头处,添加:
@model ViewModelTestModel
这时候,再使用@Model
的时候,就会自动解析成ViewModelTestModel了。
整体Index.cshtml内容如下:
@model ViewModelTestModel
Hello World!
<h2>@ViewData["Title"]</h2>
<h4>@ViewBag.Name</h4>
@Model.Name + @Model.Age
然后重启服务后,刷新页面,会看到类似的内容:
3. 总结
我们在这一篇介绍了视图的一些概念,并介绍了如何使用控制器给视图传递数据。下一篇将讲解一下路由的高级作用,如何通过路由携带数据。
更多内容烦请关注我的博客《高先生小屋》
【asp.net core 系列】3 视图以及视图与控制器的更多相关文章
- asp.net core系列 30 EF管理数据库架构--必备知识 迁移
一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...
- asp.net core系列 40 Web 应用MVC 介绍与详细示例
一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...
- asp.net core系列 39 Web 应用Razor 介绍与详细示例
一. Razor介绍 在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor. 这样开发Web包括了MVC框架和Razor框架.对于Razor来说 ...
- asp.net core 系列 16 Web主机 IWebHostBuilder
一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...
- asp.net core 系列 14 错误处理
一.概述 本文介绍处理 ASP.NET Core 应用中常见错误的一些方法.主要是关于:开发环境异常页:非开发环境配置自定义异常处理页:配置状态代码页(没有正文响应,http状态400~599的). ...
- asp.net core系列 39 Razor 介绍与详细示例
原文:asp.net core系列 39 Razor 介绍与详细示例 一. Razor介绍 在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- 【asp.net core 系列】 1 带你了解一下asp.net core
0. 前言 这是一个新的系列,名字是<ASP.NET Core 入门到实战>.这个系列主讲ASP.NET Core MVC,辅助一些前端的基础知识(能用来实现我们需要的即可,并非主讲).同 ...
- 【asp.net core 系列】4. 更高更强的路由
0. 前言 在之前我们介绍了请求通过路由寻找到控制器,以及控制器与视图的数据流转.那么,我们回过头来,再看看路由的一些其他用法. 1. 路由属性(Route Attribute) 按照英文的直接翻译, ...
随机推荐
- search(10)- elastic4s-multi_match:多字段全文搜索
在全文搜索中我们常常会在多个字段中匹配同一个查询条件或者在不同的字段中匹配不同的条件.比如下面这个例子: GET /books/_search { "query": { " ...
- 74LS 系列 名称解释
摘自:http://blog.sina.com.cn/s/blog_502ffce50100j9db.html -------------------------------------------- ...
- 用一个python文件去调用另一个python文件,关于相对路径的处理?
比如用a.py调用执行b.py,但是a.py和b.py路径环境不一样,而b.py中有使用相对路径读取文件,这时会报错,怎么在a.py中进行配置,使其调用b.py时路径和其相同,能否做到? 比如目录结构 ...
- Dubbo对Spring Cloud说:来老弟,我要拥抱你
项目地址 https://github.com/yinjihuan/kitty-cloud 前言 Kitty Cloud 开源后有以为朋友在 GitHub 上给我提了一个 issues,问为什么项目中 ...
- centos6 升级gcc 无法识别的命令行选项“-std=gnu++1y”的解决办法
npm install 提示: 1.下载源文件,并安装: wget http://people.centos.org/tru/devtools-2/devtools-2.repo mv devtool ...
- 【python接口自动化】- openpyxl读取excel数据
前言:目前我们进行测试时用于存储测试数据的软件几乎都是excel,excel方便存储和管理数据,读取数据时也比较清晰,测试时我们需要从excel从读取测试数据,结束后还需把测试结果写入到excel中, ...
- 移动端布局的一些设置(在viewport里设置使页面显示相同宽度,显示相同像素大小)
viewport(视口) 具体数值(不设置时默认为980 ,部分安卓手机不支持设置成具体数值) width=device-width 和设备宽度保持一致 user-scalable=no 是否允许用户 ...
- MySQL 间隙锁
一.根据案例二:不同索引加锁顺序的问题,模拟重现死锁(详细操作步骤) 1.RR级别下,更新操作默认会加行级锁,行级锁会对索引加锁 2.如果更新语句使用多个索引,行级锁会先锁定普通索引,再锁定聚簇索引 ...
- 存储系列之 LUN 和 LVM
一.LUN 1.LUN的由来 上一篇文章已经介绍了RAID技术的原理,那么RAID的实现呢?有两种方式,RAID软件和RAID硬件.但是因软件RAID占用主机CPU和主机内存,而且RAID功能不易实现 ...
- Educational Codeforces Round 56 (Rated for Div. 2) F. Vasya and Array
题意:长度为n的数组,数组中的每个元素的取值在1-k的范围内或者是-1,-1代表这个元素要自己选择一个1-k的数字去填写,然后要求填完的数组中不能出现连续长度大于len的情况,询问填空的方案数. 题解 ...