URL is a term familiar to a lot of people since the beginning of the internet age. Actually, not every internet user is familiar with that URL thing, but at least there are some knowing that copying some letters from the top of your browser and sending them to a friend might help him in opening the same page in his browser. People who are familiar with the internet may have heard the term URI and know that is something like the URL. Finally there is is another yet term connected with the previous ones; that's the URN. We are going to find what each one of these terms is about, what they are made for and how .NET may help us to handle them.
Introduction
A nice way to begin, is by saying what these things are. So here's what each term stands for:
URI : Uniform Resource Identifier
URL : Uniform Resource Locator
URN : Uniform Resource Name
We can now tell that they are all referring to some uniform resource. Uniform resources can actually be a lot of stuff. An image, as well as a website address can be such a resource.
So they all refer to uniform resources. And what do they tell us about such resources? A URI is an identifier, a URL is a locator and a URN is a name. Even though this may not mean much to you to this point, by the time you reach the bottom of the article you will realize that these names are all the fuss is about.
URIs
As told, the URI is used to identify the resource. What does identify mean? In a few words to say which is the resource we are looking for out of a group of resources.
Supposing there is a resource called Sherlock Holmes. Under that name most people may think of the famous detective created by Arthur Conan Doyle. However can we really be sure that by saying Sherlock Holmes we are referring to the famous detective and not to own of its relatives who may bare the same name? This is where the URI comes in play. The URI will indicate the detective and nothing but that.
So what is "Sherlock Holmes" to the person we have just described? It is his name. In other words Sherlock Holmes would be that resource's URN.
And what would URL (the locator) be? That might be the way a person in need of detective skills might find Sherlock Holmes, in other words his address. URL would this way be 221B, Baker Street, London, supposing that this address is always uniquely connected to our detective.
Now, let's take a look at the following diagram.
A resource can always be identified by a URI. The diagram tells us that a URI may be either a URL or a URN or both. Back to our previous example, this means that the Sherlock Holmes resource can either be identified using its name (URN - Sherlock Holmes) or its location (URL - 221B, Baker Street, London).
Moving on to our familiar URL.
URLs
So what is a URL?
This can be a url : http://dotnethints.com/
This can also be a url: http://dotnethints.com/images/uploads/news/new_17.jpg
URLs tell us how we can find and obtain the specified resource. Getting the http://dotnethints.com/images/uploads/news/new_17.jpg URL, we know that we may find the picture located within the images/uploads/news path of the root menu.
Keep in mind that dotnethints.com is not a unique URL as more than one URLs could be created depending on the application protocol.
For example http://dotnethints.com/ is not the same URL as ftp://dotnethints.com/. Each one represents a different URL, URI and resource.
Content negotiation is a case where a URI may end up in different resource versions (different URLs) depending on circumstances. For example an image can be returned as GIF or PNG file in case the client's browser may not support one of them.
URNs
So, since URLs work just fine the way we described, why do we need that URN thing? Well, imagine we transferred our website from http://dotnethints.com/ to http://dotnethints_newwebsite.com/. A person who would request http://dotnethints.com/ would get a 404 error. However the resource would still be available online.
A URL describes the resources based on its location; as a result it creates a connection between them. Now, imagine creating a simple request for our dotnethints.com resource and automatically getting its URL in order to get our resource, no matter where that would be located right now.
That is the ultimate target of the URNs. Being able to locate all resources based on their names. Till then however let's take a look at what a URN looks like.
urn:NID:NSS
Every URN starts with "urn:" followed by NID and NSS (separated by a colon), where NID and NSS stand for the namespace Identifier and the Namespace Specific String respectively.
For example considering that isbn (International Standard Book Number) is the namespace concerning book standards, a travel guide to Rome which happens to be in my bookcase is uniquely identified by ISBN-13 9781409373162. Romeo and Juliet is also identified by ISBN 0-486-27557-4. That way the URN we could use to identify that book would be urn:isbn:0-486-27557-4.
Keep in mind that a URN may contain extra namespaces eg urn:NID1:NID2:NSS
Namespace Identifiers can also be used in XML Schemas to define namespaces eg
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:some_namespace" ...
And .NET
Uri is quite a useful class created to describe a uri address. The easiest way to create a Uri object is using the string of the address it represents. For example
Uri uri = new Uri("http://dotnethints.com");
Uri uri = new Uri("http://dotnethints.com/blog?id=47");
Uri uri = new Uri("urn:dotnethints.com");
However the following line
Uri uri = new Uri("dotnethints.com");
will throw a System.UriFormatException as we cannot turn every possible string into a Uri.
There are two ways to avoid this exception. First one is to use Uri's TryCreate method. TryCreate is similar to TryParse method. It will try to create a Uri object using a string. If it fails, the Uri is set to null.
For example
Uri uri = new Uri();
Uri.TryCreate("http://dotnethints.com/blog", UriKind.Absolute, out uri);
creates a proper Uri. However using
Uri uri = new Uri();
Uri.TryCreate("dotnethints.com/blog", UriKind.Absolute, out uri);
we get a Uri equal to null.
The second way, is to use another Uri method, the IsWellFormedUriString. This method returns true if the string is properly formatted. The following lines will show you how it works.
string uriString = "http://dotnethints.com";
Uri uri = new Uri();
if (Uri.IsWellFormedUriString(uriString, UriKind.Absolute))
uri = new Uri(uriString);
A common way to create the Uri for the current page (in case of ASP.NET applications) is to use Request.Url.
We can also use the UriBuilder class in order to create a Uri. Think of UriBuilder as a way of creating Uris separated on parts. For example, scheme, host, path and query refer to the Uri parts respectively. When our UriBuilder object is complete we can use its Uri parameter to create the Uri.
The Uri created in the following example is the same as the one created by new Uri("http://dotnethints.com/blog?id=47").
UriBuilder builder = new UriBuilder();
builder.Scheme = "http";
builder.Host = "dotnethints.com";
builder.Path = "blog";
builder.Query = "id=47";
Uri uri = builder.Uri;
So far we have found out how to create a Uri object. Let's see how we can use it.
The Uri class carries along some interesting parameters, for example AbsolutePath, Query and Segments which make things easier when dealing with uris. The following example shows how usefull the Uri class can be.
Uri uri = new Uri("http://dotnethints.com/blog?id=47");
URIlit.Text = "OriginalString : " + uri.OriginalString;
URIlit.Text += "<br/> AbsolutePath : " + uri.AbsolutePath;
URIlit.Text += "<br/> PathAndQuery : " + uri.PathAndQuery;
URIlit.Text += "<br/> Query : " + uri.Query;
URIlit.Text += "<br/> Scheme : " + uri.Scheme;
URIlit.Text += "<br/> DnsSafeHost : " + uri.DnsSafeHost;
URIlit.Text += "<br/> Segments:";
foreach (string segment in uri.Segments)
URIlit.Text += segment + " - ";
OriginalString : http://dotnethints.com/blog?id=47
AbsolutePath : /blog
PathAndQuery : /blog?id=47
Query : ?id=47
Scheme : http
DnsSafeHost : dotnethints.com
Segments:/ - blog -
Reaching the end of this article we are going to create a method that can handle a uri's query string. The method returns the given Uri having inserted new query string value or replaced the existing one, if present. This example, apart from helping in Uris and UriBuilders better understanding, may also prove practically useful.
// Replace or insert proper value into uri's query string
private Uri SetValueInQueryString(Uri uri, string strQueryParameter, string strQueryValue)
{
//ParseQueryString returns an encoded NameValueCollection
var queryStringValues = HttpUtility.ParseQueryString(uri.Query);
//Insert or update selected name
queryStringValues.Set(strQueryParameter, strQueryValue);
//Create the new uri using a UriBuilder
UriBuilder builder = new UriBuilder(uri);
builder.Query = queryStringValues.ToString();
return builder.Uri;
}
Summary
Urls represent a resource’s location while urns represent its unique name. A Uri can be either a url or a urn. So far, urls are mostly used in comparison to urns. .NET contains the Uri and UriBuilder classes that help us to handle and create uris.