2014-01-21 3 views
1

У меня есть приложение ASP.NET, которое должно иметь несколько макетов для просмотров. Существует обычная веб-макет и «статический» макет для автономной страницы без зависимостей (для использования в качестве шаблона отображения в системе управления doc).ASP.NET CssMinify, HttpContextBase

Это достаточно просто, чтобы иметь возможность переключить его расположение.

Таким образом, макет все-в-одной странице должен включать весь его CSS в тег <style> внутри страницы. Я нашел способ, чтобы выяснить, какие файлы находятся в узелок и написал метод, как так:

@MyCode.IncludeCSS("~/StaticLayout/css") 

Он читает файлы CSS в пачке и выделяет их содержимое в страницу внутри <style> тега.

Но я хотел бы минимизировать CSS.

Я не смог найти документацию для System.Web.Optimization.CssMinify. Вам необходимо вызвать метод Process, которому необходим BundleContext. Итак ... найдите один, создайте? MSDN isn't much use

public BundleContext(
    HttpContextBase context, 
    BundleCollection collection, 
    string bundleVirtualPath 
) 

Parameters 
    context 
     Type: System.Web.HttpContextBase 
     The context. 

Ну, это определенно полезно. У меня не было никакого способа узнать, что context (контекста типа) был контекстом, пока какой-то выпуклый колосс интеллекта в Редмонде не ушел от его занятого сна, чтобы подтолкнуть определенную статью перед ней своими жирными лапами перед проходя в луже теплого слюни.

Тем не менее, я до сих пор не знаю, что это такое или откуда вы его получили, и Google тоже. HttpContext.Current не является производным от него и не имеет свойств (которые я могу найти), которые есть.

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

Кто-нибудь это сделал?

+1

Быстрое примечание: вы можете получить экземпляр «HttpContextBase» без труда: 'new HttpContextWrapper (HttpContext.Current)' (или вставить рамки DI по вашему выбору, чтобы избежать жесткого кодирования зависимости). –

ответ

1

Эд Планкетт,

Если вы используете это как HTML помощник HttpContextBase могут быть захвачены из ViewContext.HttpContext собственности. Это может быть создано, например.

public static IHtmlString BundleCss(this HtmlHelper html, string outputPath, params string[] cssFilePaths) 
{ 
    var collection = new BundleCollection(); 
    foreach (var cssFilePath in cssFilePaths) 
     collection.Add(new Bundle(cssFilePath)); 

    var bundler = new BundleContext(html.ViewContext.HttpContext, collection, outputPath); 
    //... ommitted code 
    System.Web.Optimization.CssMinify minify = new CssMinify(); 
    minify.Process(bundler, response); 
    //... TODO: Grab the response content and return 
} 

Да, это базовый пример использования HTML-помощника. Дайте мне знать, если это не ответит на ваш вопрос.

EDIT: После повторного чтения вопроса я уточняю свой ответ. Таким образом, вышеупомянутое помогает найти свойство HttpContextBase. Однако я думаю, что вопрос заключается в том, как вы можете действительно читать содержимое файлов, их минимизировать и помещать в тег <style> на странице.

я принял удар на написание моей собственной интерпретации вашего требования и придумал следующий набор классов

Мой CssOutputBundler класс:

public class CssOutputBundler 
{ 
    static readonly Dictionary<string, string> cachedOutput = new Dictionary<string, string>(); 
    readonly string tempFileOutputPath; 
    readonly HtmlHelper helper; 
    readonly IList<string> virtualFilePaths; 

    public CssOutputBundler(HtmlHelper helper, string tempFileOutputPath) 
    { 
     if (helper == null) 
      throw new ArgumentNullException("helper null"); 
     if (string.IsNullOrWhiteSpace(tempFileOutputPath)) 
      this.tempFileOutputPath = tempFileOutputPath; 
     this.helper = helper; 
     this.virtualFilePaths = new List<string>(); 
     this.tempFileOutputPath = tempFileOutputPath; 
    } 

    public CssOutputBundler Add(string cssFilePath) 
    { 
     if (!this.virtualFilePaths.Contains(cssFilePath)) 
      this.virtualFilePaths.Add(cssFilePath); 
     return this; 
    } 

    public IHtmlString Minify() 
    { 
     if (helper == null) 
      throw new ArgumentNullException("helper null"); 

     string cache_string = string.Join(",", this.virtualFilePaths); 
     if(cachedOutput.ContainsKey(cache_string)) 
      return formatResponse(File.ReadAllText(cachedOutput[cache_string])); 
     var bundle = new StyleBundle(this.tempFileOutputPath).Include(this.virtualFilePaths.ToArray()); 
     var collection = new BundleCollection(); 
     collection.Add(bundle); 
     var context = new BundleContext(helper.ViewContext.HttpContext, collection, ""); 
     var response = bundle.GenerateBundleResponse(context); 
     System.Web.Optimization.CssMinify minify = new CssMinify(); 
     minify.Process(context, response); 
     string serverPath = helper.ViewContext.HttpContext.Server.MapPath(this.tempFileOutputPath); 
     string outputPath = Guid.NewGuid().ToString() + ".css"; 
     while(File.Exists(Path.Combine(serverPath, outputPath))) 
      outputPath = Guid.NewGuid().ToString() + ".css"; 

     File.WriteAllText(outputPath, response.Content); 
     cachedOutput[cache_string] = outputPath; 
     return formatResponse(response.Content); 
    } 

    IHtmlString formatResponse(string responseContent) 
    { 
     StringBuilder responseBuilder = new StringBuilder(); 
     responseBuilder.AppendLine("<style type=\"text/css\">"); 
     responseBuilder.Append(responseContent); 
     responseBuilder.AppendLine("</style>"); 
     return helper.Raw(responseBuilder.ToString()); 
    } 
} 

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

Если у нас есть, мы читаем временный вложенный скрипт, который хранится на жестком диске.

Примечание:Я использовал хранилище на жестком диске, а не в памяти. Это можно легко изменить, набив полный контент в статический словарь или другой ресурс для кеширования.

Если этот набор файлов не был в комплекте, миниатюрный и т. Д., То мы переходим к пакету и минимизируем набор. Наконец, мы храним файл на HDD и возвращаем ответ. Так что это довольно легко.

Теперь, чтобы реализовать класс, я просто написал быстрый HTML-помощник, так как класс Minits поддерживает цепочки для Add. Файлы могут быть реализованы красиво.

HTML-Helper:

public static CssOutputBundler BundleCss(this HtmlHelper helper, string outputVirtualPath) 
{ 
    return new CssOutputBundler(helper, outputVirtualPath); 
} 

Ok базовая реализация для пакетирования. Теперь этот помощник принимает строку outputVirtualPath, это виртуальный PATH для хранения временных файлов. Если вы решите устранить сохранение на HDD и использовать систему кеша, вы можете удалить этот параметр из помощника и класса.

Наконец, это может быть использовано в вашей точке зрения, как ...

@Html.BundleCss("~/Content/").Add("~/Content/Site.css").Add("~/Content/themes/base/jquery-ui.css").Minify(); 

Где ~/Content/ это виртуальный путь на жестком диске для хранения файлов минимизированы. Затем добавим два файла: "~/Content/Site.css" и ~/Content/themes/base/jquery-ui.css. Наконец вызовите метод minify, который возвращает строку html. Такие как ...

<style type="text/css"> 
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)} ....more css 
</style> 

Cheers.

+0

Это начало, спасибо. Что такое 'outputPath'? Вы знаете что-нибудь о '[BundleResponse] (http://msdn.microsoft.com/en-us/library/dn202155 (v = vs.110) .aspx)'? –

+1

Я отредактировал свой ответ, чтобы включить полный образец. – Nico

+0

Wow. В наши дни у них действительно лучшие дизайнеры API. Большое спасибо за вашу помощь! –

Смежные вопросы