Uri.TryCreate выдает UriFormatException? - PullRequest
11 голосов
/ 13 июля 2009

У меня есть метод, который пытается создать Uri, а затем очистить его (удаляет фрагменты, исключает некоторые домены и шаблоны строк запросов и т. Д.). Метод выглядит так:

static public bool TryCreateCleanUri(Uri baseUri, string relstr, out Uri result)
{
    if (!Uri.TryCreate(baseUri, relstr, out result))
    {
        return false;
    }
    return CleanupUri(result, out result);
}

Этот метод работал отлично в течение нескольких месяцев. Но прошлой ночью это не удалось. Uri.TryCreate () выдал исключение! Вот трассировка стека:

ERROR: Unhandled exception caught.  Program terminating.
System.UriFormatException: Invalid URI: The hostname could not be parsed.
   at System.Uri.CreateHostStringHelper(String str, UInt16 idx, UInt16 end, Flags& flags, String& scopeId)
   at System.Uri.CreateHostString()
   at System.Uri.GetComponentsHelper(UriComponents uriComponents, UriFormat uriFormat)
   at System.Uri.CombineUri(Uri basePart, String relativePart, UriFormat uriFormat)
   at System.Uri.GetCombinedString(Uri baseUri, String relativeStr, Boolean dontEscape, String& result)
   at System.Uri.ResolveHelper(Uri baseUri, Uri relativeUri, String& newUriString, Boolean& userEscaped, UriFormatException& e)
   at System.Uri.TryCreate(Uri baseUri, Uri relativeUri, Uri& result)
   at System.Uri.TryCreate(Uri baseUri, String relativeUri, Uri& result)

Документация для Uri.TryCreate(Uri, String, out Uri) говорит, что возвращаемое значение равно True в случае успеха, False в противном случае, но об исключениях ничего не говорится. Тем не менее, документация для Uri.TryCreate(Uri, Uri, out Uri) гласит:

Этот метод создает URI, помещает это в канонической форме, и подтверждает Это. Если происходит необработанное исключение, этот метод ловит это. Если хотите создать Uri и получить исключения использования один из конструкторов Uri.

Трассировка стека показывает, что исключение было сгенерировано в Uri.TryCreate(Uri, Uri, out Uri), что, согласно документации, не должно происходить.

Это очень редкое явление. Я использовал этот код в течение нескольких месяцев, пропуская через него буквально миллиарды URL, и до сих пор не сталкивался с проблемой. К сожалению, я не знаю, какое сочетание вещей вызвало проблему. Я надеюсь построить тестовый пример, который показывает ошибку.

Это известная ошибка в Uri.TryCreate или я что-то упустил?

Ответы [ 3 ]

18 голосов
/ 22 июля 2009

Не желая ждать несколько месяцев, пока мой код снова столкнется с этой ситуацией, я потратил некоторое время с ILDASM, чтобы выяснить, что делает TryCreate, а затем немного больше времени придумал способ воспроизвести ошибку.

Причиной сбоя в Uri.TryCreate(Uri baseUri, Uri relativeUri, out Uri result) является неправильно отформатированный baseUri. Например, конструктор Uri позволяет следующее:

Uri badUri = new Uri("mailto:test1@mischel.comtest2@mischel.com");

Согласно RFC для URI mailto: это не должно быть разрешено. И хотя конструктор создает и возвращает Uri объект, при попытке доступа (к некоторым из) его свойств выбрасывается UriFormatException. Например, учитывая приведенный выше код, эта строка выдаст исключение:

string badUriString = badUri.AbsoluteUri;

Мне кажется довольно интересным, что класс Uri использует два разных алгоритма синтаксического анализа: один используется во время конструирования, а другой - для получения отдельных компонентов.

Передача этого недействительного Uri в TryCreate приведет к исключению, которое я описал в исходном вопросе. Метод TryCreate проверяет параметр baseUri на null, но не (не могу, я бы предположил) проверить его в противном случае. Следует предположить, что, если параметр не равен NULL, переданный объект является полностью инициализированным и действительным экземпляром Uri. Но в какой-то момент при построении результата TryCreate пытается получить компоненты baseUri и выдается исключение.

Я не могу сказать, что моя программа действительно обнаружила URL mailto:, который был отформатирован таким образом. Тем не менее, я могу с некоторой степенью уверенности сказать, что причиной сбоя в моей программе стал неверный объект Uri, просто потому, что трассировка стека исключений из моей программы совпадает с трассировкой стека из тестовой программы. Проще говоря, ошибка заключается в конструкторе Uri (а также в методах TryCreate), которые позволяют создавать недействительный Uri.

Вы можете следить за сообщением об ошибке в Microsoft Connect.

3 голосов
/ 13 июля 2009

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

static public bool TryCreateCleanUri(Uri baseUri, string relstr, out Uri result)
{
    try {
        if (!Uri.TryCreate(baseUri, relstr, out result))
        {
            return false;
        }
    }
    catch (UriFormatException ex) {
        throw new InalidOperationException(
            String.Format("Can create URI for base={0}, rel={1}", baseUri.ToString(), relstr),
            ex);
    }        
    return CleanupUri(result, out result);
}
0 голосов
/ 20 июля 2016
 public static bool CheckUrlValid(string url)
    {
        Uri uriResult;
        bool result = Uri.TryCreate(url, UriKind.Absolute, out uriResult);
        if(result)
        {
            uriResult = new Uri(url);
            if (uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp)
                return true;
        }

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