c# - 将多个复杂对象传递给 post/put Web API 方法

标签 c# asp.net asp.net-web-api asp.net-web-api2 dotnet-httpclient

有人可以帮助我了解如何将多个对象从 C# 控制台应用程序传递到 Web API Controller ,如下所示吗?

using (var httpClient = new System.Net.Http.HttpClient())
{
    httpClient.BaseAddress = new Uri(ConfigurationManager.AppSettings["Url"]);
    httpClient.DefaultRequestHeaders.Accept.Clear();
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));   

    var response = httpClient.PutAsync("api/process/StartProcessiong", objectA, objectB);
}

我的 Web API 方法是这样的:

public void StartProcessiong([FromBody]Content content, [FromBody]Config config)
{

}

最佳答案

在当前版本的 Web API 中,使用多个复杂对象(例如您的ContentConfig 复杂对象)在 Web API 方法签名中不允许。我打赌 config(您的第二个参数)总是返回 NULL。这是因为对于一个请求,只能从正文中解析出一个复杂对象。出于性能原因,Web API 请求主体只允许被访问和解析一次。因此,在对“content”参数的请求主体进行扫描和解析后,所有后续主体解析都将以“NULL”结尾。所以基本上:

  • 只有一个项目可以归因于[FromBody]
  • 可以使用 [FromUri] 归因于任意数量的项目。

以下是来自 Mike Stall's excellent blog article 的有用摘录(老歌但戈尔迪!)。您需要注意第 4 项:

Here are the basic rules to determine whether a parameter is read with model binding or a formatter:

  1. If the parameter has no attribute on it, then the decision is made purely on the parameter's .NET type. "Simple types" use model binding. Complex types use the formatters. A "simple type" includes: primitives, TimeSpan, DateTime, Guid, Decimal, String, or something with a TypeConverter that converts from strings.
  2. You can use a [FromBody] attribute to specify that a parameter should be from the body.
  3. You can use a [ModelBinder] attribute on the parameter or the parameter's type to specify that a parameter should be model bound. This attribute also lets you configure the model binder. [FromUri] is a derived instance of [ModelBinder] that specifically configures a model binder to only look in the URI.
  4. The body can only be read once. So if you have 2 complex types in the signature, at least one of them must have a [ModelBinder] attribute on it.

It was a key design goal for these rules to be static and predictable.

A key difference between MVC and Web API is that MVC buffers the content (e.g. request body). This means that MVC's parameter binding can repeatedly search through the body to look for pieces of the parameters. Whereas in Web API, the request body (an HttpContent) may be a read-only, infinite, non-buffered, non-rewindable stream.

您可以自己阅读这篇非常有用的文章的其余部分,所以,长话短说,目前您尝试做的事情以那种方式是不可能的(意思是,您必须要有创意)。以下不是解决方案,而是解决方法,并且只有一种可能性;还有其他方法。

解决方案/解决方法

(免责声明:我自己没有使用过它,我只是知道理论!)

一种可能的“解决方案”是使用 JObject目的。该对象提供了一种专门为处理 JSON 而设计的具体类型。

您只需调整签名以从正文中接受一个复杂的对象,JObject,我们称它为stuff。然后,您需要手动解析 JSON 对象的属性并使用泛型来混合具体类型。

例如,下面是一个简单的例子,可以给你一个想法:

public void StartProcessiong([FromBody]JObject stuff)
{
  // Extract your concrete objects from the json object.
  var content = stuff["content"].ToObject<Content>();
  var config = stuff["config"].ToObject<Config>();

  . . . // Now do your thing!
}

我确实说过还有其他方法,例如,您可以简单地将两个对象包装在您自己创建的 super 对象中,然后将其传递给您的操作方法。或者,您可以通过在 URI 中提供其中之一来简单地消除请求正文中对两个复杂参数的需要。或者……好吧,你明白了。

让我重申一下,我自己没有尝试过任何这些,尽管理论上应该都有效。

关于c# - 将多个复杂对象传递给 post/put Web API 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24874490/

相关文章:

c# - .Net CORE Web API 无缓存但仍然发生

c# - 使用 ASP.NET Web API 进行依赖注入(inject)

c# - 知道文件何时在 Windows 8 上更改

asp.net - System.Web.Security.MembershipProvider 在哪里?

c# - 如何防止加载开源项目的重新编译.net dll

javascript - 编写 AJAX Post HTTP 请求

asp.net - 限制 ASP.NET Web API 服务的并发请求

c# - 如何从函数中的选择查询返回 int 值?

c# - 输入数组比该表中的列数长。异常(exception)

c# - 与许多独立线程同步