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

how to upload values as array using c# webclient ? eg items[]="foo" items[]="foo2"

如何使用 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得到它的权利。

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 中,当您为现有键添加新值时,它看起来像是将新值与前一个值连接起来,但实际上它也存储在数组中。

=> 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 编码并保留数组结构!

=> 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() 方法将为您处理 url 编码。

您遇到的问题是由于使用了 NamedValueCollection。如果您在调试器中检查 NamedValueCollection 的内容,您会注意到它将所有值聚合在一个键下。这是因为您提供给 NamedValueCollection 的名称键完全相同。

为避免这种情况,您必须手动生成数据负载字符串。为了让我的回答中下面的 Linq Select 语句变得简单,我切换到一个集合,该集合不根据键的唯一性组织 key/value 对。例如,您可以使用这样的列表:

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

基于此集合,您可以 "manually" 编写数据负载字符串,同时确保名称和值都已正确转义:

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