Asp.Net MVC Bundling,检测丢失文件的最佳方法

时间:2014-05-22 09:27:31

标签: asp.net-mvc

我刚刚追查了一个由于缺少javascript文件而导致的错误,它无声地失败了。

文件的缩小版本存在但不是完整版本,客户端上没有呈现链接(我期待)但我也没有例外。我想知道文件是否不存在。

(为了清楚,捆绑包没有尝试包含缩小版本,它试图包含完整版本,但是缩小版本存在于脚本目录中)

我是否必须编写一些自定义内容来检测此内容,或者MVC是否内置了任何内容来报告此内容?

感谢

4 个答案:

答案 0 :(得分:26)

我开始使用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);
    }
}

这样您就不必明确调用辅助方法PreCheck()。它还支持ASP.NET的通配符{version}*

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

答案 1 :(得分:1)

我无法相信这种反模式"存在!如果您没有看到错误,则没有错误!

无论如何,我喜欢上面的解决方案。另一个是输出链接/脚本,即使它在BundleTable.EnableOptimizations为false时丢失 - 这是一个非常明显的事情,在调试时尝试,然后在浏览器上的各种检查器/调试器中显而易见的是哪个文件是失踪。对于调试事情来说,这似乎是一件显而易见的事情,我花了几个小时没有意识到丢失文件。另一方面,默默地忽略了捆绑的缺失部分,这是错误的,它加强了我可怕的调试会话。

嗯,这不会让我两次受伤 - 创伤持久。

答案 2 :(得分:1)

使用BundleTable.VirtualPathProvider包装器的另一种方法:

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);
        }
    }
}

BundleHelpers.InitBundles()中运行BundleConfig.cs

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

答案 3 :(得分:0)

我稍微更改了代码。而不是抛出错误,它不会添加任何捆绑文件。如果您对多个项目使用相同的通用捆绑包配置,则需要这样做

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;
    }
}