在以前的几篇中,咱们大概介绍了如何建立一个asp.net core mvc项目以及http请求如何被路由转交给对应的执行单元。这一篇咱们将介绍一下控制器与视图直接的关系。html
这里的视图不是数据库里的视图,是一种展现技术。在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
两个文件(注意,有个前置下划线)。c#
咱们知道,在cshtml文件中,虽然极大的减小了服务器代码,可是有时候没法避免的使用一些C#代码。那么就会产生一个问题,不少类都有本身的命名空间,若是咱们在某个或某几个或某些视图中须要访问这些类和方法,那么一个视图一个视图的写引用有点不太现实,由于这太繁琐了。服务器
因此asp.net core mvc 设置了在名为_ViewImports.cshtml的文件中添加引用,则在Views下全部视图中都生效。那么,先来看看这个文件里有啥吧:mvc
@using MvcWeb @using MvcWeb.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
能够看到,这里引用了项目的命名空间和项目下Modes命名空间的全部内容。由于咱们以前建立的测试项目名称就是 MvcWeb。asp.net
最后一行是一个 cshtml标记引用,第一个星号表示当前项目的全部TagHelper实现都引用,后面的表示引入aps.net core mvc内置的TagHelper。布局
关于 TagHelper,这篇就先不介绍了。测试
_ViewStart.cshtml
做用从名字中可见一二,这个文件用来配置一些在视图刚开始加载时的一些配置内容。先看一下,默认的里面是什么吧:spa
@{ 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
的视图做为布局页。
固然,这个页面不仅有这个做用,小伙伴们能够本身尝试下哦。
在上一节中,咱们指定了一个布局页的名称。布局页也是视图中的一种,但咱们也只指定了名称,但没有指定路径。asp.net core是如何发现这个名称的视图呢?
asp.net core 会按照如下顺序查找对应的视图文件:
因此,_Layout
也会按照这个顺序查找,为了不没必要要的混淆,咱们只在Shared目录下写了_Layout.cshtml
。这也是一般的作法,该文件表示一个全局的布局页。
在上一篇《【asp.net core 系列】2 控制器与路由的恩怨情仇》中,咱们介绍了三种建立控制器的方法,而且最后推荐使用名字以Controller结尾并继承Controller类的写法。我将在这里为你们再次讲解为何推荐这样写:
嗯,暂时就这两点。别看少,可是这很重要。
在以前介绍的时候,有提到过当咱们访问一个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的处理结果,在这里能够理解为固定写法。
在控制器里,View 方法表示使用一个视图进行渲染,默认是使用方法同名的视图。固然,既然是默认的,那就必定有不默认的时候。对的,View方法提供了几个重载版本,这些重载版本里有一个名字为viewName
的参数,这个参数就是用来指定视图名称的。
那么,咱们能够指定哪些视图名称:
这两种都是不用携带路径的视图名,能够省略文件扩展名(cshtml)。
固然,还能够指定其余路径下的视图文件,如:
Views/Home/About.cshtml
表示从根目录下查找到这个视图,这种写法必须指定扩展名../Manage/Index
表示在Manage控制器目录下的Index以前介绍了如何使用视图、如何指定视图名称,可是还缺最关键的一步,那就是如何给视图传递数据。
一般状况下,Action方法中给视图传递数据,只有这三种是推荐的:
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); }
在上一小节中,咱们分别使用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
而后重启服务后,刷新页面,会看到相似的内容:
咱们在这一篇介绍了视图的一些概念,并介绍了如何使用控制器给视图传递数据。下一篇将讲解一下路由的高级做用,如何经过路由携带数据。
更多内容烦请关注个人博客《高先生小屋》