Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Caching WCF javascript proxy on browser

, 4 Apr 2012
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.
WcfJavascriptProxyCaching.zip
WcfJavascriptProxyCaching
WcfJavascriptProxyCaching.suo
WcfService1
App_Data
bin
WcfService1.dll
WcfService1.pdb
Global.asax
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
TempPE
WcfService1.dll
WcfService1.pdb
Properties
Service1.svc
WcfService1.csproj.user
#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)

About the Author


| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 4 Apr 2012
Article Copyright 2012 by Omar Al Zabir
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid