how to create manifest if bundling and minification is used in ASP.NET MVC4

2k views Asked by At

ASP.NET MVC4 application MVC4 buildit bundling and minification is used. Application should work also in offline.

I tried to create manifest using code below but this does not work since v= parameters will change if source code is changed. How to create manifest which works without manually changing bundle query string parameters if bundling and minification are used?

<!DOCTYPE html>
<html manifest="~/Sale/Manifest">

<head>

    @Erp.Helpers.Bundles.Render("~/css/pos", new { media = "screen" })
    @Erp.Helpers.Bundles.Render("~/css/receipt", new { media = "print" })
    @Scripts.Render("~/pos.js")
</head>

controller:

public ContentResult Manifest()
        {
            return new ContentResult()
            {
                Content = @"CACHE MANIFEST
CACHE:
pos?v=esdw2223023094323
css/pos?v=ewe3334324r33432343
css/receipt?v=w333543334324r33432343

NETWORK:
*
"
   };
}

C# Web.Optimization Bundles and HTML5 cache Manifest contains similar question without answer.

Update

I tried answers but got error in chrome console

Application Cache Error event: Resource fetch failed (404) http://localhost:52216/erp/Sale/pos.js 

Application is running using

        BundleTable.EnableOptimizations = true;

and in debug mode by pressing F5 from VSE 2013 for Web

I tried suggestions in answers using

public class SaleController : ControllerBase
{

    public ContentResult Manifest()
    {
        return new ContentResult()
        {
            Content = string.Format(@"CACHE MANIFEST
CACHE:
   {0}
   {1}
   {2}
", 
Scripts.Url("pos.js"),  // tried also Scripts.Url("pos")
Styles.Url("css/pos"),
Styles.Url("css/receipt")),

... in controller.

view source in browser shows

<html manifest="/erp/Sale/Manifest">
<head>
  <link href="/erp/css/pos?v=sN8iz_u3gRGE6MQKGq6KocU-SUIUMcQxKVuESa_L2l41" rel="stylesheet" media="screen"/>
    <link href="/erp/css/receipt?v=C6qCUe6W1VM6yxNe-RgZRY9R0Gws1vU0lMuoKIn1uVE1" rel="stylesheet" media="print"/>
    <script src="/erp/pos.js?v=a-TsureIIlzxwhaItWMV7Ajfw-YXE3x6hUld3cxwAqI1"></script>

generated manifest contains

CACHE MANIFEST
CACHE:
/erp/Sale/pos.js
/erp/Sale/css/pos
/erp/Sale/css/receipt

How to fix this ? It looks like invalid urls are generated to manifest:

  1. Sale directory is added
  2. Query string is not present
3

There are 3 answers

4
Pervez Choudhury On BEST ANSWER

There are methods on the Styles and Scripts objects in System.Web.Optimization that will give you the URL of the resource.

You can call Scripts.Url(string) to give you the URL of the script file, complete with the hash. You can also call Styles.Url(string) to give you the URL of the style sheet, complete with the hash.

using System.Web.Optimization;
using System.Web.Mvc;

namespace StackOverflow.Controllers
{
    public class StackOverflowController : Controller
    {
        public ContentResult Manifest()
        {
            return new ContentResult()
            {
                Content = string.Format( 
@"CACHE MANIFEST
CACHE:
{0}
{1}
{2}

NETWORK:
*
",
 Scripts.Url("~/pos.js"),
 Styles.Url("~/css/pos"),
 Styles.Url("~/css/receipt"))
            };
        }
    }
}

The cache-busting hashes will only be added when the site is run with <compilation debug="false" /> specified in the web.config file.

2
samjudson On

Scripts.Url gives you the URL for the bundle, without rendering out the script tags. Does that answer your question?

0
Hugo On

You can use Scripts.RenderFormat or Styles.RenderFormat to render the full list of files when run with debug="true" and only the minified version when run with debug="false".

Here's an example:

    public ActionResult AppManifest()
    {
        string cacheFiles = "";

        cacheFiles = Scripts.RenderFormat("{0}",
            "~/bundles/jquery",
            "~/bundles/jqueryval",
            "~/bundles/bootstrap").ToString();

        cacheFiles += Styles.RenderFormat("{0}",
            "~/Content/css");

        string manifest = String.Format(@"CACHE MANIFEST

  CACHE:
  {0}", cacheFiles);

        return Content(manifest, "text/cache-manifest");
    }