概述
本节学习如何创建控制器(Controller)和它们的操作(Action)。
本节主要内容:
Controller 和 Action 的基本概念
Controller 的设计
Action 的设计
什么是 Controller 和 Action
Controller 是定义了一组 Action 的类。Action 是 Controller 内用于处理 HTTP 请求的方法。
HTTP 请求通过 URL 路由映射到 Controller 的具体 Action,路由的细节在下一节讨论。
Action 的返回结果一般分两种:
启动视图的渲染,并返回渲染结果
调用其它 Action,这也称为重定向
Controller 的设计
为了设计好控制器,要遵循一些约束和规范。
约束是必需遵守的;规范是大家普遍遵守的,为了写出更容易合作的代码。
约束:将类标记为 Controller
类至少要满足以下任意一个约束,才能被 ASP.NET Core 框架识别为 Controller:
类名以 Controller 为后缀
类继承自名为 Contoller 或以 Controller 为后缀的类
类使用 [Controller] 特性标注
下例的类都算 Controller:
using Microsoft.AspNetCore.Mvc;
namespace App.Controllers
{
// Controller 1: the class name is suffixed with "Controller"
public class ProductController
{
// Actions
}
// Controller 2: the class inherits from a class whose name is or is suffixed with "Controller"
public class Product : Controller
{
// Actions
}
// Controller 3: the class is decorated with the [Controller] attribute
[Controller]
public class Product
{
// Actions
}
// Controller 4: preferred name
public class ProductController : Controller
{
// Actions
}
}
实际项目中最常见的是第四种,即继承自 Controller 又以 Controller 为名称后缀。这样做的好处是将 Product 的控制器类与模型类区分开来。
规范:设计 Controller
我们应遵循以下规范,以便使 Controller 适用于真实项目:
将所有 Controller 类放在项目根目录下的 Controllers 文件夹中。这使得控制器类都在 Controllers 名称空间下,大幅降低维护成本
使控制器类继承自 Microsoft.AspNetCore.Mvc.Controller。这允许你重用 Controller 基类实现的属性和方法。例如,调用 View 渲染视图,调用 RedirectToAction 进行重定向
ASP.NET Core Web 程序的控制器命名都使用单数名词
- 究其原因是 ASP.NET Core Web API 程序的控制器命名会使用复数名词。如此规范有助于我们区分不同功能的控制器类,尤其是当我们在同一个项目中既有 Web 程序又有 Web API 程序时
请参考课程 Build Web APIs using ASP.NET 了解如何使用 ASP.NET Core 创建 Web API 程序。
Action 的设计
Controller 中的 public 方法,除了用 [NonAction] 标注的都算是 Action。
Action 主要职责就是处理业务逻辑,然后返回渲染的视图(HTML 内容)或重定向,没有太多的设计规范,下面以按产品名搜索产品为例。
搜索到该名称产品就筛选并渲染出来,搜索不到就依然展示所有产品。
public class ProductController : Controller
{
public DatabaseContext dbContext { get; set; }
public IActionResult GetProductsByName(string name)
{
IList<Product> products = null;
if(String.IsNullOrWhiteSpace(name))
{
products = dbContext.GetAllProducts();
}
else
{
products = dbContext.GetProductsByName(name);
}
return RedirectToAction("Index", products);
}
public IActionResult Index(IList<Product> products)
{
return View(products);
}
}
Action 的返回值
理论上 Action 方法可以返回任意返回值:
public class SampleController
{
public string SayHello()
{
return "Hello, ASP.NET Core!";
}
public double Add(double a, double b)
{
return a + b;
}
public IActionResult CylinderVolume(double r, double h)
{
double v = Math.PI * Math.Pow(r, 2) * h;
return new JsonResult(v);
}
}
假设包含该 SampleController 的 Web 程序运行在 TCP 5000 端口上监听 HTTP请求。
如果在浏览器的地址栏中键入 http://localhost:5000/sample/sayhello 并按 Enter 键,浏览器发送的 HTTP 请求将触发 SayHello 操作。SayHello 将返回纯文本字符串 “Hello, ASP.NET Core!”。字符串将通过 HTTP 响应返回到你的浏览器,并显示在浏览器中
URL http://localhost:5000/sample/add?a=10&b=20 将触发 Add 操作,你的浏览器将显示 30.0。但这个 30.0 既不是字符串也不是 double 值。它是一个 JSON 对象。也就是说,默认情况下,ASP.NET Core 会将非 IActionResult 类型的返回值转换为 JSON 对象
同理,URL http://localhost:5000/sample/cylindervolume?r=10&h=20 将触发 CylinderVolume 操作,浏览器将显示 6283.1853071795867。该值也是 JSON 对象。不同之处在于它是通过 JsonResult 显式转换而来的
拥有隐式/显式将返回值转换为 JSON 对象的功能意味着 ASP.NET Core Web 程序也可以用作 Web API 程序。但这样做徒增复杂度,项目中还是应该分开它们。
所以除了 JsonResult 外,常见的 ASP.NET Core Web 程序的 Action 基本都返回 IActionResult 类型值。
作为 C# 程序员,你可能会问:“IActionResult 是个接口,我们是否需要记住它的实现类然后创建要返回的操作的实例?”答案是不必。因为大多数 Action 最终只做两件事 —— 要么渲染视图,要么重定向到另一个 Action,而这两操作在 Microsoft.AspNetCore.Mvc.Controller 中已经实现了,分别是 View 和 RedirectToAction。
总之,Action 方法的最后一句基本都是 return View(/*...*/)
或 return RedirectToAction(/*...*/)
。