asp,net core 3.1 的 Controller 和 Action

对于 MVC 视图应用而言,Action 返回的结果通常是一个 View,即页面;

而对于 Web API 应用程序来说,则返回相应的资源或者 HTTP 状态码。

Controller

根据约定,继承自位于 Microsoft.AspNetCore.Mvc 命名空间下的 Controller 类,而这个 Controller 类又继承自 ControllerBase 抽象类。

如果一个类并不满足上述约定,那么只要为它添加[Controller]特性,仍然能够将它作为 Controller 处理;反之,如果为一个 Controller 添加[NotController]特性。

[Controller]
public class Blogs
{
}

[NonController]
public class ValueController
{
}

Action

每个 Action 都应返回 IActionResult 类型或ActionResult<T> 类型的值作为 HTTP 请求的结果。

常见的类别,包括

  1. 状态码
  2. 对象的状态码
  3. 重定向
  4. 内容

状态码

返回一个 HTTP 状态码给客户端

对应的状态码描述ControllerBase中的方法
200操作成功Ok()
400错误的请求BadRequest()
204操作成功,但未返回任何内容NoContent()
404请求的资源找不到NotFound()
401未授权Unauthorized()
415无法处理请求附带的媒体格式

如果要返回上述状态码之外的结果,则可以使用 StatusCode 方法,并为该方法指明具体的状态码。

return StatusCode(403);

直接使用状态码数字有可能会出错,更简单且直观的方法是,使用Microsoft.AspNetCore.Http 命名空间下的 StatusCodes 静态类

return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status200OK);

对象的状态码

这一类结果继承自 ObjectResult,包括 OkObjectResult、CreatedResultNotFoundObjectResult 等。

public IActionResult DoSomething()
{
		var result = new OkObjectResult(new { message = "success", currentDate = DateTime.Now});
		return result;
}

重定向

包括 RedirectResult、LocalRedirectResult、RedirectToActionResultRedirectToRouteResult 等。

// 重定向到指定的URL
return Redirect("http://www.asp.net/");
// 重定向到当前应用程序中的另一个URL
return LocalRedirect("/account/login");
// 重定向到指定的Action
return RedirectToAction("login");
// 重定向到指定的路由
return RedirectToRoute("default"new { action = "login", controller = "Login" });

内容

包括 ViewResult、PartialViewResult、JsonResultContentResult 等,其中 ViewResultPartialViewResult 在 MVC 视图应用中非常常见,用于返回相应的页面;JsonResult 用于返回JSON 字符串,ContentResult 用于返回一个字符串。


.net core web api 能够使用 /Controller/Action 访问控制器配置

控制器特性改写如下:

[ApiController]
[Route("[controller]/[action]")]

示例:
在这里插入图片描述
请求Get方法的url为
在这里插入图片描述


WebApi官网学习记录—webapi中controlleraction的选择

如果framework找到一个匹配的URI,创建一个包含占位符值的字典,key就是这些占位符(不包括大括号),value来自URI或者默认值,这个字典存储在IHttpRouteData对象中。默认值可能是RouteParameter.Optional,此时对应的key/value不会被添加到该字典中。

routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{category}/{id}",
    defaults: new { category = "all", id = RouteParameter.Optional }
);

对于URI"api/products",route dictionary中包括:

  • controller:“product”
  • category:“all”

对于URI"api/products/toys/123",route directionary中包括:

  • controller:“products”
  • category:“toys”
  • id:“123”

Controller的选择:

route dictionary中找到“controller
取到key的值,和"Controller"组合到一起,然后得到对应的controller的类型名
在web api的controller中查找这个类型名的controller

Action的选择:

  • action必须匹配HTTP method
  • 如果route dictionary存在"action",则action的名字需与之匹配
  • 对于action的每个参数,如果参数来自URI,则这个参数名必须能在route dictionary或URI中带的参数中找到【可选参数与复杂类型除外】
  • 尽可能匹配多的参数,最好的匹配可能是一个没有参数的方法
routes.MapHttpRoute(
    name: "ApiRoot",
    routeTemplate: "api/root/{id}",
    defaults: new { controller = "products", id = RouteParameter.Optional }
);
routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

public class ProductsController : ApiController
{
    public IEnumerable<Product> GetAll() {}
    public Product GetById(int id, double version = 1.0) {}
    [HttpGet]
    public void FindProductsByName(string name) {}
    public void Post(Product value) {}
    public void Put(int id, Product value) {}
}

HTTP Request:

GET http://localhost:34701/api/products/1?version=1.5&details=1

依据以上原则分析最终选择的action是:GetById


Web Api 2(三)之路由与Action的选择

路由(Route)

Web Api中的路由与Asp.net mvc中的路由基本上一样,一个路由看起来像是一个URI路径,但是路由中包含一些大括号包括的占位符(place holder),例如:

api/{Controller}/{Action}/{Id}

当你创建一个路由的时候,你可以为一个或多个占位符设置默认值,例如下面的例子将Controller设为Account,如果请求访问的URL没有提供Controller时,将会使用设置的默认的 Controller

defaults:new {Controller=Account}

你还可以为占位符设置一些限制,下面的例子限制Id只能为数字

constraints:new{ id = @"\d+"}

Web Api中的路由主要有三个主要的功能:

  • 将请求的URI与路由模板进行匹配
  • 选择Controller
  • 选择Action

当收到请求是,Web Api会尝试着将请求URI与路由表(Route Table)中注册的路由模板进行比对,模板中的字面值(Literals)必须被准确的匹配,如上面例子中的api片段,请求的URL必须包含api才能匹配上面的路由,而占位符可以匹配任何值(除非你有其它特殊的限制),将请求的URL进行匹配时,只会比对路由模板中有的片段(Segment),而路由模板中没有的则不会比对,如主机名(host name)、查询参数(query parameters)等,之后选择路由表中匹配的第一个路由来进行下一步的处理

Web Api提供的默认路由如下:

 config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

default中设置的id = RouteParameter.Optional表示路由模板中id是不是必须的,而是可选的,只有在请求的URL存在时才会被赋值

路由字典(Route Dictionary)

如果请求的URL匹配到了与之匹配的路由时,Web api会创建一个Dictionary来存放URL中与路由模板中占位符对应的字段值,这个DictionaryKey就是路由模板的占位符的名称(不包括大括号),这些值即可能来自URL,也可能来自注册路由时设置的默认值。而这个Dictionary就存放IHttpRouteData类型的对象中。

注意 : 如果路由中的占位符被设置为 RouteParameter.Optional,那么这个参数的值(即RouteParameter.Optional)不会被加入到上述的Dictionary中。但如果这个占位符被分配了具体的值的话,这个Dictionary中还是会存储这个值的,例如:api/products,那么此时这个Dictionary中存储的就是:

  • controller: “products”
  • category:“all”

并不会存储: id:RouteParameter.Optional,在比如,api/products/toys/123,那么此时这个Dictionary中存储的就是:

  • controller:“products”
  • catagory: “toys”
  • id : “123”

这个字典中甚至可以包含路由模板中不存在,但在默认值中存在的值,例如:

routes.MapHttpRoute(
    name:"Root",
    routeTemplate:"api/root/{id}",
    default:new { controller="customers",id = RouteParameter.Optional}
)

如果URL中分离出的片段为api/root/8,那么此时这个Dictionary中存储的是:

  • controller:"customers
  • id : “8”

Controller的选择

Controller的选择是通过IHttpControllerSelector.SelectController 的方法来实现的,这个方法接收一个** HttpRequestMessage类型对象返回一个 HttpControllerDescriptor ,默认使用的是Web api内部提供的 DefaultHttpControllerSelector**,这个类使用下面的逻辑来选择Controller

  1. 以"Controller"为Key到上述的Dictionary(存储在IHttpRouteData类型中)查找对应的Value
  2. 在获取到的值(即请求的Controller名称)后面附加"Controller"字符串去获取对应的Controller的类型名称
  3. 拿第二步得到的Controller的名称去获取对应的Web Api Controller对象(ApiController类型)

例如,如果路由字典(Route Dictionary)包含键值对(key-value pair)"Controller=products",那么控制器的类型便是"ProductsController",如果没有找到与之匹配的ApiController类型或者有多个匹配,则返回一个错误给请求的客户端。

在第三步中,DefaultHttpControllerSelector 使用 IHttpControllerTypeResolver(典型的IOC应用)接口去获取所有的ApiController类型(均派生在ApiController),这个接口返回满足一下条件的所有公共(Public)类型:

  • 实现IHttpController接口
  • 非抽象类
  • 类名以"Controller"结束

Action的选择

在得到匹配的Controller类型后,Web Api会调用IHttpActionSelector.SelectAction方法去选择Action,这个方法接收一个HttpControllerContext类型参数,返回一个HttpActionSelector类型实例。选择Action的大致过程如下:

  1. 查看请求的Http Method(Get、POST等),获取请求的Action名称,方法和获取Controller名称的方法一致,以"Action"为Key到路由字典中获取对应值
  2. 查看路由表中注册的路由模板中的默认值
  3. 查看Controller中定义的Action方法的参数,找出参数最匹配的一个Action

那么,满足什么条件的方法才能被视为一个Action呢?满足如下条件的方法便会被认为是Action

  • 定义在Controller中的所有公共的实例方法(不包括一些具有特殊名称的方法,如构造函数、事件、运算符重载等)

Web Api仅仅选择那些与请求的Http Method匹配的Action

  • 一个Action如果没有特殊说明,那么它的Http MethodPOST
  • 你可以通过[HttpGet]、[HttpPost]、[HttpDelete]、[HttpHead]、[HttpOptions]、[HttpPatch]、[HttpPut] 特性来显式的声明一个Action的支持的Http Method,也可以通过HttpVerbs特性来声明。
  • 如果一个Action的名称以Post、Get、Patch、Head、Put、Options、Delete等字符开头的,则认为该Action支持对应的Http
    Method。

Action 的参数绑定

Web Api中,Action的参数的创建过程称为参数的绑定,遵照一下的规则:

  • 简单类型(Simple Type)的参数从URI中获取其参数值
  • 复杂类型(Complex Type)的参数从Http的请求报文中获取其参数值

那么如何区分简单类型和复杂类型呢?在Web Api中,如果一个数据类型支持源自字符串的类型转换,那么该数据对象就是简单类型,否则,该数据对象就是复杂类型,按照这个判断的标准,Net中的所有的基元类型(Primative Type)和可空值类型(Nullable Type)、外加 DateTime, Decimal, Guid, String, and TimeSpan.都是简单类型,而一个自定义的类型默认情况下都是复杂类型.对于一个Action来说,之多有一个参数来自于Http请求报文

注: 在C#中,能够直接被编译器识别的类型称为基元类型.如int、byte等,其分别对应着FCL中的System.Int32System.Byte

了解了上面的东西后,我们看一下Action 选择的机制(简单参数类型)

  1. Controller中所有满足请求Http MethodAction放入一个列表中
  2. 如果路由字典中存在"Action"条目,则从创建好的Action列表中移除名称不匹配的Action.
  3. 尝试着通过URI去获取Action的参数

  • 对于每个Action,获取其简单参数类型的参数列表,这其中不包括可选参数(Optional Parameters
  • 试着根据参数名称从参数列表、路由字典(Route Dictionary)或查询字符串(Query String)中获取对应的参数值,这个匹配过程参数名称不区分大小写,也不依赖于参数的顺序。
  • 选择一个Action,其参数列表中的每个参数在URI都有与之对应的参数值
  • 如果有多个Action满足条件,则选择一个最为匹配的一个

忽略那些应用了[NonAction]特性的Action

其它

Web Api的路由过程是支持扩展的,当内置的实现逻辑不足以满足应用的需求时,此时,便可以通过实现相应的接口来对逻辑进行自定义。其中相关的接口及其作用如下:

接口描述
IHttpControllerSelector选择控制器
IHttpControllerResolver获取控制器类型列表,默认的DefaultHttpControllerSelector从
获取的控制器类型列表中选择控制器
IAssemblyResolver获取项目的程序集列表,IHttpControllerTypeResolver使用这个列表去查找控制器类型
IHttpControllerActivator创建控制器实例
IHttpActionSelector选择Action
IHttpActionInvoker执行Action

在实现某个接口后,然后使用HttpConfiguration类的Service集合去注册后,Web Api便会使用自定义的逻辑去替换掉内置的默认实现。

var config = GlobalConfiguration.Configuration;
config.Services.Replace(typeof(IHttpControllerSelector),new MyControllerSelector(config));
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ASP.NET Core 3.1是一个跨平台、高性能的开源框架,它可以帮助我们快速地构建Web应用程序。ASP.NET Core 3.1中文教程可以为初学者提供一个快速上手的指南,帮助他们了解和掌握该框架的各种功能。 在学习ASP.NET Core 3.1教程之前,我们需要了解一些基本的编程概念和技能, 包括C#语言的基础知识、MVC(Model View Controller)等常见的编程模式、以及前端技术如HTML、CSS和JavaScript等。此外,我们还需要对.NET Core框架有一定的了解,如.NET Core的概念、架构和基础组件等。 学习ASP.NET Core 3.1的教程需要深入理解其设计方案和特点,例如跨平台、高性能、依赖注入、实时通信等。此外,我们还需要熟悉其主要组件,如ASP.NET Core的中间件、MVC框架、Entity Framework Core等。 在学习ASP.NET Core 3.1的教程时,我们需要通过实践才能更好地理解其所涉及的技术和概念。因此,我们需要通过编写各种实际的Web应用程序和示例,来实践和掌握所学的技巧和知识。 总之,学习ASP.NET Core 3.1的中文教程需要较深的前置知识储备和实操经验,而且需要坚持不懈地学习和练习以提高自己的技能水平。 ### 回答2: ASP.NET Core 3.1是目前为止最新的ASP.NET Core版本,它是一个跨平台的Web应用程序开发框架。对于想要学习ASP.NET Core 3.1的开发者来说,中文教程是非常重要的。 现在,有很多中文教程可以帮助开发者快速入门ASP.NET Core 3.1。这些教程通常包括以下内容: 1. ASP.NET Core 3.1的基础知识:网页处理、路由、控制器等; 2. ASP.NET Core 3.1中的模型、视图和控制器; 3. 动作过滤器和特性; 4. 实体框架和数据库相关操作; 5. API设计和测试等。 这些教程通常包含实例和练习,能够帮助开发者深入理解ASP.NET Core 3.1的开发原理。另外,一些知名的在线教育平台,如网易云课堂等,也提供了ASP.NET Core 3.1的中文课程,有兴趣的开发者可以去尝试。 总的来说,学习ASP.NET Core 3.1需要投入时间和精力,但是中文教程能够让初学者更加轻松地掌握ASP.NET Core 3.1的开发技能,更好地进行ASP.NET Core 3.1的开发工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值