Подтвердить что ты не робот

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?

4b9b3361

Ответ 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);

}