103

How do you check that a uri string is valid (that you can feed it to the Uri constructor)?

So far I only have the following but for obvious reasons I'd prefer a less brute way:

    Boolean IsValidUri(String uri)
    {
        try
        {
            new Uri(uri);
            return true;
        }
        catch
        {
            return false;
        }
    }

I tried Uri.IsWellFormedUriString but it doesn't seem to like everything that you can throw at the constructor. For example:

String test = @"C:\File.txt";
Console.WriteLine("Uri.IsWellFormedUriString says: {0}", Uri.IsWellFormedUriString(test, UriKind.RelativeOrAbsolute));
Console.WriteLine("IsValidUri says: {0}", IsValidUri(test));

The output will be:

Uri.IsWellFormedUriString says: False
IsValidUri says: True

Update/Answer

The Uri constructor uses kind Absolute by default. This was causing a discrepancy when I tried using Uri.TryCreate and the constructor. You do get the expected outcome if you match the UriKind for both the constructor and TryCreate.

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Manuel
  • 10,869
  • 14
  • 55
  • 86

6 Answers6

104

A well-formed URI implies conformance with certain RFCs. The local path in your example is not conformant with these. Read more in the IsWellFormedUriString documentation.

A false result from that method does not imply that the Uri class will not be able to parse the input. While the URI input might not be RFC conformant, it still can be a valid URI.

Update: And to answer your question - as the Uri documentation shows, there is a static method called TryCreate that will attempt exactly what you want and return true or false (and the actual Uri instance if true).

Franci Penov
  • 74,861
  • 18
  • 132
  • 169
  • The question is "How do you check that a uri string is valid (that you can feed it to the Uri constructor)?" – Manuel Jan 29 '11 at 05:25
  • 1
    TryCreate doesn't really tell you if a string will be accepted by the constructor. See Update. – Manuel Jan 29 '11 at 20:55
  • @Manuel: that doesn't make sense at all - the outcome of `TryCreate` and the `Uri` constructor should be identical - try to pass the `UriKind` like you did for `TryCreate`. – BrokenGlass Jan 29 '11 at 21:05
  • 1
    You're right. The constructor uses the default kind Absolute. Thanks. – Manuel Jan 29 '11 at 21:17
  • 3
    According to .Net sources [the IsWellFormedUriString method contains the TryCreate method call plus extra checks](http://referencesource.microsoft.com/#System/net/System/UriExt.cs,24b1613846e7f879), therefore I prefer to use the IsWellFormedUriString method as more powerful for such tasks. – Igor Kustov Nov 19 '15 at 08:12
  • `Uri.IsWellFormedUriString("http://dasda", UriKind.Absolute)` return `true`. – huang Oct 10 '19 at 15:39
  • @JokeHuang That's what I would expect, because `http//dasda` is an absolute URI that refers to a host named `dasda` on the local network. – Franci Penov Oct 14 '19 at 22:33
  • @JokeHuang In particular, RFC 3986 is very explicit that the name resolution for URIs that specify a registered name for the authority part of the URI is not expected to use specific lookup method (ie. DNS), and can use any OS-dependent method like NetInfo or yellow pages ( yes, that is in RFC 3986, 3.2.2 Host - https://tools.ietf.org/html/rfc3986#page-11 :-) ) – Franci Penov Oct 14 '19 at 22:38
68

Since the accepted answer doesn't provide an explicit example, here is some code to validate URIs in C#:

Uri outUri;

if (Uri.TryCreate("ThisIsAnInvalidAbsoluteURI", UriKind.Absolute, out outUri)
   && (outUri.Scheme == Uri.UriSchemeHttp || outUri.Scheme == Uri.UriSchemeHttps))
{
    //Do something with your validated Absolute URI...
}
DiscDev
  • 38,652
  • 20
  • 117
  • 133
  • 3
    Don't trust Uri.TryCreate function! This will also allow bad URLs. Try this 'http:// http:// google.com/page' (remove spaces). This URL pass the TryCreate function, but it's wrong. – No1Lives4Ever Oct 05 '15 at 10:01
  • 8
    @No1Lives4Ever You are correct that it parses as valid what you mentioned, but this is technically not wrong. The explanation in English: using the http protocol (**http://**), connect to the DNS entry for "http" (http://**http**) using an explicit (but omitted) port (http://http**:**) - so I'll assume the default for the protocol; you supplied an empty first level folder (http://http:**//**) but I know what you meant ;) followed by a path segment "google.com" (http://http://**google.com/**) and then the resource "page" (http://http://google.com/**page**) – mlhDev Jan 12 '16 at 15:23
11

Assuming we only want to support absolute URI and HTTP requests, here is a function that does what you want:

public static bool IsValidURI(string uri)
{
    if (!Uri.IsWellFormedUriString(uri, UriKind.Absolute))
        return false;
    Uri tmp;
    if (!Uri.TryCreate(uri, UriKind.Absolute, out tmp))
        return false;
    return tmp.Scheme == Uri.UriSchemeHttp || tmp.Scheme == Uri.UriSchemeHttps;
}
Joe
  • 7,113
  • 1
  • 29
  • 34
cdiggins
  • 17,602
  • 7
  • 105
  • 102
  • 7
    According to .Net sources [your second check **!Uri.TryCreate(uri, UriKind.Absolute, out tmp)** is redundant because the IsWellFormedUriString method already contains the TryCreate method call](http://referencesource.microsoft.com/#System/net/System/UriExt.cs,24b1613846e7f879) – Igor Kustov Nov 19 '15 at 08:19
  • 1
    The second check is needed to make the third (and final) check possible. Without it, there is no `tmp`. The first step is arguably redundant in this instance... – Joe Jun 22 '16 at 15:01
3

In my case I just wanted to test the uri, I don't want to slow down the application testing the uri.

Boolean IsValidUri(String uri){
  return Uri.IsWellFormedUriString(uri, UriKind.Absolute);
}
leopal
  • 4,711
  • 1
  • 25
  • 35
3

Try it:

private bool IsValidUrl(string address)
    {
        return Uri.IsWellFormedUriString(address, UriKind.RelativeOrAbsolute);
    }
BiBi
  • 31
  • 1
  • 2
0

In your case the uri argument is an absolute path which refers to a file location, so as per the doc of the method it returns false. Refer to this

Vijay Sirigiri
  • 4,653
  • 29
  • 31
  • I'm using UriKind.RelativeOrAbsolute so it shouldn't matter. Either way it doesn't work with UriKind.Relative or UriKind.Absolute so no luck there. – Manuel Jan 29 '11 at 05:16