Asp.Net MVC JavaScriptView
For a while now I’ve wanted the ability to generate javascript file like I generate html files. Take a little bit of the power of the WebForm view engine (just a little bit) and give that to me for JavaScript.
Why? I have a few reasons. Number one is I want to remove all of my JavaScript from the html, so the JavaScript is loaded via script tags. Once that happens, then I can have the JavaScript cached by the browser and speed up my application a bit. What I need the Asp.Net engine for was to give me accurate links to web site resources (images, web services, call, other javascript files, etc). These are thing that I don’t want to hard wire, mostly because I’ve bitten off the Asp.Net Routing engine bug. So, I want to use the Asp.Net Routing engine to tell me where to find stuff.
Not that I’ve committed to Asp.Net MVC I’ve come to a realization that making dynamic javascript files is well within my reach. Actually, it is almost there already; Asp.Net MVC ships with a JavaScriptResult. The downside of that result action is that the object expects you to hand it the JavaScript as a string, which it pushes to the browser as a file. I want to give a method a JavaScript View for that. The other good news about JavaScriptResult is that it doesn’t do much (just set the response.ContentType to application/x-javascript). So I could grab all of the View methods, turn them into extension methods, rename them, and then use them for my own underhanded affairs.
Luckily we can all grab the Asp.Net MVC source code and go to town. I didn’t modify the original source, but I defined a new class (JavaScriptFileResult) and a bunch of extension methods for the Asp.Net MVC Controller to give you JavaScriptView methods. You can see a usage in the first piece of code.
1: public ActionResult JsConstants( )
2: {
3: return this.JavaScriptView();
4: }
Now below is the actually extension methods and class needed. Put this in your project some place and go to down.
1: public class JavaScriptFileResult: ViewResult
2: {
3: public override void ExecuteResult(ControllerContext context)
4: {
5: base.ExecuteResult(context);
6: HttpResponseBase response = context.HttpContext.Response;
7: response.ContentType = "application/x-javascript";
8: }
9: }
10:
11: public static class JavaScriptControllerExtensions
12: {
13: public static ViewResult JavaScriptView(this Controller controller )
14: {
15: return JavaScriptView(controller, null /* viewName */, null /* masterName */, null /* model */);
16: }
17:
18: public static ViewResult JavaScriptView(this Controller controller, object model)
19: {
20: return JavaScriptView(controller, null /* viewName */, null /* masterName */, model);
21: }
22:
23: public static ViewResult JavaScriptView(this Controller controller, string viewName)
24: {
25: return JavaScriptView(controller, viewName, null /* masterName */, null /* model */);
26: }
27:
28: public static ViewResult JavaScriptView(this Controller controller, string viewName, string masterName)
29: {
30: return JavaScriptView(controller, viewName, masterName, null /* model */);
31: }
32:
33: public static ViewResult JavaScriptView(this Controller controller, string viewName, object model)
34: {
35: return JavaScriptView(controller, viewName, null /* masterName */, model);
36: }
37:
38: public static ViewResult JavaScriptView(this Controller controller, string viewName, string masterName, object model)
39: {
40: if( model != null )
41: {
42: controller.ViewData.Model = model;
43: }
44:
45: return new JavaScriptFileResult
46: {
47: ViewName = viewName,
48: MasterName = masterName,
49: ViewData = controller.ViewData,
50: TempData = controller.TempData
51: };
52: }
53:
54: public static ViewResult JavaScriptView(this Controller controller, IView view)
55: {
56: return JavaScriptView(controller, view, null /* model */);
57: }
58:
59: public static ViewResult JavaScriptView(this Controller controller, IView view, object model)
60: {
61: if( model != null )
62: {
63: controller.ViewData.Model = model;
64: }
65:
66: return new JavaScriptFileResult
67: {
68: View = view,
69: ViewData = controller.ViewData,
70: TempData = controller.TempData
71: };
72: }
Now the view, here is what it looks like:
1: <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
2: var UrlList = {
3: SubscriptionList: '<%=Url.Action("SubscriptionList", "Channel") %>',
4: MoreSubscriptions: '<%=Url.Action("More", "Channel") %>',
5: WaitGif: '<%=Url.Content("~/Content/img/ajaxloader.gif") %>',
6: };
Like I stated before, I was looking to get uris for the most part. But this could also be a strongly typed view where you have to pass in real data.
Finally, loading this view into my page. You saw the controller action was “JsConstants” above, which was in my HomeController (not shown), so here is how I ask the routing engine for the JavaScript file.
1: <script type="text/javascript" src="<%=Url.Content("~/Home/JsConstants") %>"></script>
So far I am happy with this technique. But if you see something that can be improved, please let me know.


