C# 如何对复杂数据类型使用FormUrlEncodedContent?

C# 如何对复杂数据类型使用FormUrlEncodedContent?,c#,.net,dotnet-httpclient,C#,.net,Dotnet Httpclient,我需要与只接受表单编码有效负载的第三方端点进行交互。端点需要在该端点处使用复杂的数据类型,这意味着类似于以下内容(但形式编码,而不是JSON): 我的谷歌搜索和端点的文档表明这应该像这样进行表单编码: foo=bar&baz[zip]=zap foo=bar&baz[zip]=zap 我使用的是HttpClient,我想使用FormUrlEncodedContent,但当我这样做时,它会用转义字符替换我的[] public class Tests { [Fact]

我需要与只接受表单编码有效负载的第三方端点进行交互。端点需要在该端点处使用复杂的数据类型,这意味着类似于以下内容(但形式编码,而不是JSON):

我的谷歌搜索和端点的文档表明这应该像这样进行表单编码:

foo=bar&baz[zip]=zap
foo=bar&baz[zip]=zap
我使用的是
HttpClient
,我想使用
FormUrlEncodedContent
,但当我这样做时,它会用转义字符替换我的
[]

public class Tests
{
    [Fact]
    public void Test()
    {
        var content = new Dictionary<String, String>
        {
            { "foo", "bar" },
            { "baz[zip]", "zap" }
        };
        var formContent = new FormUrlEncodedContent(content);
        Assert.Equal("foo=bar&baz[zip]=zap", formContent.ReadAsStringAsync().Result);
    }
}

你的问题有两个问题。第一:

我的谷歌搜索表明这应该是这样编码的表单:

foo=bar&baz[zip]=zap
foo=bar&baz[zip]=zap
没有。没有将多维键值结构转换为一维键值结构的约定或标准

如果你仔细想想,这样的转变很快就会变得非常笨拙。对象语义比URL编码语义更具表现力。FWIW,他们甚至无法就如何将普通数组编码为URL达成一致,尽管这很容易实现

因为并没有标准,所以归根结底是建立一个服务器和客户端可以接受的约定。最让人头疼、最不容易产生讨厌虫子的惯例是(*):

  • 将对象序列化为JSON。这给了你一个字符串
  • 将该字符串作为URL参数中的值传输
  • 在接收端执行相反的操作
因此,在JS中,您将执行以下操作:

encodeURIComponent(JSON.stringify({
    "foo": "bar",
    "baz": {
        "zip": "zap"
    }
}));
这给了你

"%7B%22foo%22%3A%22bar%22%2C%22baz%22%3A%7B%22zip%22%3A%22zap%22%7D%7D"
这可以作为URL参数安全地传输,并以最小的工作量进行处理

对于.NET,您可以从几个序列化选项中选择,其中两个是DataContractJsonSerializer和JavaScriptSerializer

我强烈建议不要为此任务使用您自己的序列化方案


第二:

但当我这样做时,它会用转义字符替换我的[]

public class Tests
{
    [Fact]
    public void Test()
    {
        var content = new Dictionary<String, String>
        {
            { "foo", "bar" },
            { "baz[zip]", "zap" }
        };
        var formContent = new FormUrlEncodedContent(content);
        Assert.Equal("foo=bar&baz[zip]=zap", formContent.ReadAsStringAsync().Result);
    }
}
当然。URL编码的键-值对中的键受与值相同的规则约束。像
{“A&b”:“c&d”}
这样的一对将被编码为
A%26b=c%26d
。实际上,您可以将其作为
%61%26%62=%63%26%64
发送。换句话说,URL解码值,但在接收端忘记URL解码关键字名称是一个错误。忘记URL编码键名也是如此。讨论URL中可以使用何种形式的字符



(*)缺少“直接将数据传输为
内容类型:application/json
,这比将其压缩为查询字符串更好。

正如我在问题中提到的,我正在与第三方api交互,因此我无法选择序列化格式。他们的文档有一个带有
-d bar[zip]的curl示例=zap
,Google建议,虽然不是标准的,但这是以编码形式发送复杂对象的最常见机制(我认为jquery就是这样做的)。我同意api不应该这样做,但我仍然必须处理它。正如回答中提到的,没有标准,所有内容都基于约定。没有.NET函数会提供现成的格式。如果端点记录它期望的约定,则需要自己编写相应的序列化程序。@Micah很抱歉,这不是你想听到的,但是这并不能改变答案正确的事实。:)添加一个直接回答问题的新答案,或者重新构造这个答案,我会接受。目前,这个答案认为这个问题无效,我不同意。我同意你的结论我想做的是不可能的,但我相信这个问题是有效和合理的。特别是,删除使用替代编码格式的建议,因为我在与第三方端点交互。理想情况下,事先声明从FormUrlEncodedContent中获取所需编码是不可能的可能以及原因。是的,我认为这个问题是无效的,因为你是基于错误的假设开始的,即有某种标准,并且.NET中存在实现此标准的函数。我尽了最大努力纠正这些假设。我没有说你想要的是不合理的,我说你必须实现这是你自己的问题。我冒昧地提出了一个明智的选择,我当然不会采纳这个建议。其他发现这个问题的人可能会受到较少的限制来使用它。