Uri.TryCreate抛出UriFormatException?
我有一个方法,尝试创建一个Uri,然后清理它(删除片段,排除一些域和查询字符串模式等)。 该方法如下所示:
static public bool TryCreateCleanUri(Uri baseUri, string relstr, out Uri result) { if (!Uri.TryCreate(baseUri, relstr, out result)) { return false; } return CleanupUri(result, out result); }
这种方法已经好几个月了。 但是昨晚它失败了。 Uri.TryCreate()抛出exception! 这是堆栈跟踪:
ERROR: Unhandled exception caught. Program terminating. System.UriFormatException: Invalid URI: The hostname could not be parsed. at System.Uri.CreateHostStringHelper(String str, UInt16 idx, UInt16 end, Flags& flags, String& scopeId) at System.Uri.CreateHostString() at System.Uri.GetComponentsHelper(UriComponents uriComponents, UriFormat uriFormat) at System.Uri.CombineUri(Uri basePart, String relativePart, UriFormat uriFormat) at System.Uri.GetCombinedString(Uri baseUri, String relativeStr, Boolean dontEscape, String& result) at System.Uri.ResolveHelper(Uri baseUri, Uri relativeUri, String& newUriString, Boolean& userEscaped, UriFormatException& e) at System.Uri.TryCreate(Uri baseUri, Uri relativeUri, Uri& result) at System.Uri.TryCreate(Uri baseUri, String relativeUri, Uri& result)
Uri.TryCreate(Uri, String, out Uri)
文档说如果成功则返回值为True
,否则返回False
,但它对exception没有提及。 但是, Uri.TryCreate(Uri, Uri, out Uri)
文档说:
此方法构造URI,将其置于规范forms,并validation它。 如果发生未处理的exception,则此方法捕获它。 如果要创建Uri并获取exception,请使用其中一个Uri构造函数。
堆栈跟踪显示exception是在Uri.TryCreate(Uri, Uri, out Uri)
引发的,根据文档,这不应该发生。
这种情况非常罕见。 几个月来我一直在使用该代码,通过它运行数十亿个URL,直到现在才遇到问题。 不幸的是我不知道是什么组合导致了这个问题。 我希望构建一个显示错误的测试用例。
这是Uri.TryCreate
一个已知错误,还是我错过了什么?
我不愿意等待几个月让我的代码再次遇到这种情况,我花了一些时间与TryCreate
一起弄清楚TryCreate
正在做什么,然后再花一点时间想出一种重现错误的方法。
Uri.TryCreate(Uri baseUri, Uri relativeUri, out Uri result)
崩溃的原因似乎是格式错误的baseUri
。 例如, Uri
构造函数允许以下内容:
Uri badUri = new Uri("mailto:test1@mischel.comtest2@mischel.com");
根据RFC for mailto:URIs,不应该允许。 虽然构造函数创建并返回一个Uri
对象,但尝试访问(某些)其属性会抛出UriFormatException
。 例如,给定上面的代码,此行将抛出exception:
string badUriString = badUri.AbsoluteUri;
我发现Uri
类似乎使用了两种不同的解析算法:一种在构造过程中使用,另一种在内部用于获取各个组件。
将此无效的Uri
传递给TryCreate
将导致我在原始问题中描述的exception。 TryCreate
方法检查baseUri
参数是否为null
,但是不会(不能,我会想象)validation它。 必须假设,如果参数为非null,则传递的对象是完全初始化且有效的Uri
实例。 但是在构造结果的某个时刻, TryCreate
尝试获取baseUri
的组件并抛出exception。
我不能说我的程序实际上遇到了mailto:这种格式化的URL。 但是,我可以肯定地说,无效的Uri
对象是我程序崩溃的原因,只是因为我程序中的exception堆栈跟踪与测试程序中的堆栈跟踪相匹配。 简单地说,该bug是在Uri
构造函数(以及TryCreate
方法)中,它允许创建无效的Uri
。
您可以按照Microsoft Connect上的错误报告进行操作。
现在您知道它可能会失败,让我们获取更多信息:
static public bool TryCreateCleanUri(Uri baseUri, string relstr, out Uri result) { try { if (!Uri.TryCreate(baseUri, relstr, out result)) { return false; } } catch (UriFormatException ex) { throw new InalidOperationException( String.Format("Can create URI for base={0}, rel={1}", baseUri.ToString(), relstr), ex); } return CleanupUri(result, out result); }
public static bool CheckUrlValid(string url) { Uri uriResult; bool result = Uri.TryCreate(url, UriKind.Absolute, out uriResult); if(result) { uriResult = new Uri(url); if (uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp) return true; } return false; }