将多个复杂对象传递给 post/put Web API 方法 [英] Pass multiple complex objects to a post/put Web API method

查看:46
本文介绍了将多个复杂对象传递给 post/put Web API 方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can some please help me to know how to pass multiple objects from a C# console app to Web API controller as shown below?

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 方法是这样的:

My Web API method is like this:

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

}

推荐答案

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

In the current version of Web API, the usage of multiple complex objects (like your Content and Config complex objects) within the Web API method signature is not allowed. I'm betting good money that config (your second parameter) is always coming back as NULL. This is because only one complex object can be parsed from the body for one request. For performance reasons, the Web API request body is only allowed to be accessed and parsed once. So after the scan and parsing occurs of the request body for the "content" parameter, all subsequent body parses will end in "NULL". So basically:

  • 只能用 [FromBody] 对一项进行归因.
  • 可以使用 [FromUri] 对任意数量的项目进行归因.
  • Only one item can be attributed with [FromBody].
  • Any number of items can be attributed with [FromUri].

以下是 Mike Stall 的优秀博客文章(老歌但黄金!).您需要注意第 4 项:

Below is a useful extract from Mike Stall's excellent blog article (oldie but goldie!). You'll want to pay attention to item 4:

以下是确定是使用模型绑定还是格式化程序读取参数的基本规则:

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

  1. 如果参数上没有属性,则完全根据参数的 .NET 类型做出决定.简单类型"使用模型绑定.复杂类型使用格式化程序.简单类型"包括:原语TimeSpanDateTimeGuidDecimalString 或带有 TypeConverter 的东西从字符串转换.
  2. 您可以使用 [FromBody] 属性来指定参数应该来自正文.
  3. 您可以在参数或参数类型上使用 [ModelBinder] 属性来指定参数应该是模型绑定的.此属性还允许您配置模型绑定器.[FromUri][ModelBinder] 的派生实例,专门配置模型绑定器以仅查看 URI.
  4. 正文只能读取一次.因此,如果您在签名中有 2 个复杂类型,那么其中至少一个必须具有 [ModelBinder] 属性.
  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.

MVC 和 Web API 之间的主要区别在于 MVC 缓冲内容(例如请求正文).这意味着 MVC 的参数绑定可以重复搜索主体以查找参数.而在 Web API 中,请求主体(HttpContent)可能是只读的、无限的、非缓冲的、不可回绕的流.

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.

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

You can read the rest of this incredibly useful article on your own so, to cut a long story short, what you're trying to do is not currently possible in that way (meaning, you have to get creative). What follows is not a solution, but a workaround and only one possibility; there are other ways.

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

(Disclaimer: I've not used it myself, I'm just aware of the theory!)

一种可能的解决方案"是使用 JObject 对象.这个对象提供了一个专门为处理 JSON 而设计的具体类型.

One possible "solution" is to use the JObject object. This objects provides a concrete type specifically designed for working with JSON.

您只需调整签名以仅接受来自主体的一个复杂对象,即 JObject,我们称之为 stuff.然后,您需要手动解析 JSON 对象的属性并使用泛型来混合具体类型.

You simply need to adjust the signature to accept just one complex object from the body, the JObject, let's call it stuff. Then, you manually need to parse properties of the JSON object and use generics to hydrate the concrete types.

例如,下面是一个简单的例子,可以让您了解:

For example, below is a quick'n'dirty example to give you an idea:

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!
}

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

I did say there are other ways, for example you can simply wrap your two objects in a super-object of your own creation and pass that to your action method. Or you can simply eliminate the need for two complex parameters in the request body by supplying one of them in the URI. Or ... well, you get the point.

让我重申一下,我自己没有尝试过任何这些,尽管理论上它应该都可以运行.

Let me just reiterate I've not tried any of this myself, although it should all work in theory.

这篇关于将多个复杂对象传递给 post/put Web API 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆