C# Uri.TryCreate 抛出 UriFormatException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1120283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Uri.TryCreate throws UriFormatException?
提问by Jim Mischel
I have a method that tries to create a Uri and then clean it up (removes fragments, excludes some domains and query string patterns, etc.). The method looks like this:
我有一个方法尝试创建一个 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);
}
This method has been working fine for months. But last night it failed. Uri.TryCreate() threw an exception! Here's the stack trace:
这种方法几个月来一直运行良好。但是昨晚失败了。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)
Documentation for Uri.TryCreate(Uri, String, out Uri)
says that the return value is True
if successful, False
otherwise, but it's silent about exceptions. However, documentation for Uri.TryCreate(Uri, Uri, out Uri)
says:
文档Uri.TryCreate(Uri, String, out Uri)
说True
如果成功则返回值,False
否则返回值,但它对异常保持沉默。但是,文档Uri.TryCreate(Uri, Uri, out Uri)
说:
This method constructs the URI, puts it in canonical form, and validates it. If an unhandled exception occurs, this method catches it. If you want to create a Uri and get exceptions use one of the Uri constructors.
此方法构造 URI,将其置于规范形式中,并对其进行验证。如果发生未处理的异常,此方法会捕获它。如果要创建 Uri 并获得异常,请使用 Uri 构造函数之一。
The stack trace shows that the exception was thrown in Uri.TryCreate(Uri, Uri, out Uri)
, which, according to the documentation, shouldn't happen.
堆栈跟踪显示异常被抛出Uri.TryCreate(Uri, Uri, out Uri)
,根据文档,这不应该发生。
This is a very rare occurrence. I've been using that code for months, running literally billions of urls through it, and haven't encountered a problem until now. Unfortunately I don't know what combination of things caused the problem. I'm hoping to construct a test case that shows the error.
这是非常罕见的情况。我已经使用该代码几个月了,通过它运行了数十亿个网址,直到现在还没有遇到问题。不幸的是,我不知道是什么组合导致了这个问题。我希望构建一个显示错误的测试用例。
Is this a known bug in Uri.TryCreate
, or am I missing something?
这是 中的已知错误Uri.TryCreate
,还是我遗漏了什么?
采纳答案by Jim Mischel
Unwilling to wait potentially several months for my code to encounter this situation again, I spent some time with ILDASM to figure out what TryCreate
is doing, and then a little more time coming up with a way to reproduce the error.
不愿意等待几个月的时间让我的代码再次遇到这种情况,我花了一些时间在 ILDASM 上弄清楚发生了什么TryCreate
,然后再花一点时间想出一种重现错误的方法。
The reason for the crash in Uri.TryCreate(Uri baseUri, Uri relativeUri, out Uri result)
appears to be a badly formatted baseUri
. For example, the Uri
constructor allows the following:
崩溃的原因Uri.TryCreate(Uri baseUri, Uri relativeUri, out Uri result)
似乎是格式错误的baseUri
. 例如,Uri
构造函数允许以下内容:
Uri badUri = new Uri("mailto:test1@mischel.comtest2@mischel.com");
According to the RFC for mailto: URIs, that shouldn't be allowed. And although the constructor creates and returns a Uri
object, trying to access (some of) its properties throws UriFormatException
. For example, given the above code, this line will throw an exception:
根据 mailto: URI 的 RFC,这是不允许的。尽管构造函数创建并返回了一个Uri
对象,但尝试访问它的(某些)属性时会抛出UriFormatException
. 例如,给定上面的代码,这一行将抛出异常:
string badUriString = badUri.AbsoluteUri;
I find it rather interesting that the Uri
class appears to use two different parsing algorithms: one used during construction, and one used internally for getting the individual components.
我发现相当有趣的是,Uri
该类似乎使用了两种不同的解析算法:一种在构造期间使用,另一种在内部用于获取单个组件。
Passing this invalid Uri
to TryCreate
will result in the exception that I described in the original question. The TryCreate
method checks the baseUri
parameter for null
, but doesn't (can't, I would imagine) validate it otherwise. It has to assume that, if the parameter is non-null, the passed object is a fully initialized and valid Uri
instance. But at some point in constructing the result, TryCreate
attempts to obtain the components of baseUri
and an exception is thrown.
将此 invalid 传递Uri
给TryCreate
将导致我在原始问题中描述的异常。该TryCreate
方法检查 的baseUri
参数null
,但不会(不能,我想)以其他方式验证它。它必须假设,如果参数非空,则传递的对象是一个完全初始化且有效的Uri
实例。但是在构造结果的某个时刻,TryCreate
尝试获取 的组件baseUri
并抛出异常。
I can't say that my program actually encountered a mailto: URL that was formatted this way. I can say with some degree of certainty, though, that an invalid Uri
object was the cause of the crash in my program, simply because the exception stack trace from my program matches the stack trace from the test program. Simply put, the bug is in the Uri
constructor (and also in the TryCreate
methods) which allow the invalid Uri
to be created.
我不能说我的程序实际上遇到了一个以这种方式格式化的 mailto: URL。不过,我可以肯定地说,无效Uri
对象是我程序崩溃的原因,这仅仅是因为我程序的异常堆栈跟踪与测试程序的堆栈跟踪相匹配。简单地说,错误在于Uri
构造函数(以及TryCreate
方法)中,它允许Uri
创建无效。
You can follow the bug reporton Microsoft Connect.
您可以关注Microsoft Connect 上的错误报告。
回答by John Saunders
Now that you know it can fail, let's get more information:
现在您知道它可能会失败,让我们获取更多信息:
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 InvalidOperationException(
String.Format("Can create URI for base={0}, rel={1}", baseUri.ToString(), relstr),
ex);
}
return CleanupUri(result, out result);
}
回答by Seven
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;
}