簡體   English   中英

ASP.NET 在捆綁中使用嵌入式資源

[英]ASP.NET using embedded resources in 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從傳遞的程序集中讀取內容:

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\”不存在。 無法開始監視文件更改。

更新此 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返回 null。

要安全地確定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 的所有資源文件並因此在已發布的站點中,則會特別發生這種情況 - 它沒有創建此文件夾。

對於 bundle - 它在創建 bundle 時保留時間戳,並監視文件夾中的任何文件更改以觸發 bundle 文件中的更新。

這里 - SomeFolder 中沒有要監控的文件 - 因為所有文件都是嵌入的。 沒有找到阻止文件夾監視的方法——但是通過處理這個特定的異常,它可以被忽略。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM