Web Api中[FromRoute]和[FromBody]有什么区别?

16 asp.net asp.net-web-api

Web Api中[FromRoute]和[FromBody]有什么区别?

[Route("api/Settings")]
public class BandwidthController : Controller
{
    // GET: api/Settings
    [HttpGet]
    public IEnumerable<Setting> GetSettings()
    {
        return _settingRespository.GetAllSettings();
    }

    // GET: api/Settings/1
    [HttpGet("{facilityId}", Name = "GetTotalBandwidth")]
    public IActionResult GetTotalBandwidth([FromRoute] int facilityId)
    {
        if (!ModelState.IsValid)
        {
            return HttpBadRequest(ModelState);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

也是为了[FromRoute].

// PUT: api/Setting/163/10
[HttpPut]
public void UpdateBandwidthChangeHangup([FromRoute] int facilityId, int bandwidthChange)
{
    _settingRespository.UpdateBandwidthHangup(facilityId, bandwidthChange);
}
Run Code Online (Sandbox Code Playgroud)

我可以用[FromBody]吗?

Igo*_*gor 25

FromBody

指定应使用请求正文绑定参数或属性.

使用FromBody属性时,您指定数据来自请求正文的主体,而不是来自请求URL/URI.您不能将此属性与HttpGet请求一起使用,只能使用PUT,POST和Delete请求.此外,您只能FromBody在Web API中为每个操作方法使用一个属性标记(如果在mvc核心中发生了更改,我找不到任何支持它的内容).

FromRouteAttribute

摘要:指定应使用当前请求中的route-data绑定参数或属性.

本质上,FromRoute它将查看您的路由参数并基于此提取/绑定数据.由于路由在外部调用时通常基于URL.在以前的web api版本中,这与之相当FromUri.

[HttpGet("{facilityId}", Name = "GetTotalBandwidth")]
public IActionResult GetTotalBandwidth([FromRoute] int facilityId)
Run Code Online (Sandbox Code Playgroud)

因此,这将尝试facilityId基于具有相同名称的route参数进行绑定.

Complete route definition: /api/Settings/GetTotalBandwidth/{facilityId}
Complete received url: /api/Settings/GetTotalBandwidth/100
Run Code Online (Sandbox Code Playgroud)

编辑

根据您的上一个问题,这里是相应的代码,假设您希望163绑定到facilityId,10绑定到bandwidthChange参数.

// PUT: api/Setting/163/10

[HttpPut("{facilityId}/{bandwidthChange}")] // constructor takes a template as parameter
public void UpdateBandwidthChangeHangup([FromRoute] int facilityId, [FromRoute] int bandwidthChange) // use multiple FromRoute attributes, one for each parameter you are expecting to be bound from the routing data
{
    _settingRespository.UpdateBandwidthHangup(facilityId, bandwidthChange);
}
Run Code Online (Sandbox Code Playgroud)

如果您在其中一个参数中有一个复杂的对象,并且您希望将其作为Http请求的主体发送,那么您可以使用FromBody而不是使用FromRoute该参数.下面是使用ASP.NET Core MVC构建您的第一个Web API的示例

[HttpPut("{id}")]
public IActionResult Update([FromRoute] string id, [FromBody] TodoItem item);
Run Code Online (Sandbox Code Playgroud)

也有在MVC核心的其他选项像FromHeaderFromFormFromQuery.


Sto*_*ely 5

[FromRoute] 与 [FromBody] 的混淆

Microsoft 在 ASP.NET 方面做得很好,试图将 Internet 技术连接到他们的框架和系统中。但在此过程中,他们经常试图在非常简单的 HTTP 和 HTML 技术之上修补他们的技术解决方案,从而使开发人员感到困惑。人们走开时假设他们的解决方案代表了万维网的工作原理……但事实并非如此。.NET Framework 和 ASP.NET Core 版本中的路由 URL 解决方案仍然让许多人感到困惑。

希望这有帮助...

当您在 ASP.NET Core 中创建基本“路由”时,您将浏览器的URL 地址路径绑定到ASP.NET 编译的应用程序内的特定控制器类及其子 Method()。绑定意味着他们设计的中间件会嗅探 URL 地址并尝试将其拆开,然后将这些片段与您网站内的代码进行匹配。

特殊的 Controller-ControllerBase 类在 ASP.NET 中使用映射到类中子方法的常规路由模板和路由属性来处理此过程。这包括这些方法的参数。然后,这会将所有 URL 浏览器地址路径请求“路由”到 ASP.NET 中 Web 应用程序内的一组特定代码。

不幸的是,配置此绑定的方法太多。在过去,它是一堆路由模板到控制器和方法的随机组合,以及将 url 映射到参数的附加代码。但对于查询字符串之类的东西,情况并不总是很清楚。ASP.NET Core 尝试使用这些新的属性路由装饰(例如 [FromRoute] 等)来清理混乱。

那么它们是如何工作的呢?

[Route("/mypath/{myid}")]
public string MyMethod(int myid){...}

The above matches this browser URL address on the Web:
http://example.com/mypath/5
Run Code Online (Sandbox Code Playgroud)

在最简单的形式中,ASP.NET MVC 或 WebAPI 使用“路由”文本字符串将特定方法参数名称映射到匹配的 URL 路径。[FromRoute]通过将方法参数名称显式绑定到 URL 的匹配部分来提供帮助{}

[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
    [HttpGet("{facilityId}")]// "/api/test/26"
    public IActionResult GetTotalBandwidth([FromRoute] int facilityId)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,属性[FromRoute]修饰是可选的,因为 ASP.NET 中的中间件默认会尝试为您开箱即用地映射该属性。如果你离开[FromRoute],它会尝试将你的参数名称映射到内部的路由模板名称{},如下所示:

[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
    [HttpGet("{facilityId}")]// "/api/test/26"
    public IActionResult GetTotalBandwidth(int facilityId)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

[FromQuery]然而,根据 Microsoft 的说法,它仅绑定到位于 URL 路由之外的查询字符串 URL 参数。但我一直将它们视为 URL 的一部分。在过去的 ASP.NET 迭代中,这一点被忽略了,因此人们不得不捏造一种方法来使用Request.QueryString. 所以这个新功能解决了这个问题:

[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
    [HttpGet("{facilityId}")]// "/api/test/26?num=5"
    public IActionResult GetTotalBandwidth(int facilityId,[FromQuery] int num)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

[FromBody] 完全不同!

从 a 捕获数据POST一直很棘手。ASP.NET 通过允许路由 URL 映射系统在侦听 POST 和 URL 请求时正常工作,但使用附加方法参数属性系统来绑定到使用[FromBody]. 对于 POST HTTP VERB 类型,POST 是唯一的,因为 POST 与 URL 映射无关。但在本例中,ASP.NET 使用属性参数绑定系统来为您获取表单字段数据。

让我们首先看看POST 表单字段是如何工作的。

当您使用“method=post”发送 HTML 表单数据时,如下所示:

<!doctype html>
<html xml:lang="en-us" lang="en-us">
<head></head>
<body>

<form id="f1" name="f1" method="post" action="">
  <input type="text" id="field1" name="field1" size="20" value="" />
  <button id="mybutton" name="mybutton" value="submit">Submit</button>
</form>

</body>
</html>
Run Code Online (Sandbox Code Playgroud)

...发送打包在请求“正文”内的表单字段数据,就像 POST 一样:

HTTP HEADER
Content-Type: text/html
Last-Modified: Fri, 27 Jan 2023 17:45:32 GMT

HTTP BODY
field1=hello&mybutton=submit
Run Code Online (Sandbox Code Playgroud)

请注意,表单字段 POST 数据位于请求发布 ( field1=hello&mybutton=submit) 的特殊“正文”或有效负载部分内。要获取该数据,您需要在 ASP.NET 参数装饰中使用[FromForm](对于传统的名称-值形式 POST 数据)或[FromBody](仅限特殊的 JavaScript JSON Post 数据),如下所示:

// Note: In the example below, "field1" only captures one field.

[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
    [HttpPost]// "/api/test"
    public string MyPostMethod([FromForm] string field1)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

[FromForm]捕获常规 HTML POST 表单字段(一个字段或所有字段)作为WebAPI POST 端点中的名称-值对。

[FromBody]捕获表单字段,但仅作为 JSON 数据,需要将额外的内容类型“application/json”添加到发送到服务器的 POST 请求中。由于 HTML 表单无法做到这一点,因此在使用[FromBody].

因此,[FromBody]几乎总是与 POST 一起使用,与将路由模板绑定为 URL 的一部分(如 [FromRoute] 或 [FromQuery] 可能会做的事情)无关,而只是捕获通常在发送的 POST 请求表单提交中找到的任何 POST 数据在 Http 请求包内。

希望有帮助!