控制器是ASP.NET Core 应用程序的大脑,它处理进入的请求,对模型提供的数据进行操作并且选择对应的View将数据呈现在浏览器中,控制器位于应用程序根目录的Controllers文件夹下,他们是普通的C#类,类里面包含的方法被称为Action方法,Action方法处理HTTP请求并向客户端发送Response响应,ASP.NET Core View负责将Controller发送的数据显示到浏览器端, 通过View我们也可以提交数据到Controller,View位于应用程序根目录的Views文件夹中,Views目录下的文件夹和Controller一一映射,在这些Controller文件夹内部,每个View是和Controller的方法一一映射的,例如:HomeController的视图位于Views->Home文件夹,相同的规律,StudentController的视图位于Views->Student
首先创建一个ASP.NET Core MVC应用程序,命名为AspNetCore.Controllers, 打开Controllers目录,你会发现一个HomeController.cs, ASP.NET Core MVC为我们提供了一个默认的控制器
namespace AspNetCore.Controllers.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
1 HomeController继承自Controller类
为了理解Controller的工作,我们只需要用Index方法,因此我们在Controller类中只保留Index方法把剩下的全部删除,删除完之后更新代码,更新完之后的代码如下:
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.Controllers.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
}
}
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<p>Welcome from <b>Index View</b> of <b>Home Controller</p>
</div>
运行你应用程序,你将会看到这个视图呈现在浏览器中
2 ViewData什么是以及如何使用它
ViewData是一个ViewDataDictionary对象,可以通过字符串键来访问该对象,它本质是一个字典并且可以使用它把值从Controllers传递到Views或者也可以从Views传递到Layout View,在我们视图中,我们设置ViewData对象ViewData["Title"] = "Home Page",在layout视图中读取这个值(Views->Shared文件). layout试图使用它来设置页面的标题
你能使用ViewData传输任何类型的值像简单类型(strings,int,float) 或者类对象,下面例子我使用2个ViewData对象:
1 存储person的name属性值
public IActionResult SomeAction()
{
ViewData["Name"] = "GuiBingBing";
ViewData["Address"] = new Address
{
HouseNo = "",
City = ""
};
return View();
}
现在在视图上,我展示2个ViewData对象中的值:
@{
// casting address to Address.cs class object
var address = ViewData["Address"] as Address;
}
<p>Hello: @ViewData["Name"]</p>
<p>With Address: @address.HouseNo, @address.City</p>
ControllerBase类是一个抽象的类不支持使用视图工作,当我们构建WebApi时我们可以让控制器继承自这个类
我们修改一下HomeController的Index视图
@{
ViewData["Title"] = "Home Page";
}
<form class="form-horizontal" method="post" asp-action="ReceivedDataByRequest">
<div class="mb-3 row">
<div class="col-sm-1">
<label>名称:</label>
</div>
<div class="col-sm-11">
<input class="form-control" name="name" />
</div>
</div>
<div class="mb-3 row">
<div class="col-sm-1">
<label>性别:</label>
</div>
<div class="col-sm-11">
<select class="form-control" name="sex">
<option value="M">Male</option>
<option value="F">Female</option>
</select>
</div>
</div>
<div class="mb-3 row">
<div class="col-sm-11 offset-sm-1">
<button type="submit" class="btn btn-primary">提交</button>
</div>
</div>
</form>
在表单上使用Bootstrap的样式表,来改善表单呈现效果
添加了2个HTML标签 - 一个为输入框 & 一个为下拉选择框,用户将填充或者选择一个值在下拉框中,点击提交按钮,这些控件的值将被传输到控制器,我们将显示这些值,注意这两个控件的名称是name和sex label仅仅是为了显示文本
public IActionResult ReceivedDataByRequest()
{
var name = Request.Form["name"];
var sex = Request.Form["sex"];
return View("ReceivedDataByRequest", $"{name} sex is {sex}");
}
View("ReceivedDataByRequest", $"{name} sex is {sex}");
第一个参数表示呈现的视图的名称,第二个参数传输到View的数据
现在我们针对这个方法创建一个视图文件,因此右击Views->Home文件夹并且选择Add->New Item,然后对话框选择
Razor View-Empty 选项并且命名视图ReceivedDataByRequest在视图中添加下面代码:
@model string
<h1>@Model</h1>
视图的数据能够非常容易的传输到Action方法参数中,让我们做一个简单的解释,我们表单有2个html控件允许用户输入他们自己的名称和性别,我们可以在action方法中添加参数用来接收这两个控件的值,但是需要注意参数的名称必须和这两个控件的名称相同
public IActionResult ReceivedDataByParameter(string name, string sex)
{
return View("ReceivedDataByParameter", $"{name} sex is {sex}");
}
注意action方法的两个参数-name&sex, 他们的名字和控件的名字是相同的这点需要注意,因为name和sex的值是字符串类型,我们需要提供2个字符串类型的值,如果你想访问一个新的字段"age"的值你需要在action方法中添加一个新的int类型的参数
修改一下Index视图,asp-action="ReceivedDataByRequest"
标签修改为asp-action="ReceivedDataByParameter"这将改变表单的action属性为ReceivedDataByParameter,因此当我们点击提交按钮时ReceivedDataByParameter方法将调用,代码如下:
public IActionResult ReceivedDataByParameter(string name, string sex)
{
return View("ReceivedDataByParameter", $"{name} sex is {sex}");
}
最后,添加一个新的Razor视图在Views->Home文件夹,命名为ReceivedDataByParameter,这个视图将显示如下信息
@model string
<h1>@Model</h1>
3.3 使用查询字符串将视图的值传递到控制器
<a href="/Home/ReceivedDataByParameter?name=jack sparrow&sex=m" class="link-primary">Primary link</a>
最后,为了在控制器中接收值,在action方法中添加模型类型,让我们通过一个例子来演示一下
我们在Models文件夹下创建一个Person的类,包含如下代码:
namespace AspNetCore.Controllers.Models
{
public class Person
{
public string name { get; set; }
public string sex { get; set; }
}
}
public IActionResult ReceivedDataByModelBinding(Person person)
{
return View("ReceivedDataByModelBinding", person);
}
@model Person
<h1>@Model.name sex is @Model.sex</h1>
@model Person
@{
ViewData["Title"] = "Home Page";
}
@*<form class="form-horizontal" method="post" asp-action="ReceivedDataByRequest">*@
@*<form class="form-horizontal" method="post" asp-action="ReceivedDataByParameter">*@
<form class="form-horizontal" method="post" asp-action="ReceivedDataByModelBinding">
<div class="mb-3 row">
<div class="col-sm-1">
<label>名称:</label>
</div>
<div class="col-sm-11">
@*<input class="form-control" name="name" />*@
<input class="form-control" asp-for="name" />
</div>
</div>
<div class="mb-3 row">
<div class="col-sm-1">
<label>性别:</label>
</div>
<div class="col-sm-11">
@*<select class="form-control" name="sex">*@
<select class="form-control" asp-for="sex">
<option value="M">Male</option>
<option value="F">Female</option>
</select>
</div>
</div>
<div class="mb-3 row">
<div class="col-sm-11 offset-sm-1">
<button type="submit" class="btn btn-primary">提交</button>
</div>
</div>
</form>
这里需要注意几点
1 这个视图接收的模型类型是person - @model Person
2表单asp-action帮助标签的值被修改为ReceivedData-ByModelBinding
3使用Person类的name和sex属性来绑定html控件的(input&select),使用模型类的属性绑定asp-for="class_property"绑定这些控件
我们使用ASP.NET Core创建一个上传文件的功能,注意我们提交表单使用POST方法并且设置enctype="multipart/form-data"
在Index视图添加下面代码,我们没有使用"asp-action"标记指定方法名称,默认调用我们Home控制器中的Index方法,同时注意上传文件类型的控件为file,控件的名称为photo
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<label>Photo:</label>
<input type="file" class="form-control" name="photo" />
</div>
<div class="m-1">
<button class="btn btn-primary" type="submit">Upload</button>
</div>
</form>
接下来在Home控制器中添加一个Post版本的Index方法并且包含了IFormFile photo参数获取上传的文件,我们上传这个文件到wwwroot文件因此我必须注入IWebHostEnvironment在控制器的构造函数中
[HttpPost]
public async Task<IActionResult> Index(IFormFile photo)
{
using (var stream = new FileStream(Path.Combine(_hostingEnvironment.WebRootPath, photo.FileName), FileMode.Create))
{
await photo.CopyToAsync(stream);
}
return View();
}
这节我们主要介绍了从把数据从View传输到Controller的几种方式,第一种方式使用Request.Form,第二种方式使用参数,第三种方式使用查询字符串,第四种方式使用模型绑定
https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/Fundamentals/AspNetCore.Controllers/AspNetCore.Controllers