Premier Web Design, Web Development and eCommerce Development in Virginia, Washington DC and Maryland

Ameronix is a web design and development firm capable of planning, developing and maintaining basic websites to advanced websites ranging from informative websites to eCommerce platforms and social networking websites to high end corporate intranet/portal websites.
Ameronix is a web design and development firm capable of planning, developing and maintaining basic websites to advanced websites ranging from informative websites to eCommerce platforms and social networking websites to high end corporate intranet/portal websites.

Posts Tagged ‘ASP .NET’

Script Tags and Master Pages in ASP

Saturday, February 23rd, 2008

Introduction

In a recent ASP .NET project I decided to use a global “Master Page” to contain my major theme code and use individual ASPX pages strictly for content. As a personal preference I like to use absolute paths relative to the site root. I very rarely have path issues when using absolute paths. This project requires that relative paths be used since the web application would be switching domains and placed within a sub-directory. One of the advantages of Master pages is that any pages in a sub-directory that utilize a Master page in the application’s root directory have their relative links updated automatically. The server adds the correct number of “../”’s to the front of the path. According to the MSDN documentation this occurs on all ASP web controls (anything that is <asp:….>). I noticed that my <link> paths were also automatically being updated, neat.

The Problem:

The problems started to show up when I added JavaScript to the Master page for navigation. Everything worked fine in the application’s root directory (also the location of the Master Page file), but for pages in a sub-directory the script tag’s “src” attribute was not updating. Thus my navigation did not work and any other scripts would not load.

The Solution:

To rectify this error I had to write a custom server control. Having never done this before I hit some problems, but I will go through all of the steps to get the custom control created and working.

  1. Create a new Class in your project, name it “Script.cs”, it should be placed in the App_Code directory.
  2. Import the necessary namespaces and declare your namespace (this is very important)
    using System;
    using System.ComponentModel;
    using System.Security.Permissions;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    namespace Ameronix
  3. Next declare a couple of enums for the script type and script language, these will make future expansion easier.
    
    public enum ScriptType { javascript };
    
    public enum ScriptLanguage { javascript };
  4. Since this is a control that is not visible to the user we are extending the .NET class “Control”. We also need to set some security levels and toolbox data.
    
        [
    
        AspNetHostingPermission(SecurityAction.Demand,
    
            Level = AspNetHostingPermissionLevel.Minimal),
    
        AspNetHostingPermission(SecurityAction.InheritanceDemand,
    
            Level = AspNetHostingPermissionLevel.Minimal),
    
        DefaultProperty("ScriptSource"),
    
        ToolboxData("<{0}:Javascript runat\"server\" />")
    
        ]
    
        public class Script : Control
  5. Next we declare our properties that will be accessible. I have included the Script’s source, type, and language, as these are the most common.
    
            /// <summary>
    
            /// The source url for the script
    
            /// </summary>
    
           [
    
            Bindable(true),
    
            Category("Behavior"),
    
            DefaultValue(""),
    
            Description("The relative path to the javascript file."),
    
            Localizable(false)
    
            ]
    
            public string ScriptSource
    
            {
    
                get { return ViewState["ScriptSource"] as string; }
    
                set { ViewState["ScriptSource"] = value; }
    
            }        /// <summary>
    
            /// The type of script this is
    
            /// </summary>
    
            public ScriptType ScriptType
    
            {
    
                get { return (ViewState["ScriptType"] == null) ? ScriptType.javascript : (ScriptType)ViewState["ScriptType"]; }
    
                set { ViewState["ScriptType"] = value; }
    
            }
    
    /// <summary>
    
            /// The language the script is written in
    
            /// </summary>
    
            public ScriptLanguage ScriptLanguage
    
            {
    
                get { return (ViewState["ScriptLanguage"] == null) ? ScriptLanguage.javascript : (ScriptLanguage)ViewState["ScriptLanguage"]; }
    
                set { ViewState["ScriptLanguage"] = value; }
    
            }
  6. Finally we override the Render() method so we can actually output the element.
    
    
            /// <summary>
    
            /// Renders the control at runtime
    
            /// </summary>
    
            /// <param name="writer">The writer to use to output the HTML</param>
    
            protected override void Render(HtmlTextWriter writer)
    
            {
    
                base.Render(writer);            string type;
    
                string language;
    
    switch (ScriptType)
    
                {
    
                    case ScriptType.javascript:
    
                    default:
    
                        type = “text/javascript”;
    
                        break;
    
                }
    
    switch (ScriptLanguage)
    
                {
    
                    case ScriptLanguage.javascript:
    
                    default:
    
                        language = “javascript”;
    
                        break;
    
                }
    
    writer.Write(”<script src=\”{0}\” type=\”{1}\” language=\”{2}\”></script>”, ResolveClientUrl(ScriptSource), type, language);
    
    writer.Write(Environment.NewLine);
    
            }

    The most important line converts our relative link for any page underneath a sub-directory.

    
    
    writer.Write("<script src=\"{0}\" type=\"{1}\" language=\"{2}\"></script>", ResolveClientUrl(ScriptSource), type, language);
    
    

    The code should resemble the following:

    
    
    using System;
    
    using System.ComponentModel;
    
    using System.Security.Permissions;
    
    using System.Web;
    
    using System.Web.UI;
    
    using System.Web.UI.WebControls;namespace Ameronix
    
    {
    
    public enum ScriptType { javascript };
    
        public enum ScriptLanguage { javascript };
    
    [
    
        AspNetHostingPermission(SecurityAction.Demand,
    
            Level = AspNetHostingPermissionLevel.Minimal),
    
        AspNetHostingPermission(SecurityAction.InheritanceDemand,
    
            Level = AspNetHostingPermissionLevel.Minimal),
    
        DefaultProperty(”ScriptSource”),
    
        ToolboxData(”<{0}:Javascript runat\”server\” />”)
    
        ]
    
        public class Script : Control
    
        {
    
            /// <summary>
    
            /// The source url for the script
    
            /// </summary>
    
           [
    
            Bindable(true),
    
            Category(”Behavior”),
    
            DefaultValue(”"),
    
            Description(”The relative path to the javascript file.”),
    
            Localizable(false)
    
            ]
    
            public string ScriptSource
    
            {
    
                get { return ViewState[”ScriptSource”] as string; }
    
                set { ViewState[”ScriptSource”] = value; }
    
            }
    
    /// <summary>
    
            /// The type of script this is
    
            /// </summary>
    
            public ScriptType ScriptType
    
            {
    
                get { return (ViewState[”ScriptType”] == null) ? ScriptType.javascript : (ScriptType)ViewState[”ScriptType”]; }
    
                set { ViewState[”ScriptType”] = value; }
    
            }
    
    /// <summary>
    
            /// The language the script is written in
    
            /// </summary>
    
            public ScriptLanguage ScriptLanguage
    
            {
    
                get { return (ViewState[”ScriptLanguage”] == null) ? ScriptLanguage.javascript : (ScriptLanguage)ViewState[”ScriptLanguage”]; }
    
                set { ViewState[”ScriptLanguage”] = value; }
    
            }
    
    /// <summary>
    
            /// Renders the control at runtime
    
            /// </summary>
    
            /// <param name=”writer”>The writer to use to output the HTML</param>
    
            protected override void Render(HtmlTextWriter writer)
    
            {
    
                base.Render(writer);
    
    string type;
    
                string language;
    
    switch (ScriptType)
    
                {
    
                    case ScriptType.javascript:
    
                    default:
    
                        type = “text/javascript”;
    
                        break;
    
                }
    
    switch (ScriptLanguage)
    
                {
    
                    case ScriptLanguage.javascript:
    
                    default:
    
                        language = “javascript”;
    
                        break;
    
                }
    
    writer.Write(”<script src=\”{0}\” type=\”{1}\” language=\”{2}\”></script>”, ResolveClientUrl(ScriptSource), type, language);
    
    writer.Write(Environment.NewLine);
    
            }
    
        }
    
    }
  7. Now we have a new control, but our ASP pages cannot see it. We need to map the namespace in our application. Open your web.config file and add the following to your system.web directive.
    
    
          <pages>
    
            <controls>
    
              <add tagPrefix="amx" namespace="Ameronix"/>
    
            </controls>
    
          </pages>
    
    

    The tag prefix will be useful shortly so don’t forget it.

  8. In your master page file start a new tag “<amx:” auto complete should display “Script” now. Fill in the required variables and your new control will be used in the master page. Note: you MUST include runat=”server” or the control will not be converted into the appropriate script tag. For example:
    
    
    <amx:Script ID="js_jquery" ScriptSource="resources/js/jquery.js" ScriptType="javascript" ScriptLanguage="javascript" runat="server" />