Click here to Skip to main content
15,887,676 members
Articles / Web Development / ASP.NET

Caching WCF javascript proxy on browser

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
4 Apr 2012CPOL3 min read 40.3K   236   17  
WCF Javascript Proxies (Service.svc/js) are never cached. They get generated and downloaded on every page view thus increasing page download time and server CPU. Here's an HttpModule to cache WCF Javascript Proxy on browser and respond with HTTP 304, if unchanged.
#undef IIS6
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;

namespace WcfService1
{
    public sealed class JavascriptProxyCacheModule : IHttpModule
    {
        private HttpApplication app;
                
        public void Init(HttpApplication context)
        {
            app = context;
            app.EndRequest += new EventHandler(app_EndRequest);
            app.BeginRequest += new EventHandler(app_BeginRequest);
        }

        void app_BeginRequest(object sender, EventArgs e)
        {
            var path = app.Context.Request.Path.ToLower().Replace('\\', '/');
            if (IsWcfJavacsriptProxy(path))
            {
                // versioning is used by using (xxx) in the path of the script
                // reference. for ex, /(v2)/Service.svc/js
                // In this case, remove the (v2)/ 
                int pos = path.IndexOf('(');
                if (pos > 0)
                {
                    int endPos = path.IndexOf(')');
                    path = path.Substring(0, pos) + path.Substring(endPos + 2);
                    app.Context.RewritePath(path);

                    string ifModifiedSince = app.Context.Request.Headers["If-Modified-Since"];
                    if (!string.IsNullOrEmpty(ifModifiedSince))
                    {
                        string filePath = app.Context.Request.PhysicalPath;
                        DateTime fileLastModifyDateTime = File.GetLastWriteTime(filePath);
                        DateTime browserLastModifyDateTime;
                        if (DateTime.TryParse(ifModifiedSince, out browserLastModifyDateTime))
                        {
                            if ((browserLastModifyDateTime - fileLastModifyDateTime).Seconds > 5)
                            {
                                app.Context.Response.StatusCode = 304;
                                app.Context.Response.End();
                            }
                        }
                    }
                }                
            }
        }

        private void app_EndRequest(object sender, EventArgs e)
        {
            var path = app.Context.Request.Path.ToLower().Replace('\\', '/');
            
            if (app.Context.Response.StatusCode == 200
                || app.Context.Response.StatusCode == 202)
            {
                if (IsWcfJavacsriptProxy(path) && IsVersioned())
                {
                    var lastModified = DateTime.UtcNow;
                    // Expire by tomorrow 7 AM always.
                    var expires = lastModified.AddDays(1).Subtract(lastModified.TimeOfDay).AddHours(7);
                    HttpCachePolicy cache = app.Context.Response.Cache;
                    cache.SetLastModified(lastModified);
                    cache.SetExpires(expires);
                    cache.SetCacheability(HttpCacheability.Public);
                }
            }            

        }

        private bool IsWcfJavacsriptProxy(string path)
        {
            // It has to be a .svc extension hit
            // And it must have the version number on the URL. Don't want to accidentally
            // cache non versioned WCF proxies.
            // Then it must have a /js or /jsdebug hit
            return path.Contains(".svc/") 
                && (path.EndsWith("/js") || path.EndsWith("/jsdebug"));
        }

        private bool IsVersioned()
        {
            return app.Context.Request.RawUrl.IndexOf('(') > 0;
        }

        public void Dispose()
        {            
#if IIS6
            app.EndRequest -= app_EndRequest;
            app.BeginRequest -= app_BeginRequest;            
#endif
            app = null;            
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect BT, UK (ex British Telecom)
United Kingdom United Kingdom

Comments and Discussions