Uri.TryCreate throws UriFormatException?

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

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.

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 badUri = new Uri("mailto:[email protected]@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:

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.

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.

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.

You can follow the bug report on Microsoft Connect.

Tags:

C#

.Net