Embed and using RequireJS in ASP.Net WebForm

So you have ASP.Net Web application and you want to do AMD module pattern in your scripts? If it so, then you’re in a same page with me.

I’d like to share with you how I do that, so you might want to give some comments for improvements – and that would be nice :)

AMD Module Pattern in WebForm

AMD module pattern is cool, but doing AMD module in ASP.NET WebForm is not as easy as you doing it with ASP.NET MVC or even Node. Because main concern in AMD module pattern is script loader or module loader.

In ASP.NET MVC you can easily use your actual contents folder or script folder as a web content folder, which will makes script easier to be loaded.

But not in ASP.NET WebForm. In ASP.NET WebForm you often need to store your scripts as WebResource that will be handled by ScriptManager, especially if you want to build custom server control like AjaxControlToolkit or something.

I’ve been working with RequireJS as my AMD module framework and script loader for several projects in ASP.NET MVC, so I’ll use it again this time in my WebForm application.

Walkthrough

Say you already have ASP.Net web form application, or maybe not… but just to be clear let’s create a new one for this walkthrough.

Please follow this steps:

  1. In Visual Studio, Create ASP.NET Empty Web Site project called WebApp.
  2. Create folder called Scripts and add RequireJS (require.js) there. You can download require.js from here: http://requirejs.org/docs/download.html#requirejs. Or alternatively you might want to install RequireJS by nuget package, thus you don’t need to create Scripts folder – nuget will create it for you.
  3. Create main.js script file inside Scripts folder. This file will be our application main script file.
  4. Change Build Action property of those 2 files as Embedded Resource. So far, it should be like this:
    scripts-structure-1
  5. Enable embedded main.js and require.js for use as a Web resource. This is done by applying WebResourceAttribute for those files:
    [assembly: WebResource("WebApp.Scripts.require.js", "text/javascript")]
    [assembly: WebResource("WebApp.Scripts.main.js", "text/javascript")]

    You can apply this attribute on whatever startup code you have, but since we don’t have it yet for now let’s apply it on AssemblyInfo.cs file.

    assembly-info

  6. We want to load RequireJS loaded on the head of HTML tag, as you can see on RequireJS documentation:
    <!DOCTYPE html>
    <html>
        <head>
            <title>My Sample Project</title>
            <!-- data-main attribute tells require.js to load
                 scripts/main.js after require.js loads. -->
            <script data-main="scripts/main" src="scripts/require.js"></script>
        </head>
        <body>
            <h1>My Sample Project</h1>
        </body>
    </html>

    Alright, we want have this: <script data-main=”scripts/main” src=”scripts/require.js”></script> in our web form. But of course that will not done by simply copy paste that script, right? :)

    Now it would be little bit hacky. Since this script is should be reusable, I prefer to have custom script manager that I can use in every pages – so let’s start by creating our custom script manager. Add class derived from System.Web.UI. ScriptManager called AppScriptManager. In this AppScriptManager we will manage RequireJS script tag – so it will be always automatically added on every pages that using this custom script manager. The complete code of AppScriptManager should looks like this:

    using System;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    
    namespace WebApp
    {
        public class AppScriptManager : ScriptManager
        {
            protected override void OnInit(EventArgs e)
            {
                // Build requirejs start-up script
                var requireJsUrl = GetWebResourceUrl("WebApp.Scripts.require.js");
                var mainScriptUrl = GetWebResourceUrl("WebApp.Scripts.main.js");
    
                var js = new HtmlGenericControl("script");
                js.Attributes["type"] = "text/javascript";
                js.Attributes["data-main"] = mainScriptUrl;
                js.Attributes["src"] = requireJsUrl;
                Page.Header.Controls.Add(js);
    
                base.OnInit(e);
            }
    
            string GetWebResourceUrl(string resource)
            {
                return Page.ClientScript.GetWebResourceUrl(this.GetType(), resource);
            }
        }
    }

    It will resulting RequireJS script located inside HTML head tag like this:

    <script type="text/javascript" data-main="/WebResource.axd?d=KvPphKM4CotnzPZHD5xe1SqQdCAMbPwv_QeAxnToCUVxdo9jBcCfuVltjPRMci2Z98brZV77CrNhZsnpDaUbnSjn-SEK-lmlZzqu0XuO2BY1&amp;t=635067158285221152" src="/WebResource.axd?d=ZDwD38MtgM6KgI3r0IKzQcDGzve4tum-JoYDUWUdwjrXMHs_IYivu-0Bd6CZs7dMwPSfQuU0CvKpdXL0NHyVGJVlQLUpLQtnu2-G8oTUZ42Oii5ujE81dKDUx7VOD8Pa0&amp;t=635067158285221152"></script>
  7. Now open main.js and put this script :
    define(function (require) {
        console.log('main script is loaded');
    });
  8. To test this stuff is working, just create one WebForm named Default.aspx. Open it in design mode, you should see AppScriptManager located on Visual Studio toolbox. Just drag it to the page:web-form
  9. OK, now it’s time to prove it. Run this app and open your browser console and you should see ‘main script is loaded’ text there:browser-view

 

That’s all, I hope this helps, that’s the best thing I know how to make RequireJS works with WebForm application. Just let me know if there’s another better option out there.

Thanks for reading!

 

adiono