我有一个尝试创建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()抛出异常!这是堆栈跟踪:
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
,但它对异常保持沉默。但是,Uri.TryCreate(Uri, Uri, out Uri)
的文档说:
此方法构造URI,puts 它以规范形式,并验证 它。如果发生未处理的异常, 这个方法抓住了它。如果你想 创建一个Uri并获得例外使用 其中一个Uri构造函数。
堆栈跟踪显示Uri.TryCreate(Uri, Uri, out Uri)
中引发了异常,根据文档,该异常不应发生。
这种情况非常罕见。几个月来我一直在使用该代码,通过它运行数十亿个URL,直到现在才遇到问题。不幸的是我不知道是什么组合导致了这个问题。我希望构建一个显示错误的测试用例。
这是Uri.TryCreate
中的已知错误,还是我错过了什么?
答案 0 :(得分:18)
我不愿意等待几个月让我的代码再次遇到这种情况,我花了一些时间与ILDASM一起弄清楚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
。例如,给定上面的代码,这一行将引发异常:
string badUriString = badUri.AbsoluteUri;
我觉得有趣的是Uri
类似乎使用了两种不同的解析算法:一种在构造过程中使用,一种在内部用于获取各个组件。
将此无效Uri
传递给TryCreate
将导致我在原始问题中描述的例外情况。 TryCreate
方法检查baseUri
的{{1}}参数,但不会(不能,我会想到)验证它。必须假设,如果参数为非null,则传递的对象是完全初始化且有效的null
实例。但是在构造结果的某个时刻,Uri
尝试获取TryCreate
的组件并抛出异常。
我不能说我的程序实际上遇到了一个以这种方式格式化的mailto:URL。但是,我可以肯定地说,无效的baseUri
对象是我程序中崩溃的原因,只是因为我程序中的异常堆栈跟踪与测试程序中的堆栈跟踪相匹配。简而言之,该错误位于Uri
构造函数(以及Uri
方法)中,允许创建无效的TryCreate
。
您可以关注Microsoft Connect上的bug report。
答案 1 :(得分:3)
现在您知道它可能会失败,让我们获取更多信息:
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);
}
答案 2 :(得分:-1)
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;
}