2014-05-22 33 views
12

我剛剛追趕了一個由於缺少JavaScript文件而導致的錯誤,這是一次失敗的沉默。Asp.Net MVC捆綁,檢測丟失文件的最佳方式

該文件的縮小版本存在,但不是完整版本,客戶端上沒有呈現鏈接(我期待)但我也沒有得到例外。我想知道該文件是否不存在。

(僅僅是明確的,捆綁沒有嘗試包括縮小的版本,它試圖包含完整版,但縮小的版本是在腳本目錄存在)

我必須寫自定義來檢測這個或MVC是否有內置的報告?

感謝

+0

哪個鏈接未在客戶端上呈現?捆綁的重點在於減少文件數量,因此除非您使用'BundleTable.EnableOptimizations = false;'啓用診斷模式,否則客戶端上每捆只能獲取一個文件。通過該設置,您可以使用Fiddler2查看請求並查看任何缺少的腳本。 –

+0

試試這個http://stackoverflow.com/questions/20869907/。關鍵是你應該沒有縮小版本。至少是那個,沒有'.min.js'。據我所知,捆綁運行** **從未使用分鐘,它總是不minifing它itslef –

+0

拉迪姆,謝謝,不過這不是說鏈接什麼,」 ......將被搜索,如果沒有找到,電流將精縮「這表明,如果它的存在將使用它 – tony

回答

23

我想出了使用下面的擴展方法Bundle

public static class BundleHelper 
{ 
    [Conditional("DEBUG")] // remove this attribute to validate bundles in production too 
    private static void CheckExistence(string virtualPath) 
    { 
     int i = virtualPath.LastIndexOf('/'); 
     string path = HostingEnvironment.MapPath(virtualPath.Substring(0, i)); 
     string fileName = virtualPath.Substring(i + 1); 

     bool found = Directory.Exists(path); 

     if (found) 
     { 
      if (fileName.Contains("{version}")) 
      { 
       var re = new Regex(fileName.Replace(".", @"\.").Replace("{version}", @"(\d+(?:\.\d+){1,3})")); 
       fileName = fileName.Replace("{version}", "*"); 
       found = Directory.EnumerateFiles(path, fileName).FirstOrDefault(file => re.IsMatch(file)) != null; 
      } 
      else // fileName may contain '*' 
       found = Directory.EnumerateFiles(path, fileName).FirstOrDefault() != null; 
     } 

     if (!found) 
      throw new ApplicationException(String.Format("Bundle resource '{0}' not found", virtualPath)); 
    } 

    public static Bundle IncludeExisting(this Bundle bundle, params string[] virtualPaths) 
    { 
     foreach (string virtualPath in virtualPaths) 
      CheckExistence(virtualPath); 

     return bundle.Include(virtualPaths); 
    } 

    public static Bundle IncludeExisting(this Bundle bundle, string virtualPath, params IItemTransform[] transforms) 
    { 
     CheckExistence(virtualPath); 
     return bundle.Include(virtualPath, transforms); 
    } 
} 

這樣你就不必打電話給你的helper方法PreCheck()明確。它還支持ASP.NET的通配符{version}*

bundles.Add(new ScriptBundle("~/test") 
    .IncludeExisting("~/Scripts/jquery/jquery-{version}.js") 
    .IncludeExisting("~/Scripts/lib*") 
    .IncludeExisting("~/Scripts/model.js") 
    ); 
+0

有用的東西!一個備註:你可以用'FirstOrDefault(文件=> re.IsMatch(文件))''替換其中(文件=> re.IsMatch(文件))FirstOrDefault()'。 – user1068352

0

我無法相信這個「​​反模式」的存在!如果您看不到任何錯誤,那就沒有錯誤!

無論如何,我喜歡上面的解決方案。另一種方法是輸出鏈接/腳本,即使它在BundleTable.EnableOptimizations爲false時丟失 - 在調試時這是非常明顯的事情,然後在瀏覽器上的各種檢查器/調試器中顯而易見,哪些文件是失蹤。這似乎是一件很明顯的事情,我花了幾個小時纔沒有意識到丟失了文件。另一種方式,默默地忽略了缺失的部分,是非常錯誤的,它加強了我可怕的調試過程。那麼,這不會咬我兩次 - 創傷持久。

0

我改變了一下代碼。不會拋出錯誤,它不會添加任何包文件。

public class VirtualPathProviderExt : VirtualPathProvider 
{ 
    private readonly VirtualPathProvider _provider; 

    public VirtualPathProviderExt(VirtualPathProvider provider) 
    { 
     _provider = provider; 
    } 

    public override string CombineVirtualPaths(string basePath, string relativePath) 
    { 
     return _provider.CombineVirtualPaths(basePath, relativePath); 
    } 

    public override ObjRef CreateObjRef(Type requestedType) 
    { 
     return _provider.CreateObjRef(requestedType); 
    } 

    public override bool DirectoryExists(string virtualDir) 
    { 
     return _provider.DirectoryExists(virtualDir); 
    } 

    public override bool Equals(object obj) 
    { 
     return _provider.Equals(obj); 
    } 

    private static readonly Regex _ignorePathsRegex = new Regex(@"\.debug\.\w+$|^~/bundle.config$", RegexOptions.IgnoreCase | RegexOptions.Compiled); 

    public override bool FileExists(string virtualPath) 
    { 
     var result = _provider.FileExists(virtualPath); 
     if (!result && !_ignorePathsRegex.IsMatch(virtualPath)) 
     { 
      Logger.Instance.Log(RecType.Error, "Bundle file not found: " + virtualPath); 
     } 

     return result; 
    } 

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) 
    { 
     return _provider.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); 
    } 

    public override string GetCacheKey(string virtualPath) 
    { 
     return _provider.GetCacheKey(virtualPath); 
    } 

    public override VirtualDirectory GetDirectory(string virtualDir) 
    { 
     return _provider.GetDirectory(virtualDir); 
    } 

    public override VirtualFile GetFile(string virtualPath) 
    { 
     return _provider.GetFile(virtualPath); 
    } 

    public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) 
    { 
     return _provider.GetFileHash(virtualPath, virtualPathDependencies); 
    } 

    public override int GetHashCode() 
    { 
     return _provider.GetHashCode(); 
    } 

    public override object InitializeLifetimeService() 
    { 
     return _provider.InitializeLifetimeService(); 
    } 

    public override string ToString() 
    { 
     return _provider.ToString(); 
    } 
} 

捆綁幫手:

public static class BundleHelpers 
{ 
    public static void InitBundles() 
    { 
     if (!(BundleTable.VirtualPathProvider is VirtualPathProviderExt)) 
     { 
      BundleTable.VirtualPathProvider = new VirtualPathProviderExt(BundleTable.VirtualPathProvider); 
     } 
    } 
} 

而且在BundleConfig.cs運行BundleHelpers.InitBundles()是,如果你使用的是相同的公共束配置多個項目

public static class BundleHelper 
{ 
    private static bool CheckExistence(string virtualPath) 
    { 
     int i = virtualPath.LastIndexOf('/'); 
     string path = HostingEnvironment.MapPath(virtualPath.Substring(0, i)); 
     string fileName = virtualPath.Substring(i + 1); 

     bool found = Directory.Exists(path); 

     if (found) 
     { 
      if (fileName.Contains("{version}")) 
      { 
       var re = new Regex(fileName.Replace(".", @"\.").Replace("{version}", @"(\d+(?:\.\d+){1,3})")); 
       fileName = fileName.Replace("{version}", "*"); 
       found = Directory.EnumerateFiles(path, fileName).Where(file => re.IsMatch(file)).FirstOrDefault() != null; 
      } 
      else // fileName may contain '*' 
       found = Directory.EnumerateFiles(path, fileName).FirstOrDefault() != null; 
     } 
     return found; 
     //if (!found) 
     //throw new ApplicationException(String.Format("Bundle resource '{0}' not found", virtualPath)); 
    } 

    public static Bundle IncludeExisting(this Bundle bundle, params string[] virtualPaths) 
    { 
     foreach (string virtualPath in virtualPaths) 
      if (CheckExistence(virtualPath)) 
      { 
       bundle.Include(virtualPath); 
      } 

     return bundle; 
    } 

    public static Bundle IncludeExisting(this Bundle bundle, string virtualPath, params IItemTransform[] transforms) 
    { 
     if (CheckExistence(virtualPath)) 
      bundle.Include(virtualPath, transforms); 
     return bundle; 
    } 
} 
1

另一種方法使用BundleTable.VirtualPathProvider包裝要求:

public class BundleConfig 
{ 
    public static void RegisterBundles(BundleCollection bundles) 
    { 
     BundleHelpers.InitBundles(); 
     ...