• .NTE Core MVC中的控制器用法
  • 发布于 2个月前
  • 204 热度
    0 评论
  • 北风吹
  • 0 粉丝 40 篇博客
  •   
控制器是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 控制器的例子
首先创建一个ASP.NET Core MVC应用程序,命名为AspNetCore.Controllers, 打开Controllers目录,你会发现一个HomeController.cs, ASP.NET Core MVC为我们提供了一个默认的控制器

我们可以看到HomeController的全部代码如下
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类
2 它有3个action方法-Index,Privacy&Error
3 使用依赖注入技术在它构造函数中注入了ILogger服务
为了理解Controller的工作,我们只需要用Index方法,因此我们在Controller类中只保留Index方法把剩下的全部删除,删除完之后更新代码,更新完之后的代码如下:
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.Controllers.Controllers
{
    public class HomeController : Controller
    {
        // 堆代码 duidaima.com
        private readonly ILogger<HomeController> _logger;
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }
        public IActionResult Index()
        {
            return View();
        }
    }
}
HomeController中的Index方法有自己对应的视图文件Index.cshtml,该文件位于View->Home文件夹下
@{
    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>
视图包含两种类型的代码:
1 Razor表达式使用@符号,这里我们可以使用C#代码例如ViewData
2 HTML标签设计视图的UI
让我们移除div内容并且添加如下代码:
@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <p>Welcome from <b>Index View</b> of <b>Home Controller</p>
</div>
运行你应用程序,你将会看到这个视图呈现在浏览器中


二. ViewData什么以及如何使用它
ViewData是一个ViewDataDictionary对象,可以通过字符串键来访问该对象,它本质是一个字典并且可以使用它把值从Controllers传递到Views或者也可以从Views传递到Layout View,在我们视图中,我们设置ViewData对象ViewData["Title"] = "Home Page",在layout视图中读取这个值(Views->Shared文件). layout试图使用它来设置页面的标题。

我们检查一下_layout.cshtml 并且看到当前页面的title是如何设置的

你能使用ViewData传输任何类型的值像简单类型(strings,int,float) 或者类对象,下面例子我使用2个ViewData对象:
1 存储person的name属性值
2 存储person类address对象,address是一个类有两个属性"HouseNo"和"City"
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>

三.Views到Controllers传递数据
用户可以在视图中定义html表单,用户可以填充数据并提交表单,数据会从表单传输到Controllers,我们将学习数据如何从View传输到Controllers
从视图到控制器有3种传输数据的方式,分别是 - 表单对象,查询字符串,模型绑定,让我们做一些例子来说明
3.1 控制器Request属性-Request.Form
ControllerBase类的Request属性返回HttpRequest对象,该对象描述从客户端接收到的请求。
ControllerBase类是一个抽象的类不支持使用视图工作,当我们构建WebApi时我们可以让控制器继承自这个类。

HttpRequest包含Form属性,返回一个FormData对象的字典,你可以使用Form属性读取从View传输过来的数据创建一个表单在视图上并且在控制器中接收数据。

我们修改一下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仅仅是为了显示文本。

表单标签包含了一个asp-action="ReceivedDataByRequest"的特性,这个帮助标签针对表单创建了action属性,因此在这个例子中,当用户点击提交按钮时,将会调用控制器的ReceivedDataByRequest方法。
在HomeController中创建一个ReceivedDataByRequest方法,这个方法将从视图中接收数据,因此添加下面代码,创建这个action方法
public IActionResult ReceivedDataByRequest()
{
    var name = Request.Form["name"];
    var sex = Request.Form["sex"];
    return View("ReceivedDataByRequest", $"{name} sex is {sex}");
}
我们在action方法中使用Request.Form获取表单的值,它返回表单数据字典,因此Request.Form["name"]通过name的名字来获取表单控件输入的值,相同的方式Request.Form["sex"]通过name获取选择空间的值。
注意返回另一个View叫ReceivedDataByRequest在Action方法的最后一行,这个使用2个参数签名View方法,代码如下:
View("ReceivedDataByRequest", $"{name} sex is {sex}");
第一个参数表示呈现的视图的名称,第二个参数传输到View的数据,现在我们针对这个方法创建一个视图文件,因此右击Views->Home文件夹并且选择Add->New Item,然后对话框选择。

Razor View-Empty 选项并且命名视图ReceivedDataByRequest在视图中添加下面代码:
@model string
<h1>@Model</h1>
这个视图相对简单并且包含了2行代码,视图接收一个字符串数据(看action方法最后一行View()方法的第二个参数),因此我定义一个模型为-@model string , 最后我们在h1标签中展示数据 - @Model(注意首字母大写),因此,无论我们从action方法传递什么,这个View都会在h1标签中显示它
现在运行你应用,在表单中输入数据并且按下提交按钮,你提交的值将会显示在浏览器中,显示如下:
图片

3.2 在Action方法的参数中接收数据
视图的数据能够非常容易的传输到Action方法参数中,让我们做一个简单的解释,我们表单有2个html控件允许用户输入他们自己的名称和性别,我们可以在action方法中添加参数用来接收这两个控件的值,但是需要注意参数的名称必须和这两个控件的名称相同

在HomeController.cs文件,添加一个新的action方法名字为ReceivedDataByParameter,代码如下:
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 使用查询字符串将视图的值传递到控制器
控制器能够捕获URL中的查询字符串,在Index试图中添加一个超链接在查询字符串中使用name和sex
<a href="/Home/ReceivedDataByParameter?name=jack sparrow&sex=m" class="link-primary">Primary link</a>
单击此锚点标记时,查询字符串将携带姓名和性别值,ReceivedDataByParameter操作方法的参数将接收这些值
3.4 使用模型绑定将视图的值传递到控制器
使用模型绑定你需要创建一个模型,这个模型是普通的类文件位于Models文件夹,然而你必须使用表单映射这个模型类的属性。最后,为了在控制器中接收值,在action方法中添加模型类型,让我们通过一个例子来演示一下。我们在Models文件夹下创建一个Person的类,包含如下代码:
namespace AspNetCore.Controllers.Models
{
    public class Person
    {
        public string name { get; set; }
        public string sex { get; set; }
    }
}
这个类中有2个属性,.NET 会使用View中html控件的值自动填充这两个属性。接下来在HomeController中加一个新的action方法ReceivedDataByModelBinding,代码如下:
public IActionResult ReceivedDataByModelBinding(Person person)
{
    return View("ReceivedDataByModelBinding", person);
}
这个方法有一个Person类型的参数,因此.NET 使用了模型绑定技术,在最后一行代码中将Person对象的数据传递给ReceivedDataByModelBinding视图,因此,意味着这个View将接收一个Person类型。在Views->Home文件夹中创建一个ReceivedDataBy-ModelBinding视图,这个视图相对比较简单,他接收Person类型并显示Person类中name和sex属性的值。
@model Person
<h1>@Model.name sex is @Model.sex</h1>
我们接下来进入最后部分,为了让ASP.NET Core运行时能更好将表单和实体类做映射,因此我们需要更新一下Index视图中的表单,修改的代码如下:
@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"绑定这些控件

运行应用程序,在表单中输入值并且点击提交按钮,你会看到模型绑定属性开始工作并且通过终端用户输入的数据显示在ReceivedDataByModelBinding视图,如下图所示:

4 ASP.NET Core 上传文件
我们使用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,第二种方式使用参数,第三种方式使用查询字符串,第四种方式使用模型绑定
用户评论