Asp.Net MVC Bundling, лучший способ обнаружить отсутствующий файл - программирование
Подтвердить что ты не робот

Asp.Net MVC Bundling, лучший способ обнаружить отсутствующий файл

Я только что преследовал ошибку, которая была вызвана отсутствующим файлом javascript, она терпела неудачу.

Минимальная версия файла присутствовала, но не полная версия, ссылка не отображается на клиенте (что я ожидал), но я тоже не получаю исключения. Я хотел бы узнать, нет ли файла.

(просто чтобы быть понятным, пакет не пытался включить мини-версию, он попытался включить полную версию, но миниатюрная версия присутствовала в каталоге script)

Должен ли я написать что-то пользовательское, чтобы обнаружить это, или у MVC есть что-нибудь встроенное, чтобы сообщить об этом?

спасибо

4b9b3361

Ответ 1

Я пришел к использованию следующих методов расширения для 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")
    );

Ответ 2

Другой способ использования оболочки 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

Я не могу поверить, что этот "анти-шаблон" существует! Если вы не видите ошибок, ошибок нет!

В любом случае, мне нравится решение выше. Другим будет вывод link/ script, даже если он отсутствует, когда BundleTable.EnableOptimizations является ложным - это очень очевидная вещь, которую нужно попробовать при отладке, а затем это будет очевидно в различных инспекторах/отладчиках в браузерах, которые файл отсутствует. Это казалось такой очевидной вещью для отладки, что я провел часы, не понимая, что там отсутствуют файлы. Другой способ, молча игнорируя недостающие части пучка, настолько ошибочен, что он усилил мою ужасную сессию отладки.

Хорошо, это не укусит меня дважды - травма терпит.

Ответ 4

Я немного изменил код. Вместо того, чтобы бросать ошибку, он не добавит никакого пакета. это требуется, если вы используете одну и ту же конфигурацию общих пакетов для нескольких проектов.

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