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

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

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

209229 次浏览

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

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

  • 如果参数是 “简单”型的,则 WebAPI 尝试获取值 从 URI。简单类型包括。NET 基元类型(int、 bool、 double 等) ,加上 TimeSpan、 DateTime、 Guid、 decal 和 string,再加上任何带有可从字符串转换的类型转换器的类型。

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

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

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

如果你谷歌“网络应用程序接口参数绑定”在网络上有 很多 更多 资料

当参数具有[ FromBody ]时,Web API 使用 Content-Type 头来选择格式化程序。在这个例子中,内容类型是“ application/JSON”,请求主体是一个原始的 JSON 字符串(不是 JSON 对象)。

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

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

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

详情请浏览网页: Https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

默认行为是:

  1. 如果参数是 原语类型(intbooldouble、 ...) ,则 Web API 尝试从 HTTP 请求的 < em > URI 中获取值。

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

所以,如果你有:

  • URI 中的基元类型 < em > or
  • 体内的一种复杂类型

那么你就不需要添加任何属性(不管是 [FromBody]还是 [FromUri])。

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

或者,如果在 < em > 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;
}

来自微软的 ASP.NET Web API 中的参数绑定文档:

当参数具有[ FromBody ]时,Web API 使用 Content-Type 头 选择格式化程序。在此示例中,内容类型为 “ application/JSON”,请求主体是一个原始的 JSON 字符串(而不是一个 < strong > 最多只允许从 消息主体

这应该会奏效:

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

这是行不通的:

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

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

除了上面的答案。

还可以使用[ 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