Класс System.Uri

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

Универсальный код ресурса (URI) — это компактное представление ресурса, доступного вашему приложению в интрасети или в Интернете. Класс Uri определяет свойства и методы обработки URI, включая синтаксический анализ, сравнение и объединение. Uri Свойства класса доступны только для чтения; для создания изменяемого объекта используйте UriBuilder класс.

Относительные URI (например, "/new/index.htm") должны быть расширены относительно базового URI, чтобы они были абсолютными. Этот MakeRelativeUri метод предоставляется для преобразования абсолютных URI в относительные URI при необходимости.

Конструкторы Uri не экранировать строки URI, если строка является хорошо сформированным URI, включая идентификатор схемы.

Свойства Uri возвращают каноническое представление данных в escape-кодировке, при этом все символы со значениями Юникода больше 127 заменены шестнадцатеричными эквивалентами. Чтобы поместить универсальный код ресурса (URI) в каноническую форму, Uri конструктор выполняет следующие действия:

  • Преобразует схему URI в нижний регистр.

  • Преобразует имя узла в нижний регистр.

  • Если имя узла является IPv6-адресом, используется канонический IPv6-адрес. ScopeId и другие необязательные данные IPv6 удаляются.

  • Удаляет номера портов по умолчанию и пустые.

  • Преобразует неявные пути к файлам без схемы file:// (например, "C:\my\file") в явные пути к файлам с помощью схемы file://.

  • Экранированные символы (также известные как октеты в кодировке процента), которые не имеют зарезервированной цели, декодируются (также известные как незакрытые). К этим незарегистрационным символам относятся прописные и строчные буквы (%41-%5A и %61-%7A), десятичные цифры (%30-%39), дефис (%2D), период (%2E), подчеркивание (%5F) и тильда (%7E).

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

  • Для иерархических URI узел не завершается косой чертой (/), добавляется.

  • По умолчанию все зарезервированные символы в URI экранируются в соответствии с RFC 2396. Это поведение изменяется, если включена функция синтаксического анализа международных идентификаторов ресурсов или международного доменного имени, в этом случае зарезервированные символы в URI экранируются в соответствии с RFC 3986 и RFC 3987.

Как часть канонизации в конструкторе для некоторых схем, точек и пустых сегментов (/./, /../и //) сжимаются (иными словами, удаляются). Схемы, для которых Uri компактные сегменты включают http, https, tcp, net.pipe и net.tcp. Для некоторых других схем эти последовательности не сжимаются. В следующем фрагменте кода показано, как выглядит сжатие на практике. Экранированные последовательности не отображаются при необходимости, а затем сжимаются.

var uri = new Uri("http://myUrl/../.."); // http scheme, unescaped
OR
var uri = new Uri("http://myUrl/%2E%2E/%2E%2E"); // http scheme, escaped
OR
var uri = new Uri("ftp://myUrl/../.."); // ftp scheme, unescaped
OR
var uri = new Uri("ftp://myUrl/%2E%2E/%2E%2E"); // ftp scheme, escaped

Console.WriteLine($"AbsoluteUri: {uri.AbsoluteUri}");
Console.WriteLine($"PathAndQuery: {uri.PathAndQuery}");

При выполнении этого кода он возвращает выходные данные, аналогичные следующему тексту.

AbsoluteUri: http://myurl/
PathAndQuery: /

Вы можете преобразовать содержимое Uri класса из ссылки на URI в кодированном escape-коде в ссылку на доступный для чтения универсальный код ресурса (URI) с помощью ToString метода. Обратите внимание, что некоторые зарезервированные символы по-прежнему могут быть экранированы в выходных данных ToString метода. Это позволяет обеспечить однозначное восстановление универсального кода ресурса (URI) из возвращаемого ToStringзначения.

Некоторые URI включают идентификатор фрагмента или запрос или оба. Идентификатор фрагмента — это любой текст, который следует знаку номера (#), не включая знак номера; Текст фрагмента хранится в свойстве Fragment . Сведения о запросе — это любой текст, следующий за вопросительным знаком (?) в URI; Текст запроса хранится в свойстве Query .

Примечание.

Класс URI поддерживает использование IP-адресов в четырехнамерной нотации для протокола IPv4 и шестнадцатеричного двоеточия для протокола IPv6. Не забудьте заключить адрес IPv6 в квадратные скобки, как в http://[::1].

Поддержка международного идентификатора ресурса

Веб-адреса обычно выражаются с помощью универсальных идентификаторов ресурсов, состоящих из очень ограниченного набора символов:

  • буквы верхнего и нижнего регистра английского алфавита в кодировке ASCII;
  • цифры от 0 до 9;
  • небольшое количество других символов ASCII.

Спецификации для URI описаны в RFC 2396, RFC 2732, RFC 3986 и RFC 3987, опубликованных рабочей задачей Интернета (IETF).

Идентификаторы, которые упрощают идентификацию ресурсов с помощью языков, отличных от английского, и разрешают символы, отличные от ASCII (символы в наборе символов Юникода или ISO 10646), называются международными идентификаторами ресурсов (IRIs). Спецификации IRI документально зафиксированы в стандарте RFC 3987, опубликованном IETF. Использование IRI позволяет применять в URL символы Юникода.

В платформа .NET Framework версии 4.5 и более поздних версий IRI всегда включена и не может быть изменена с помощью параметра конфигурации. Параметр конфигурации можно задать в файле machine.config или в файле app.config , чтобы указать, требуется ли синтаксический анализ имени домена (IDN), примененного к доменному имени. Например:

<configuration>
  <uri>
    <idn enabled="All" />
  </uri>
</configuration>

Включение IDN преобразует все метки Юникода в доменное имя в эквиваленты Punycode. Имена Punicode содержат только символы ASCII и всегда начинаются с префикса "xn--". Это сделано для того, чтобы поддерживать существующие DNS-серверы в интрасети, так как большинство DNS-серверов поддерживает только символы ASCII (см. RFC 3940).

Включение идентификатора Uri.DnsSafeHost влияет на значение свойства. Включение idN также может изменить поведение Equalsметодов и GetComponentsIsWellFormedOriginalString методов. OriginalString

В зависимости от используемых DNS-серверов можно использовать три возможных значения идентификаторов:

  • idn enabled = All

    Это значение преобразует любые доменные имена Юникода в эквиваленты Punycode (имена IDN).

  • idn enabled = AllExceptIntranet

    Это значение преобразует все доменные имена Юникода, а не в локальной интрасети, чтобы использовать эквиваленты Punycode (имена IDN). В этом случае для обработки международных имен в локальной интрасети DNS-серверы, используемые для интрасети, должны поддерживать разрешение имен Юникода.

  • idn enabled = None

    Это значение не преобразует доменные имена Юникода в использование Punycode. Это значение по умолчанию.

Нормализация и проверка символов выполняются в соответствии с последними правилами IRI в RFC 3986 и RFC 3987.

Обработку IRI и IDN в Uri классе также можно контролировать с помощью System.Configuration.IriParsingElementSystem.Configuration.IdnElementклассов параметров конфигурации и System.Configuration.UriSection параметров конфигурации. Параметр System.Configuration.IriParsingElement включает или отключает обработку IRI в классе Uri. Параметр System.Configuration.IdnElement включает или отключает обработку IDN в классе Uri.

Параметр конфигурации для и System.Configuration.IriParsingElementSystem.Configuration.IdnElement считывается один раз при создании первого System.Uri класса. Изменения, внесенные в параметры конфигурации после этого, игнорируются.

Расширен был также и класс System.GenericUriParser, который теперь позволяет создавать настраиваемые средства синтаксического анализа, поддерживающие IRI и IDN. Поведение объекта System.GenericUriParser задается путем передачи побитового сочетания значений, доступных в перечислении System.GenericUriParserOptions, конструктору System.GenericUriParser. Тип GenericUriParserOptions.IriParsing указывает на то, что средство синтаксического анализа поддерживает правила анализа, определенные стандартом RFC 3987 для международных кодов ресурсов (IRI).

Тип GenericUriParserOptions.Idn указывает, что средство синтаксического анализа поддерживает синтаксический анализ имени домена (IDN). В .NET 5 и более поздних версиях (включая .NET Core) и платформа .NET Framework 4.5+, идентификаторы всегда используются. В предыдущих версиях параметр конфигурации определяет, используется ли идентификатор idN.

Поддержка неявного пути к файлу

Uri также можно использовать для представления путей локальной файловой системы. Эти пути можно представить явным образом в URI, которые начинаются с схемы file:// и неявно в URI, которые не имеют схемы file://. В качестве конкретного примера следующие два URI являются допустимыми и представляют один и тот же путь к файлу:

Uri uri1 = new Uri("C:/test/path/file.txt") // Implicit file path.
Uri uri2 = new Uri("file:///C:/test/path/file.txt") // Explicit file path.

Эти неявные пути к файлам не соответствуют спецификации URI и поэтому следует избегать, когда это возможно. При использовании .NET Core в системах на основе Unix неявные пути к файлам могут быть особенно проблемными, так как абсолютный неявный путь к файлу неотличим от относительного пути. Если такая неоднозначность присутствует, Uri по умолчанию следует интерпретировать путь как абсолютный универсальный код ресурса (URI).

Вопросы безопасности

Из-за проблем безопасности приложение должно использовать осторожность при принятии Uri экземпляров из ненадежных источников и с dontEscape заданным значением true в конструкторе. Можно проверка строку URI для допустимости, вызвав IsWellFormedOriginalString метод.

При работе с ненадежными входными данными пользователя подтвердите предположения о вновь созданном Uri экземпляре перед доверием к его свойствам. Это можно сделать следующим образом:

string userInput = ...;

Uri baseUri = new Uri("https://myWebsite/files/");

if (!Uri.TryCreate(baseUri, userInput, out Uri newUri))
{
    // Fail: invalid input.
}

if (!baseUri.IsBaseOf(newUri))
{
    // Fail: the Uri base has been modified - the created Uri is not rooted in the original directory.
}

Эту проверку можно использовать в других случаях, например при работе с UNC-путями, просто изменив следующее baseUri:

Uri baseUri = new Uri(@"\\host\share\some\directory\name\");

Замечания, связанные с быстродействием

При использовании файла web.config, содержащего URI для инициализации приложения, необходимо дополнительное время для обработки URI, если их идентификаторы схемы являются нестандартными. В таком случае инициализировать затронутые части приложения при необходимости URI, а не во время начала.