Asp.Net MVC Bundling, лучший способ обнаружить отсутствующий файл
Я только что преследовал ошибку, которая была вызвана отсутствующим файлом javascript, она терпела неудачу.
Минимальная версия файла присутствовала, но не полная версия, ссылка не отображается на клиенте (что я ожидал), но я тоже не получаю исключения. Я хотел бы узнать, нет ли файла.
(просто чтобы быть понятным, пакет не пытался включить мини-версию, он попытался включить полную версию, но миниатюрная версия присутствовала в каталоге script)
Должен ли я написать что-то пользовательское, чтобы обнаружить это, или у MVC есть что-нибудь встроенное, чтобы сообщить об этом?
спасибо
Ответы
Ответ 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;
}
}