Uri.TryCreate抛出UriFormatException?

时间:2009-07-13 15:46:31

标签: c# .net

我有一个尝试创建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中的已知错误,还是我错过了什么?

3 个答案:

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