我尝试为电影网站构建搜索查询,而我作为欧洲人,我们有一些奇怪的角色。
这是我的起始代码:
private static string GetSearchUrl(string name)
{
var uriBuilder = new UriBuilder("https://www.themoviedb.org/search");
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("query", name);
uriBuilder.Query = query.ToString();
var searchUrl = uriBuilder.ToString();
return searchUrl;
}
这些是我的测试用例:
const string Source = "Zur Hölle mit den Paukern";
const string Source = "Astérix & Obélix";
当我在
net6.0
中创建单元测试库时,一切都很好,结果是:
https://www.themoviedb.org:443/search?query=Zur+H%c3%b6lle+mit+den+Paukern
https://www.themoviedb.org:443/search?query=Ast%c3%a9rix+%26+Ob%c3%a9lix
但是,在我的目标框架中运行完全相同的功能
net481
我明白了
https://www.themoviedb.org:443/search?query=Zur+H%u00f6lle+mit+den+Paukern
https://www.themoviedb.org:443/search?query=Ast%u00e9rix+%26+Ob%u00e9lix
ö
字符在 %c3%b6
中编码为 net6.0
,但在 %u00f6
中编码为 net481
。
é
在 %c3%a9
中编码为 net6.0
,但在 %u00e9
中编码为 net481
。
这不能用作调用 URL(至少在 themoviedb.org 上不能)
我首先尝试将编码从 UTF-8 转换为 Windows-1252:
var win1252 = Encoding.GetEncoding(1252).GetString(Encoding.UTF8.GetBytes(name));
query.Add("query", win1252);
但这没有什么区别。
我也在不同的地方玩过
Uri.EscapeDataString()
,但这通常会让事情变得更糟。
在
net6.0
中,query
后面的实际类型是
System.Collections.Specialized.NameValueCollection
{System.Web.HttpUtility.HttpQSCollection}
在
net481
是
System.Collections.Specialized.NameValueCollection
{System.Web.HttpValueCollection}
但这些是
HttpUtility.ParseQueryString()
调用返回的内部实现
在 Heretic Monkey 的帮助下,我决定编写自己版本的 QueryBuilder,它可以在
net6.0
和 net481
中实现我的目的:
public sealed class HttpGetQueryBuilder
{
private readonly Dictionary<string, string> _queryParameters;
public HttpGetQueryBuilder()
{
_queryParameters = new Dictionary<string, string>();
}
public HttpGetQueryBuilder(string query)
: this()
{
var keyValues = HttpUtility.ParseQueryString(query);
foreach (var key in keyValues.AllKeys)
{
this.Add(key, keyValues[key]);
}
}
public string this[string key]
{
get => _queryParameters[key];
set => _queryParameters[key] = value;
}
public void Add(string key, string value)
=> _queryParameters.Add(key, value);
public override string ToString()
{
var queryBuilder = new StringBuilder();
var keyIndex = 0;
foreach (var keyValue in _queryParameters)
{
queryBuilder.Append($"{Uri.EscapeDataString(keyValue.Key)}={Uri.EscapeDataString(keyValue.Value)}");
keyIndex++;
if (keyIndex < _queryParameters.Count)
{
queryBuilder.Append('&');
}
}
return queryBuilder.ToString();
}
}