These are typically related to Javascript, CSS (Stylesheet), AJAX calls, and so on. It actually took me a long time to figure out all the small things that all of the sudden did not work after I implemented routing. This blogpost attempts to give you a list of the most common issues, and I also try to explain some workarounds that I implemented.
If you are just starting out with asp.net 4.0 and want to implement routing, then you should start out by reading Scott Guthrie's blog from october 2009. Scott gives here a simplied, but very good explanation of the asp.net 4.0 routing features.
Here I will explain three things that I had to fix in order for the routing to work properly. But first a few words about my content management system - PrimePublish. My system is a Content Management System with a dynamic menu structure. This means that an administrator of the system can assign new menu names, edit existing menus, or delete menus. One menu can also contain one or more articles. An implementation like this would typically have an URL like www.primedesign.no/show.aspx?menuID=241. The URLs could often be much more complicated, containing return URL information, languague code and so on. Below are a few things I would like to point out for you - things that possibly could help you implement asp.net routing faster and better. 1. A Note About Referencing Routing Data 2. Javascript not Loading Correctly 3. Set up Ignore Routing to Stop Routing of Certain Files, Notable Requests for .axd and favicon 4. Javascript Event Handlers like onMouseOver, onMouseOut Referencing Routing Data So with asp.net 4.0 routing using forms, how would you access a menu id like www.primedesign.no/show.aspx?menuID=241. After all, what you are trying to achieve is a human readable URL - something that should look like the following www.primedesign.no/Home. This URL will map to the same URL as shown above. There are several approaches to this. The trick here is that we don't use a menu id any more. We must, therefore, find an other way of referencing our menus in the database. The obvious choice here is to use the menu name, but before you can use the menu name as an index in the database, you must make certain that the name is unique. What I ended up doing was not actually requiering the menu name to be unique, but I instead generated unique routing names based on the menu and the path. This unique routing name is generated in my MenuManager when creating or editing a menu, and the route name is then stored in the database. When editing, make sure that you also keep the old name, so that any external (or internal) links to this menu route will still work. Search engines really don't like broken links! Another way to reference a menu, without using the menu name, could be to embed the menu ID into the menu route, i.e., www.primedesing.no/241/Home. This way, your program could reference the 241 and still use that as an ID for the menu. This implementation would require fewer modifications to your program, but is slightly less user friendly. You should remember, though, that one of the reasons for implementing routing is to allow the user to "guess" our URL, and thereby change the URL string to access pages in the system. Javascript not Loading Correctly Often, programmers will put all their Javascript in one file and link the file in the <head> section of the master file, together with linking stylesheets. My Javascript linking was as follows:
<script type="text/javascript" src="App_Themes/Res/Script.js"></script>
When applying routing, this construct will cause the javascript to not load correctly giving you all kinds of weird error messages. After numerous hours searching on the web, I eventually found out that javascript should be loaded using a ScriptManager. The ScriptManager somehow magically figures out the correct path for the javascript and solves the problem. Here is how I now load my Javascript:
<telerik:RadScriptManager ID="RadScriptManager1" Runat="server" EnableScriptLocalization="true" EnableScriptGlobalization="true"> <Scripts> <asp:ScriptReference NotifyScriptLoaded="true" Path="~/App_Themes/Res/Script.js" /> </Scripts> </telerik:RadScriptManager>
When Microsoft implemented routing into ASP.NET MVC (later implemented into ASP.NET 4.0), they decided that by default, routing should not apply to files on disk. That means, routing checks to see if the file is on disk before attempting to route (via the Virtual Path Provider).
If the file is on disk, it will not be routed and the web server will handle the request normally. If the file doesn't exist, routing will be applied. This implementation makes sure that requests for static resources on disk (such as images) are not unintentionally being routed. This default can be changed by setting the property RouteTable.Routes.RouteExistingFiles to be true in your Web.config.
However, since many features of ASP.NET makes requests for .axd files that do not exist on disk, we need to tell the routing system that it should ignore routing for calls to these files and rather be given normal ASP.NET handling. This is done by adding the following line of code to your Global.asax file. routes.Add(new Route("{resource}.axd/{*pathInfo}", new StopRoutingHandler()));
This handles the standard .axd requests.
However, there are other cases where you might have requests for files that don’t exist on disk. For example, if you register an HTTP Handler directly to a type that implements IHttpHandler. Not to mention requests for favicon.ico that the browser makes automatically. ASP.NET Routing attempts to route these requests to a controller.
One solution to this is to add an appropriate ignore route to indicate that routing should ignore these requests. Unfortunately, we can’t do something like this: {*path}.aspx/{*pathinfo} since only one "catch-all" route is allowed and it must happened at the end of the URL. However, from Phil Haack's excellend blogpost on MVC - Make Routing Ignore Requests For A File Extension - I found out that it is possible to do a catch-all route by setting appropriate constraints. Phil's blog gives an explanation on how to do this in MVC. Since I am using ASP.NET forms, the code I used is as follows:
routes.Add(new Route("{*favicon}", null, new RouteValueDictionary { { "favicon", @"(.*/)?favicon.ico(/.*)?" } }, new StopRoutingHandler()));
So in this case, these routes will match (and thus ignore) all requests for favicon.ico (no matter which directory) as well as requests for a .aspx file. Since we told routing to ignore these requests, normal ASP.NET processing of these requests will occur. You may, of course, use similar constructs for other file types, i.e., {*allaspx} with a constraint of { { "allaspx", @".*\.aspx(/.*)?" } } Javascript Event Handlers Be aware of Javascripts, especially the "Event Handlers". These are commands that work directly with existing HTML commands. They work so closely in fact, they work by being embedded right into the HTML command itself. Examples of Javascript event handlers are onMouseOver, onMouseOut, onClick, alert. Joe Burns has some nice examples for the usage of these event handlers in his blogpost called Advanced JavaScript for Web Developers: onClick and onMouseOver. The reason why I mention these Javascript event handlers, is that they gave me quite a headache when implementing routing into my system. I use the onMouseOver and onMouseOut in a few places in the system to swap images - i.e., the image is lit up when you mouse over the image. What happens when you implement routing is that the path will be different depending on where you are in the hierarchy of the system, so the image position is not always referring to the root level. In my system, I have a button called "btnNewArticle". As you can see, the button uses the Javascript Event Handlers onMouseOver and onMouseOut. When implementing routing for asp.net forms, I discovered that the images would not load correctly when mousing over or out of the image. The images loads correctly in the first place tough, and with the paths to the images being exactly the same for both the initial loading (ImageUrl), and the onMouseOver / onMouseOut, it problem facing me wasn't exactly intuitive :) I also tried all variations of the path of course - also the absolute path like "this.src='/images/page_add.png'", but this didn't help either. With routing implemented, the images that the Javascript Event Handler will try to load would change from something like this: http://www.primedesign.no/images/page_add.png to http://www.primedesign.no/Produkter/PrimePublish/images/page_add.png I finally figured out a solution, and that is to force the images in the Javascript to load from the root. An implementation of this is shown below. I have an ImageButton in my system with onMouseOver and onMouseOut events implemented. I now have to make sure that the images are always being referenced from the root of the path.
<asp:ImageButton ID="btnNewArticle" runat="server" PostBackUrl="<settes i Page_Load>" onmouseover="this.src='images/page_add.png';" onmouseout="this.src='images/page_add_pale.png';" ImageUrl="images/page_add_pale.png" ToolTip="<%$ Resources: Resource, strNewArticle %>" />
I, therefore, implemented the following C# code into my Page_Load routine:
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //Force onMouseOver and onMouseOut images to reference the root. btnNewArticle.Attributes.Add("onMouseOver", "this.src='" + HttpContext.Current.Request.ApplicationPath.ToString() + "/images/page_add.png'"); btnNewArticle.Attributes.Add("onMouseOut", "this.src='" + HttpContext.Current.Request.ApplicationPath.ToString() + "/images/page_add_pale.png'"); //Do whatever... } }
The HttpContext.Current.Request.ApplicationPath gets the root of the path, in my case it would return /www.primedesign.no. Add "/images/page_add.png" to that and you have an absolute path which will reference the image correctly. Please leave a comment if you have other suggestions or comments. Hope this helps! André Vold
Here's a short little BLOGGER BIO to tell you a little bit about my background - and why I chose to get into programming and SEO.
I grew up in Norway, but went to school in the U.S. I have a degreen in computer science from Arizona State University. After graduating I moved back to Norway where I got a job working at Norwegian Data and later IBM. I went on to do a Masters of Management at BI in Oslo. After several years as a senior executive at IBM I decided to start my own company, Apropos Internet. In 2004 I started Virosafe Norway, a company that imports and distributes data security products, and now I am CEO of Lumino as well.
It's always been essential for me to stay up to date on the latest trends and developments in technology - not only to stay current as a programmer, but also to ensure my success as an entrpreneur. Lumino blog articles contain a variety of topics that have been useful for my own businesses - perhaps you will find them useful as well.