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); } }