UrlEncode non-string properties for HTTP Post thro

2019-07-13 20:35发布

问题:

This code is in python

dataParams = urllib.urlencode({
    "name": "myname",      
    "id": 2,        
    })

    dataReq = urllib2.Request('mylink', dataParams)
    dataRes = urllib2.urlopen(dataReq)

Now i am trying to convert it into C#.Till now I have been able to do this only

 var dataParams = new FormUrlEncodedContent(
             new KeyValuePair<string, string>[]
             {
                 new KeyValuePair<string, string>("name", myname"),                     
                 new KeyValuePair<string, string>("id", "2"),
             });

  httpResponse = await httpClient.PostAsync(new Uri(dataString),dataParams);
  httpResponseBody = await httpResponse.Content.ReadAsStringAsync();   

But my problem is posting the content since the post data needs to be both int and string.But I am able to only send data in string format using FormUrlEncodedContent.So how do I send the post request with proper parameters.

回答1:

I am not sure what do you mean by post data needs to be both int and string, because application/x-www-form-urlencoded is basically a string with string key-value pairs.

So it doesn't matter if your original id parameter is a string "2" or a number 2.

It will be encoded the same: name=mynameValue&id=2

So there is nothing wrong with your code. Just use ToString method on original int value to get its string representation:

var id = 2;
var dataParams = new FormUrlEncodedContent(
     new KeyValuePair<string, string>[]
     {
         new KeyValuePair<string, string>("name", myname"),                     
         new KeyValuePair<string, string>("id", id.ToString()),
     });

You can make something like this to urlencode complex types with less boilerplate, and it will even look more like the original python code:

public static class HttpUrlEncode
{
    public static FormUrlEncodedContent Encode(Object obj)
    {
        if (obj == null)
            throw new ArgumentNullException("obj");

        var props = obj
            .GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .ToDictionary(
                prop => 
                    prop.Name,
                prop => 
                    (prop.GetValue(obj, null) ?? String.Empty).ToString());

        return new FormUrlEncodedContent(props);
    }
}


var dataParams = HttpUrlEncode.Encode(
    new 
    {
        name = "myname",
        id = 2
    });       


回答2:

If you don't mind a small library dependency, Flurl [disclosure: I'm the author] makes this as short and succinct as your Python sample, maybe more so:

var dataParams = new {
    name: "myname",
    id: 2
};

var result = await "http://api.com".PostUrlEncodedAsync(dataParams).ReceiveString();


回答3:

If your data will contain both number and string values, you can use a KeyValuePair<string,object>, which should accept any of your data. So your code could be:

var contentString = JsonConvert.SerializeObject(
         new KeyValuePair<string, object>[]
         {
             new KeyValuePair<string, object>("name", "myname"),                     
             new KeyValuePair<string, object>("id", 2),
         });
var requestMessage = new HttpRequestMessage(HttpMethod.Post, "URI") {
    Content = new StringContent(contentString)
};
httpResponse = await httpClient.SendAsync(requestMessage);