Когда.NET System.Uri
класс анализирует строки, он выполняет некоторую нормализацию на входе, таком как печатание строчными литерами схемы и имени хоста. Это также обрезает запаздывание периодов от каждого сегмента контура. Эта последняя функция является фатальной для приложений OpenID, потому что некоторые OpenIDs (как выпущенные от Yahoo) включают закодированные сегменты контура base64, которые могут закончиться периодом.
Как я могу отключить это обрезающее период поведение класса Uri?
Регистрация моего собственного использования схемы UriParser.Register
с синтаксическим анализатором, инициализированным с GenericUriParserOptions.DontCompressPath
избегает периода, обрезая и некоторых других операций, которые являются также нежелательным для OpenID. Но я не могу зарегистрировать новый синтаксический анализатор для существующих схем как HTTP и HTTPS, который я должен сделать для OpenIDs.
Другой подход, который я попробовал, регистрировал мою собственную новую схему и программировал пользовательский синтаксический анализатор для возврата схемы к стандартным схемам HTTP как часть парсинга:
public class MyUriParser : GenericUriParser
{
private string actualScheme;
public MyUriParser(string actualScheme)
: base(GenericUriParserOptions.DontCompressPath)
{
this.actualScheme = actualScheme.ToLowerInvariant();
}
protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
{
string result = base.GetComponents(uri, components, format);
// Substitute our actual desired scheme in the string if it's in there.
if ((components & UriComponents.Scheme) != 0)
{
string registeredScheme = base.GetComponents(uri, UriComponents.Scheme, format);
result = this.actualScheme + result.Substring(registeredScheme.Length);
}
return result;
}
}
class Program
{
static void Main(string[] args)
{
UriParser.Register(new MyUriParser("http"), "httpx", 80);
UriParser.Register(new MyUriParser("https"), "httpsx", 443);
Uri z = new Uri("httpsx://me.yahoo.com/b./c.#adf");
var req = (HttpWebRequest)WebRequest.Create(z);
req.GetResponse();
}
}
Это на самом деле почти работает. Uri
экземпляр сообщает о https вместо httpsx везде - кроме Uri. Само свойство Scheme. Это - проблема, когда Вы передаете это Uri
экземпляр к HttpWebRequest
отправить запрос к этому адресу. По-видимому, это проверяет свойство Scheme и не распознает его как 'https', потому что это просто отправляет простой текст в 443 порта вместо SSL.
Я рад за любое решение что:
Uri.Path
Microsoft заявляет, что это будет исправлено в .NET 4.0 (хотя из комментариев видно, что это еще не исправлено)
Однако на этой странице есть обходной путь. Однако он включает использование отражения для изменения параметров, поэтому он может не соответствовать требованию среднего доверия. Просто прокрутите вниз и нажмите вкладку «Временные решения».
Спасибо jxdavis и Google за этот ответ:
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/5206beca-071f-485d-a2bd-657d635239c9
Мне любопытно, если часть проблемы заключается в том, что вы учитываете только «не сжимать путь», вместо всех значений по умолчанию базового парсера HTTP: (включая UnEscapeDotsAndSlashes)
private const UriSyntaxFlags HttpSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.AllowIdn | UriSyntaxFlags.UnEscapeDotsAndSlashes | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.CompressPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MustHaveAuthority);
Это в отличие от новостей, в которых есть флаги (например):
private const UriSyntaxFlags NewsSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHavePath);
Черт, Брэндон Блэк опередил меня, пока я печатал что-то вверх ...
Это может улучшить читаемость кода:
namespace System
{
[Flags]
internal enum UriSyntaxFlags
{
AllowAnInternetHost = 0xe00,
AllowAnyOtherHost = 0x1000,
AllowDnsHost = 0x200,
AllowDOSPath = 0x100000,
AllowEmptyHost = 0x80,
AllowIdn = 0x4000000,
AllowIPv4Host = 0x400,
AllowIPv6Host = 0x800,
AllowIriParsing = 0x10000000,
AllowUncHost = 0x100,
BuiltInSyntax = 0x40000,
CanonicalizeAsFilePath = 0x1000000,
CompressPath = 0x800000,
ConvertPathSlashes = 0x400000,
FileLikeUri = 0x2000,
MailToLikeUri = 0x4000,
MayHaveFragment = 0x40,
MayHavePath = 0x10,
MayHavePort = 8,
MayHaveQuery = 0x20,
MayHaveUserInfo = 4,
MustHaveAuthority = 1,
OptionalAuthority = 2,
ParserSchemeOnly = 0x80000,
PathIsRooted = 0x200000,
SimpleUserSyntax = 0x20000,
UnEscapeDotsAndSlashes = 0x2000000,
V1_UnknownUri = 0x10000
}
}
Это работает?
public class MyUriParser : UriParser
{
private string actualScheme;
public MyUriParser(string actualScheme)
{
Type type = this.GetType();
FieldInfo fInfo = type.BaseType.GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
fInfo.SetValue(this, GenericUriParserOptions.DontCompressPath);
this.actualScheme = actualScheme.ToLowerInvariant();
}
protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
{
string result = base.GetComponents(uri, components, format);
// Substitute our actual desired scheme in the string if it's in there.
if ((components & UriComponents.Scheme) != 0)
{
string registeredScheme = base.GetComponents(uri, UriComponents.Scheme, format);
result = this.actualScheme + result.Substring(registeredScheme.Length);
}
return result;
}}
Вы должны быть в состоянии избежать "." используя "% 2E", но это дешевый и грязный выход.
Вы можете попробовать немного поиграть с опцией dontEscape , и это может изменить то, как Ури обращается с этими персонажами.
Дополнительная информация здесь: http://msdn.microsoft.com/en-us/library/system.uri.aspx
Также проверьте следующее (см. DontUnescapePathDotsAndSlashes): { {1}} http: // msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx