ScriptReference.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / Orcas / RTM / ndp / fx / src / xsp / System / Web / Extensions / ui / ScriptReference.cs / 2 / ScriptReference.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI { 
    using System; 
    using System.ComponentModel;
    using System.Collections; 
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Reflection;
    using System.Security; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Web; 
    using System.Web.UI;
    using System.Web.UI.WebControls; 
    using System.Web.Handlers;
    using System.Web.Resources;
    using System.Web.Util;
 
    using Debug = System.Diagnostics.Debug;
 
    [ 
    AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), 
    DefaultProperty("Path"),
    ]
    public class ScriptReference {
        // Maps Pair(resource name, assembly) to string (partial script path) 
        private static readonly Hashtable _scriptPathCache = Hashtable.Synchronized(new Hashtable());
 
        private bool _alwaysLoadBeforeUI; 
        private string _assembly;
        private IClientUrlResolver _clientUrlResolver; 
        private bool _isStaticReference;
        private bool _ignoreScriptPath;
        private string _name;
        private bool _notifyScriptLoaded = true; 
        private Control _containingControl;
        private string _path; 
        private string[] _resourceUICultures; 
        private ScriptMode _scriptMode;
 
        public ScriptReference() {}

        public ScriptReference(string name, string assembly) : this() {
            Name = name; 
            Assembly = assembly;
        } 
 
        public ScriptReference(string path) : this() {
            Path = path; 
        }

        internal ScriptReference(string name, IClientUrlResolver clientUrlResolver, Control containingControl) {
            Debug.Assert(!String.IsNullOrEmpty(name), "The script's name must be specified."); 
            Debug.Assert(clientUrlResolver != null && clientUrlResolver is ScriptManager, "The clientUrlResolver must be the ScriptManager.");
            Name = name; 
            ClientUrlResolver = clientUrlResolver; 
            IsStaticReference = true;
            ContainingControl = containingControl; 
        }

        internal bool AlwaysLoadBeforeUI {
            get { 
                return _alwaysLoadBeforeUI;
            } 
            set { 
                _alwaysLoadBeforeUI = value;
            } 
        }

        [
        Category("Behavior"), 
        DefaultValue(""),
        ResourceDescription("ScriptReference_Assembly") 
        ] 
        public string Assembly {
            get { 
                return (_assembly == null) ? String.Empty : _assembly;
            }
            set {
                _assembly = value; 
            }
        } 
 
        // Used by ScriptManager to associate a ScriptReference with its url resolver
        // (i.e. ScriptManager or ScriptManagerProxy) 
        internal IClientUrlResolver ClientUrlResolver {
            get {
                return _clientUrlResolver;
            } 
            set {
                _clientUrlResolver = value; 
            } 
        }
 
        internal Control ContainingControl {
            get {
                return _containingControl;
            } 
            set {
                _containingControl = value; 
            } 
        }
 
        private ScriptMode EffectiveScriptMode {
            get {
                if (ScriptMode == ScriptMode.Auto) {
                    // - When only Path is specified, ScriptMode.Auto is equivalent to ScriptMode.Release. 
                    // - When only Name is specified, ScriptMode.Auto is equivalent to ScriptMode.Inherit.
                    // - When Name and Path are both specified, the Path is used instead of the Name, but 
                    //   ScriptMode.Auto is still equivalent to ScriptMode.Inherit, since the assumption 
                    //   is that if the Assembly contains both release and debug scripts, the Path should
                    //   contain both as well. 
                    return (String.IsNullOrEmpty(Name) ? ScriptMode.Release : ScriptMode.Inherit);
                }
                else {
                    return ScriptMode; 
                }
            } 
        } 

        [ 
        Category("Behavior"),
        DefaultValue(false),
        ResourceDescription("ScriptReference_IgnoreScriptPath")
        ] 
        public bool IgnoreScriptPath {
            get { 
                return _ignoreScriptPath; 
            }
            set { 
                _ignoreScriptPath = value;
            }
        }
 
        // isStaticReference is true if the reference came from a ScriptManager or ScriptManagerProxy scripts collection,
        // false if it came from an IScriptControl or ExtenderControl. 
        internal bool IsStaticReference { 
            get {
                return _isStaticReference; 
            }
            set {
                _isStaticReference = value;
            } 
        }
 
        [ 
        Category("Behavior"),
        DefaultValue(""), 
        ResourceDescription("ScriptReference_Name")
        ]
        public string Name {
            get { 
                return (_name == null) ? String.Empty : _name;
            } 
            set { 
                _name = value;
            } 
        }

        [
        Category("Behavior"), 
        DefaultValue(true),
        ResourceDescription("ScriptReference_NotifyScriptLoaded") 
        ] 
        public bool NotifyScriptLoaded {
            get { 
                return _notifyScriptLoaded;
            }
            set {
                _notifyScriptLoaded = value; 
            }
        } 
 
        [
        Category("Behavior"), 
        DefaultValue(""),
        ResourceDescription("ScriptReference_Path"),
        UrlProperty("*.js")
        ] 
        public string Path {
            get { 
                return (_path == null) ? String.Empty : _path; 
            }
            set { 
                _path = value;
            }
        }
 
        [
        ResourceDescription("ScriptReference_ResourceUICultures"), 
        DefaultValue(null), 
        Category("Behavior"),
        MergableProperty(false), 
        TypeConverter(typeof(StringArrayConverter)),
        SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
            Justification = "String[] has existing TypeConverter support, which we don't want to add for List to the assembly just for this property and at this point in the product cycle.")
        ] 
        public string[] ResourceUICultures {
            get { 
                return _resourceUICultures; 
            }
            set { 
                _resourceUICultures = value;
            }
        }
 
        [
        Category("Behavior"), 
        DefaultValue(ScriptMode.Auto), 
        ResourceDescription("ScriptReference_ScriptMode")
        ] 
        public ScriptMode ScriptMode {
            get {
                return _scriptMode;
            } 
            set {
                if (value < ScriptMode.Auto || value > ScriptMode.Release) { 
                    throw new ArgumentOutOfRangeException("value"); 
                }
                _scriptMode = value; 
            }
        }

        private CultureInfo DetermineCulture() { 
            if ((ResourceUICultures == null) || (ResourceUICultures.Length == 0)) {
                // In this case we want to determine available cultures from assembly info if available 
                if (!String.IsNullOrEmpty(Name)) { 
                    return ScriptResourceHandler
                        .DetermineNearestAvailableCulture(GetAssembly(), Name, CultureInfo.CurrentUICulture); 
                }
                return CultureInfo.InvariantCulture;
            }
            CultureInfo currentCulture = CultureInfo.CurrentUICulture; 
            while (!currentCulture.Equals(CultureInfo.InvariantCulture)) {
                string cultureName = currentCulture.ToString(); 
                foreach (string uiCulture in ResourceUICultures) { 
                    if (String.Equals(cultureName, uiCulture.Trim(), StringComparison.OrdinalIgnoreCase)) {
                        return currentCulture; 
                    }
                }
                currentCulture = currentCulture.Parent;
            } 
            return currentCulture;
        } 
 
        internal Assembly GetAssembly() {
            string assemblyName = Assembly; 
            if (String.IsNullOrEmpty(assemblyName)) {
                return AssemblyCache.SystemWebExtensions;
            }
            else { 
                // Use AssemblyCache instead of directly calling Assembly.Load(), for improved perf.
                // Increases requests/second by over 150% in ScriptManagerAssembly.aspx test. 
                return AssemblyCache.Load(assemblyName); 
            }
        } 

        // Release: foo.js
        // Debug:   foo.debug.js
        private static string GetDebugName(string releaseName) { 
            // Since System.Web.Handlers.AssemblyResourceLoader treats the resource name as case-sensitive,
            // we must do the same when verifying the extension. 
            // Ignore trailing whitespace. For example, "MicrosoftAjax.js " is valid (at least from 
            // a debug/release naming perspective).
            if (!releaseName.EndsWith(".js", StringComparison.Ordinal)) { 
                throw new InvalidOperationException(
                    String.Format(CultureInfo.CurrentUICulture, AtlasWeb.ScriptReference_InvalidReleaseScriptName, releaseName));
            }
 
            return ReplaceExtension(releaseName);
        } 
 
        // Script path may contain a query string, while script name may not
        // Release: foo.js?key=value 
        // Debug:   foo.debug.js?key=value
        private static string GetDebugPath(string releasePath) {
            // Per RFC 3986, the '?' delimits the query, regardless of the protocol.  This overrides
            // an earlier RFC, which stated that FTP protocol allows '?' as path characters. 
            string pathWithoutQuery;
            string query; 
            if (releasePath.IndexOf('?') >= 0) { 
                int indexOfQuery = releasePath.IndexOf('?');
                pathWithoutQuery = releasePath.Substring(0, indexOfQuery); 
                query = releasePath.Substring(indexOfQuery);
            }
            else {
                pathWithoutQuery = releasePath; 
                query = null;
            } 
 
            if (!pathWithoutQuery.EndsWith(".js", StringComparison.Ordinal)) {
                throw new InvalidOperationException( 
                    String.Format(CultureInfo.CurrentUICulture, AtlasWeb.ScriptReference_InvalidReleaseScriptPath, pathWithoutQuery));
            }

            return ReplaceExtension(pathWithoutQuery) + query; 
        }
 
        private string GetPath(string releasePath, ScriptManager scriptManager) { 
            if (String.IsNullOrEmpty(Name)) {
                return GetPathWithoutName(releasePath, scriptManager); 
            }
            else {
                return GetPathWithName(releasePath, scriptManager);
            } 
        }
 
        // When Name is empty, there is no Name/Assembly logic involved. 
        private string GetPathWithoutName(string releasePath, ScriptManager scriptManager) {
            if (IsDebuggingEnabled(scriptManager)) { 
                return GetDebugPath(releasePath);
            }
            else {
                return releasePath; 
            }
        } 
 
        // When Name and Path are both specified, the Path is used instead of the Name, but we
        // still verify that the named resource exists in the assembly.  We also look inside the 
        // assembly to determine whether to use the debug or release script.  The assumption is
        // that if the Assembly contains only a release script, the path should contain only a
        // release script as well.
        private string GetPathWithName(string releasePath, ScriptManager scriptManager) { 
            if (ShouldUseDebugScript(Name, GetAssembly(), scriptManager)) {
                return GetDebugPath(releasePath); 
            } 
            else {
                return releasePath; 
            }
        }

        private string GetResourceName(string releaseName, Assembly assembly, ScriptManager scriptManager) { 
            string resourceName;
 
            if (ShouldUseDebugScript(releaseName, assembly, scriptManager)) { 
                resourceName = GetDebugName(releaseName);
            } 
            else {
                resourceName = releaseName;
            }
 
            return resourceName;
        } 
 
        // Format: ///
        // This function does not canonicalize the path in any way (i.e. remove duplicate slashes). 
        // You must call ResolveClientUrl() on this path before rendering to the page.
        private static string GetScriptPath(
            string resourceName,
            Assembly assembly, 
            CultureInfo culture,
            string scriptPath) { 
 
            return scriptPath + "/" + GetScriptPathCached(resourceName, assembly, culture);
        } 

        // Cache partial script path, since Version.ToString() and HttpUtility.UrlEncode() are expensive.
        // Increases requests/second by 50% in ScriptManagerScriptPath.aspx test.
        private static string GetScriptPathCached(string resourceName, Assembly assembly, CultureInfo culture) { 
            Tuple key = new Tuple(resourceName, assembly, culture);
            string scriptPath = (string)_scriptPathCache[key]; 
 
            if (scriptPath == null) {
                // Need to use "new AssemblyName(assembly.FullName)" instead of "assembly.GetName()", 
                // since Assembly.GetName() requires FileIOPermission to the path of the assembly.
                // In partial trust, we may not have this permission.
                AssemblyName assemblyName = new AssemblyName(assembly.FullName);
 
                string name = assemblyName.Name;
                string version = assemblyName.Version.ToString(); 
                string fileVersion = AssemblyUtil.GetAssemblyFileVersion(assembly); 

                if ((!culture.Equals(CultureInfo.InvariantCulture)) && 
                    resourceName.EndsWith(".js", StringComparison.OrdinalIgnoreCase)) {

                    resourceName = resourceName.Substring(0, resourceName.Length - 3) +
                        "." + culture.Name + ".js"; 
                }
 
                // Assembly name, fileVersion, and resource name may contain invalid URL characters (like '#' or '/'), 
                // so they must be url-encoded.
                scriptPath = String.Join("/", new string[] { 
                    HttpUtility.UrlEncode(name), version, HttpUtility.UrlEncode(fileVersion), HttpUtility.UrlEncode(resourceName)
                });

                _scriptPathCache[key] = scriptPath; 
            }
 
            return scriptPath; 
        }
 
        internal string GetUrl(ScriptManager scriptManager, IControl scriptManagerControl, bool zip) {
            bool hasName = !String.IsNullOrEmpty(Name);
            bool hasAssembly = !String.IsNullOrEmpty(Assembly);
            bool hasPath = !String.IsNullOrEmpty(Path); 

            if (!hasName && !hasPath) { 
                throw new InvalidOperationException(AtlasWeb.ScriptReference_NameAndPathCannotBeEmpty); 
            }
 
            if (hasAssembly && !hasName) {
                throw new InvalidOperationException(AtlasWeb.ScriptReference_AssemblyRequiresName);
            }
 
            // If Path+Name are specified, Path overrides Name.
            if (hasPath) { 
                return GetUrlFromPath(scriptManager); 
            }
            else { 
                Debug.Assert(hasName);
                return GetUrlFromName(scriptManager, scriptManagerControl, zip);
            }
        } 

        private string GetUrlFromName(ScriptManager scriptManager, IControl scriptManagerControl, bool zip) { 
            string releaseName = Name; 

            Assembly assembly = GetAssembly(); 
            // GetResourceName() throws exception if the resource name does not exist in the assembly
            string resourceName = GetResourceName(releaseName, assembly, scriptManager);

            string url; 
            CultureInfo culture = (scriptManager.EnableScriptLocalization ?
                DetermineCulture() : CultureInfo.InvariantCulture); 
 
            if (IgnoreScriptPath || String.IsNullOrEmpty(scriptManager.ScriptPath)) {
                url = ScriptResourceHandler 
                    .GetScriptResourceUrl(assembly, resourceName, culture, zip, NotifyScriptLoaded);
            }
            else {
                string path = GetScriptPath(resourceName, assembly, culture, scriptManager.ScriptPath); 
                // Always want to resolve ScriptPath urls against the ScriptManager itself,
                // regardless of whether the ScriptReference was declared on the ScriptManager 
                // or a ScriptManagerProxy. 
                url = scriptManagerControl.ResolveClientUrl(path);
            } 

            return url;
        }
 
        private string GetUrlFromPath(ScriptManager scriptManager) {
            string releasePath = Path; 
 
            string path = GetPath(releasePath, scriptManager);
            // Once the path has been determined, add localization if necessary 
            if (scriptManager.EnableScriptLocalization) {
                CultureInfo culture = DetermineCulture();
                if (!culture.Equals(CultureInfo.InvariantCulture)) {
                    path = (path.Substring(0, path.Length - 2) + culture.ToString() + ".js"); 
                }
            } 
            string resolvedUrl = _clientUrlResolver.ResolveClientUrl(path); 

            return resolvedUrl; 
        }

        private bool IsDebuggingEnabled(ScriptManager scriptManager) {
            // Deployment mode retail overrides all values of ScriptReference.ScriptMode. 
            if (scriptManager.DeploymentSectionRetail) {
                return false; 
            } 

            switch (EffectiveScriptMode) { 
                case ScriptMode.Inherit:
                    return scriptManager.IsDebuggingEnabled;
                case ScriptMode.Debug:
                    return true; 
                case ScriptMode.Release:
                    return false; 
                default: 
                    Debug.Fail("Invalid value for ScriptReference.EffectiveScriptMode");
                    return false; 
            }
        }

        internal bool IsFrameworkAssembly() { 
            return (GetAssembly() == AssemblyCache.SystemWebExtensions);
        } 
 
        // Assumes the input ends with ".js".  Replaces the ".js" at the end of the input
        // with ".debug.js". 
        private static string ReplaceExtension(string pathOrName) {
            Debug.Assert(pathOrName.EndsWith(".js", StringComparison.Ordinal));
            return (pathOrName.Substring(0, pathOrName.Length - 2) + "debug.js");
        } 

        private bool ShouldUseDebugScript(string releaseName, Assembly assembly, ScriptManager scriptManager) { 
            bool useDebugScript; 
            string debugName = null;
 
            if (IsDebuggingEnabled(scriptManager)) {
                debugName = GetDebugName(releaseName);

                // If an assembly contains a release script but not a corresponding debug script, and we 
                // need to register the debug script, we normally throw an exception.  However, we automatically
                // use the release script if ScriptReference.ScriptMode is Auto.  This improves the developer 
                // experience when ScriptMode is Auto, yet still gives the developer full control with the 
                // other ScriptModes.
                if (ScriptMode == ScriptMode.Auto && !WebResourceUtil.AssemblyContainsWebResource(assembly, debugName)) { 
                    useDebugScript = false;
                }
                else {
                    useDebugScript = true; 
                }
            } 
            else { 
                useDebugScript = false;
            } 

            // Verify that assembly contains required web resources.  Always check for release
            // script before debug script.
            WebResourceUtil.VerifyAssemblyContainsReleaseWebResource(assembly, releaseName); 
            if (useDebugScript) {
                Debug.Assert(debugName != null); 
                WebResourceUtil.VerifyAssemblyContainsDebugWebResource(assembly, debugName); 
            }
 
            return useDebugScript;
        }

        // Improves the UI in the VS collection editor, by displaying the Name or Path (if available), or 
        // the short type name.
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] 
        public override string ToString() { 
            if (!String.IsNullOrEmpty(Name)) {
                return Name; 
            }
            else if (!String.IsNullOrEmpty(Path)) {
                return Path;
            } 
            else {
                return GetType().Name; 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK