MVC4 StyleBundle не отображает пакет в правильном порядке
Я пытаюсь отрисовать связку css-файлов, но вывод получается в неправильном порядке. Я попробовал решение @ MVC4 Beta Minification and Bundling: упорядочивание файлов и отладка в браузере , но это не помогло. Вот связка:
bundles.Add(new StyleBundle("~/stylesheet")
.Include("~/css/main.css")
.Include("~/css/mvc.css")
.Include("~/js/jquery.thickbox.css")
.Include("~/js/jquery.rating.css")
.Include("~/css/ProductListing.css")
.Include("~/css/dropdown/dropdown.css")
.Include("~/css/dropdown/dropdown.vertical.css")
.Include("~/js/fancybox/jquery.fancybox-1.3.1.css")
.Include("~/css/scartpopup.css")
.Include("~/css/ShoppingCart.css")
.Include("~/css/ceebox.css")
.Include("~/css/tooltip.css")
.Include("~/css/recent_blog_posts.css")
.Include("~/css/ProductDetail.css")
.Include("~/css/jquery-ui-1.7.3.custom.css")
.Include("~/css/filter_box.css")
.Include("~/css/custom_page.css")
.Include("~/css/Checkout.css")
.Include("~/css/CheckoutButton.css")
);
И вот результат, как вы можете видеть, jQuery-ui выходит на первое место.
<link href="/css/jquery-ui-1.7.3.custom.css" rel="stylesheet"/>
<link href="/css/main.css" rel="stylesheet"/>
<link href="/css/mvc.css" rel="stylesheet"/>
<link href="/js/jquery.thickbox.css" rel="stylesheet"/>
<link href="/js/jquery.rating.css" rel="stylesheet"/>
<link href="/css/ProductListing.css" rel="stylesheet"/>
<link href="/css/dropdown/dropdown.css" rel="stylesheet"/>
<link href="/css/dropdown/dropdown.vertical.css" rel="stylesheet"/>
<link href="/js/fancybox/jquery.fancybox-1.3.1.css" rel="stylesheet"/>
<link href="/css/scartpopup.css" rel="stylesheet"/>
<link href="/css/ShoppingCart.css" rel="stylesheet"/>
<link href="/css/ceebox.css" rel="stylesheet"/>
<link href="/css/tooltip.css" rel="stylesheet"/>
<link href="/css/recent_blog_posts.css" rel="stylesheet"/>
<link href="/css/ProductDetail.css" rel="stylesheet"/>
<link href="/css/filter_box.css" rel="stylesheet"/>
<link href="/css/custom_page.css" rel="stylesheet"/>
<link href="/css/Checkout.css" rel="stylesheet"/>
<link href="/css/CheckoutButton.css" rel="stylesheet"/>
Как я могу убедиться, что таблицы стилей отображаются в правильном порядке?
1 ответ:
Связывание не должно отображать CSS-файлы в одном и том же порядке, оно следует другой логике. Если вам нужно отрисовать их как определено, то вы должны создать пользовательский IBundleOrderer и установить его в пакет как требуемый Orderer:
public class AsDefinedBundleOrderer : IBundleOrderer { public IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files) { return files; } }
И
var bundle = new StyleBundle("~/stylesheet"); bundle.Orderer = new AsDefinedBundleOrderer(); bundles.Add(bundle);
Тогда это ничего не сделает со списком, поэтому рендер будет рендерить их точно в том же порядке.
Обновление порядка по умолчанию
Связывание использует понятие
IBundleOrderer
для сортировки элементов в пределахBundle
. КлассBundle
обладает свойствомOrderer
, которое выглядит следующим образом:public IBundleOrderer Orderer { get { if (this._orderer == null) return (IBundleOrderer) DefaultBundleOrderer.Instance; else return this._orderer; } set { this._orderer = value; this.InvalidateCacheEntries(); } }
Таким образом, по умолчанию orderer на самом деле является
DefaultBundleOrderer
, пока вы не перепишете его с помощью пользовательского orderer.У
IBundleOrderer
есть следующая подпись:public interface IBundleOrderer { IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files); }
Реализация
DefaultBundleOrderer
этого упорядочивает файлы поBundleContext
, Вот фрагмент из реализацииOrderFiles
:foreach (BundleFileSetOrdering ordering in (IEnumerable<BundleFileSetOrdering>) context.BundleCollection.FileSetOrderList) DefaultBundleOrderer.AddOrderingFiles(ordering, (IEnumerable<FileInfo>) list, fileMap, foundFiles, result);
Так что другой результат происходит потому, что это. Это, конечно, не случайность алгоритм сортировки :) Правила определены в классе
BUndleCollection
:public static void AddDefaultFileOrderings(IList<BundleFileSetOrdering> list) { if (list == null) throw new ArgumentNullException("list"); BundleFileSetOrdering bundleFileSetOrdering1 = new BundleFileSetOrdering("css"); bundleFileSetOrdering1.Files.Add("reset.css"); bundleFileSetOrdering1.Files.Add("normalize.css"); list.Add(bundleFileSetOrdering1); BundleFileSetOrdering bundleFileSetOrdering2 = new BundleFileSetOrdering("jquery"); bundleFileSetOrdering2.Files.Add("jquery.js"); bundleFileSetOrdering2.Files.Add("jquery-min.js"); bundleFileSetOrdering2.Files.Add("jquery-*"); bundleFileSetOrdering2.Files.Add("jquery-ui*"); bundleFileSetOrdering2.Files.Add("jquery.ui*"); bundleFileSetOrdering2.Files.Add("jquery.unobtrusive*"); bundleFileSetOrdering2.Files.Add("jquery.validate*"); list.Add(bundleFileSetOrdering2); BundleFileSetOrdering bundleFileSetOrdering3 = new BundleFileSetOrdering("modernizr"); bundleFileSetOrdering3.Files.Add("modernizr-*"); list.Add(bundleFileSetOrdering3); BundleFileSetOrdering bundleFileSetOrdering4 = new BundleFileSetOrdering("dojo"); bundleFileSetOrdering4.Files.Add("dojo.*"); list.Add(bundleFileSetOrdering4); BundleFileSetOrdering bundleFileSetOrdering5 = new BundleFileSetOrdering("moo"); bundleFileSetOrdering5.Files.Add("mootools-core*"); bundleFileSetOrdering5.Files.Add("mootools-*"); list.Add(bundleFileSetOrdering5); BundleFileSetOrdering bundleFileSetOrdering6 = new BundleFileSetOrdering("prototype"); bundleFileSetOrdering6.Files.Add("prototype.js"); bundleFileSetOrdering6.Files.Add("prototype-*"); bundleFileSetOrdering6.Files.Add("scriptaculous-*"); list.Add(bundleFileSetOrdering6); BundleFileSetOrdering bundleFileSetOrdering7 = new BundleFileSetOrdering("ext"); bundleFileSetOrdering7.Files.Add("ext.js"); bundleFileSetOrdering7.Files.Add("ext-*"); list.Add(bundleFileSetOrdering7); }
Поэтому, когда вы вызываете это из
Application_Start
:BundleConfig.RegisterBundles(BundleTable.Bundles);
Фактически вы передаете значение по умолчанию
BundleCollection
, определенное в библиотеке.Таким образом, мы имеем
BundleFileSetOrdering
экземпляры, передаваемые один за другим в:private static void AddOrderingFiles(BundleFileSetOrdering ordering, IEnumerable<FileInfo> files, Dictionary<string, HashSet<FileInfo>> fileMap, HashSet<FileInfo> foundFiles, List<FileInfo> result) { foreach (string key in (IEnumerable<string>) ordering.Files) { if (key.EndsWith("*", StringComparison.OrdinalIgnoreCase)) { string str = key.Substring(0, key.Length - 1); foreach (FileInfo fileInfo in files) { if (!foundFiles.Contains(fileInfo) && fileInfo.Name.StartsWith(str, StringComparison.OrdinalIgnoreCase)) { result.Add(fileInfo); foundFiles.Add(fileInfo); } } } else if (fileMap.ContainsKey(key)) { List<FileInfo> list = new List<FileInfo>((IEnumerable<FileInfo>) fileMap[key]); list.Sort((IComparer<FileInfo>) FileInfoComparer.Instance); foreach (FileInfo fileInfo in list) { if (!foundFiles.Contains(fileInfo)) { result.Add(fileInfo); foundFiles.Add(fileInfo); } } } } }
Заключение
Если мы хотим упростить процесс, то можем сказать, что библиотека предпочитает какие-то файлы и делает некоторую сортировку по другим файлам, если найдено несколько возможностей. Это ожидаемое поведение большую часть времени, но, как вы можете видеть, оно легко переопределяется с помощью
AsDefinedBundleOrderer
, поэтому он ничего не делает с данным набором файлов, поэтому порядок остается первоначальным.