asp.net Web API中的[FromRoute]和[FromBody]有什么区别?

hjqgdpho  于 2023-02-01  发布在  .NET
关注(0)|答案(2)|浏览(271)

在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);
        }
    }
}

同样适用于PUT

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

我可以使用[FromBody]吗?

kxeu7u2r

kxeu7u2r1#

指定应使用请求正文绑定参数或属性。
使用FromBody属性时,指定数据来自请求正文的正文,而不是来自请求URL/URI。不能将此属性用于HttpGet请求,只能用于PUT、POST、和删除请求。此外,在Web API中,每个操作方法只能使用一个FromBody属性标记(如果这在MVC核心中发生了变化,我找不到任何支持它的东西)。

摘要:指定应使用当前请求中的路由数据绑定参数或属性。
本质上,FromRoute会查看您的路由参数,并基于此提取/绑定数据。当外部调用路由时,通常基于URL。在以前版本的web api中,这与FromUri相当。

[HttpGet("{facilityId}", Name = "GetTotalBandwidth")]
public IActionResult GetTotalBandwidth([FromRoute] int facilityId)

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

Complete route definition: /api/Settings/GetTotalBandwidth/{facilityId}
Complete received url: /api/Settings/GetTotalBandwidth/100

编辑

根据您的上一个问题,假设您希望将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);
}

如果您在其中一个参数中有一个复杂对象,并且您希望将其作为Http请求的主体发送,那么您可以在该参数上使用FromBody而不是FromRoute

[HttpPut("{id}")]
public IActionResult Update([FromRoute] string id, [FromBody] TodoItem item);

MVC核心中还有其他选项,如FromHeaderFromFormFromQuery

kr98yfug

kr98yfug2#

混淆[从路线]与[从车身]

微软在ASP.NET方面做得很好,它试图将互联网技术连接到他们的框架和系统中。但是在这个过程中,他们常常试图在非常简单的HTTP和HTML技术之上修补他们的技术解决方案,从而使开发人员感到困惑。人们认为他们的解决方案代表了万维网的工作方式......而实际上它根本没有。NET框架和核心版本的ASP.NET仍然令许多人困惑。
希望这能帮上忙...
当你在ASP.NET核心中创建一个基本的"路由"时,**你将你的浏览器的 * URL地址路径 * 绑定到一个特定的 * Controller类和它的子方法()
(在ASP.NET编译的应用程序中)。绑定意味着他们设计的 * Middleware * 会嗅探URL地址,并尝试将其分解,然后将这些片段与你网站中的代码进行匹配。
特殊的Controller-ControllerBase类在ASP.NET中使用Map到类中的子方法的常规路由模板和路由属性来处理此过程。这包括这些方法的 * 参数 *。然后,这将所有URL浏览器地址路径请求"路由"到ASP.NET中Web应用程序中的特定代码集。
不幸的是,有太多的方式来配置这个绑定。在过去,它是一堆随机组合的路由模板到控制器和方法,与额外的代码Map一个url到参数。但这并不总是明确的东西,如 * 查询字符串 *。ASP.NET核心试图清理这些混乱的新属性路由装饰,如[FromRoute]等。
那么它们是如何工作的呢?

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

The above matches this browser URL address on the Web:
http://example.com/mypath/5

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

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

然而,[FromRoute]属性修饰是可选的,因为ASP.NET中的中间件在默认情况下会尝试为您Map它。如果您关闭[FromRoute],它会尝试将您的参数名称Map到{}中的路由模板名称,如下所示:

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

然而,根据微软的说法,[FromQuery]只绑定到Querystring 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)
    {
        ...
    }
}

[FromBody]完全不同!

POST捕获数据总是很棘手。ASP.NET通过允许路由URLMap系统在侦听POST和URL请求时正常工作,但使用额外的方法参数属性系统绑定到使用[FromBody]传入的数据,来帮助解决这个问题。对于POST HTTP VERB类型,POST是唯一的,因为POST与URLMap无关。2但是在这个例子中,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>

...发送封装在请求"主体"内的表单字段数据,如POST:

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

HTTP BODY
field1=hello&mybutton=submit

请注意,表单字段POST数据位于请求post(field1=hello&mybutton=submit)的特殊"body"或有效负载部分中。要获取该数据,需要在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)
    {
        ...
    }
}

[FromForm]在WebAPI POST端点中将常规HTML POST表单字段(一个字段或所有字段)捕获为 * 名称-值 * 对。
[FromBody]捕获表单字段,但仅作为JSON数据捕获,需要在发送到服务器的POST请求中添加额外的内容类型"application/json"。由于HTML表单无法执行此操作,因此在使用[FromBody]时必须使用JavaScript。
因此,[FromBody]几乎总是与POST一起使用,与[FromRoute]或[FromQuery]可能做的那样将Route Template绑定为URL的一部分无关,而只是捕获通常在HTTP请求包内发送的POST请求表单提交中找到的任何POST数据。
希望能有所帮助!

相关问题