当.NET System.Uri
类解析字符串时,它会对输入执行一些规范化操作,例如对方案和主机名进行较低的设置。它还会修剪每个路径段的尾随时段。后一个特性对OpenID应用程序来说是致命的,因为一些OpenID(如雅虎发布的那些)包括base64编码的路径段,可能以句点结束。
如何禁用Uri类的周期修剪行为?
使用UriParser.Register
注册我自己的方案和使用GenericUriParserOptions.DontCompressPath
初始化的解析器,可以避免周期修剪,以及其他一些对OpenID也不可取的操作。但我无法为HTTP和HTTPS等现有方案注册新的解析器,我必须为OpenID做这些。
我尝试的另一种方法是注册我自己的新方案,并编程自定义解析器以将方案更改回标准HTTP(s)方案,作为解析的一部分:
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
答案 0 :(得分:5)
微软称它将在.NET 4.0中修复(尽管从评论中可以看出它还没有修复)
然而,该页面上有一种解决方法。它涉及使用反射来改变选项,因此它可能不符合中等信任要求。只需滚动到底部,然后单击“解决方法”选项卡。
感谢jxdavis和Google的回答:
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/5206beca-071f-485d-a2bd-657d635239c9
答案 1 :(得分:2)
我很好奇,如果问题的一部分是你只考虑“不压缩路径”,而不是基本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
}
}
答案 2 :(得分:1)
你应该能够逃脱'。'使用'%2E',但这是廉价而肮脏的出路。
您可能会尝试使用 dontEscape 选项,这可能会改变Uri处理这些字符的方式。
更多信息: http://msdn.microsoft.com/en-us/library/system.uri.aspx
另请参阅以下内容(请参阅DontUnescapePathDotsAndSlashes): http:// msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx
答案 3 :(得分:1)
这有用吗?
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;
}}