如何创建使用GenericUriParserOptions.DontCompressPath解析的Uri实例

当.NET System.Uri类解析字符串时,它会对输入执行一些规范化,例如对方案和主机名进行下限。 它还会修剪每个路径段的尾随时段。 后一个特性对于OpenID应用程序是致命的,因为一些OpenID(如从Yahoo发布的那些)包括base64编码的路径段,其可以以句点结束。

如何禁用Uri类的周期修剪行为?

使用UriParser.Register注册我自己的方案,使用UriParser.Register初始化的解析器可以避免周期修剪,以及其他一些对OpenID也不可取的操作。 但我无法为HTTP和HTTPS等现有方案注册新的解析器,我必须为OpenID做这些。

我尝试的另一种方法是注册我自己的新方案,并编程自定义解析器以将方案更改回标准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。

我很高兴任何解决方案:

  1. Uri.Path保留路径段中的尾随句Uri.Path
  2. 在传出的HTTP请求中包含这些句点。
  3. 理想情况下适用于ASP.NET中等信任(但不是绝对必要)。

微软称它将在.NET 4.0中得到修复(尽管从评论中可以看出它尚未修复)

https://connect.microsoft.com/VisualStudio/feedback/details/386695/system-uri-incorrectly-strips-trailing-dots?wa=wsignin1.0#tabs

但是,该页面上有一种解决方法。 它涉及使用reflection来改变选项,因此它可能不符合中等信任要求。 只需滚动到底部,然后单击“解决方法”选项卡。

感谢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); 

Dang,Brandon Black在打字的时候打败了我…

这可能有助于代码可读性:

 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 } } 

你应该能够逃脱’。’ 使用’%2E’,但这是廉价和肮脏的出路。

您可能会尝试使用dontEscape选项,它可能会改变Uri处理这些字符的方式。

更多信息: http : //msdn.microsoft.com/en-us/library/system.uri.aspx

另请参阅以下内容(请参阅DontUnescapePathDotsAndSlashes):http:// msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx

这有用吗?

 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; }}