I have a controller action that returns Javascript file. I can reference this file from my view and it works fine. I\'d like to put it in a System.Web.Optimization.Bundle with t
Here is what I did for this scenario. I defined a "Bundle Result" and then in my Controller method, just returned a Bundle by name. I am using ETags (If-None-Match Header) as an optimization for client caching.
eg:
public ActionResult ReturnFooBundle()
{
return new BundleResult("foo", TimeSpan.FromDays(7));
}
Here is the BundleResult implementation:
public class BundleResult
: ActionResult
{
private class BundleInfo
{
public string BundleETag;
public DateTime LastModified;
public Bundle TheBundle;
public BundleResponse Response;
}
private static Dictionary _bundleCache = new Dictionary();
public string BundleName { get; private set; }
public TimeSpan CacheExpiry { get; private set; }
public BundleResult(string bundleName, TimeSpan cacheExpiry)
{
BundleName = bundleName;
CacheExpiry = cacheExpiry;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
BundleInfo bundleInfo = GetBundle(context.HttpContext);
string requestETag = context.HttpContext.Request.Headers["If-None-Match"];
if (!string.IsNullOrEmpty(requestETag) && (requestETag == bundleInfo.BundleETag))
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified;
context.HttpContext.Response.StatusDescription = "Not Modified";
return;
}
else
{
BundleResponse bundleResponse = bundleInfo.Response;
HttpResponseBase response = context.HttpContext.Response;
response.Write(bundleResponse.Content);
response.ContentType = bundleResponse.ContentType;
HttpCachePolicyBase cache = response.Cache;
cache.SetCacheability(HttpCacheability.ServerAndPrivate);
cache.SetLastModified(bundleInfo.LastModified);
cache.SetETag(bundleInfo.BundleETag);
}
}
private BundleInfo GetBundle(HttpContextBase context)
{
// lookup the BundleResponse
BundleInfo retVal;
lock (_bundleCache)
{
_bundleCache.TryGetValue(BundleName, out retVal);
}
if(retVal != null)
{
#if DEBUG
// see if the contents have been modified.
BundleContext bundleContext = new BundleContext(context, BundleTable.Bundles, BundleName);
DateTime lastModified = retVal.TheBundle.EnumerateFiles(bundleContext).Select(fi => fi.LastWriteTimeUtc).Max();
if (lastModified > retVal.LastModified)
{
// regenerate the bundleInfo
retVal = null;
}
#endif
}
if (retVal == null)
{
string rawBundleName = BundleTable.Bundles.ResolveBundleUrl(BundleName);
string hash = rawBundleName.Substring(rawBundleName.IndexOf("?v=") + 3);
Bundle bundle = BundleTable.Bundles.GetBundleFor(BundleName);
BundleContext bundleContext = new BundleContext(context, BundleTable.Bundles, BundleName);
BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
DateTime lastModified = bundle.EnumerateFiles(bundleContext).Select(fi => fi.LastWriteTimeUtc).Max();
retVal = new BundleInfo
{
BundleETag = hash,
Response = bundleResponse,
TheBundle = bundle,
LastModified = lastModified,
};
lock (_bundleCache)
{
_bundleCache[BundleName] = retVal;
}
}
return retVal;
}
}