/// <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;

            }

        }

    }