【发布时间】:2016-01-14 10:30:32
【问题描述】:
我正在尝试实现一种通用方法,以便为我的 Web 解决方案中的不同程序集提供使用来自嵌入式资源的嵌入式 JavaScript 和 CSS 文件的可能性。 This blog post 展示了一种使用 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从传递的程序集中读取内容:
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 中的嵌入资源。
我收到以下异常:
目录 'C:\webs\ProjectA\Scripts\SomeFolder\' 不存在。无法开始监控文件更改。
更新 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>
【问题讨论】:
-
你的 Startup 类在哪里?在 ProjectA 中还是在 ProjectB 中?
-
ProjectA 是一个包含 VirtualPathProvider 的 NuGet 包。 ProjectB 另一个 NuGet 包,它提供了一些带有视图的功能(有多个)。 NuGet 包 ProjectB 依赖于 NuGetPackage ProjectA。应用程序安装 ProjectB NuGetPackages。因此 Startup 在 ProjectA 和 ProjectB 之外,但 ProjectA 和 ProjectB 可以挂钩到 PreApplicationStartMethod。
-
似乎
IsEmbeddedPath方法返回false而它应该返回true。您能告诉我们错误发生之前path和resourceName的值吗? -
如果我调试
IsEmbeddedPath返回true并且GetFile也被调用并返回嵌入资源的流。 -
@PascalBerger
IsEmbeddedPath总是返回true。通过查看调用堆栈,我们可以看到GetCacheDependency被调用,然后基类GetCacheDependency被调用,这意味着IsEmbeddedPath返回false一次。
标签: c# asp.net-mvc embedded-resource bundling-and-minification virtualpathprovider