如何强制BundleCollection刷新MVC4中的缓存脚本包

Jam*_*rgy 84 c# asp.net asp.net-mvc-4 bundling-and-minification asp.net-optimization

...或者我是如何学会停止担心的,只是针对来自Microsoft的完全未记录的API编写代码.是否有官方System.Web.Optimization发布的实际文档?'cuz我肯定找不到任何,没有XML文档,所有的博客文章都引用了与实际上不同的RC API.安美居..

我正在编写一些代码来自动解析javascript依赖项,并从这些依赖项中动态创建bundle.一切都很好,除非您编辑脚本或以其他方式进行更改,这些更改会影响捆绑而不重新启动应用程序,否则不会反映更改.所以我添加了一个禁用缓存依赖项的选项,以便在开发中使用.

但是,即使捆绑集合已更改,显然也会BundleTables缓存URL .例如,在我自己的代码中,当我想重新创建一个包时,我做了类似这样的事情:

// remove an existing bundle
BundleTable.Bundles.Remove(BundleTable.Bundles.GetBundleFor(bundleAlias));

// recreate it.
var bundle = new ScriptBundle(bundleAlias);

// dependencies is a collection of objects representing scripts, 
// this creates a new bundle from that list. 

foreach (var item in dependencies)
{
    bundle.Include(item.Path);
}

// add the new bundle to the collection

BundleTable.Bundles.Add(bundle);

// bundleAlias is the same alias used previously to create the bundle,
// like "~/mybundle1" 

var bundleUrl = BundleTable.Bundles.ResolveBundleUrl(bundleAlias);

// returns something like "/mybundle1?v=hzBkDmqVAC8R_Nme4OYZ5qoq5fLBIhAGguKa28lYLfQ1"
Run Code Online (Sandbox Code Playgroud)

每当我删除并重新创建具有相同别名的捆绑包,绝对没有任何反应:bundleUrl返回ResolveBundleUrl的内容与删除并重新创建捆绑包之前相同."相同"是指内容哈希值不变以反映捆绑包的新内容.

编辑 ...实际上,它比那更糟糕.该束本身是外面不知何故缓存Bundles集合.如果我只生成自己的随机哈希以防止浏览器缓存脚本,ASP.NET将返回旧脚本.所以,显然,删除捆绑BundleTable.Bundles实际上并没有做任何事情.

我可以简单地更改别名来解决这个问题,这对于开发来说是可以的,但我不喜欢这个想法,因为它意味着我必须在每次加载页面后弃用别名,或者让BundleCollection的大小增加每页加载.如果你把它放在生产环境中,那将是一场灾难.

因此,似乎在提供脚本时,它会被独立于实际BundleTables.Bundles对象进行缓存.因此,如果您重新使用URL,即使您在重新使用它之前删除了它所引用的包,它也会响应其缓存中的任何内容,并且更改该Bundles对象不会刷新缓存 - 因此只有项目(或相反,将使用具有不同名称的新项目.

行为似乎很奇怪...从集合中删除一些东西应该从缓存中删除它.但事实并非如此.必须有一种方法来刷新此缓存并使其使用当前内容BundleCollection而不是首次访问该包时缓存的内容.

知道怎么做吗?

有这种ResetAll方法有一个未知的目的,但它只是打破了事情,所以不是这样.

Hao*_*ung 33

我们听到你对文档的痛苦,遗憾的是这个功能仍在快速变化,生成文档有一些滞后,几乎可以立即过时. Rick的博客文章是最新的,我试图在这里回答问题,同时传播当前的信息.我们目前正在设置我们的官方codeplex网站,该网站将始终提供最新文档.

现在关于如何从缓存中清除包的具体问题.

  1. 我们使用从请求的bundle url生成的密钥将捆绑的响应存储在ASP.NET缓存中,即Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"]我们还针对用于生成此捆绑包的所有文件和目录设置缓存依赖性.因此,如果任何底层文件或目录发生更改,则将刷新缓存条目.

  2. 我们并不真正支持基于每个请求实时更新BundleTable/BundleCollection.完全支持的方案是在应用程序启动期间配置捆绑包(这样在Web场方案中一切正常,否则如果发送到错误的服务器,某些捆绑请求将最终为404).看看你的代码示例,我的猜测是你试图在特定请求上动态修改bundle集合?任何类型的捆绑管理/重新配置都应该伴随appdomain重置,以确保所有设置都正确.

因此,请勿在不回收应用域的情况下修改捆绑定义.您可以自由修改捆绑包内的实际文件,这些文件应自动检测并为您的捆绑网址生成新的哈希码.

  • 谢谢你带来你的直接知识!是的 - 我正在尝试动态修改捆绑集合.捆绑包是基于*another*脚本中描述的一组依赖关系构建的(也就是说,本身,不一定是bundle的一部分) - 这就是我遇到这个问题的原因.由于更改捆绑包中的脚本会强制刷新,因此可以完成 - 是否有可能添加手动刷新方法?这并不重要 - 这是为了方便开发 - 但我讨厌创建代码,如果在prod上意外使用可能会导致问题. (2认同)
  • 据我所知,这不起作用.也就是说,如果我更改组成文件,则不会清除服务器缓存,如此处所述.你必须回收这个东西才能得到任何改变.有人知道官方文件到底在哪里吗? (2认同)

Lef*_*tyX 20

我有类似的问题.
在我的班上,BundleConfig我试图看看使用的效果是什么BundleTable.EnableOptimizations = true.

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        BundleTable.EnableOptimizations = true;

        bundles.Add(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

一切都很好.
在某些时候,我正在做一些调试并将属性设置为false.
我很难理解发生了什么,因为似乎jquery(第一个)的包不会被解析和加载(/bundles/jquery?v=).

在发誓之后,我想(?!)我已经设法解决了问题.尝试添加bundles.Clear()bundles.ResetAll()在注册开始时,事情应该重新开始工作.

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Clear();
        bundles.ResetAll();

        BundleTable.EnableOptimizations = false;

        bundles.Add(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经意识到只有在我更改EnableOptimizations属性时才需要运行这两种方法.

更新:

深入挖掘我发现BundleTable.Bundles.ResolveBundleUrl并且@Scripts.Url似乎有解决捆绑路径的问题.

为简单起见,我添加了一些图片:

图片1

我关闭了优化并捆绑了一些脚本.

图片2

同一束包含在身体中.

图片3

@Scripts.Url给出了捆绑的"优化"路径,同时@Scripts.Render生成合适的路径.
同样的事情发生在BundleTable.Bundles.ResolveBundleUrl.

我使用的是Visual Studio 2010 + MVC 4 + Framework .Net 4.0.

  • 所以只是为了解释这些方法做:Scripts.Url仅仅是BundleTable.Bundles.ResolveBundleUrl一个别名,它也将解决非捆绑的URL,因此它碰巧知道包的通用网址解析.Scripts.Render使用EnableOptimizations标志来确定是否呈现对bundle或组成bundle的组件的引用. (6认同)
  • 我刚尝试过,STILL没有刷新缓存!! 我清除它,`ResetAll`,并尝试在启动和内联时将'EnableOptimizations`设置为false,当我需要重置缓存时,没有任何事情发生.哎呀. (2认同)

Zac*_*Zac 8

考虑到郝公的建议不要因为网络农场场景而这样做,我认为有很多场景你可能想要这样做.这是一个解决方案:

BundleTable.Bundles.ResetAll(); //or something more specific if neccesary
var bundle = new Bundle("~/bundles/your-bundle-virtual-path");
//add your includes here or load them in from a config file

//this is where the magic happens
var context = new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, bundle.Path);
bundle.UpdateCache(context, bundle.GenerateBundleResponse(context));

BundleTable.Bundles.Add(bundle);
Run Code Online (Sandbox Code Playgroud)

您可以随时调用上述代码,您的捆绑包将会更新.这在EnableOptimizations为true或false时都有效 - 换句话说,这将在调试或实时方案中抛出正确的标记,具有:

@Scripts.Render("~/bundles/your-bundle-virtual-path")
Run Code Online (Sandbox Code Playgroud)