我们在ASP.NET MVC 4设置中使用BundleTransformer库。我们的Web应用程序是一个相当薄的层,所有服务器逻辑都在后端服务中处理。
安装完成后,所有资源都将安装在文件系统上的Web应用程序旁边,但出于更新原因,我们需要能够从服务中提供JavaScript和CSS(LESS)等资源 - 然后它们将覆盖本地(文件系统)版本。
从本质上讲,如果从服务中获得,我们从那里提供所请求的资源。如果没有,我们将回退到文件系统并从那里提供文件。
这一切都像魅力一样,然后我们介绍了LESS和@import
陈述,现在事情已经不再那么好了。
我们仍然希望在Http Cache中缓存LESS转换的结果,并且我们希望在依赖项发生更改时使该结果无效。 VirtualPathProvider中的当前实现可以做到这一点,但是如果我更新单个文件(例如JavaScript文件),它将不会更新。
我的VirtualPathProvider看起来像这样:
public class ViewsAndScriptsPathProvider : VirtualPathProvider {
private static IApplicationServiceResourcesManager ResourceManager {
get { return InstanceProvider.Get<IApplicationServiceResourcesManager>(); }
}
public override bool FileExists(string virtualPath) {
var exists = ResourceManager.Exists(virtualPath);
return exists || base.FileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath) {
VirtualFile file;
if (ResourceManager.TryGet(virtualPath, out file)) {
return file;
}
return base.GetFile(virtualPath);
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) {
bool isRelevant = ResourceManager.IsRelevant(virtualPath);
if (isRelevant) {
var cachekeys = virtualPathDependencies.Cast<string>().Where(dependency => virtualPath != dependency).ToArray();
return new CacheDependency(null, cachekeys);
}
if (IsBundle(virtualPath)) {
return new CacheDependency(null, new[] { ResourceManager.ComponentCacheKey }, utcStart);
}
return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
private bool IsBundle(string virtualPath) {
return virtualPath.StartsWith("~/bundles/", StringComparison.InvariantCultureIgnoreCase)
|| virtualPath.StartsWith("~/css/", StringComparison.InvariantCultureIgnoreCase);
}
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) {
byte[] bhash;
string filehash;
if (ResourceManager.TryGetFileHash(virtualPath, out bhash)) {
filehash = BitConverter.ToString(bhash);
} else {
filehash = Previous.GetFileHash(virtualPath, virtualPathDependencies);
}
return filehash;
}
}
将ResourceManager视为服务的代理/缓存。
我的大问题是我不完全了解CacheDependency的工作。如果我添加一个包含virtualPath本身的cachekey(第二个参数),那么我会在服务器中获得一个无限循环。
如果我只是返回null
,那么它将无法为@imports
工作。
如果有人可以解释或指出VirtualPathProvider应该如何实现GetCacheDependency和GetFileHash函数,我或许可以解决这个问题。
答案 0 :(得分:1)
我实际上是在前一段时间制定了一个解决方案,它与HttpCache如何与CacheDependency对象一起工作有关。然而,它相当复杂。
基本上我有三种情况:
对于1.我使用CacheDependency对象作为文件位置。这是标准的,默认情况下VirtualPathProvider的工作方式。
对于2.我使用自定义(派生)ResourceCacheDependency,当代理具有新版本时,它实现逻辑以使自身无效。
对于3.我使用AggregateCacheDependency对象,该对象同时具有物理文件的CacheDependency和ResourceCacheDependency对象。
对于所有虚拟路径依赖项(资源的依赖项列表),我重复上述假设,并将其构建到AggreateCacheDependency中(它可能具有很多依赖项)。
在我的VirtualPathProvider的自定义实现中,我重写了GetCacheDependency方法,以根据上述分析返回相关的CacheDependency对象。