我将数据发布到一项服务,该服务要求我提交重复的查询字符串键(丑陋且未在任何标准中指定)。
我正在使用WebClient对象来构建请求。我想继续使用它,因为它经常在项目的其他地方使用。
当我这样做时
foreach(var f in formats)
client.QueryString.Add("formats", f);
我收到服务不支持的列表&formats=format_1,format_2,format_3
。
有没有比这种老派丑陋更好的选择:
var extraQueryString = string.Empty;
extraQueryString += "?apiKey=" + TRANSCODE_KEY;
extraQueryString += "&fileKey=" + fileKey;
foreach (var f in formats)
extraQueryString += "&formats=" + f;
var response = client.UploadData(TRANSCODE_URI + "task" + extraQueryString , new byte[] { });
答案 0 :(得分:1)
原因是NameValueCollection
用逗号分隔重复键。您可以扩展NameValueCollection
并覆盖Get
方法,并让它返回您想要的格式。
public class DupeNVC: NameValueCollection
{
private string _duplicateKey;
public DupeNVC(string duplicateKey = null)
{
_duplicateKey = duplicateKey;
}
public override string Get(int index)
{
//check if duplicate key has been specified
//if not, then call the default Get implementation
if (!String.IsNullOrEmpty(_duplicateKey))
{
ArrayList list = (ArrayList)base.BaseGet(index);
int num = (list != null) ? list.Count : 0;
if (num == 1)
{
return (string)list[0];
}
if (num > 1)
{
StringBuilder stringBuilder = new StringBuilder((string)list[0]);
for (int i = 1; i < num; i++)
{
//format our string and append the duplicate key specified
stringBuilder.AppendFormat("&{0}=", _duplicateKey);
stringBuilder.Append((string)list[i]);
}
return stringBuilder.ToString();
}
return null;
}
else
return base.Get(index);
}
}
你可以像普通的NameValueCollection
一样使用它,但是如果你在构造函数中传入一个重复的strning,它会查找该重复的键并运行上面的修改过的代码(否则它只会使用默认的{{ 1}}方法。
base.Get
这尚未经过全面测试,但应输出您想要的查询字符串格式。当然,这可以通过收集重复键来进一步扩展,但这只是为了让您了解当前的问题。
答案 1 :(得分:0)
这是我的看法。 WebClient本质上类似于此类的ToString方法。它获取所有键,然后一次检索一个值,并进行连接。因此,我重写了AllKeys以返回包含重复元素的数组。
例如,如果特定键具有多个值:
nvc["hello"] = { "a", "b", "c" }
然后,我的AllKeys将返回一个带有“ hello”的数组3次。 WebClient会天真地请求3次。字典会跟踪请求“ hello”的次数,然后每次返回一个不同的值(伪枚举器)
public class ParrotingNameValueCollection : NameValueCollection
{
Dictionary<string, int> _indexTracker = new Dictionary<string, int>();
public override string[] AllKeys
{
get
{
var l = new List<string>();
foreach (var k in base.AllKeys)
{
foreach (var x in (ArrayList)base.BaseGet(k))
l.Add(k);
_indexTracker[k] = 0;
}
return l.ToArray();
}
}
public override string Get(string name)
{
var list = (ArrayList)base.BaseGet(name);
var toReturn = (string)list[_indexTracker[name]];
_indexTracker[name]++;
return toReturn;
}
public override string ToString()
{
string delimiter = String.Empty;
StringBuilder values = new StringBuilder();
foreach (string name in this.AllKeys)
{
values.Append(delimiter);
values.Append((name));
values.Append("=");
values.Append((this[name]));
delimiter = "&";
}
return values.ToString();
}
}