如何强制 BundleCollection 在 MVC4 中刷新缓存的脚本包 [英] How to force BundleCollection to flush cached script bundles in MVC4

查看:20
本文介绍了如何强制 BundleCollection 在 MVC4 中刷新缓存的脚本包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

...或者我是如何学会不再担心,而是针对 Microsoft 完全未公开的 API 编写代码.是否有任何关于 System.Web.Optimization 官方发布的实际文档?因为我肯定找不到任何,没有 XML 文档,并且所有的博客文章都引用了 RC API,这是完全不同的.随便..

... or how I learned to stop worrying and just write code against completely undocumented APIs from Microsoft. Is there any actual documentation of the official System.Web.Optimization release? 'cuz I sure can't find any, there's no XML docs, and all the blog posts refer to the RC API which is substantially different. Anyhoo..

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

I am writing some code to automatically resolve javascript dependencies and am creating bundles on the fly from those dependencies. Everything works great, except if you edit scripts or otherwise make changes that would affect a bundle without restarting the application, the changes won't be reflected. So I added an option to disable caching of the dependencies for use in development.

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

However, apparently BundleTables caches the URL even if the bundle collection has changed. For example, in my own code when I want to re-create a bundle I do something like this:

// 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"

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

Whenever I remove & recreate a bundle with the same alias, absolutely nothing happens: the bundleUrl returned from ResolveBundleUrl is the same as before I removed & recreated the bundle. By "the same" I mean that the content hash is unchanged to reflect the new contents of the bundle.

edit...实际上,它比那要糟糕得多.bundle 本身 以某种方式缓存在 Bundles 集合之外.如果我只是生成自己的随机散列来防止浏览器缓存脚本,ASP.NET 将返回旧脚本.因此,显然,从 BundleTable.Bundles 中删除包实际上并没有做任何事情.

edit... actually, it's much worse than that. The bundle itself is cached somehow outside of the Bundles collection. If I just generate my own random hash to prevent the browser from caching the script, ASP.NET returns the old script. So, apparently, removing a bundle from BundleTable.Bundles does not actually do anything.

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

I can simply change the alias to get around this problem, and that is OK for development, but I don't like that idea since it means either I have to deprecate aliases after each page load, or have a BundleCollection that grows in size on every page load. If you left this on in a production environment, it would be a disaster.

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

So it seems that when a script is served, it gets cached independent of the actual BundleTables.Bundles object. So if you re-use a URL, even if you've removed the bundle that it referred to before reusing it, it responds with whatever's in its cache, and altering the Bundles object does not flush the cache -- so only new items (or rather, new items with a different name) would ever be used.

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

The behavior seems odd... removing something from the collection should remove it from the cache. But it doesn't. There must be a way to flush this cache and have it use the current contents of the BundleCollection instead of what it cached when that bundle was first accessed.

知道我该怎么做吗?

有一个 ResetAll 方法,它的目的未知,但无论如何它都会破坏事情,所以不是.

There is this ResetAll method which has an unknown purpose but it just breaks things anyway so that isn't it.

推荐答案

我们听到了您对文档的痛苦,不幸的是,此功能仍在快速变化,并且生成文档有一些滞后,并且几乎可以立即过时.Rick 的博文 是最新的,我已经尝试回答问题同时也在这里传播当前的信息.我们目前正在建立我们的官方 Codeplex 网站,该网站将始终提供最新的文档.

We hear your pain on documentation, unfortunately this feature is still changing quite fast, and generating documentation has some lag, and can be outdated almost immediately. Rick's blog post is up to date, and I've tried to answer questions here as well to spread current info in the meantime. We are currently in the process of setting up our official codeplex site which will have always current documentation.

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

Now in regards to your specific issue of how to flush bundles form the cache.

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

  1. We store the bundled response inside of the ASP.NET cache using a key generated off of the bundle url requested, i.e. Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"] we also setup cache dependencies against all of the files and directories that were used to generate this bundle. So if any of the underlying files or directories change, the cache entry will get flushed.

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

We don't really support live updating of the BundleTable/BundleCollection on a per request basis. The fully supported scenario is that bundles are configured during app start(this is so everything works properly in the web farm scenario, otherwise some bundle requests would end up being 404's if sent to the wrong server). Looking at your code example, my guess is that you are trying to modify the bundle collection dynamically on a particular request? Any kind of bundle administration/reconfiguration should be accompanied by an appdomain reset to guarantee everything has been setup correctly.

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

So avoid modifying your bundle definitions without recycling your app domain. You are free to modify the actual files inside of your bundles, that should automatically be detected and generate new hashcodes for your bundle urls.

这篇关于如何强制 BundleCollection 在 MVC4 中刷新缓存的脚本包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆