Mr.Gao

高先生小屋

  • 主页
  • C#
  • 每日转载

【asp.net core 系列】3 视图以及视图与控制器

阅读数:0次 2023-03-08
字数统计: 5.6k字   |   阅读时长≈ 11分
  • 本文作者: Mr.Gao
  • 本文链接: https:/www.attachie.club/post/71.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!

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/

image-20200601225734470

应该是类似的页面。

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

然后重启服务后,刷新页面,会看到类似的内容:

image-20200601235928566

3. 总结

我们在这一篇介绍了视图的一些概念,并介绍了如何使用控制器给视图传递数据。下一篇将讲解一下路由的高级作用,如何通过路由携带数据。

  • C#
  • C#
  • web

扫一扫,分享到微信

【转载】 Linux-包教包会系列
【asp.net core 系列】4 更高更强的路由
  1. 0.前言
  2. 1. 视图
    1. 1.1 在视图中引用命名空间
    2. 1.2 ViewsStart
    3. 1.3 视图检索
  3. 2. 控制器与视图的关系
    1. 2.1 使用视图
    2. 2.2 指定视图
    3. 2.3 给视图传递数据
    4. 2.4 在视图中使用
  4. 3. 总结
© 2019-2025 Mr.Gao
Theme:hexo-theme-yilia-plus by Litten
晋ICP备2023000821号-1   
本站总访问量次 | 本站访客数人