C# 主机如何可能抛出UriFormatException?

C# 主机如何可能抛出UriFormatException?,c#,.net,exception,url,uri,C#,.net,Exception,Url,Uri,消息框会显示一个地址,如 mailto:webmaster[@]somehost?webmaster 这显然是畸形的,但我不明白为什么它没有被第一个捕捉块捕捉到 它只能抛出InvalidOperationException。这是相当有问题的,因为这意味着我的应用程序可以在任何时候爆炸 [[snip]]如果深入研究Uri.Host属性real deep,它最终可以调用一个静态函数GetException,该函数针对无效Uri的不同情况返回UriFormatException对象。打印出您获得的完整

消息框会显示一个地址,如

mailto:webmaster[@]somehost?webmaster

这显然是畸形的,但我不明白为什么它没有被第一个捕捉块捕捉到

它只能抛出InvalidOperationException。这是相当有问题的,因为这意味着我的应用程序可以在任何时候爆炸


[[snip]]

如果深入研究Uri.Host属性real deep,它最终可以调用一个静态函数GetException,该函数针对无效Uri的不同情况返回UriFormatException对象。打印出您获得的完整UriFormatException,并将其与Uri.GetException生成的比较。您可能会从中获得更多细节。

首先,我想说,使用异常检查有效性并不是一个好主意,因为您可以使用方法。因此,您可以重写代码,而不依赖于抛出和捕获哪个异常

所以最好改变你的想法

foreach (var node in root.Find("a[href]"))
{
    var href = node.Attributes["href"].Value;
    Uri uri;
    try
    {
        uri = new Uri(item.Value.Uri, href);
    }
    catch(UriFormatException)
    {
        continue;
    }
    // *snip*
    try
    {
        if (_imageHosts.IsMatch(uri.Host)) // <--- problematic line
            priority--;
    }catch(UriFormatException)
    {
        MessageBox.Show(uri.OriginalString); // <--- gets displayed when I expected it wouldn't
        continue;
    }
    // *snip*
}

但无论如何,这不是全额支票

至于你的问题,答案相对简单。假设格式不正确,您就错了:

mailto:webmaster[@]somehost?webmaster

URI就是这样的

{scheme name}:{hierarchy part}[?{query}][{fragment}]

显然对你的输入有效。您将使用mailto:scheme以资源的URI结束

当您尝试访问主机属性时,假定资源是Http,但默认情况下使用的mailto方案解析器无法解析主机组件的原始字符串,因此引发异常

因此,要正确填写支票,您必须稍微修改代码:

Uri uri;
if (!Uri.TryCreate(item.Value.Uri, href, out uri)) continue;
阅读一些关于

此处根据@Mark注释进行更新


我敢肯定,当我试图获取AbsoluteUri属性时,它也抛出了一个异常。为什么会失败呢

您无法通过方案检查,因为它将被邮寄到。下面是快速测试:

Uri uri;
if (!Uri.TryCreate(item.Value.Uri, href, out uri)) continue;

if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) continue;
它以错误的计划结束。也许我没有正确地理解你

当您将href更改为:

        var baseUri = new Uri("http://localhost");
        const string href = "mailto: webmaster [ @ ] somehost ?webmaster";

        Uri uri;
        if (!Uri.TryCreate(baseUri,href, out uri)) 
        {
            Console.WriteLine("Can't create");
            return;
        }

        if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
        {
            Console.WriteLine("Wrong scheme");
            return;
        }

        Console.WriteLine("Testing uri: {0}", uri);
它正确地传递,并自动将uri转义到:

此外,您还可以使用所有uri组件

我试图在以下第一部分中解释的主要问题:

在我看来,您错误地将任何统一资源标识符视为基于https的url,但这是错误的。邮寄地址:webmaster@somehost.tst或gopher://gopher.hprc.utoronto.ca/ 或迈尔eshandler://something@还有一个可以成功解析的有效URI。看看

所以

Uri构造函数行为是预期的且正确

它尝试验证以下对象的传入URI:

UriSchemeFile-指定URI是指向文件的指针。 UriSchemeFtp-指定通过文件传输协议FTP访问URI。 UriSchemeGopher-指定通过Gopher协议访问URI。 UriSchemeHttp-指定通过超文本传输协议HTTP访问URI UriSchemeHttps-指定通过安全超文本传输协议HTTPS访问URI。 UriSchemeMailto-指定URI是电子邮件地址,可通过简单网络邮件协议SNMP访问。 UriSchemeNews-指定URI是Internet新闻组,可通过网络新闻传输协议NNTP访问。 UriSchemeNntp-指定URI是Internet新闻组,可通过网络新闻传输协议NNTP访问 基本URI解析器在方案未知时使用,请参见

例如,基本上Uri.TryCreate和scheme会进行足够的检查,以获取可以传递到.NET HttpWebRequest的链接。你真的不需要检查它们的格式是否正确。如果链接是坏的、格式不正确的或不存在,你只需要在尝试请求它们时得到相应的HttpError

至于你的例子:

它通过我的检查并成为:

您不需要检查它是否格式正确。只需执行基本检查并尝试请求。希望能有帮助

此外,字符串mailto:webmaster[@]somehost?webmaster的格式不正确。我的字面意思是,那根绳子,里面有愚蠢的s和所有的东西


此字符串的格式不正确,因为它包含排除的字符,所以它的格式不正确,但由于URI方案的一致性通用语法,它仍然可以被视为有效。请检查它在使用http:.创建时是如何转义的。

根据Nick的回答:

        const string href = "http: webmaster [ @ ] somehost ?webmaster";

我敢肯定,当我试图获取AbsoluteUri属性时,它也抛出了一个异常。为什么会失败?另外,字符串mailto:webmaster[@]somehost?webmaster的格式不正确。我的意思是,那个字符串,里面有愚蠢的[]s和所有东西。我想mailtos会有一个绝对的URI。。。我想不是。我会按照你当时的建议检查这个方案的!Uri是基于WebClient.DownloadData的,我基本上希望允许任何可以处理的。。。默认情况下,.NET Framework支持以http:开头的URI,
https:、ftp:、和文件:方案标识符。-我想我也应该包括这些。Uri.iswellFormedUrString根据RFC2396-统一资源标识符Uri:通用语法检查Uri一致性,如2.4.3所述。排除US-ASCII字符。必须在URI中转义空格。我也会更新我的答案。
        const string href = "http: webmaster [ @ ] somehost ?webmaster";
private static readonly string[] SupportedSchmes = { Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeFtp, Uri.UriSchemeFile };

private static bool TryCreateUri(string uriString, out Uri result)
{
    return Uri.TryCreate(uriString, UriKind.Absolute, out result) && SupportedSchmes.Contains(result.Scheme);
}

private static bool TryCreateUri(Uri baseAddress, string relativeAddress, out Uri result)
{
    return Uri.TryCreate(baseAddress, relativeAddress, out result) && SupportedSchmes.Contains(result.Scheme);
}