ASP.NET Core MVC从Controller传递内容协商数据到View

文章目录

  • Controller请求及相应流程说明
    • 从Controller中返回JSON数据
  • 从控制器中返回内容协商内容
  • 从Controller返回View
    • MVC中的View
    • 视图文件结构
    • 视图发现
    • View重载方法
  • 自定义视图发现
    • 指定视图文件路径
    • 相对视图路径
    • 其他View()重载方法
  • 从Controller传递数据到View
    • 数据从Controller传递到View的方法
    • 使用ViewData将数据从Controller传递到View
    • 使用ViewBag将数据从Controller传递到View
    • ViewData与ViewBag的对比
    • 在ASP.NET Core MVC中创建一个强类型视图
  • 总结

Controller请求及相应流程说明

ASP.NET Core MVC从Controller传递内容协商数据到View_第1张图片

  • MVC中的Controller是一个类文件,控制器继承自Microsoft.AspNetCore.Mvc.Controller。
  • Controller类名称后缀为Controller,比如HomeController、StudentController。
  • 当来自浏览器的请求到达我们的应用程序时,MVC中的Controller会处理传入的HTTP请求并响应用户操作。
  • Controller类中包含一组公共方法。Controller类中的这些公共方法称为操作方法,通过这些操作方法可以处理传入的HTTP请求。
  • 假设读者在浏览器地址栏中输入了http://localhost:5000/home/details并按Enter键。
  • URL"/home/details"会映射到HomeController中的Details公共操作方法。
  • 映射由应用程序中定义的路由规则完成。
  • 请求到达Controller操作方法。作为处理该请求的一部分,Controller创建Model。
  • Controller通过依赖注入注册的服务来查询模型数据。比如,我们要查询学生的数据,就需要通过HomeController依赖的IStudentRepository服务。
  • IStudentRepository服务使用构造函数注入的方式注册到HomeController。
  • 请注意,我们将注入的依赖项分配给了readonly字段。这是一个很好的做法,因为这可以防止在使用的过程中意外地为其分配另一个值。
  • 当Controller拥有所需地模型数据时,比如我们正在提供的服务或RESTful API,它就可以简单地返回该模型数据。

从Controller中返回JSON数据

​ 以下代码返回JSON数据,请注意,将Details()方法的返回类型设置为JsonResult,因为我们显式返回JSON类型数据。在这种情况下,Details()方法始终返回JSON类型数据。

 public class HomeController:Controller
    {
        private readonly IStudentRepository _studentRepository;

        public HomeController(IStudentRepository studentRepository)
        {
            _studentRepository = studentRepository;
        }
        public JsonResult Details()
        {
            Student model = _studentRepository.GetStudent(1);
            return Json(model);
        }
    }

​ 现在我们运行项目。浏览器从服务端获得了JSON数据,并将其自动转移为Unicode字符集编码的文本。为了方便显示,需要额外安装一个插件(我用的是JSON Formatter,类似插件很多),格式化后的效果如图所示:

ASP.NET Core MVC从Controller传递内容协商数据到View_第2张图片

​ 因为我们指定了返回类型是JSON,所以浏览器不需要进行内容协商并忽略Accept Header

从控制器中返回内容协商内容

​ 内容协商属于HTTP,HTTP提供了内容协商方法,允许客户端和服务端有这样的协定。通过这些方法,单一的URL就可以代表不同的资源(如同一个网站页面的法语版和英语版),这些不同的版本称为变体。

​ 举个例子,如果某个站点有使用法语和使用英语的两种用户,需要用这两种语言提供网站站点信息。理想情况如下,服务端应当向英语用户发送英文版,向法语用户发送法文版——用户只要访问网站主页就能得到相应语言的内容。

​ 修改HomeController中Details()方法的返回类型,代码如下:

 public class HomeController:Controller
    {
        private readonly IStudentRepository _studentRepository;

        public HomeController(IStudentRepository studentRepository)
        {
            _studentRepository = studentRepository;
        }
        public ObjectResult Details()
        {
            Student model = _studentRepository.GetStudent(1);
            return new  ObjectResult(model);
        }
    }

​ 请注意,上面的示例代码遵循内容协商,但是为了让代码能够返回XML格式的数据,我们必须通过调用ConfigureServices()方法中的AddXml SerialzerFormatters()。

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews(a => a.EnableEndpointRouting = false).AddXmlSerializerFormatters();

            services.AddSingleton<IStudentRepository, StudentRepository>();
        }

​ 这样,如果将请求头设置为application/xml,则返回XML数据。如果将请求头设置为application/json,则返回JSON数据。

从Controller返回View

​ 以下实例代码返回View类型。请注意,在返回View时要将Details()方法的返回类型设置为ViewResult。

  public class HomeController:Controller
    {
        private readonly IStudentRepository _studentRepository;

        public HomeController(IStudentRepository studentRepository)
        {
            _studentRepository = studentRepository;
        }
        public ViewResult Details()
        {
            Student model = _studentRepository.GetStudent(1);
            return  View(model);
        }
    }

​ 此时如果运行应用程序并导航到http://localhost:5000/home/details,我们会收到以下错误。这是因为还没有创建所需的View文件。

在这里插入图片描述

MVC中的View

  • 用于显示Controller提供给它的Model的业务数据。
  • 视图是带有嵌入Razor标记的HTML模板。
  • 如果编程语言是C#,则视图文件具有.cshtml扩展名。

比如,在MVC项目中,我们有两个Controller:HomeControllerStudentController

HomeController有以下3个操作方法:

  • Details()。
  • Edit()。
  • Index()。

StudentController有以下3个操作方法:

  • Details()。
  • Edit()。
  • List()。

视图文件结构

​ 我们看一下视图文件夹结构(稍后会有创建步骤),如图所示:

ASP.NET Core MVC从Controller传递内容协商数据到View_第3张图片

  • 所有HomeController的视图都位于Views文件夹中的Home文件夹中。
  • 所有StudentController的视图都位于Views文件夹中的Student文件夹中。

视图发现

​ 查看HomeController,其中只有一个操作方法Details()。

  • Details() 方法会调用View() 方法返回一个视图。
  • View() 方法是由基类Controller提供。
public class HomeController:Controller
{
    public ViewResult Details()
    {
        return View();
    }
}

Details() 操作方法会返回一个视图,因此默认情况下MVC会查找具有相同名称且扩展名为.cshtml的视图文件。在这种情况下,它会查找Details.cshtml。它按指定的顺序查找此文件。

Controller的名称是HomeController,它在/Views/Home/文件夹中,如果在Views/Shared/文件夹中找到了视图文件,则视图会生成HTML响应发出请求的客户端。

​ 如果找不到视图文件,则会报错。

​ 现在可以在项目的根目录创建路径为/Views/Home/Details.cshtml的文件夹和视图文件,步骤如下:

  • 创建Views文件夹和Home文件夹。
  • 右击Home文件夹,选择添加➡新建项
  • 在弹出的窗口中,选泽Razor视图,修改名称为Details.cshtml

View重载方法

​ ASP.NET Core MVC中还提供了几个View()重载方法。如果我们在使用下面的View()重载方法,则它将查找与Action()方法同名的视图文件。

  • View()。
  • View(object model)。

比如,我们从HomeControllerDetails() 方法返回一个View()。默认情况下,MVC在Views/Home文件夹中查找名为Details .cshtml的视图文件。

public class HomeController:Controller
{
    public ViewResult Details()
    {
        return View();
    }
}

自定义视图发现

​ 如果读者不喜欢默认约定,则可以使用View(string viewName)方法的重载版本,该方法将view.Name作为参数,以查找具有读者自定义名称的视图文件。

​ 在以下示例中,MVC查找名为Test.cshtml而不是Details.cshtml的视图文件。如果我们没有指定视图名称,则它会查找Details.cshtml

public class HomeController:Controller
{
    public ViewResult Details()
    {
        return View("Test");
    }
}

指定视图文件路径

​ 我们可以指定视图名称视图文件路径。在以下示例中,我们指定了视图文件的绝对路径。因此,在这种情况下,MVC会在MyViews文件夹中查找名为Test.cshtml的视图文件。如果我们没有指定视图文件的路径,则默认情况下,MVC会在Views/Home文件夹中查找Details.cshtml文件。

public class HomeController:Controller
{
    public ViewResult Details()
    {
        return View("MyViews/Test.cshtml");
    }
}

​ 请注意以下几点:

  • 使用绝对路径时,必须加上.cshtml扩展名。
  • 如果使用绝对路径,则MVC会从项目的根目录开始搜索,推荐使用/或~/。

以下三行代码实现的功能是一样的:

return View("MyViews/Test.cshtml");
return View("/MyViews/Test.cshtml");
return View("~/MyViews/Test.cshtml");

相对视图路径

​ 指定视图文件路径时,我们也可以使用相对路径。使用相对路径,我们可以不指定文件扩展名.cshtml。在以下示例中,MVC会在路径为Views/Test的文件夹中查找Update.cshtml文件。

../表示父级目录,./表示当前目录,/表示根目录。

public class HomeController:Controller
{
     public ViewResult Details()
        {
            return View("../Test/Update");
        }
}

其他View()重载方法

重载方法 描述
View(object model) 使用此重载方法将模式数据从控制器传递到视图。
View(string viewName,object model) 传递视图名称和模型数据

从Controller传递数据到View

数据从Controller传递到View的方法

​ 在ASP.NET Core MVC中,有以下3种方法可以将数据从Controller传递到View。

  • 使用ViewData。
  • 使用ViewBag。
  • 使用强类型模型对象,这也叫做强类型视图

通过使用ViewData或ViewBag传递数据,我们会创建一个弱类型的视图。

使用ViewData将数据从Controller传递到View

​ 我们希望将HomeController的Details()操作方法种的Student模型数据和视图页面的Title传递给Details.cshtml视图。因此,修改HomeController中的Details()方法,如下所示:

 public ViewResult Details()
        {
            Student model = _studentRepository.GetStudent(1);
            //使用ViewData将PageTitle和Student模型传递给View
            ViewData["PageTitle"] = "Student Details";
            ViewData["Student"] = model;
            return View();
        }

在View中访问ViewData

​ 要将HomeController的Details()方法中的ViewData传递到View,需要修改Details.cshtml文件中的代码,如下所示:

<!--Studet类所在的命名空间为WebApplication12.Models,读者根据自己实际情况引用-->
@using WebApplication12.Models
<html>
<head>
    <title>Details</title>
</head>

<body>
    <h3>@ViewData["PageTitle"]</h3>

    @{ var student = ViewData["Student"] as Student;}
    <div>
        姓名:@student.Name
    </div>
    <div>
        邮箱:@student.Email
    </div>
    <div>
        主修科目:@student.Major
    </div>
</body>
</html>

​ 运行项目后的结果如图所示:

ASP.NET Core MVC从Controller传递内容协商数据到View_第4张图片

弱类型对象DataView说明

  • ViewData时弱类型的字典(dictionary)对象。

  • 我们使用string类型的键值对来存储和查询ViewData字典中的数据。可以从ViewData字典中直接访问数据,而无须将数据转换为string类型。

  • 如果访问的是任何其他类型的数据,则我们需要将其显示的地转换为我们期望的类型。

  • 在本例中,我们声明Student对象可以分别访问Student 对象的Name、Email和Major属性。

  • ViewData在运行时会进行动态解析,不提供编译时类型检查,因此我们不会获得智能提示。由于我们没有智能提示,因此会导致编写代码的速度降低,拼写错误和打错的可能性也变大。

  • 我们只会在项目运行时知道这些错误。

  • 出于这个原因,我们通常不使用View Data。

  • 当使用ViewData时,我们最终会创建一个弱类型的视图。

    实际上,ViewBagViewData的包装器。通过ViewData,我们使用string类型的键名来存储和查询数据。而对于ViewBag,我们则使用的是动态属性而不是字符串键。

使用ViewBag将数据从Controller传递到View

​ 同样,修改HomeController中的Details()操作方法,如下所示。请注意,我们在ViewBag中使用的是动态属性而不是字符串键值对。

  public ViewResult Details()
        {
            Student model = _studentRepository.GetStudent(1);
            //将PageTitle和Student模型对象存储在ViewBag
            //我们正在使用动态属性PageTitle和Student
            ViewBag.PageTitle = "学生详情";
            ViewBag.Student = model;
      
            return View();
        }

​ 在View中访问ViewBag,要将ViewBag的数据从HomeController的Details()操作方法传递到View。

修改Details.cshtml视图文件中的代码,图下所示:

<head>
    <title>Detailstitle>
head>

<body>
    <h3>@ViewBag.PageTitleh3>

    <div>
        姓名:@ViewBag.Student.Name
    div>
    <div>
        邮箱:@ViewBag.Student.Email
    div>
    <div>
        主修科目:@ViewBag.Student.Major
    div>
body>
html>

​ 请注意,我们使用相同的动态属性PageTitle和Student来访问ViewBag数据。

​ 运行项目,结果如图所示:

ASP.NET Core MVC从Controller传递内容协商数据到View_第5张图片

ViewData与ViewBag的对比

  • ViewDataViewBag两者都可以从控制器传递数据到视图。
  • ViewBagViewData的包装器。
  • 它们都是创建弱类型的视图。
  • ViewData中使用字符串键来存储和查询ViewData字典中的数据。在ViewBag中使用动态属性来存储和查询数据。
  • ViewDataViewBag都是在运行时动态解析。
  • ViewDataViewBag不提供编译时类型检查,因此我们不能得到智能提示。

在ASP.NET Core MVC中创建一个强类型视图

强类型视图——Controller代码

​ 将数据从控制器传递到视图的首选方法是使用强类型视图。要创建强类型视图,请在控制器中将模型对象传递给View()方法。请注意,在下面的示例中,我们将Student模型对象传递给View()方法。

  public ViewResult Details()
        {
            Student model = _studentRepository.GetStudent(1);
            ViewBag.PageTitle = "学生详情";

            return View(model);
        }

强类型视图——View代码

​ 要创建强类型视图,请使用@model指令在视图中指定模型类型。

​ 在下面的示例代码中,我们告诉视图它将使用命名空间WebApplication12.Models中的对象。使用@model指令将Student对象作为模型。

​ 请注意,在指令(@model)中,m是小写的。而要访问模型对象属性时,我们使用@Model。在@Model中,M是大写的。

​ 在下面的示例代码中,访问Student对象属性,如我们正在使用的姓名、邮箱和主修科目,对应@Model.Name@Model.Email@Model.Major

@model WebApplication12.Models.Student
<html>
    <head>
            <title>Details</title>
    </head>
    <body>
        <h3>@ViewBag.PageTitle</h3>
        <div>
            姓名:@Model.Name
        </div>
        <div>
            邮箱:@Model.Email
        </div>
        <div>
            主修科目:@Model.Major
        </div>
    </body>
</html>

强类型视图优点

​ 强类型视图与ViewData、ViewBag不同,强类型视图提供编译时类型检查与智能提示。通过智能提示,我们可以提高工作效率,错误拼写的概率几乎为零。如果我们确实犯了错,则将在编译时看到错误信息,而不是在运行时才看到它们。

​ 因此,我们建议使用强类型视图将数据从控制器传递到视图。

总结

MVC的流程回顾。

  • 当来自浏览器的请求到达我们的应用程序时,MVC中的控制器会处理传入的HTTP请求并响应用户操作。
  • 控制器构建Model。
  • 如果我们正在构建API,则将模型数据返回给调用方(比如:返回JSON数据)。
  • 或选择View并将Model数据传递到View,然后视图生成所需的HTML来显示数据。

视图文件的特点如下:

  • 视图文件具有.cshtml的扩展名。
  • 视图文件是带有嵌入Razor标记的HTML模板。
  • 可能包含Controller提供给它的Model业务数据。

视图发现的特点如下:

  • View()或View(object model):查找与操作方法同名的视图文件。
  • 关于View(string viewName)方法的内容,需要注意以下几点:
    • 可查询自定义名称的视图文件。
    • 读者可以指定视图名称或者试图路径。
    • 视图文件路径可以是绝对路径,也可以是相对路径。
    • 绝对路径必须指定.cshtml扩展名。
    • 使用相对路径时,不用带扩展名.cshtml。
  • 将数据从控制器传递到View的3种方法如下:
    • 使用ViewData
      • ViewData是弱类型的字典对象。
      • 使用string类型的键值,存储和查询ViewData字典中的数据。
    • 使用ViewBag
      • ViewBag是ViewData的包装器。
      • 它们都创建了一个弱类型的视图。
      • ViewData使用字符串键来存储和查询数据。
      • ViewBag使用动态属性来存储和查询数据。
      • 它们均是在运行时解析。均不提供编译时类型检查,没有智能提示。
    • 强类型视图
      • 首选方法是使用强类型视图,将数据Controller传递到View。
      • 请在View中使用@model指令指定Model类型。
      • 使用@Model访问模型对象属性。
      • 强类型视图提供编译时类型检查和智能提示。

你可能感兴趣的:(#,ASP.NET,Core,asp.net,core,mvc)