我正在尝试实现一种通用方法,为我的Web解决方案中的不同程序集提供使用嵌入式资源中的JavaScript和CSS文件的可能性。这篇博客文章展示了使用VirtualPathProvider的技巧。这很有效,但是每个包含嵌入式资源的程序集都需要包含VirtualPathProvider。
我试图增强来自博客文章的VirtualPathProvider,以便可以将程序集传递给它并从其程序集加载资源。
检查资源是否为此程序集的嵌入式资源是通过检查在
在包含嵌入资源的项目(ProjectB)中,我仍然在
我试图增强来自博客文章的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>
IsEmbeddedPath
总是返回true
。通过查看调用堆栈,我们可以看到先调用了GetCacheDependency
,然后调用了基础的GetCacheDependency
,这意味着IsEmbeddedPath
有一次返回了false
。 - Cyril DurandFileExists
中设置一个条件为virtualPath.Contains("MyScript.js")
的断点,如果它被调用,则virtualPath
被设置为~/Scripts/SomeFolder/MyScript.js
。在IsEmbeddedPath
中,resourceName是ProjectA.SomeFolder.MyScript.js
,它存在于assemblyResourceNames
中,因此返回true
。我还在GetFile
中设置了另一个具有相同条件的断点,然后调用该函数。资源的VirtualFile
对象从那里返回。之后不会再调用FileExists
或GetFile
。 - Pascal Berger