///
<summary>
/// Creates
dynamic Manifest to cache entire website for offline use when in debug mode.
/// /manifest.ashx will
produce a manifest file that is written to Manifest.txt for
/// production server use.
///
/// Once
in production, the handler just returns whatever is contained in Manifest.txt
///
/// With GoDaddy, I have found it much faster to dump the text file
than to parse the
/// server directories each time.
///
/// Jake Drew - 05/22/2012
/// </summary>
public class Manifest : IHttpHandler
{
/// <summary>
/// Defines
the file types that should be included in the Manifest file when it is
///
created.
/// All other file types
are excluded.
/// </summary>
const
string FileTypes =
"*.aspx;*.htm;*.js;*.css;*.gif;*.png;*.jp*g;*.ico;*.txt;*.tif";
/// <summary>
/// Determines
the version number contained in the Manifest.
This could also be set
///
to
something
///
dynamic such as the date, depending on your requirements.
/// </summary>
const
string ManifestVersion
= "v1";
/// <summary>
/// A
list of folder names in the root directory to include in the Manifest file.
/// </summary>
HashSet<string> includeFolders =
new HashSet<string> {"css","elements","inc"};
/// <summary>
/// A
list of file names in any folder to exclude from the Manifest file.
/// </summary>
HashSet<string> excludeFiles = new HashSet<string> { "Manifest.txt"
};
/// <summary>
/// This
property determines if the application is in DEBUG or RELEASE mode.
/// </summary>
public static bool
IsDebug
{
get
{
bool
debug = false;
try
{
#if DEBUG
debug = true;
#endif
}
catch
{
debug = false;
}
return debug;
}
}
/// <summary>
/// If
the web request occurs during DEBUG mode, dynamically recreate the Manifest.txt
///
file.
/// If
the web request is NOT in DEBUG mode, the contents of the Manifest.txt file are
/// processed as
/// the
website's Manifest file.
/// </summary>
/// <param
name="context"></param>
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
StringBuilder SB = new StringBuilder();
if(IsDebug)
{
response.ContentType = "text/cache-manifest";
SB.AppendLine("CACHE MANIFEST");
SB.AppendLine("# " + ManifestVersion);
SB.AppendLine("# Root Path: "
+ request.PhysicalApplicationPath);
SB.AppendLine();
SB.AppendLine("CACHE:");
SB.AppendLine("# Jquery Libraries");
//Add jquery entires to the mainfest file.
SB.AppendLine(@"http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js");
SB.AppendLine(@"http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-
ui.min.js");
SB.AppendLine();
SB.AppendLine("# Site Content");
string[] filePatterns = FileTypes.Split(new string[] { ";" },
StringSplitOptions.RemoveEmptyEntries);
List<string> cacheFileList = new List<string>();
foreach
(string filePattern in filePatterns)
{
cacheFileList.AddRange(Directory.GetFiles(request.PhysicalApplicationPath,
filePattern, SearchOption.AllDirectories));
}
cacheFileList.Sort();
foreach
(string filePath in cacheFileList)
{
string path = String.Format("{0}/{1}", request.ApplicationPath,
filePath.Replace(request.PhysicalApplicationPath,
"").Replace(@"\", "/"));
char[] del = new char[] { '/' };
string[] folder = path.Split(del,
StringSplitOptions.RemoveEmptyEntries);
if (folder.Count() <= 1 || includeFolders.Contains(folder[0]))
{
path
= path.Substring(2);
if (!excludeFiles.Contains(path))
SB.AppendLine(path);
}
}
//Add NETWORK section to the
mainfest file.
SB.AppendLine();
SB.AppendLine("NETWORK:");
SB.AppendLine("http://*");
SB.AppendLine("https://*");
//Create an updated manifest file
using (StreamWriter writer = new StreamWriter(request.PhysicalApplicationPath
+ "Manifest.txt"))
{
writer.Write(SB.ToString());
}
}
//Create a response from the contents of the Manifest.txt
file.
//This file was dynamically created by this process, if in
DEBUG mode.
context.Response.ContentType = "text/cache-manifest";
context.Response.WriteFile(context.Server.MapPath("Manifest.txt"));
}
public bool IsReusable
{
get
{
return false;
}
}
}