If web page uses too much JavaScript files and CSS files, it takes time to load every file to client side, especially if using HTTPS. The code below shows how to compress all JavaScript and CSS files into one download to Client side, which saves bandwidth and loading speed.
The idea is actually add a new httpHandlers.
First, in the web.config, add code below to the system.web section.
Second, in the .aspx page, other than add reference to JavaScript files or CSS files, use the code below instead.
<%= customLibrary.ScriptCombiner.GetScriptTags("ElementEditor") %>
Here, "customLibrary" is your own library, "ScriptCombiner" is a class in your library, "GetScriptTags" is a function to do the job.
using System;
using System.IO;
using System.Text;
using System.Web;
public class ScriptCombiner : IHttpHandler
{
private readonly static TimeSpan CACHE_DURATION = TimeSpan.FromDays(30);
private HttpContext context;
public void ProcessRequest(HttpContext context)
{
this.context = context;
HttpRequest request = context.Request;
// Read setName, version from query string
string setName = (request["s"]!=null)?request["s"]:string.Empty;
string version = (request["v"]!=null)?request["v"]:string.Empty;
// Decide if browser supports compressed response
bool isCompressed = this.CanGZip(context.Request);
// If the set has already been cached, write the response directly from
// cache. Otherwise generate the response and cache it
if (!this.WriteFromCache(setName, version, isCompressed))
{
using (MemoryStream memoryStream = new MemoryStream(8092))
{
// Decide regular stream or gzip stream based on whether the response can be compressed or not
//using (Stream writer = isCompressed ? (Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) : memoryStream)
using (Stream writer = isCompressed ? (Stream)(new ICSharpCode.SharpZipLib.GZip.GZipOutputStream(memoryStream)) : memoryStream)
{
// Read the files into one big string
StringBuilder allScripts = new StringBuilder();
foreach (string fileName in GetScriptFileNames(setName))
allScripts.Append(this.readAllText(context.Server.MapPath(fileName)));
// Minify the combined script files and remove comments and white spaces
JavaScriptMinifier minifier = new JavaScriptMinifier();
string minified = minifier.Minify(allScripts.ToString());
// Send minfied string to output stream
byte[] bts = Encoding.UTF8.GetBytes(minified);
writer.Write(bts, 0, bts.Length);
}
// Cache the combined response so that it can be directly written
// in subsequent calls
byte[] responseBytes = memoryStream.ToArray();
context.Cache.Insert(GetCacheKey(setName, version, isCompressed),
responseBytes, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
CACHE_DURATION);
// Generate the response
this.WriteBytes(responseBytes, isCompressed);
}
}
}
private string readAllText(string filePath)
{
StreamReader reader = new StreamReader(filePath, System.Text.Encoding.Default);
byte[] data=Encoding.Default.GetBytes(reader.ReadToEnd());
reader.Close();
//return (new ASCIIEncoding()).GetString(data);
return (new UTF8Encoding()).GetString(data);
}
private bool WriteFromCache(string setName, string version, bool isCompressed)
{
byte[] responseBytes = context.Cache[GetCacheKey(setName, version, isCompressed)] as byte[];
if (responseBytes == null || responseBytes.Length == 0)
{
//irAutoLog.addLog("NoCache", "HttpCombiner." + setName + "." + version + "." + isCompressed);
return false;
}
//irAutoLog.addLog("GetCache", "HttpCombiner." + setName + "." + version + "." + isCompressed);
this.WriteBytes(responseBytes, isCompressed);
return true;
}
private void WriteBytes(byte[] bytes, bool isCompressed)
{
HttpResponse response = context.Response;
response.AppendHeader("Content-Length", bytes.Length.ToString());
response.ContentType = "application/x-javascript";
if (isCompressed)
response.AppendHeader("Content-Encoding", "gzip");
else
response.AppendHeader("Content-Encoding", "utf-8");
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.Now.Add(CACHE_DURATION));
context.Response.Cache.SetMaxAge(CACHE_DURATION);
response.ContentEncoding = Encoding.Unicode;
response.OutputStream.Write(bytes, 0, bytes.Length);
response.Flush();
}
private bool CanGZip(HttpRequest request)
{
string acceptEncoding = request.Headers["Accept-Encoding"];
if ((acceptEncoding!=null && acceptEncoding!=string.Empty) &&
(acceptEncoding.IndexOf("gzip")>-1 || acceptEncoding.IndexOf("deflate")>-1))
return true;
return false;
}
private string GetCacheKey(string setName, string version, bool isCompressed)
{
return "HttpCombiner." + setName + "." + version + "." + isCompressed;
}
public bool IsReusable
{
get { return true; }
}
// private helper method that return an array of file names inside the text file stored in App_Data folder
private static string[] GetScriptFileNames(string setName)
{
string[] fileNames = new string[] {};
switch (setName)
{
case "Reports":
fileNames = new string[2]
{
"js/jsGlobalReporting.js",
"js/jsReport_New.js"
};
break;
case "ReportViewer":
fileNames = new string[6]
{
"js/jsGlobalReporting.js",
"js/json.js",
"js/jsJSONObject.js",
"js/jsReportViewer_Grid_View.js",
"js/jsReportViewer_PageElement_Advanced.js",
"js/jsReportViewer_Advanced.js"
};
break;
case "ElementEditor":
fileNames = new string[6]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/jquery.grid.edit.js",
"js/json2.js",
"js/jsJSONObject.js",
"js/jsReportViewer_ElementEditor.js"
};
break;
case "PageEditor":
fileNames = new string[5]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsJSONObject.js",
"js/jsReportViewer_PageEditor.js"
};
break;
case "ReportSetup":
fileNames = new string[3]
{
"js/json.js",
"js/jsGlobalReporting.js",
"js/jsReportViewer_ReportSetup.js"
};
break;
case "FormViewer":
fileNames = new string[5]
{
"js/jquery-1.3.2.min.js",
"js/jquery-ui-1.7.1.custom.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsFormViewer.js"
};
break;
case "Forms":
fileNames = new string[4]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsForms.js"
};
break;
case "FormDesigner":
fileNames = new string[4]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsFormDesigner.js"
};
break;
case "SignOff":
fileNames = new string[4]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsReport_SignOff.js"
};
break;
}
return fileNames;
}
public static string GetScriptTags(string setName)
{
string result = null;
System.Version ver = irGlobal.getExecutingAssemblyVersion();
string version = (ver==null)?"100":ver.ToString();
//#if (DEBUG)
// foreach (string fileName in GetScriptFileNames(setName))
// {
// result += String.Format("\n", VirtualPathUtility.ToAbsolute(fileName), version);
// }
//#else
result += String.Format("", setName, version);
//#endif
return result;
}
}
No comments:
Post a Comment