zoukankan      html  css  js  c++  java
  • Asp.net MVC Bundle 的使用与扩展

    一、Asp.net 自带Bundle的使用:

    1. 在Globale中注册与配置

    BundleConfig.RegisterBundles(BundleTable.Bundles);
    public class BundleConfig
        {
            // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
            public static void RegisterBundles(BundleCollection bundles)
            {
                // Use the development version of Modernizr to develop with and learn from. Then, when you're
                // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
                bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                            "~/Scripts/modernizr-*"));
    
                bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                            "~/Scripts/jquery-{version}.js"));
    
    #if !DEBUG
                BundleTable.EnableOptimizations = true;
    #endif
            }
        }

    2. 页面上使用

    @Scripts.Render("~/bundles/jquery")

    二、扩展使用-动态Bundle

    要求达到以下目标:1. 支持动态页面上的Bundle,而不必每次在Global中添加Bundle。2.支持Javascript混淆

    1. 扩展方法

    public static class Extension
        {
            public static IHtmlString Script(this HtmlHelper helper, params string[] urls)
            {
                var bundleDirectory = "~/bundles/" + MakeBundleName("js", urls);
                var bundle = BundleTable.Bundles.GetBundleFor(bundleDirectory);
                if (bundle == null)
                {
                    var transform = new JavascriptObfuscator();
                    bundle = new ScriptBundle(bundleDirectory).Include(urls);
                    bundle.Transforms.Add(transform);
                    BundleTable.Bundles.Add(bundle);
                }
                return Scripts.Render(bundleDirectory);
            }
    
            public static IHtmlString Style(this HtmlHelper helper, params string[] urls)
            {
                var bundleDirectory = "~/bundles/" + MakeBundleName("css", urls);
                var bundle=BundleTable.Bundles.GetBundleFor(bundleDirectory);
                if (bundle == null)
                {
                    bundle = new StyleBundle(bundleDirectory).Include(urls);
                    BundleTable.Bundles.Add(bundle);
                }
                return Styles.Render(bundleDirectory);
            }
    
            private static string MakeBundleName(string type, params string[] urls)
            {
                var array =
                    urls.SelectMany(url => url.Split('/'))
                        .SelectMany(url => url.Split('.'))
                        .Distinct()
                        .Except(new[] {"~", type});
    
                return string.Join("-", array);
            }
        }

    JavascriptObfuscator 类的实现

    public class JavascriptObfuscator : IBundleTransform
        {
            public void Process(BundleContext context, BundleResponse response)
            {
                var p = new ECMAScriptPacker(ECMAScriptPacker.PackerEncoding.Normal, true, false);
    
                response.Content = p.Pack(response.Content);
            }
        }

    2. 页面上使用

    @Html.Style("~/Scripts/JQueryUI2/themes/smoothness/jquery.ui.theme.css", "~/Scripts/JQueryUI2/themes/smoothness/jquery.ui.menu.css")
     @Html.Script("~/Scripts/JQueryUI2/ui/jquery.ui.core.js", "~/Scripts/JQueryUI2/ui/jquery.ui.position.js", "~/Scripts/JQueryUI2/ui/jquery.ui.widget.js", "~/Scripts/JQueryUI2/ui/jquery.ui.menu.js")

    附录:javascript混淆器代码

    /// <summary>
        /// Packs a javascript file into a smaller area, removing unnecessary characters from the output.
        /// </summary>
        public class ECMAScriptPacker : IHttpHandler
        {
            /// <summary>
            /// The encoding level to use. See http://dean.edwards.name/packer/usage/ for more info.
            /// </summary>
            public enum PackerEncoding { None = 0, Numeric = 10, Mid = 36, Normal = 62, HighAscii = 95 };
    
            private PackerEncoding encoding = PackerEncoding.Normal;
            private bool fastDecode = true;
            private bool specialChars = false;
            private bool enabled = true;
    
            string IGNORE = "$1";
    
            /// <summary>
            /// The encoding level for this instance
            /// </summary>
            public PackerEncoding Encoding
            {
                get { return encoding; }
                set { encoding = value; }
            }
    
            /// <summary>
            /// Adds a subroutine to the output to speed up decoding
            /// </summary>
            public bool FastDecode
            {
                get { return fastDecode; }
                set { fastDecode = value; }
            }
    
            /// <summary>
            /// Replaces special characters
            /// </summary>
            public bool SpecialChars
            {
                get { return specialChars; }
                set { specialChars = value; }
            }
    
            /// <summary>
            /// Packer enabled
            /// </summary>
            public bool Enabled
            {
                get { return enabled; }
                set { enabled = value; }
            }
    
            public ECMAScriptPacker()
            {
                Encoding = PackerEncoding.Normal;
                FastDecode = true;
                SpecialChars = false;
            }
    
            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="encoding">The encoding level for this instance</param>
            /// <param name="fastDecode">Adds a subroutine to the output to speed up decoding</param>
            /// <param name="specialChars">Replaces special characters</param>
            public ECMAScriptPacker(PackerEncoding encoding, bool fastDecode, bool specialChars)
            {
                Encoding = encoding;
                FastDecode = fastDecode;
                SpecialChars = specialChars;
            }
    
            /// <summary>
            /// Packs the script
            /// </summary>
            /// <param name="script">the script to pack</param>
            /// <returns>the packed script</returns>
            public string Pack(string script)
            {
                if (enabled)
                {
                    script += "
    ";
                    script = basicCompression(script);
                    if (SpecialChars)
                        script = encodeSpecialChars(script);
                    if (Encoding != PackerEncoding.None)
                        script = encodeKeywords(script);
                }
                return script;
            }
    
            //zero encoding - just removal of whitespace and comments
            private string basicCompression(string script)
            {
                ParseMaster parser = new ParseMaster();
                // make safe
                parser.EscapeChar = '\';
                // protect strings
                parser.Add("'[^'\n\r]*'", IGNORE);
                parser.Add(""[^"\n\r]*"", IGNORE);
                // remove comments
                parser.Add("\/\/[^\n\r]*[\n\r]");
                parser.Add("\/\*[^*]*\*+([^\/][^*]*\*+)*\/");
                // protect regular expressions
                parser.Add("\s+(\/[^\/\n\r\*][^\/\n\r]*\/g?i?)", "$2");
                parser.Add("[^\w\$\/'"*)\?:]\/[^\/\n\r\*][^\/\n\r]*\/g?i?", IGNORE);
                // remove: ;;; doSomething();
                if (specialChars)
                    parser.Add(";;[^\n\r]+[\n\r]");
                // remove redundant semi-colons
                parser.Add(";+\s*([};])", "$2");
                // remove white-space
                parser.Add("(\b|\$)\s+(\b|\$)", "$2 $3");
                parser.Add("([+\-])\s+([+\-])", "$2 $3");
                parser.Add("\s+");
                // done
                return parser.Exec(script);
            }
    
            WordList encodingLookup;
            private string encodeSpecialChars(string script)
            {
                ParseMaster parser = new ParseMaster();
                // replace: $name -> n, $$name -> na
                parser.Add("((\$+)([a-zA-Z\$_]+))(\d*)",
                    new ParseMaster.MatchGroupEvaluator(encodeLocalVars));
    
                // replace: _name -> _0, double-underscore (__name) is ignored
                Regex regex = new Regex("\b_[A-Za-z\d]\w*");
    
                // build the word list
                encodingLookup = analyze(script, regex, new EncodeMethod(encodePrivate));
    
                parser.Add("\b_[A-Za-z\d]\w*", new ParseMaster.MatchGroupEvaluator(encodeWithLookup));
    
                script = parser.Exec(script);
                return script;
            }
    
            private string encodeKeywords(string script)
            {
                // escape high-ascii values already in the script (i.e. in strings)
                if (Encoding == PackerEncoding.HighAscii) script = escape95(script);
                // create the parser
                ParseMaster parser = new ParseMaster();
                EncodeMethod encode = getEncoder(Encoding);
    
                // for high-ascii, don't encode single character low-ascii
                Regex regex = new Regex(
                        (Encoding == PackerEncoding.HighAscii) ? "\w\w+" : "\w+"
                    );
                // build the word list
                encodingLookup = analyze(script, regex, encode);
    
                // encode
                parser.Add((Encoding == PackerEncoding.HighAscii) ? "\w\w+" : "\w+",
                    new ParseMaster.MatchGroupEvaluator(encodeWithLookup));
    
                // if encoded, wrap the script in a decoding function
                return (script == string.Empty) ? "" : bootStrap(parser.Exec(script), encodingLookup);
            }
    
            private string bootStrap(string packed, WordList keywords)
            {
                // packed: the packed script
                packed = "'" + escape(packed) + "'";
    
                // ascii: base for encoding
                int ascii = Math.Min(keywords.Sorted.Count, (int)Encoding);
                if (ascii == 0)
                    ascii = 1;
    
                // count: number of words contained in the script
                int count = keywords.Sorted.Count;
    
                // keywords: list of words contained in the script
                foreach (object key in keywords.Protected.Keys)
                {
                    keywords.Sorted[(int)key] = "";
                }
                // convert from a string to an array
                StringBuilder sbKeywords = new StringBuilder("'");
                foreach (string word in keywords.Sorted)
                    sbKeywords.Append(word + "|");
                sbKeywords.Remove(sbKeywords.Length - 1, 1);
                string keywordsout = sbKeywords.ToString() + "'.split('|')";
    
                string encode;
                string inline = "c";
    
                switch (Encoding)
                {
                    case PackerEncoding.Mid:
                        encode = "function(c){return c.toString(36)}";
                        inline += ".toString(a)";
                        break;
                    case PackerEncoding.Normal:
                        encode = "function(c){return(c<a?"":e(parseInt(c/a)))+" +
                            "((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))}";
                        inline += ".toString(a)";
                        break;
                    case PackerEncoding.HighAscii:
                        encode = "function(c){return(c<a?"":e(c/a))+" +
                            "String.fromCharCode(c%a+161)}";
                        inline += ".toString(a)";
                        break;
                    default:
                        encode = "function(c){return c}";
                        break;
                }
    
                // decode: code snippet to speed up decoding
                string decode = "";
                if (fastDecode)
                {
                    decode = "if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;}";
                    if (Encoding == PackerEncoding.HighAscii)
                        decode = decode.Replace("\\w", "[\xa1-\xff]");
                    else if (Encoding == PackerEncoding.Numeric)
                        decode = decode.Replace("e(c)", inline);
                    if (count == 0)
                        decode = decode.Replace("c=1", "c=0");
                }
    
                // boot function
                string unpack = "function(p,a,c,k,e,d){while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}";
                Regex r;
                if (fastDecode)
                {
                    //insert the decoder
                    r = new Regex("\{");
                    unpack = r.Replace(unpack, "{" + decode + ";", 1);
                }
    
                if (Encoding == PackerEncoding.HighAscii)
                {
                    // get rid of the word-boundries for regexp matches
                    r = new Regex("'\\\\b'\s*\+|\+\s*'\\\\b'");
                    unpack = r.Replace(unpack, "");
                }
                if (Encoding == PackerEncoding.HighAscii || ascii > (int)PackerEncoding.Normal || fastDecode)
                {
                    // insert the encode function
                    r = new Regex("\{");
                    unpack = r.Replace(unpack, "{e=" + encode + ";", 1);
                }
                else
                {
                    r = new Regex("e\(c\)");
                    unpack = r.Replace(unpack, inline);
                }
                // no need to pack the boot function since i've already done it
                string _params = "" + packed + "," + ascii + "," + count + "," + keywordsout;
                if (fastDecode)
                {
                    //insert placeholders for the decoder
                    _params += ",0,{}";
                }
                // the whole thing
                return "eval(" + unpack + "(" + _params + "))
    ";
            }
    
            private string escape(string input)
            {
                Regex r = new Regex("([\\'])");
                return r.Replace(input, "\$1");
            }
    
            private EncodeMethod getEncoder(PackerEncoding encoding)
            {
                switch (encoding)
                {
                    case PackerEncoding.Mid:
                        return new EncodeMethod(encode36);
                    case PackerEncoding.Normal:
                        return new EncodeMethod(encode62);
                    case PackerEncoding.HighAscii:
                        return new EncodeMethod(encode95);
                    default:
                        return new EncodeMethod(encode10);
                }
            }
    
            private string encode10(int code)
            {
                return code.ToString();
            }
    
            //lookups seemed like the easiest way to do this since 
            // I don't know of an equivalent to .toString(36)
            private static string lookup36 = "0123456789abcdefghijklmnopqrstuvwxyz";
    
            private string encode36(int code)
            {
                string encoded = "";
                int i = 0;
                do
                {
                    int digit = (code / (int)Math.Pow(36, i)) % 36;
                    encoded = lookup36[digit] + encoded;
                    code -= digit * (int)Math.Pow(36, i++);
                } while (code > 0);
                return encoded;
            }
    
            private static string lookup62 = lookup36 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
            private string encode62(int code)
            {
                string encoded = "";
                int i = 0;
                do
                {
                    int digit = (code / (int)Math.Pow(62, i)) % 62;
                    encoded = lookup62[digit] + encoded;
                    code -= digit * (int)Math.Pow(62, i++);
                } while (code > 0);
                return encoded;
            }
    
            private static string lookup95 = "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ";
    
            private string encode95(int code)
            {
                string encoded = "";
                int i = 0;
                do
                {
                    int digit = (code / (int)Math.Pow(95, i)) % 95;
                    encoded = lookup95[digit] + encoded;
                    code -= digit * (int)Math.Pow(95, i++);
                } while (code > 0);
                return encoded;
            }
    
            private string escape95(string input)
            {
                Regex r = new Regex("[xa1-xff]");
                return r.Replace(input, new MatchEvaluator(escape95Eval));
            }
    
            private string escape95Eval(Match match)
            {
                return "\x" + ((int)match.Value[0]).ToString("x"); //return hexadecimal value
            }
    
            private string encodeLocalVars(Match match, int offset)
            {
                int length = match.Groups[offset + 2].Length;
                int start = length - Math.Max(length - match.Groups[offset + 3].Length, 0);
                return match.Groups[offset + 1].Value.Substring(start, length) +
                    match.Groups[offset + 4].Value;
            }
    
            private string encodeWithLookup(Match match, int offset)
            {
                return (string)encodingLookup.Encoded[match.Groups[offset].Value];
            }
    
            private delegate string EncodeMethod(int code);
    
            private string encodePrivate(int code)
            {
                return "_" + code;
            }
    
            private WordList analyze(string input, Regex regex, EncodeMethod encodeMethod)
            {
                // analyse
                // retreive all words in the script
                MatchCollection all = regex.Matches(input);
                WordList rtrn;
                rtrn.Sorted = new StringCollection(); // list of words sorted by frequency
                rtrn.Protected = new HybridDictionary(); // dictionary of word->encoding
                rtrn.Encoded = new HybridDictionary(); // instances of "protected" words
                if (all.Count > 0)
                {
                    StringCollection unsorted = new StringCollection(); // same list, not sorted
                    HybridDictionary Protected = new HybridDictionary(); // "protected" words (dictionary of word->"word")
                    HybridDictionary values = new HybridDictionary(); // dictionary of charCode->encoding (eg. 256->ff)
                    HybridDictionary count = new HybridDictionary(); // word->count
                    int i = all.Count, j = 0;
                    string word;
                    // count the occurrences - used for sorting later
                    do
                    {
                        word = "$" + all[--i].Value;
                        if (count[word] == null)
                        {
                            count[word] = 0;
                            unsorted.Add(word);
                            // make a dictionary of all of the protected words in this script
                            //  these are words that might be mistaken for encoding
                            Protected["$" + (values[j] = encodeMethod(j))] = j++;
                        }
                        // increment the word counter
                        count[word] = (int)count[word] + 1;
                    } while (i > 0);
                    /* prepare to sort the word list, first we must protect
                        words that are also used as codes. we assign them a code
                        equivalent to the word itself.
                       e.g. if "do" falls within our encoding range
                            then we store keywords["do"] = "do";
                       this avoids problems when decoding */
                    i = unsorted.Count;
                    string[] sortedarr = new string[unsorted.Count];
                    do
                    {
                        word = unsorted[--i];
                        if (Protected[word] != null)
                        {
                            sortedarr[(int)Protected[word]] = word.Substring(1);
                            rtrn.Protected[(int)Protected[word]] = true;
                            count[word] = 0;
                        }
                    } while (i > 0);
                    string[] unsortedarr = new string[unsorted.Count];
                    unsorted.CopyTo(unsortedarr, 0);
                    // sort the words by frequency
                    Array.Sort(unsortedarr, (IComparer)new CountComparer(count));
                    j = 0;
                    /*because there are "protected" words in the list
                      we must add the sorted words around them */
                    do
                    {
                        if (sortedarr[i] == null)
                            sortedarr[i] = unsortedarr[j++].Substring(1);
                        rtrn.Encoded[sortedarr[i]] = values[i];
                    } while (++i < unsortedarr.Length);
                    rtrn.Sorted.AddRange(sortedarr);
                }
                return rtrn;
            }
    
            private struct WordList
            {
                public StringCollection Sorted;
                public HybridDictionary Encoded;
                public HybridDictionary Protected;
            }
    
            private class CountComparer : IComparer
            {
                HybridDictionary count;
    
                public CountComparer(HybridDictionary count)
                {
                    this.count = count;
                }
    
                #region IComparer Members
    
                public int Compare(object x, object y)
                {
                    return (int)count[y] - (int)count[x];
                }
    
                #endregion
            }
            #region IHttpHandler Members
    
            public void ProcessRequest(HttpContext context)
            {
                // try and read settings from config file
                if (System.Configuration.ConfigurationSettings.GetConfig("ecmascriptpacker") != null)
                {
                    NameValueCollection cfg =
                        (NameValueCollection)
                        System.Configuration.ConfigurationSettings.GetConfig("ecmascriptpacker");
                    if (cfg["Encoding"] != null)
                    {
                        switch (cfg["Encoding"].ToLower())
                        {
                            case "none":
                                Encoding = PackerEncoding.None;
                                break;
                            case "numeric":
                                Encoding = PackerEncoding.Numeric;
                                break;
                            case "mid":
                                Encoding = PackerEncoding.Mid;
                                break;
                            case "normal":
                                Encoding = PackerEncoding.Normal;
                                break;
                            case "highascii":
                            case "high":
                                Encoding = PackerEncoding.HighAscii;
                                break;
                        }
                    }
                    if (cfg["FastDecode"] != null)
                    {
                        if (cfg["FastDecode"].ToLower() == "true")
                            FastDecode = true;
                        else
                            FastDecode = false;
                    }
                    if (cfg["SpecialChars"] != null)
                    {
                        if (cfg["SpecialChars"].ToLower() == "true")
                            SpecialChars = true;
                        else
                            SpecialChars = false;
                    }
                    if (cfg["Enabled"] != null)
                    {
                        if (cfg["Enabled"].ToLower() == "true")
                            Enabled = true;
                        else
                            Enabled = false;
                    }
                }
                // try and read settings from URL
                if (context.Request.QueryString["Encoding"] != null)
                {
                    switch (context.Request.QueryString["Encoding"].ToLower())
                    {
                        case "none":
                            Encoding = PackerEncoding.None;
                            break;
                        case "numeric":
                            Encoding = PackerEncoding.Numeric;
                            break;
                        case "mid":
                            Encoding = PackerEncoding.Mid;
                            break;
                        case "normal":
                            Encoding = PackerEncoding.Normal;
                            break;
                        case "highascii":
                        case "high":
                            Encoding = PackerEncoding.HighAscii;
                            break;
                    }
                }
                if (context.Request.QueryString["FastDecode"] != null)
                {
                    if (context.Request.QueryString["FastDecode"].ToLower() == "true")
                        FastDecode = true;
                    else
                        FastDecode = false;
                }
                if (context.Request.QueryString["SpecialChars"] != null)
                {
                    if (context.Request.QueryString["SpecialChars"].ToLower() == "true")
                        SpecialChars = true;
                    else
                        SpecialChars = false;
                }
                if (context.Request.QueryString["Enabled"] != null)
                {
                    if (context.Request.QueryString["Enabled"].ToLower() == "true")
                        Enabled = true;
                    else
                        Enabled = false;
                }
                //handle the request
                TextReader r = new StreamReader(context.Request.PhysicalPath);
                string jscontent = r.ReadToEnd();
                r.Close();
                context.Response.ContentType = "text/javascript";
                context.Response.Output.Write(Pack(jscontent));
            }
    
            public bool IsReusable
            {
                get
                {
                    if (System.Configuration.ConfigurationSettings.GetConfig("ecmascriptpacker") != null)
                    {
                        NameValueCollection cfg =
                            (NameValueCollection)
                            System.Configuration.ConfigurationSettings.GetConfig("ecmascriptpacker");
                        if (cfg["IsReusable"] != null)
                            if (cfg["IsReusable"].ToLower() == "true")
                                return true;
                    }
                    return false;
                }
            }
    
            #endregion
        }

    总结:

    1. 通过继承IBundleTransform接口能够对Asp.net MVC中自带Bundle类进行扩展。

    2. 可以动态添加Bundle,而不必在Globale中一次性全都添加。

    3. 除了Asp.net MVC自带的Bundle外,还有其他的Bundle插件,例如Bundle Transformer: YUI 1.8.0

    本文摘自:http://blog.csdn.net/leewhoee/article/details/19107013#t3

  • 相关阅读:
    SpinLock 实现
    支持正则或通配符的hashmap
    HTTP报文
    Protostuff序列化
    【转】轻量级分布式 RPC 框架
    Servlet 3特性:异步Servlet
    Web服务器的工作原理
    《恰如其分的软件架构:风险驱动的设计方法》——读书笔记
    Java socket中关闭IO流后,发生什么事?(以关闭输出流为例)
    Java Socket常见异常处理 和 网络编程需要注意的问题
  • 原文地址:https://www.cnblogs.com/cxp9876/p/3824609.html
Copyright © 2011-2022 走看看