Как это возможно для Uri.Host, чтобы бросить UriFormatException? - PullRequest
0 голосов
/ 20 октября 2010
foreach (var node in root.Find("a[href]"))
{
    var href = node.Attributes["href"].Value;
    Uri uri;
    try
    {
        uri = new Uri(item.Value.Uri, href);
    }
    catch(UriFormatException)
    {
        continue;
    }
    // *snip*
    try
    {
        if (_imageHosts.IsMatch(uri.Host)) // <--- problematic line
            priority--;
    }catch(UriFormatException)
    {
        MessageBox.Show(uri.OriginalString); // <--- gets displayed when I expected it wouldn't
        continue;
    }
    // *snip*
}

Окно сообщения отображается с адресом вроде

mailto: веб-мастер [@] somehost? Веб-мастер

Что, очевидно, искажено, но я не понимаю, почему он не был пойман первым блоком захвата?

MSDN сообщает , что может бросить только InvalidOperationException. Это довольно проблематично, потому что это означает, что мое приложение может взорваться в любое время!

[[надрез]]

Ответы [ 3 ]

8 голосов
/ 20 октября 2010

Прежде всего, я хочу сказать, что не очень хорошая идея использовать Exception для проверки действительности, потому что вы можете использовать метод Uri.TryCreate .Таким образом, вы можете переписать свой код, а не полагаться на то, какое исключение может быть сгенерировано и перехвачено.

Так что лучше поменяйте

Uri uri;
try
{
    uri = new Uri(item.Value.Uri, href);
}
catch(UriFormatException)
{
    continue;
}

на

Uri uri;
if (!Uri.TryCreate(item.Value.Uri, href, out uri)) continue;

Но этоне полная проверка в любом случае.

Что касается вашего вопроса, ответ относительно прост.Вы ошибаетесь, полагая, что имеет неправильный формат:

mailto: webmaster [@] somehost? Webmaster

URI равен Унифицированный идентификатор ресурса , поэтому его basicсинтаксис

{имя схемы}: {иерархическая часть} [?{query}] [# {фрагмент}]

, очевидно, действительны для вашего ввода.Вы заканчиваете URI ресурса со схемой "mailto:".

Когда вы пытаетесь получить доступ к свойству Host, вы предполагаете, что ресурс был Http, но синтаксический анализатор "mailto", используемый по умолчанию, не может проанализировать исходную строку для хостакомпонент и, следовательно, выдвинутое исключение.

Таким образом, чтобы правильно написать чек, вам нужно немного изменить код:

Uri uri;
if (!Uri.TryCreate(item.Value.Uri, href, out uri)) continue;

if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) continue;

Прочитать некоторую информацию о UriParser


Здесь обновление, основанное на комментариях @Mark.

Я почти уверен, что оно выдало исключение, когда я тоже попытался получить свойство AbsoluteUri ... почему это должно произойти?

Вы не можете пройти проверку Схемы, так как это будет "mailto".Итак, быстрый тест:

        var baseUri = new Uri("http://localhost");
        const string href = "mailto: webmaster [ @ ] somehost ?webmaster";

        Uri uri;
        if (!Uri.TryCreate(baseUri,href, out uri)) 
        {
            Console.WriteLine("Can't create");
            return;
        }

        if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
        {
            Console.WriteLine("Wrong scheme");
            return;
        }

        Console.WriteLine("Testing uri: {0}", uri);

Закончится «Неправильная схема».Может быть, я вас не правильно понимаю?

Когда вы меняете href на:

        const string href = "http: webmaster [ @ ] somehost ?webmaster";

Он прошел правильно, автоматически экранируя uri на:

http://localhost/%20webmaster%20%5B%20@%20%5D%20somehost%20?webmaster

также вам будут доступны все компоненты uri.

Основная проблема, которую я пытаюсь объяснить в первой части, следующая:

Кажется,Вы неправильно воспринимаете любой универсальный идентификатор ресурса как URL-адрес на основе http (s), но это неправильно.mailto:webmaster@somehost.tst или gopher://gopher.hprc.utoronto.ca/ или myreshandler://something@somewhere также допустимый URI, который может быть успешно проанализирован.Взгляните на Официальные схемы, зарегистрированные IANA

Итак

Ожидается и корректно поведение Uri-конструктора.

пытается проверить входящий URI для известных схем :

  • UriSchemeFile - Указывает, что URI является указателем на файл.
  • UriSchemeFtp - Указывает, что доступ к URI осуществляется через протокол передачи файлов (FTP).
  • UriSchemeGopher - Указывает, что доступ к URI осуществляется через протокол Gopher.
  • UriSchemeHttp - Указывает, что доступ к URI осуществляется через протокол передачи гипертекста (HTTP)
  • UriSchemeHttps - Указывает, чтоДоступ к URI осуществляется через безопасный протокол передачи гипертекста (HTTPS).
  • UriSchemeMailto - Указывает, что URI является адресом электронной почты и доступ к нему осуществляется через простой сетевой почтовый протокол (SNMP).
  • UriSchemeNews - Указывает, что URI является новостной группой в Интернете и доступенчерез сетевой транспортный протокол новостей (NNTP).
  • UriSchemeNntp - Указывает, что URI является новостной группой Интернета и доступ к ней осуществляется через сетевой транспортный протокол новостей (NNTP)

Базовый синтаксический анализатор URI используется, когда схема неизвестна (см. Общий синтаксис схемы URI ).


Обычно Uri.TryCreate() и проверок схемы достаточно для получения ссылок, которые можно передать, например, в .NET HttpWebRequest.Вам действительно не нужно проверять, правильно ли они сформированы или нет.Если ссылки плохие (плохо сформированы или не существуют), вы просто получаете соответствующий HttpError при попытке их запросить.

Как в вашем примере:

http://www.google.com/search?q=cheesy poof

он проходит мой чек и становится:

http://www.google.com/search?q=cheesy%20poof

Вам не нужно проверять, хорошо ли этоили нет.Просто сделайте базовые проверки и попробуйте запрос.Надеюсь, это поможет.


Кроме того, строка mailto: webmaster [@] somehost? Webmaster неверна. Я буквально имею в виду эту строку, с глупыми [] и всем в ней

Эта строка неправильно сформирована по смыслу не правильно сформирована (поскольку содержит исключенные символы в соответствии с RFC 2396 ), но все равно может рассматриваться как Действительный из-за соответствия универсального синтаксиса схемы URI (проверьте также, как он избежал, когда создан с http:).

1 голос
/ 21 октября 2010

На основании ответа Ника:

private static readonly string[] SupportedSchmes = { Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeFtp, Uri.UriSchemeFile };

private static bool TryCreateUri(string uriString, out Uri result)
{
    return Uri.TryCreate(uriString, UriKind.Absolute, out result) && SupportedSchmes.Contains(result.Scheme);
}

private static bool TryCreateUri(Uri baseAddress, string relativeAddress, out Uri result)
{
    return Uri.TryCreate(baseAddress, relativeAddress, out result) && SupportedSchmes.Contains(result.Scheme);
}
1 голос
/ 20 октября 2010

Если вы углубитесь в свойство Uri.Host (очень глубокое), оно может в конечном итоге вызвать статическую функцию GetException, которая возвращает UriFormatException объекты для различных условий недопустимых URI.Распечатайте полный UriFormatException, который вы получаете, и сравните его с теми, которые были сгенерированы Uri.GetException.Вы можете получить более подробную информацию из этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...