This is not legal is ASP.NET. But, oh, how I wish it were.
application.js
123456
$("selector").click(function(e){e.preventDefault();$.get('@Url.Action("Version", "Home")',function(result){// SNIP! Do something with the result...});});
You cannot do this, because your *.js files don’t get processed by the view engine. Instead of rendering out a valid path, you’ll really end up with a GET request being sent to http://myapplication.com/@Url.Action(%22Version%22,%20%22Home%22). I don’t know your application, but I’m willing to bet that isn’t quite right.
Ideally, you don’t want to hard-code the URL in the jQuery $.get call. You’ll lose refactor support, and your application won’t function the same way if it is installed to a virtual directory.
The Fix
My solution is to create a controller action that returns the necessary JavaScript. We’ll start with the model that we want to emit.
publicclassRoutesController:Controller{privatestaticboolhasInitializedRoutes=false;privatestaticJavaScriptExposedRoutesroutes;publicActionResultIndex(){// We will probably want to cache this output result. It isn't going to // change during the application lifecycle. It will be much faster to// return 304's than 200's.InitializeRoutes();returnJavaScript(routes.ToString());}privatevoidInitializeRoutes(){// This won't change during an application's lifetime. We can make the routes// variable static, along with the initialization check. We cannot make the // entire method static (nor can we use a static constructor), since the UrlHelper// instance (this.Url) is not static.if(!hasInitializedRoutes){routes=newJavaScriptExposedRoutes();routes.Add("about_url",Url.Action("About","Home"));routes.Add("home_url",Url.Action("Index","Home"));routes.Add("version_url",Url.Action("Version","Home"));hasInitializedRoutes=true;}}}
When you navigate to http://site/MyAppPath/Routes/Index, this is the result. For this example, I have set up Visual Studio to run in a virtual directory name MyAppPath to demonstrate that the URL helper is doing it’s job. If you’re not using a virtual directory, then this will not be necessary for you.
First, I’m going to add a route. By default, MVC puts these in global.asax. If you’ve moved this to a config folder (like you should), then put this with the rest of your routes.
12
// This route hides the fact that routes.js is really a controller action.routes.MapRoute("JavaScript-Routes","Scripts/routes.js",new{controller="Routes",action="Index"});
This is just a little bit of obfuscation. It’s one of those little things that will makes the user experience just a little bit nicer.
Here’s what it will look like in your view.
And here’s the rendered output in HTML.
The usage is now very straightforward. We have added a global object to your site called routes. This object contains only the routes you chose to expose through your controller action. Now, if we go back to our very first example, we can easily type the following.