ASP.NET 在捆绑中使用嵌入式资源
ASP.NET using embedded resources in Bundling
我正在尝试实现一种通用方法,以便为我的 Web 解决方案中的不同程序集提供使用来自嵌入式资源的嵌入式 JavaScript 和 CSS 文件的可能性。 This blog post 展示了使用 VirtualPathProvider 的技术。这工作正常,但 VirtualPathProvider 需要包含在每个包含嵌入式资源的程序集中。
我试图从博客 post 中增强 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
从传递的程序集中读取内容:
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
class移动到主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 中的嵌入资源。
有了这个,我收到以下异常:
Directory 'C:\webs\ProjectA\Scripts\SomeFolder\' does not exist. Failed to start monitoring file changes.
更新
this Gist.
中可用的完整堆栈跟踪
更新
此外,VirtualPathProvider 本身似乎工作正常。如果我直接加载文件而不是通过包加载文件并在 web.config
中设置以下条目,它会从 ProjectB 加载嵌入式 javascript:
<system.webServer>
<handlers>
<add name="MyStaticFileHandler" path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler"/>
</handlers>
</system.webServer>
当 ASP.net 优化创建包时,它会为脚本的虚拟目录调用 GetCacheDependency
。您的 GetCacheDependency
实现只检查虚拟文件,对于虚拟目录,它依赖于基础 VirtualPathProvider
,它检查目录是否存在并且失败。
要解决此问题,您必须检查路径是否是您的脚本之一的 目录 以及 GetCacheDependency
的 return 空路径。
要安全地确定 virtualPath
是否是包目录,您可以使用 BundleTable.Bundles
集合或使用约定(即:每个包都应以 ~/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);
}
}
关于以下错误
目录 'C:\webs\ProjectA\Scripts\SomeFolder\' 不存在。无法开始监视文件更改。
如果嵌入了 SomeFolder 的所有资源文件并因此在已发布的站点中,则特别会发生这种情况 - 它没有创建此文件夹。
对于捆绑包 - 它在创建捆绑包时保留时间戳,并监视文件夹中的任何文件更改以触发捆绑包文件中的更新。
这里 - SomeFolder 中没有要监控的文件 - 因为所有文件都是嵌入的。没有找到阻止文件夹监视的方法-但是通过处理这个特定的异常,它可以被忽略。
我正在尝试实现一种通用方法,以便为我的 Web 解决方案中的不同程序集提供使用来自嵌入式资源的嵌入式 JavaScript 和 CSS 文件的可能性。 This blog post 展示了使用 VirtualPathProvider 的技术。这工作正常,但 VirtualPathProvider 需要包含在每个包含嵌入式资源的程序集中。
我试图从博客 post 中增强 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
从传递的程序集中读取内容:
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
class移动到主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 中的嵌入资源。
有了这个,我收到以下异常:
Directory 'C:\webs\ProjectA\Scripts\SomeFolder\' does not exist. Failed to start monitoring file changes.
更新 this Gist.
中可用的完整堆栈跟踪更新
此外,VirtualPathProvider 本身似乎工作正常。如果我直接加载文件而不是通过包加载文件并在 web.config
中设置以下条目,它会从 ProjectB 加载嵌入式 javascript:
<system.webServer>
<handlers>
<add name="MyStaticFileHandler" path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler"/>
</handlers>
</system.webServer>
当 ASP.net 优化创建包时,它会为脚本的虚拟目录调用 GetCacheDependency
。您的 GetCacheDependency
实现只检查虚拟文件,对于虚拟目录,它依赖于基础 VirtualPathProvider
,它检查目录是否存在并且失败。
要解决此问题,您必须检查路径是否是您的脚本之一的 目录 以及 GetCacheDependency
的 return 空路径。
要安全地确定 virtualPath
是否是包目录,您可以使用 BundleTable.Bundles
集合或使用约定(即:每个包都应以 ~/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);
}
}
关于以下错误
目录 'C:\webs\ProjectA\Scripts\SomeFolder\' 不存在。无法开始监视文件更改。
如果嵌入了 SomeFolder 的所有资源文件并因此在已发布的站点中,则特别会发生这种情况 - 它没有创建此文件夹。
对于捆绑包 - 它在创建捆绑包时保留时间戳,并监视文件夹中的任何文件更改以触发捆绑包文件中的更新。
这里 - SomeFolder 中没有要监控的文件 - 因为所有文件都是嵌入的。没有找到阻止文件夹监视的方法-但是通过处理这个特定的异常,它可以被忽略。