WebMatrix - URLs, UrlData and Routing for SEO

4.93 (14 votes)

There is a certain amount of debate surrounding the importance of friendly URLs in terms of Search Engine Optimisation and improving your ranking. One thing is certain - having friendly URLs helps users to identify whether the content at the end of a link to your site is likely to be relevant to them or not. This article examines how you can make use of the built-in support for Routing provided by ASP.NET Web Pages to not only create friendly URLs, but to work with parameters as well.

In a typical ASP.NET Web Forms application, incoming requests are mapped to physical files on disk. You can change this behaviour through the use of System.Web.Routing, which requires a little configuration within the application. ASP.NET Web Pages, on the other hand, provides support for routing out-of-the-box, although it is not as powerful as configuring your own through System.Web.Routing. Nevertheless, this in-built support is likely to be more than enough for managing friendly URLs for most sites.

First, what is meant by Friendly URLs? Take a look at the URLs on this site. This article can be found at http://www.mikesdotnetting.com/article/165/webmatrix-urls-urldata-and-routing. It should be clear to most people, just by reading the bold parts of the URL what they can expect to see if they requested it: an article on URLs, UrlData and Routing as pertaining to WebMatrix. A previous incarnation of this site would have presented the URL as http://www.mikesdotnetting.com/Article.aspx?ID=165. Not particularly meaningful... Over the years, a number of commentators have claimed that Google simply will not index URLs such as the one with the querystring. This is not true. My site was regularly indexed. However, you should be aware of this advice taken from Google's Webmaster Central guidelines:

If you decide to use dynamic pages (i.e., the URL contains a "?" character), be aware that not every search engine spider crawls dynamic pages as well as static pages. It helps to keep the parameters short and the number of them few.

Following that, is there any benefit to having key words appear in a friendlier URL? According to Google, the answer is Yes - it helps "a little bit". Of course, they won't say how much "a little bit" is.

OK. Now that we have got all that out of the way, how does Routing work with ASP.NET Web Pages? If you use Routing in ASP.NET Web Forms, or MVC, you can control how URLs map to resources with complete freedom. The built-in routing that comes with Web Pages offers a significant amount of freedom, but URLs must ultimately map to physical files on disk. That means you must have at least one file that matches part of the URL. Let's look at that in a bit more detail.

Note: I have written an article that covers applying the same routing system that you get in other parts of ASP.NET (namely MVC and Web Forms) in Web Pages sites. You can read it here: More Flexible Routing For ASP.NET Web Pages

A URL is composed of a number of parts. The first is the domain. In the case of my site, that's http://www.mikesdotnetting.com. After that comes a backslash (/) followed by one or more segments, each containing data. There is no limit to the number of segments that a URL can contain. WebMatrix will initially take all the segments and attempt to match them to a file path. If no file is found, WebMatrix will start considering trailing segments to be part of UrlData, and attempts to match the remainder to a physical file. This sounds a little confusing, so an example should help.

Create a site with the following structure:

The site has a folder called 'a', inside of which is another folder called 'a', inside of which is a third folder called 'a'. Inside of each folder (including the root folder), there is a file called 'a.cshtml'. Each file contains a paragraph describing its location. For example, the file in the root folder contains this markup:

<p>Page A in Root folder</p>

The file in the third level folder contains this markup:

<p>File A in Folder A in Folder A in Folder A</p>

If you select this file in WebMatrix and click the Run button, the resulting URL in your browser should look something like this (although your port number will very likely be different):


That's what you would expect to have to request in order to run that particular page. Now remove the ".cshtml" from the URL so that it becomes http://localhost:6324/a/a/a/a. Request this new URL, and you should get the same page - File A in Folder A in Folder A in Folder A. the Web Pages framework looks at all the segments, and attempts to turn it into a path:

In this case, it's looking for a file named 'a' three folders deep from the root, with all three folders named 'a'. If you remove the last 'a' and make another request (http://localhost:6324/a/a/a), you should get the file named 'a' two folders deep. Now change the last letter in the URL to a 'b': http://localhost:6324/a/a/b. You should get a.cshtml in the first level folder named 'a'. But what happened to the 'b' on the end of the URL? Web Pages couldn't find a file named 'b' in the second level folder, so it assumed that 'b' is UrlData, and looked to match the remaining segments to a file path. If no matches are found during the search for files, Web Pages will attempt to locate a default document instead. The two default documents which work are default.cshtml and index.cshtml in that order. However, this search is performed once, and assumes that the URL is entirely a file path, and contains no UrlData.


Essentially, UrlData behaves in a very similar way to a querystring, except that each value is located by position rather than being referenced by it's name. It is a way of passing arbitrary data via a URL. UrlData is populated to a List<string>, which can be iterated through - or you can reference items according to their numerical index (eg UrlData[0]). You can test this for yourself, by adding the following code to the deepest level 'a.cshtml' file:

<p>Total number of items in UrlData: @UrlData.Count</p>
    @for(var i = 0; i < UrlData.Count; i++){
        <li>UrlData[@i]: @UrlData[i]</li>

Now request the following URL: http://localhost:6324/a/a/a/a/b/c/d/e, and you should see that the page reports 4 items within the UrlData collection, which are iterated through and displayed according to their index in the collection:

When you reference items in the UrlData collection, you should treat them in the same way as any other user input. Just as you have manipulated the URL that you requested if you have been following along with the exercises, so a malicious user can manipulate the URL to attempt to inject something nasty into it. All the values are passed as strings, so you should use IsInt(), IsFloat() etc to test that values can be safely converted, and you should pass the resulting value as a parameter if you intend to use it as part of a database query. It is also worth pointing out that adding another backslash after the URL (http://localhost:6324/a/a/a/a/b/c/d/e/) will add another item to the UrlData collection, except that it will be empty.


Earlier, I said that UrlData behaves in a similar way to querystrings, but UrlData is not a querystring. Querystrings continue to work in exactly the same way as they do for any other framework: you append the URL with a question mark (?) followed by name/value pairs separated by ampersands (&). Going back to the deepest level 'a.cshtml' file, add the following code:

@foreach(string item in Request.QueryString){
    <p>QueryString item: name=@item, value=@Request[item]</p>

Now request the following URL:


The new piece of code iterates over each item in the querystring and prints its name and value to the browser:


This article should help to explain how routing, UrlData and querystrings work with ASP.NET Web Pages. There are good reasons for using the routing system to generate friendly URLs, not least for usability and a little SEO juice. One final thing worth explaining is how my current URL structure (which is driven by ASP.NET MVC) would work with Web Pages. Simply, all you would have to do is create a file called Article.cshtml in the root folder of your site. The number and article title will be treated as two items in UrlData - the first (UrlData[0]) is the identifier for the article, and the second (UrlData[1]) is the title which has been treated to a little method which replaces spaces with hyphens (or dashes) and removes other extraneous punctuation which is not allowed in URLs.


Date Posted:
Last Updated:
Posted by:
Total Views to date: 48815


- Bob Reid

I get a 404 error when I try routing on localhost. Any ideas as to why?

- Mike


I suspect you've done something wrong, but I have no clue what. You should post a question to a technical forum and provide a bit more detail about what you have done and what you are trying to do.

- Darren Cook

So I cannot create different friendly urls for the same page when it is passed different query strings?

So for example, myblog?postnumber=37 changed to myblog/postTitle

- Mike


You really need to use the Web Pages Routing helper for that: http://www.mikesdotnetting.com/Article/187/More-Flexible-Routing-For-ASP.NET-Web-Pages

- Jon-Paul

Is it possible to do this with a parameter to the home page? For example, www.mywebsite.com/hello to pass a parameter of "hello" to default.cshtml?

I want to do this without adding the /default/hello as it looks messy.

I have found your tutorials so helpful by the way and they have transformed the way that I use Webmatrix.

Thanks for any help.

- Mike


No it is not possible to do that with the default routing setup.



What's the performance impact of having nested files, say a/b/n/v/f while having _PageStart.cshtml in many of these folders, while compared to an MVC execution.

Is MVC, or even a universal route to an index file, manually checking if path exists and rendering corresponding files faster?

PS: I'm looking at high-performance scenarios where every instruction counts. I'm sure it really doesn't matter in normal scenarios.

- Mike


I have no idea. That's something you need to test for yourself in your own environment.

- vincenth69

Hi, I'm trying to get Data from my view but the UrlData is not recognized.
The adresse is localhost:8080/Home/Result/1 (Where the 1 is the number of the page -> the UrlData)
Yet, the DataUrl[0] is empty from my Result page and when I try a UrlData.Count() it gives me 0.
Do you know from where the problem could come from ?
As a result, I have my first iteration of the Reslut Page.
Thanks in advance.

- Mike


For your scenario to work, you would need a page called Result.cshtml in a folder called Home.

- terry

Adding parameters causes all the support files to go missing because the path to them no longer works. Page contains a references to "css/styles.css"

This works: /mypage

This fails: /mypage/someparameter

It finds the page but can't find the styles in /mypage/someparameter/css/

- Mike


Your css file behaves entirely correctly. You are providing a relative (to the url) path so it will be appended to the current url. You should provide an absolute path instead by prefixing the path with a forward slash:


The forward slash is resolved by most browsers as the root folder. In Web Pages, you can prefix the whole lot with a tilde (~) which will ensure correct resolution of the root:


- Ed

This is one of those things that make WebPages "golden" to me, and your article, though I'm only commenting now, was how I "discovered" it (1+ yrs) ago. Thank you.

Just out of curiosity, how would one replicate this behavior in (full-blown) MVC (or can/is it?), where it seems you have to define routes no matter what - I think the above is like a "dynamic optional" param route :)

- Ed

Hi mike,

On that last comment, please disregard the 2nd part...da Googles gave me dis:

Variable segments:

Recent Comments

Thomas 05/03/2018 00:59
In response to I'm Not Writing A Book On Razor Pages
There's a typo on this page: = true)] should be [BindProperty(SupportsGet = true)]...

Rolf Herbert 04/03/2018 19:25
In response to I'm Not Writing A Book On Razor Pages
So is MS deprecating razor Web Pages..? Is it dead..? I wish they would stop killing things so its...

Borut 17/02/2018 12:59
In response to I'm Not Writing A Book On Razor Pages
Mike, is it possible that Web Pages and Razor Pages "live" together in one web application? I a I...

hrboyce 09/02/2018 04:44
In response to I'm Not Writing A Book On Razor Pages
Mike, First thanks for doing this but I have to ask, any chance you would consider converting one of...

aziz sallam 07/02/2018 10:18
In response to I'm Not Writing A Book On Razor Pages
u are a great man...

Satyabrata Mohapatra 31/01/2018 11:36
In response to I'm Not Writing A Book On Razor Pages
This is a great news!!!! Thanks...

tangdf 30/01/2018 07:25
In response to I'm Not Writing A Book On Razor Pages
=> { o.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute()); }); The extension method does...

Obinna Okafor 30/01/2018 04:02
In response to I'm Not Writing A Book On Razor Pages
Thank you very much. I would like to see a project built from scratch using Razor Pages. And it show...

rachida Dukes 31/10/2017 13:52
In response to Customising Identity in Razor Pages
Thanks again for this wonderful tutorial. I followed all the steps in this section called: Adding...

Rachida 31/10/2017 12:06
In response to Customising Identity in Razor Pages
Thanks very much for this wonderful tutorial, it helped a lot....