以下代码返回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,类似插件很多),格式化后的效果如图所示:
因为我们指定了返回类型是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数据。
以下实例代码返回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项目中,我们有两个Controller:HomeController和StudentController。
HomeController有以下3个操作方法:
StudentController有以下3个操作方法:
我们看一下视图文件夹结构(稍后会有创建步骤),如图所示:
查看HomeController,其中只有一个操作方法Details()。
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的文件夹和视图文件,步骤如下:
ASP.NET Core MVC中还提供了几个View()重载方法。如果我们在使用下面的View()重载方法,则它将查找与Action()方法同名的视图文件。
比如,我们从HomeController的Details() 方法返回一个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");
}
}
请注意以下几点:
以下三行代码实现的功能是一样的:
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(object model) | 使用此重载方法将模式数据从控制器传递到视图。 |
View(string viewName,object model) | 传递视图名称和模型数据 |
在ASP.NET Core MVC中,有以下3种方法可以将数据从Controller传递到View。
通过使用ViewData或ViewBag传递数据,我们会创建一个弱类型的视图。
我们希望将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>
运行项目后的结果如图所示:
弱类型对象DataView说明
ViewData时弱类型的字典(dictionary)对象。
我们使用string类型的键值对来存储和查询ViewData字典中的数据。可以从ViewData字典中直接访问数据,而无须将数据转换为string类型。
如果访问的是任何其他类型的数据,则我们需要将其显示的地转换为我们期望的类型。
在本例中,我们声明Student对象可以分别访问Student 对象的Name、Email和Major属性。
ViewData在运行时会进行动态解析,不提供编译时类型检查,因此我们不会获得智能提示。由于我们没有智能提示,因此会导致编写代码的速度降低,拼写错误和打错的可能性也变大。
我们只会在项目运行时知道这些错误。
出于这个原因,我们通常不使用View Data。
当使用ViewData时,我们最终会创建一个弱类型的视图。
实际上,ViewBag是ViewData的包装器。通过ViewData,我们使用string类型的键名来存储和查询数据。而对于ViewBag,我们则使用的是动态属性而不是字符串键。
同样,修改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数据。
运行项目,结果如图所示:
强类型视图——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的流程回顾。
视图文件的特点如下:
视图发现的特点如下: