如何使用c#webclient将值上传为数组?例如items [] =“ foo” items [] =“ foo2”

时间:2019-06-19 12:38:32

标签: c# webclient

如何使用c#webclient上传作为数组的参数?

    public string CallWebService(string url, NameValueCollection parametres, string HttpVerb = "GET")
    {
        WebClient myWebClient = new WebClient();
        byte[] myresponse = myWebClient.UploadValues(url, HttpVerb, parametres);
        // on essaye de récuopérer l'encoding depuis les headers
        // sinon on utilise l'encoding par defaut           
        Encoding encoding;
        encoding = WebUtils.GetEncodingFrom(myWebClient.ResponseHeaders, Encoding.Default);
        return encoding.GetString(myresponse);
    }
CallWebService(url, new NameValueCollection {
            { "type_pj", "99_AU" },
            { "type_pj", "41_NC" },
            { "type_pj", "41_NC" }
}, "PATCH")

无法理解服务器端。它被视为一个字符串“ 99_AU,41_NC,41_NC”。 如果我使用

CallWebService(url, new NameValueCollection {
            { "type_pj[]", "99_AU" },
            { "type_pj[]", "41_NC" },
            { "type_pj[]", "41_NC" }
}, "PATCH")

它被视为一个数组,但仅包含一个字符串[“ 99_AU,41_NC,41_NC”]

以下卷曲正确。

curl -X PATCH \  https://... \  -d 'type_pj%5B%5D=99_AU&type_pj%5B%5D=41_NC&type_pj%5B%5D=41_NC'

服务器将其视为由3个字符串组成的数组[“ 99_AU”,“ 41_NC”,“ 41_NC”]

如何使用网络客户端实现相同的目的?

[编辑]

好像我混淆了System.Collections.Specialized.NameValueCollection和System.Web.HttpValueCollection(这也是NameValueCollection,但具有附加功能)

        var nv = new NameValueCollection {};
        nv.Add("type_pj[]", "99_AU");
        nv.Add("type_pj[]", "41_NC");
        nv.Add("withcomma", "text,with,comma");
        nv.Add("type_pj[]", "41_NC");
=> nv["type_pj[]"] = "99_AU,41_NC,41_NC" // = nv[0]
=> nv["withcomma"] = "text,with,comma" // = nv[1]

        var hv = HttpUtility.ParseQueryString(string.Empty);
        hv.Add("type_pj[]", "99_AU");
        hv.Add("type_pj[]", "41_NC");
        hv.Add("withcomma", "text,with,comma");
        hv.Add("type_pj[]", "41_NC");
        string resp = hv.ToString();

=> hv["type_pj[]"] = "99_AU,41_NC,41_NC" // = hv[0]
=> hv["withcomma"] = "text,with,comma" // = hv[1]

在HttpValueCollection中,当为现有键添加新值时,它看起来像是将新值ti与先前的值连接在一起,但在幕后它也存储在数组中。

=> hv.GetValues("type_pj[]") = ["99_AU","41_NC","41_NC"] // !!! Array of 3 strings
=> hv.GetValues("withcomma[]") = ["text,with,comma"] // !!! Array of 1 strings

HttpValueCollection有一个ToString()方法,该方法为您执行url编码,并保留数组struct!

=> hv.ToString() ="type_pj%5b%5d=99_AU&type_pj%5b%5d=41_NC&type_pj%5b%5d=41_NC&withcomma=text%2cwith%2ccomma"

所以最好的解决方案可能是使用elgonzo建议的uploadString。但是,可以使用HttpValueCollection而不是使用Lis,该方法的ToString()方法将为您处理urlencoding。

1 个答案:

答案 0 :(得分:0)

您面临的问题是由于使用 NamedValueCollection 。如果在调试器中检查您的 NamedValueCollection 的内容,您会注意到它只用一个键就可以汇总所有值。这是因为您提供给 NamedValueCollection 的名称键都是相同的。

为避免这种情况,您将必须手动生成数据有效负载字符串。为了简化我在下面的答案中的Linq Select语句,我切换到一个不根据键的唯一性来组织键/值对的集合。例如,您可以使用如下列表:

var parameters = new List<KeyValuePair<string, string>>
{
    new KeyValuePair<string,string>("type_pj[]", "99_AU"),
    new KeyValuePair<string,string>("type_pj[]", "41_NC"),
    new KeyValuePair<string,string>("type_pj[]", "41_NC")
};

基于此集合,您可以然后“手动”组成数据有效负载字符串,同时还要确保名称和值均正确转义:

var dataPayload = string.Join(
    "&",
    parameters.Select(kvp => $"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}")
);

(执行此操作的方式和方式肯定不同;我的示例仅是一般方法的说明。)

缺少的最后一步是实际发送编码的有效负载字符串并接收服务器响应。根据问题中的代码,您期望服务器响应为文本。幸运的是, WebClient 具有一个上载方法,该方法既可以接受要作为字符串上传的数据,又可以将服务器响应作为字符串返回:UploadString。根据服务器的特定要求,您可能还需要明确指定内容类型。

var myWebClient = new WebClient();
myWebClient.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
string responseString = myWebClient.UploadString(url, "PATCH", dataPayload);

正如@frenchone在评论中指出的那样,也可以从 NameValueCollection 生成编码的数据有效负载字符串,尽管使用的是稍微复杂一点的Linq语句:

var parameters = NameValueCollection
{
    { "type_pj[]", "99_AU" },
    { "type_pj[]", "41_NC" },
    { "type_pj[]", "41_NC" }
}

var dataPayload = string.Join(
    "&",
    parameters.AllKeys.SelectMany(
        key => parameters.GetValues(key).Select(val => $"{Uri.EscapeDataString(key)}={Uri.EscapeDataString(val)}")
    )
);