⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 toolkitscriptmanager.cs

📁 AJAX 应用 实现页面的无刷新
💻 CS
📖 第 1 页 / 共 3 页
字号:
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace AjaxControlToolkit
{
    /// <summary>
    /// ScriptManager derived class to add the ability to combine multiple
    /// smaller scripts into one larger one as a way to reduce the number
    /// of files the client must download
    /// </summary>
    [Themeable(true)]
    public class ToolkitScriptManager : ScriptManager
    {
        /// <summary>
        /// Request param name for the serialized combined scripts string
        /// </summary>
        private const string CombinedScriptsParamName = "_TSM_CombinedScripts_";

        /// <summary>
        /// Request param name for the hidden field name
        /// </summary>
        private const string HiddenFieldParamName = "_TSM_HiddenField_";

        /// <summary>
        /// Regular expression for detecting WebResource/ScriptResource substitutions in script files
        /// </summary>
        protected static readonly Regex WebResourceRegex = new Regex("<%\\s*=\\s*(?<resourceType>WebResource|ScriptResource)\\(\"(?<resourceName>[^\"]*)\"\\)\\s*%>", RegexOptions.Singleline | RegexOptions.Multiline);

        /// <summary>
        /// Specifies whether or not multiple script references should be combined into a single file
        /// </summary>
        public bool CombineScripts
        {
            get { return _combineScripts; }
            set { _combineScripts = value; }
        }
        private bool _combineScripts = true;

        /// <summary>
        /// Optionally specifies the URL of an HTTP handler for generating the combined script files
        /// </summary>
        /// <remarks>
        /// The handler's ProcessRequest method should call directly through to ToolkitScriptManager.OutputCombinedScriptFile
        /// </remarks>
        [UrlProperty]
        public Uri CombineScriptsHandlerUrl
        {
            get { return _combineScriptsHandlerUrl; }
            set { _combineScriptsHandlerUrl = value; }
        }
        private Uri _combineScriptsHandlerUrl;

        /// <summary>
        /// List of ScriptEntry objects tracking scripts that are used by the page
        /// </summary>
        private List<ScriptEntry> _scriptEntries;

        /// <summary>
        /// Url for the browser to request to get the combined script file
        /// </summary>
        private string _combinedScriptUrl;

        /// <summary>
        /// List of script references that have been disabled
        /// </summary>
        private List<ScriptReference> _disabledScriptReferences;

        /// <summary>
        /// List of script references that have been seen and are uncombinable
        /// </summary>
        private List<ScriptReference> _uncombinableScriptReferences;

        /// <summary>
        /// OnLoad override that runs only when serving the original page
        /// </summary>
        /// <param name="e">event args</param>
        protected override void OnLoad(EventArgs e)
        {
            // Initialize
            _disabledScriptReferences = new List<ScriptReference>();
            _uncombinableScriptReferences = new List<ScriptReference>();

            // Create a hidden field to track loaded scripts - load its contents if already present
            string hiddenFieldName = HiddenFieldName;
            string value = "";
            if (!IsInAsyncPostBack || (null == Page.Request.Form[hiddenFieldName]))
            {
                RegisterHiddenField(Page, hiddenFieldName, value);
            }
            else
            {
                value = Page.Request.Form[hiddenFieldName];
            }

            // Get the list of already-loaded scripts from the page
            _scriptEntries = DeserializeScriptEntries(value, true);

            base.OnLoad(e);
        }

        /// <summary>
        /// OnResolveScriptReference override to track combinable scripts and update the script references
        /// </summary>
        /// <param name="e">event args</param>
        protected override void OnResolveScriptReference(ScriptReferenceEventArgs e)
        {
            base.OnResolveScriptReference(e);

            // If combining scripts and this is a candidate script
            if (_combineScripts && !String.IsNullOrEmpty(e.Script.Assembly) && !String.IsNullOrEmpty(e.Script.Name))
            {
                // Initialize
                ScriptReference scriptReference = e.Script;
                ScriptEntry scriptEntry = new ScriptEntry(scriptReference);

                if (IsScriptCombinable(scriptEntry))
                {
                    if (!_scriptEntries.Contains(scriptEntry))
                    {
                        // Haven't seen this script yet; add it to the list and invalidate the Url
                        _scriptEntries.Add(scriptEntry);
                        _combinedScriptUrl = null;
                    }

                    if (null == _combinedScriptUrl)
                    {
                        // Url is invalid; update it
                        _combinedScriptUrl = String.Format(CultureInfo.InvariantCulture, "{0}?{1}={2}&{3}={4}", ((null != _combineScriptsHandlerUrl) ? _combineScriptsHandlerUrl.ToString() : Page.Request.Path), HiddenFieldParamName, HiddenFieldName, CombinedScriptsParamName, HttpUtility.UrlEncode(SerializeScriptEntries(_scriptEntries, false)));
                    }

                    // Remove the script from the list and track it
                    scriptReference.Name = "";
                    scriptReference.Assembly = "";
                    _disabledScriptReferences.Add(scriptReference);

                    // Update the common (combined) Url for all tracked scripts
                    foreach (ScriptReference disabledScriptReference in _disabledScriptReferences)
                    {
                        disabledScriptReference.Path = _combinedScriptUrl;
                    }
                }
                else
                {
                    // See if we've already seen this uncombinable script reference
                    bool alreadySeen = false;
                    foreach (ScriptReference uncombinableScriptReference in _uncombinableScriptReferences)
                    {
                        if ((uncombinableScriptReference.Assembly == scriptReference.Assembly) && (uncombinableScriptReference.Name == scriptReference.Name))
                        {
                            alreadySeen = true;
                        }
                    }
                    if (!alreadySeen)
                    {
                        // Haven't seen the script reference yet, so we need to stop building the current combined script
                        // file and let the uncombinable script reference be output so as not to alter the ordering of
                        // scripts (which may have dependencies). Update our state so we'll start building a new combined
                        // script file with the next combinable script.
                        // Note: _combinedScriptUrl was initially cleared here. While that's correct behavior (and was
                        // released without issue), not clearing it means that we can omit an unnecessary <script> tag
                        // for the scenario "CombinableA, Uncombinable?, CombinableA, Uncombinable?" because the second
                        // instance of CombinableA will reuse the URL from the first (vs. an empty one) and ScriptManager
                        // will detect and omit the redundant URL.
                        _uncombinableScriptReferences.Add(scriptReference);
                        _disabledScriptReferences.Clear();
                        foreach (ScriptEntry se in _scriptEntries)
                        {
                            se.Loaded = true;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// OnInit override that runs only when serving the combined script file
        /// </summary>
        /// <param name="e">event args</param>
        protected override void OnInit(EventArgs e)
        {
            if (!DesignMode && (null != Context) && OutputCombinedScriptFile(Context))
            {
                // This was a combined script request that was satisfied; end all processing now
                Page.Response.End();
            }
            base.OnInit(e);
        }

        /// <summary>
        /// Outputs the combined script file requested by the HttpRequest to the HttpResponse
        /// </summary>
        /// <param name="context">HttpContext for the transaction</param>
        /// <returns>true if the script file was output</returns>
        public static bool OutputCombinedScriptFile(HttpContext context)
        {
            // Initialize
            bool output = false;
            HttpRequest request = context.Request;
            string hiddenFieldName = request.Params[HiddenFieldParamName];
            string combinedScripts = request.Params[CombinedScriptsParamName];

            if (!string.IsNullOrEmpty(hiddenFieldName) && !string.IsNullOrEmpty(combinedScripts))
            {
                // This is a request for a combined script file
                HttpResponse response = context.Response;
                response.ContentType = "application/x-javascript";

                // Set the same (~forever) caching rules that ScriptResource.axd uses
                HttpCachePolicy cache = response.Cache;
                cache.SetCacheability(HttpCacheability.Public);
                cache.VaryByParams[HiddenFieldParamName] = true;
                cache.VaryByParams[CombinedScriptsParamName] = true;
                cache.SetOmitVaryStar(true);
                cache.SetExpires(DateTime.Now.AddDays(365));
                cache.SetValidUntilExpires(true);
                cache.SetLastModifiedFromFileDependencies();

                // Get the stream to write the combined script to (using a compressed stream if requested)
                // Note that certain versions of IE6 have difficulty with compressed responses, so we
                // don't compress for those browsers (just like ASP.NET AJAX's ScriptResourceHandler)
                Stream outputStream = response.OutputStream;
                if (!request.Browser.IsBrowser("IE") || (6 < request.Browser.MajorVersion))
                {
                    foreach (string acceptEncoding in (request.Headers["Accept-Encoding"] ?? "").ToUpperInvariant().Split(','))
                    {
                        if ("GZIP" == acceptEncoding)
                        {
                            // Browser wants GZIP; wrap the output stream with a GZipStream
                            response.AddHeader("Content-encoding", "gzip");
                            outputStream = new GZipStream(outputStream, CompressionMode.Compress);
                            break;
                        }
                        else if ("DEFLATE" == acceptEncoding)
                        {
                            // Browser wants Deflate; wrap the output stream with a DeflateStream
                            response.AddHeader("Content-encoding", "deflate");
                            outputStream = new DeflateStream(outputStream, CompressionMode.Compress);
                            break;
                        }
                    }
                }

                // Output the combined script

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -