谈谈ASP.NET Core MVC设计中的Controller与Action设计规范
开门见山,什么是Controller与Action?
Controller 是定义了一组 Action 的类。Action 是 Controller 内用于处理 HTTP 请求的方法。HTTP 请求通过 URL 路由映射到 Controller 的具体 Action。Action 的返回结果一般分两种:
-
启动视图的渲染,并返回渲染结果
-
调用其它 Action,这也称为重定向。这里说明一下:Post-Redirect-Get模式是常用防止表单重复提交的措施
Controller 的设计规范
为了设计好控制器,要遵循一些约束和规范。约束是为了更好的设计,在程序设计过程中约定一些规则有利于不同设计人员看懂对方的设计思路。
MVC中的约束:将类标记为 Controller
类至少要满足以下任意一个约束,才能被 ASP.NET Core 框架识别为 Controller:
-
类名以 Controller 为后缀(推荐使用)
-
类继承自名为 Contoller 或以 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 程序
MVC中的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(/*...*/)
。
文章参考于:https://www.yuque.com/yuejiangliu/dotnet/controllers-and-actions