System.Net.Uri с символами urlencoded
Мне нужно запросить следующий URL-адрес внутри моего приложения:
http://feedbooks.com/type/Crime%2FMystery/books/top
Когда я запускаю следующий код:
Uri myUri = new Uri("http://feedbooks.com/type/Crime%2FMystery/books/top");
Конструктор Uri
декодирует %2F
в литерал /
, и я получаю ошибку 404, потому что он изменил URL-адрес на:
http://feedbooks.com/type/Crime/Mystery/books/top
Класс Uri
имеет конструктор, который принимает параметр dontEscape
, но этот конструктор устарел и установка его в true
не имеет эффекта.
Моя первая мысль заключалась в том, чтобы сделать что-то вроде:
Uri myUri = new Uri("http://feedbooks.com/type/Crime%252FMystery/books/top");
С надеждой на то, что он преобразует %25
в литерал %
, но это тоже не сработало.
Любые идеи о том, как создать правильный объект Uri
для этого конкретного URL-адреса в .NET?
Ответы
Ответ 1
Я столкнулся с той же проблемой, используя 2.0...
Я обнаружил обходное решение, опубликованное в этом блоге:
// System.UriSyntaxFlags is internal, so let duplicate the flag privately
private const int UnEscapeDotsAndSlashes = 0x2000000;
public static void LeaveDotsAndSlashesEscaped(Uri uri)
{
if (uri == null)
{
throw new ArgumentNullException("uri");
}
FieldInfo fieldInfo = uri.GetType().GetField("m_Syntax", BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo == null)
{
throw new MissingFieldException("'m_Syntax' field not found");
}
object uriParser = fieldInfo.GetValue(uri);
fieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo == null)
{
throw new MissingFieldException("'m_Flags' field not found");
}
object uriSyntaxFlags = fieldInfo.GetValue(uriParser);
// Clear the flag that we don't want
uriSyntaxFlags = (int)uriSyntaxFlags & ~UnEscapeDotsAndSlashes;
fieldInfo.SetValue(uriParser, uriSyntaxFlags);
}
Он отлично работает.
Надеюсь, что это поможет (лучше поздно, чем никогда!)
Ответ 2
Это немного проще в .NET 4.0. Вы можете поместить параметр в свой конфигурационный файл следующим образом:
<uri>
<schemeSettings>
<add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
</schemeSettings>
</uri>
Он работает только для схем "http" и "https".
Или здесь новая версия метода LeaveDotsAndSlashesEscaped. Он не нуждается в конкретном экземпляре Uri, просто назовите его, когда ваше приложение запустится:
private void LeaveDotsAndSlashesEscaped()
{
var getSyntaxMethod =
typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic);
if (getSyntaxMethod == null)
{
throw new MissingMethodException("UriParser", "GetSyntax");
}
var uriParser = getSyntaxMethod.Invoke(null, new object[] { "http" });
var setUpdatableFlagsMethod =
uriParser.GetType().GetMethod("SetUpdatableFlags", BindingFlags.Instance | BindingFlags.NonPublic);
if (setUpdatableFlagsMethod == null)
{
throw new MissingMethodException("UriParser", "SetUpdatableFlags");
}
setUpdatableFlagsMethod.Invoke(uriParser, new object[] {0});
}
Ответ 3
Это ошибка Я подал некоторое время назад. Он должен быть исправлен в 4.0, но я не задерживаю дыхание. По-видимому, это все еще проблема в RC.
Ответ 4
Объединив два предыдущих ответа, вы можете получить метод, который вам нужно будет только один раз на один процесс, который работает как на .net 4, так и на .net 3.5.
// System.UriSyntaxFlags is internal, so let duplicate the flag privately
private const int UnEscapeDotsAndSlashes = 0x2000000;
private void LeaveDotsAndSlashesEscaped()
{
var getSyntaxMethod =
typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic);
if (getSyntaxMethod == null)
{
throw new MissingMethodException("UriParser", "GetSyntax");
}
var uriParser = getSyntaxMethod.Invoke(null, new object[] { "http" });
FieldInfo flagsFieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance);
if (flagsFieldInfo == null)
{
throw new MissingFieldException("UriParser", "m_Flags");
}
int flags = (int) flagsFieldInfo.GetValue(uriParser);
// unset UnEscapeDotsAndSlashes flag and leave the others untouched
flags = flags & ~UnEscapeDotsAndSlashes;
flagsFieldInfo.SetValue(uriParser, flags);
}