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