为啥我们必须指定 FromBody 和 FromUri?

Posted

技术标签:

【中文标题】为啥我们必须指定 FromBody 和 FromUri?【英文标题】:Why do we have to specify FromBody and FromUri?为什么我们必须指定 FromBody 和 FromUri? 【发布时间】:2014-08-28 19:17:33 【问题描述】:

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

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

【问题讨论】:

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

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

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

如果参数是“简单”类型,Web API 会尝试从URI 中获取值。简单类型包括 .NET 原始类型(int、bool、double 等),加上 TimeSpan、DateTime、Guid、decimal 和 string,以及任何具有可以从字符串转换的类型转换器的类型。

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

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

因此,为了回答您的问题,Web API 中 [FromBody][FromUri] 属性的需要只是在必要时覆盖上述默认行为。请注意,您可以将这两个属性用于控制器方法,但只能用于不同的参数,如 here 所示。

如果你google“web api参数绑定”,网上有a lotmoreinformation。

【讨论】:

@user3510527:如果您不想使用这些属性,则不必使用这些属性,只要您遵循默认行为即可。如果要更改默认行为,则需要使用它们。 如果它在做它的默认行为,那么为什么我们需要 ovveride 以及如果我们提到这个属性我们会得到什么好处? @user3510527 您不需要需要覆盖。您可以只使用默认行为。有人可能想要覆盖的一个示例是,如果他们想在请求的正文中提供一个简单的整数,因为默认情况下,它会期望在 URI 中找到它。基本上,您可以根据需要保留默认行为,也可以覆盖,这只是您的一个选项。我不明白这是什么混乱。 我想知道是否可以创建一个名为 JustGetIt 的属性,该属性与添加多个属性(如 [FromBody, FromQuery] 等)的目的相同【参考方案2】:

默认行为是:

    如果参数是 primitive 类型(intbooldouble、...),Web API 会尝试获取HTTP 请求的 URI 中的值。

    对于复杂类型(您自己的对象,例如:Person),Web API 会尝试从 HTTP 请求的正文

所以,如果你有:

URI 中的原始类型, 体内的复杂类型

...那么您不必添加任何属性([FromBody][FromUri] 都不需要)。

但是,如果你在 body 中有一个原始类型,那么你必须添加@987654328 @ 在您的 WebAPI 控制器方法中的原始类型参数前面。 (因为默认情况下,WebAPI 会在 HTTP 请求的 URI 中寻找原始类型。)

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

原始类型:

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 的 parameter binding in 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)  ... 

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

【讨论】:

“最多允许从消息体中读取一个参数”是特别有用的信息 这不是真的。我在 url 中使用了一个 int Id,在 body 中使用了一个对象,它工作得很好。我的对象上确实有 [FromBody],所以这可能是必需的。【参考方案3】:

除了以上答案..

[FromUri] 也可用于从 uri 参数中绑定复杂类型,而不是从查询字符串中传递参数

例如..

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

【讨论】:

【参考方案4】:

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

最多允许从消息体中读取一个参数。所以这行不通:

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

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

请浏览网站了解更多详情: https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

【讨论】:

以上是关于为啥我们必须指定 FromBody 和 FromUri?的主要内容,如果未能解决你的问题,请参考以下文章

XHR2 和[FromBody]使用说明

net core 模型绑定与之前版本的不同-FromBody 必须对应Json格式

为啥在 lock 语句中必须指定同步对象

mysql postgresql 查询不指定表名和公用文件夹

同时读取 FromUri 和 FromBody

同时使用 [FromUri] 和 [FromBody] 绑定复杂的 Web Api 方法参数