ASP.NET在Bundling中使用嵌入式资源

我正在尝试实现一种通用方法,为我的Web解决方案中的不同程序集提供使用嵌入式资源中嵌入的JavaScript和CSS文件的可能性。 此博客文章显示了使用VirtualPathProvider的技术。 这很好,但VirtualPathProvider需要包含在包含嵌入资源的每个程序集中。

我尝试从博客文章中增强VirtualPathProvider,以便可以将程序集传递给它并从程序集中加载资源:

public EmbeddedVirtualPathProvider(VirtualPathProvider previous, Assembly assembly) { this.previous = previous; this.assembly = assembly; } 

初始化时,它从传递的程序集中读取所有嵌入的资源:

 protected override void Initialize() { base.Initialize(); this.assemblyResourceNames = this.assembly.GetManifestResourceNames(); this.assemblyName = this.assembly.GetName().Name; } 

并且GetFile从传递的程序GetFile读取内容:

 public override VirtualFile GetFile(string virtualPath) { if (IsEmbeddedPath(virtualPath)) { if (virtualPath.StartsWith("~", System.StringComparison.OrdinalIgnoreCase)) { virtualPath = virtualPath.Substring(1); } if (!virtualPath.StartsWith("/", System.StringComparison.OrdinalIgnoreCase)) { virtualPath = string.Concat("/", virtualPath); } var resourceName = string.Concat(this.assembly.GetName().Name, virtualPath.Replace("/", ".")); var stream = this.assembly.GetManifestResourceStream(resourceName); if (stream != null) { return new EmbeddedVirtualFile(virtualPath, stream); } else { return _previous.GetFile(virtualPath); } } else return _previous.GetFile(virtualPath); } 

检查资源是否是此程序集的嵌入资源是通过检查Initialize方法中读取的资源名称:

 private bool IsEmbeddedPath(string path) { var resourceName = string.Concat(this.assemblyName, path.TrimStart('~').Replace("/", ".")); return this.assemblyResourceNames.Contains(resourceName, StringComparer.OrdinalIgnoreCase); } 

我将EmbeddedVirtualPathProvider类移动到主Web项目(ProjectA),因此它不需要包含在包含嵌入资源的每个程序集中,并使用Global.asax的以下代码进行注册:

 HostingEnvironment.RegisterVirtualPathProvider( new EmbeddedVirtualPathProvider( HostingEnvironment.VirtualPathProvider, typeof(ProjectB.SomeType).Assembly)); 

在包含嵌入资源(ProjectB)的项目中,我仍然在PostApplicationStartMethod创建以下包:

  BundleTable.Bundles.Add(new ScriptBundle("~/Embedded/Js") .Include("~/Scripts/SomeFolder/MyScript.js") ); 

Scripts/MyScript.js是ProjectB中的嵌入式资源。

有了这个,我收到以下exception:

目录’C:\ webs \ ProjectA \ Scripts \ SomeFolder \’不存在。 无法开始监视文件更改。

更新 此Gist中可用的完整堆栈跟踪。

更新此外,VirtualPathProvider本身似乎工作正常。 如果我直接加载文件而不是通过bundle加载并在web.config设置以下条目,它将从ProjectB加载嵌入的javascript:

      

当ASP.net优化创建捆绑包时,它GetCacheDependency为脚本的虚拟目录调用GetCacheDependency 。 您的GetCacheDependency实现仅检查虚拟文件,对于虚拟目录,它依赖于基础VirtualPathProvider ,它检查目录是否存在且失败。

要解决此问题,您必须检查路径是否是您的某个脚本的目录 ,并为GetCacheDependency返回null。

要安全地确定virtualPath是否是bundle目录,可以使用BundleTable.Bundles集合或使用约定(即:每个bundle应以〜/ Embedded开头)。

 public override CacheDependency GetCacheDependency( string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { // if(virtualPath.StartsWith("~/Embedded")) if(BundleTables.Bundles.Any(b => b.Path == virtualPath)) { return null; } if (this.IsEmbeddedPath(virtualPath)) { return null; } else { return this._previous .GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); } }