如何强制BundleCollection刷新MVC4中的缓存脚本包
...或者我如何学会停止担心,并且仅仅针对微软完全没有记录的API编写代码。 有没有官方的System.Web.Optimization
发行版的实际文档? '因为我肯定找不到任何东西,没有XML文档,所有的博客帖子都提到RC API,它们有很大的不同。 安美居..
我正在编写一些代码来自动解决JavaScript依赖关系,并从这些依赖关系中即时创建bundle。 除非您编辑脚本或以其他方式进行影响软件包而不重新启动应用程序的更改,否则一切都会很好,但这些更改不会反映出来。 所以我添加了一个选项来禁用缓存依赖项以供在开发中使用。
然而,即使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"
每当我删除并重新创建一个具有相同别名的包时,绝对不会发生任何事情:从bundleUrl
返回的ResolveBundleUrl
与之前删除并重新创建该包相同。 通过“相同”,我的意思是内容哈希值不变以反映该包的新内容。
编辑...实际上,它比这更糟糕。 Bundle本身被缓存在Bundles
集合之外。 如果我只生成自己的随机哈希以防止浏览器缓存脚本,则ASP.NET将返回旧脚本。 所以,显然,从BundleTable.Bundles
中删除一个包实际上并没有做任何事情。
我可以简单地改变别名来解决这个问题,这对于开发是可以的,但我不喜欢这个想法,因为它意味着要么在每次页面加载后都废弃别名,要么让一个BundleCollection的大小增大每页加载。 如果您将其留在生产环境中,那将是一场灾难。
所以看起来,当一个脚本被提供时,它被缓存BundleTables.Bundles
依赖于实际的BundleTables.Bundles
对象。 因此,如果您重新使用URL,即使您在重新使用它之前移除了引用的包,它也会响应其缓存中的任何内容,并且更改Bundles
对象不会刷新缓存 - 因此只有新项目或者更确切地说,使用不同名称的新项目)。
行为似乎很奇怪......从集合中删除某些东西应该将它从缓存中删除。 但事实并非如此。 必须有一种方法来刷新此缓存并让它使用BundleCollection
的当前内容,而不是第一次访问该缓存时缓存的内容。
任何想法我会如何做到这一点?
有这个ResetAll
方法有一个未知的目的,但它只是打破了事情,所以不是这样。
我们听到你对文档的痛苦,不幸的是,这个特性仍然在变化很快,生成文档有一些滞后,并且几乎可以立即过时。 瑞克的博客文章是最新的,我也试着在这里回答问题,同时传播当前的信息。 我们目前正在建立我们的官方codeplex网站,该网站始终有最新的文档。
现在关于如何从缓存中刷新bundle的具体问题。
我们使用从请求的bundle url生成的一个密钥(即Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"]
将关联的响应存储在ASP.NET缓存中,我们还设置缓存依赖关系所有用来生成这个包的文件和目录。 因此,如果任何底层文件或目录发生更改,缓存条目将被刷新。
我们并不真正支持每个请求的实时更新BundleTable / BundleCollection。 完全支持的方案是,应用程序启动期间配置了捆绑包(这是为了在Web场景中正常工作,否则如果发送到错误的服务器,某些捆绑请求最终会成为404)。 看看你的代码示例,我的猜测是你试图根据特定的请求动态修改bundle集合? 任何类型的捆绑管理/重新配置都应附带一个应用程序域重置,以确保所有设置都已正确设置。
因此,请避免修改您的包定义而不回收您的应用程序域 您可以自由修改捆绑包内的实际文件,这些文件应该被自动检测并为您的捆绑网址生成新的哈希码。
我有类似的问题。
在我的BundleConfig
类中,我试图看看使用BundleTable.EnableOptimizations = true
的效果。
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
BundleTable.EnableOptimizations = true;
bundles.Add(...);
}
}
一切工作正常。
在某些时候,我正在进行一些调试并将该属性设置为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(...);
}
}
我意识到只有当我更改EnableOptimizations
属性时,才需要运行这两个方法。
更新:
深入挖掘我发现BundleTable.Bundles.ResolveBundleUrl
和@Scripts.Url
似乎有问题来解决捆绑路径。
为了简单起见,我添加了一些图片:
我已经关闭了优化并捆绑了几个脚本。
正文中包含相同的包。
@Scripts.Url
为我提供了捆绑的“优化”路径,而@Scripts.Render
生成了正确的路径。
BundleTable.Bundles.ResolveBundleUrl
发生同样的情况。
我正在使用Visual Studio 2010 + MVC 4 + Framework .Net 4.0。
考虑到霍康的建议,不要因为网络农场的情况下这样做,我认为有很多情况下你可能想要做到这一点。 这是一个解决方案:
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);
您可以随时致电上述代码,并且您的软件包将得到更新。 这在EnableOptimizations为true或false时都有效 - 换句话说,这将在调试或实况场景中抛出正确的标记,其中:
@Scripts.Render("~/bundles/your-bundle-virtual-path")
链接地址: http://www.djcxy.com/p/67977.html
上一篇: How to force BundleCollection to flush cached script bundles in MVC4