7:Controller返回View

♣ 视频地址:https://www.bilibili.com/video/av38392956/?p=6

• Controller

• 返回IActionResult

之前建立的两个Controller(HomeController,ContactController)就是两个普通的类,它们没有继承任何类,实际上我们可以继承Controller这个父类;

这个Controller父类会提供很多上下文的相关信息,此外还提供了很多封装方法,使用这些封装的方法我们就可以很简单的把结果返回给客户端,返回的一些简单的类型,比如数值型,字符串型;也可以返回相对复杂的类型;

返回的对象,要求它实现IActionResult这个接口,有很多结果对象都实现了这个接口,这些结果可能包含Model,文件,或者是构建Html的视图(View)

我们给之前的HomeController继承Controller,然后我们再Index方法里输入this.,就可以看到很多Controller上下文的信息,如下图

下面我们改一下返回类型为IActionResult,实际上return 后面的很多方法都实现了IActionResult接口,所以我们就把IActionResult拿来当做返回类型,而不是字符串,int等等

那为什么要返回IActionResult,而不是string,int类型呢?

一:是有利于单元测试

二:1:我们看IActionResult是MVC框架里的一个东西,使用这个返回类型它不会立即返回相应,它会告诉MVC框架下一步要做什么;

     2:从MVC的角度上看,MVC是调用了Controller的这个Action,而这个Action返回的类型是IActionResult,也就是说这个Action产生了一个IActionResult这个对象,下一步MVC就要执行这个IActionResult结果对象;

  3:而如果返回类型是string的话,那么它这个Controller下的Action就会直接把字符串返回回去;

  4:现在这么写就没有直接返回回去,而是决定要把这个字符串返回回去或者是想把字符串返回回去,但是它没有这么做;

  5:而MVC框架看到Action方法返回结果之后,就知道它想要这么做,然后它在整个管道里,就会在某个地方把这个结果直接返回回去,把文字返回给客户端;

  6:所以说这么写只是决定它想做什么事,真正做的是MVC框架,它俩是分开的;

三:更灵活,易于扩展


我们建立一个Model

   public class Student
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

然后我们再Index方法里实例化一个Student,这个ObjectResult也实现了IActionResult接口

 public IActionResult Index()
 {
     var st = new Student
     {
         Id = 1,
         FirstName = "Nick",
         LastName = "Carter"
     };
     return new ObjectResult(st);
}

这个ObjectResult返回的类型并不是Controller决定的,Controller所做的事情是把学生的信息放到了ObjectResult对象里

而到底怎么处置ObjectResult,是由管道的其他环节处理的,我们看下浏览器结果是JSON,如下图

那么请求原理是:

  1:我们发出请求到达Controller的Action之后,Controller把学生的信息装到ObjectResult()对象里

  2:然后MVC管道接收到返回的ObjectResult之后呢,它需要做的是把ObjectResult转成HTTP响应返回给客户端

  3:而ObjectResult现在就需要把自己写到响应里

  4:ObjectResult还需要决定把内容到底格式化成JSON格式还是XML格式还是其他的格式,如果accept的值为application/json,那个格式化的结果就会是JSON

  


返回View

• Razor 引擎

• Controller -> ViewResult ->HTML页面

1:当我们要Action返回视图的话,就需要Razor引擎,返回结果就要是ViewResult,它里面可以带着渲染的Razor视图的名,这个视图就是cshtml结尾的文件

2:ViewResult还可以附带一个Mode对象,使用Model对象,这个视图就可以使用它来创建Html

3:Controller看到Action返回是ViewResult的话,那么MVC框架就会开始寻找View这个文件,然后执行这个视图,最终产生Html页面,然后把Html页面返回客户端

我们接下来把返回的类型改为View(),View的类型为ViewResult,这时候运行看到出现错误,名为Index的视图没有找到,如下图

那它为什么要找Index呢?

因为如果View()括号里面什么都没写,那么它就会找名问Action的视图文件,所以Action名为Index,它就会找index.cshtm这个文件

这时候我们在View里面写上Student,运行可以看到名为Student的视图文件没有找到,它是去Views下的Home文件夹去找,问什么是Home?因为是我们的Controller名,所以我们要建立视图就要建立在Views下的Home(Controller)文件夹下,如下图

 下面我们建立视图,新建Views文件夹,然后建立Home,最后添加视图名称为Index的视图

然后我们把View里的Student去掉,如下图

接着我们把index.cshtml的title改一下,并且添加在body里添加一个H1输入内容,然后运行可以看到找到了index.cshtml,如下图

现在,我们把学生的信息返回去,第一我们把st扔到View里面

然后我们在视图里使用这个Model,我们直接使用@Model,这个Model就是你从Controller里面传的对象,这个Model的M是大写的

一旦@符号出现,那么它后面的代码就是C#代码

在这里我们额外说一个,使用@this.,可以看到好多东西,这些东西都来自于Razor视图的一个父类,this就是指Razor视图的公共父类里面的方法和属性,如下图

 所以说这个Model就是this.Model,如下图

我们Student有三个属性,Id,FirstName,LastName,这时候你@Model.却点不出来这三个属性,这是为什么?

因为Model传到视图之后,Razor视图并不知道Model的具体类型,这时候它的类型是dynamic

但是这时如果你把属性名写错,写成对象并没有的属性,就会报错,如下图Student并没有Age属性

那么我们现在可以使用一个指令来让这个Model有智能提示,@model是一个指令,这个model是小写,这个指令可以提供一些信息,让Razor视图能够正确的构建代码,简而言之就是能给出智能提示

用小写的model来告诉Razor视图这个大写Model的类型是Student,如下图

这时候我们再@Model.就可以看到属性值了,如下图

这是后我们运行,可以看到出现了,如下图

 综上所述,Controller就是接收请求,然后构建Model,接着把Model传给视图,视图使用Model来构建Html


下面,我们做一个例子,上面是返回一个学生,那现在我们要返回一个学生集合

暂时我们写死这个集合,以后再连接数据库,,首先我们写一个数据的服务,数据的服务可以获取数据,可以是写死的数据,也可以是数据库里的数据

同时这个服务还需要做到让我们的Controller里面的代码与数据来源无关

1:新建文件夹Services,然后建一个接口IRpository,这里我们用泛型,因为以后可能会有不止Student一个类

我们暂时只需要一个方法,返回一个集合GetAll(),如下图

:

2:建立接口的实现类,因为现在都是写死的,所以都存在内存里,这个类叫InMemoryRepository.cs,我们在里面实现IRepository<Student>接口,并且填上三个学生的数据

3:我们考虑在使用IRepository接口的时候如何使用InMemoryRepository服务?答案是:注册容器

AddScoped表示每次HTTP请求会产生一个新的实例

 4:回到Controller,我们先用构造函数注入

  然后引入一个只读的字段 _repository

  最后我们就可以直接var list = _repository.GetAll(),这时候就会使用InMemoryRepository的方法返回的诗句,然后把list返回回去

这是,如果你安装了ReSharper可能会提示错误,原因是你传入的类型是一个集合,但是视图里声明的是单个的一个对象,不一致

这时候我们把视图改为下面这样就好了,然后在下面使用循环,F5运行可以看到出来了,如下图

猜你喜欢

转载自www.cnblogs.com/Codemandyk/p/10996068.html
今日推荐