C# 如何创建使用GenericUriParserOptions.DontCompressPath解析的Uri实例
当.NETC# 如何创建使用GenericUriParserOptions.DontCompressPath解析的Uri实例,c#,.net,http,uri,C#,.net,Http,Uri,当.NETSystem.Uri类解析字符串时,它会对输入执行一些规范化,例如将方案和主机名的大小写降低。它还修剪每个路径段的尾随周期。后一个特性对OpenID应用程序来说是致命的,因为某些OpenID(如Yahoo发布的那些)包含base64编码的路径段,这些路径段可能以句点结束 如何禁用Uri类的此期间修剪行为? 使用UriParser注册我自己的方案。使用GenericUriParserOptions初始化的解析器注册。DontCompressPath避免了周期修剪,以及OpenID不需要的
System.Uri
类解析字符串时,它会对输入执行一些规范化,例如将方案和主机名的大小写降低。它还修剪每个路径段的尾随周期。后一个特性对OpenID应用程序来说是致命的,因为某些OpenID(如Yahoo发布的那些)包含base64编码的路径段,这些路径段可能以句点结束
如何禁用Uri类的此期间修剪行为?
使用UriParser注册我自己的方案。使用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中的路径段中保留尾随句点
您应该能够使用“%2E”避免“.”,但这是一种既便宜又肮脏的方法 您可以尝试稍微使用dontEscape选项,它可能会改变Uri处理这些角色的方式 更多信息请点击此处: 另请查看以下内容(请参见DonTuneScapePathDots和Slashes):
http://msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx微软表示它将在.NET 4.0中得到修复(尽管从评论中可以看出它还没有被修复) 然而,在这一页上有一个解决办法。但是,它涉及使用反射来更改选项,因此可能无法满足中等信任要求。只需滚动到底部并单击“变通方法”选项卡 感谢jxdavis和谷歌的回答:
我很好奇,问题的一部分是否在于您只考虑了“不压缩路径”,而不是基本HTTP解析器的所有默认值:(包括UnEscapeDotsAndSlashes) 这与有标志的新闻相反(例如): 该死,布兰登·布莱克在我打字的时候打败了我 这可能有助于提高代码可读性:
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;
}}
如果您的示例代码是失败的单元测试,则说明问题所在会更容易。单元测试必须设置HTTPS web服务器来证明失败:(你是否成功地解决了这个问题?你还需要帮助吗?是的,通过复杂的混合反射(当完全信任可用时)当完全信任不可用时,还有其他魔术。中的大部分代码都致力于玩所有必要的把戏,以获得99%的正确行为。对不起,应该在m_表上进行反思并删除现有条目。如果从
GenericUriParser?这正是我添加上述注释的原因:-)我的意思是设置m_表而不是m_标志。不幸的是,MS Connect错误已过时。NET团队直接告诉我,.NET4.0不能修复dot bug。但解决办法很有趣。谢谢。死链接(connect.microsoft.com)。第二个链接指向页面底部的。谢谢,布兰登。DontUnescapePathDotsAndSlashes
选项是一种可能的解决方法,但要有效地工作,它需要应用于现有的HTTP和HTTPS解析器,这仅在.NET 4.0中是可能的(除非您按照此处其他答案中的建议使用反射)。
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;
}}