为什么我们必须指定FromBody和FromUri?


157

为什么ASP.NET Web API中需要FromBodyFromUri属性?

使用属性与不使用属性有什么区别?


11
只是为了提示何时使用[FromBody]注释可能有用:例如,发送静态凭据(例如用户名/密码)作为URL中编码的参数是不明智的做法。尽管SSL加密可能阻止第三方获得对URL中参数的读取权限,但实践仍然不佳,因为这些凭据可能存储在浏览器日志中并且是相等的,这绝对是不希望的。在这种情况下,可以使用[FromBody]注释来强制将参数存储在HTTP消息的正文中,从而引入了高
Chris

Answers:


193

当ASP.NET Web API调用控制器上的方法时,它必须为参数设置值,该过程称为参数绑定

默认情况下,Web API使用以下规则来绑定参数:

  • 如果参数是“简单”类型,则Web API会尝试从URI中获取值。简单类型包括.NET基本类型(int,bool,double等),以及TimeSpan,DateTime,Guid,十进制和字符串,以及带有可从字符串转换的类型转换器的任何类型。

  • 对于复杂类型,Web API尝试使用媒体类型格式化程序从消息正文中读取值。

因此,如果要覆盖上述默认行为并强制Web API从URI读取复杂类型,请将[FromUri]属性添加到参数中。要强制Web API从请求正文中读取简单类型,请将[FromBody]属性添加到参数中。

因此,要回答您的问题,Web API 中对[FromBody][FromUri]属性的需要只是在必要时覆盖上述默认行为。请注意,您可以使用这两个属性的控制器的方法,但仅限于不同的参数,这表现在这里

还有很多 更多的 信息在网络上,如果你谷歌“的网页API参数绑定”。


2
@ user3510527:只要您遵循默认行为,就不需要使用这些属性。如果要更改默认行为,则需要使用它们。
djikay 2014年

1
如果它正在执行其默认行为,那么为什么我们需要ovveride?如果提到此属性,我们将获得什么好处?
Rajneesh 2014年

1
@ user3510527您不需要覆盖。您可以只使用默认行为。某人可能要覆盖的一个示例是,他们是否想在请求的正文中提供一个简单的整数,因为默认情况下,它将希望在URI中找到它。基本上,您可以根据需要保留默认行为,也可以覆盖它,这只是您的选择。我不明白这是什么困惑。
djikay 2014年

我只是想知道内部工作流程,如果我们使用form属性,那么直接它将获得值,而不检查任何uri或formbody ...
Rajneesh

7
我不知道是否可以创建一个称为的属性JustGetIt,其目的与添加诸如[FromBody, FromQuery]etc之类的多个属性具有相同的目的
The Muffin Man

93

默认行为是:

  1. 如果该参数是原始类型(intbooldouble,...),网页API尝试从该值URI的HTTP请求。

  2. 对于复杂类型(您自己的对象,例如Person:),Web API尝试从HTTP请求的正文中读取值。

因此,如果您有:

  • URI中的原始类型,或者
  • 身体中的复杂类型

......那么你不必添加任何属性(既不[FromBody]也不是[FromUri])。

但是,如果你有一个基本类型体内,那么你必须添加[FromBody]在你的原始类型参数的前面,你的WebAPI控制器的方法。(因为默认情况下,WebAPI在HTTP请求的URI中查找原始类型。)

或者,如果您的URI中包含复杂类型,则必须添加。(因为默认情况下,WebAPI默认情况下会在HTTP请求的正文中查找复杂类型。)[FromUri]

基本类型:

public class UsersController : ApiController
{
    // api/users
    public HttpResponseMessage Post([FromBody]int id)
    {

    }
    // api/users/id
    public HttpResponseMessage Post(int id)
    {

    }       
}

复杂类型:

public class UsersController : ApiController
{       
    // api/users
    public HttpResponseMessage Post(User user)
    {

    }

    // api/users/user
    public HttpResponseMessage Post([FromUri]User user)
    {

    }       
}

只要您在HTTP请求中仅发送一个参数此方法就起作用发送多个时,您需要创建一个自定义模型,该模型具有如下所有参数:

public class MyModel
{
    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
}

[Route("search")]
[HttpPost]
public async Task<dynamic> Search([FromBody] MyModel model)
{
    // model.MyProperty;
    // model.MyProperty2;
}

摘自Microsoft文档中的ASP.NET Web API中的参数绑定

当参数具有[FromBody]时,Web API将使用Content-Type标头来选择格式器。在此示例中,内容类型为“ application / json”,请求主体为原始JSON字符串(不是JSON对象)。最多允许一个参数从消息正文中读取。

这应该工作:

public HttpResponseMessage Post([FromBody] string name) { ... }

这将不起作用:

// Caution: This won't work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

此规则的原因是请求正文可能存储在只能读取一次的非缓冲流中。


5
“最多允许从邮件正文读取一个参数”是特别有用的信息
Ryan

15

只是上面的答案..

[FromUri]也可以用于绑定uri参数中的复杂类型,而不是通过querystring传递参数

适用于

public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }
}

[RoutePrefix("api/Values")]
public ValuesController : ApiController
{
    [Route("{Latitude}/{Longitude}")]
    public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}

可以这样称呼:

http://localhost/api/values/47.678558/-122.130989

12

当参数具有[FromBody]时,Web API将使用Content-Type标头来选择格式器。在此示例中,内容类型为“ application / json”,请求主体为原始JSON字符串(不是JSON对象)。

最多允许一个参数从消息正文中读取。因此,这将不起作用:

 // Caution: Will not work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

此规则的原因是请求正文可能存储在只能读取一次的非缓冲流中

请访问网站以获取更多详细信息:http : //www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.