简体   繁体   中英

How do I use FormUrlEncodedContent for complex data types?

I need to interact with a third party endpoint that only accepts form encoded payloads. The endpoint wants complex data types at this endpoint, meaning something like this (but form encoded, not JSON):

{
    "foo": "bar",
    "baz": {
        "zip": "zap"
    }
}

My googling and the docs for the endpoint indicates that this should be form encoded like this:

foo=bar&baz[zip]=zap

I am using HttpClient and I want to use FormUrlEncodedContent but when I do it is replacing my [] with escaped characters.

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);
    }
}

What I end up with instead is:

foo=bar&baz%5Bzip%5D=zap

There are two issues in your question. Number one:

My googling indicates that this should be form encoded like this:

 foo=bar&baz[zip]=zap 

No. There is no convention or standard that transforms a multi-dimension key-value structure into a single-dimension one.

If you think about it, such a transformation will become very unwieldy very quickly. Object semantics are a lot more expressive than URL-encoding semantics. FWIW, they can't even agree on how to encode plain arrays into URLs, even though that would easily be possible.

Since there is no standard, it comes down to setting up a convention that server and client can live with. The convention that would cause the least headache and the least chance for nasty bugs would be (*) :

  • Serialize your object into JSON. This gives you a string.
  • Transfer that string as the value in an URL parameter.
  • Do the reverse on the receiving end.

So in JS you would do:

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

which gives you

"%7B%22foo%22%3A%22bar%22%2C%22baz%22%3A%7B%22zip%22%3A%22zap%22%7D%7D"

This can be transferred safely as an URL parameter and processed with minimal effort.

For .NET you can pick from several serialization options, two of them being the DataContractJsonSerializer and the JavaScriptSerializer, discussed over here .

I would strongly recommend against rolling your own serialization scheme for this task.


Number two:

but when I do it is replacing my [] with escaped characters.

Of course. The keys in URL-encoded key-value pairs are subject to the same rules as the values. A pair like {"a&b": "c&d"} would be encoded as a%26b=c%26d . In fact, you could send it as %61%26%62=%63%26%64 . In other words, URL-decoding values but forgetting about URL-decoding key names on the receiving end is a bug. So is forgetting about URL- encoding key names. A discussion about what characters can be used in what form in a URL is over here .


(*) Short of "transferring the data as Content-Type: application/json directly, which is preferable to squeezing it into a query string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM