# Pikku hack: CSS Combiner / Minifier ASP.NET Control

<datetime class="hidden">2010-03-25T00:00</datetime>

<!-- category -- mostlylucidcouk, Imported -->
**CAUTION: Kun sanon hakata tarkoitan sitä ...tämä ei ole millään tavalla tuotanto valmis ... se on vain näyte tässä vaiheessa. Jos se aiheuttaa koirasi räjähtää, älä syytä minua!**

Ajattelin heittää työn käynnissä verkossa, jotta ihmiset voivat pelata. Tämä on yksi minun pikku lemmikki projekteista (Iööm ei saa kirjoittaa koodia töissä ... ei dev kuin I[Olen aina muistuttanut!).

Mitä se tekee?

Yksi nykyisten verkkosivujen suurimmista suoritusongelmista on niiden palvelimelle tekemien pyyntöjen määrä, ei varsinainen palvelinpuolen käsittelyaika. [kirjoitti tästä](http://mostlylucid.net/archive/2008/07/11/spritey.my-pet-project.aspx) Luettuaan Steve Soundersin erinomaisen '[Korkean suorituskyvyn verkkosivut](http://www.amazon.com/High-Performance-Web-Sites-Essential) Se oli suoraan sanottuna yllätys minulle! No, muutenkin viime aikoina olen pelannut useita ASP.NET-palvelinohjain, jonka tarkoituksena on optimoida palvelimen puheluiden määrä ASP.NET-sovelluksella on tehdä paljon vähemmän. Ensimmäinen näistä on (tällä hetkellä) julkaisematon [CSS Sprite Control](http://mostlylucid.net/archive/2008/07/11/spritey.my-pet-project.aspx). Alla on toisen alku, tämä kirjoitettiin parin tunnin sisällä viime yönä, kun en voinut nukkua miettiessäni, miten se voisi toimia. Koodi on erittäin karkea, mutta se osoittaa konseptin melko hyvin.

Pohjimmiltaan halusin mahdollisimman pienen ponnistuksen useiden yhdistelemiseksi ja tiivistämiseksi &lt;linkki rel= stylesheet&gt; CSS-tiedostojen merkinnät yhdessä, minimoi ne käyttämällä [YUI-kompressori](http://developer.yahoo.com/yui/compressor/) ([.NET...on Codeplex](http://yuicompressor.codeplex.com/)) ja tulosteen aikariippuvainen (tässä tapauksessa tiedostolle muokattu Date Modified) hash tiedoston nimelle (kiinteässä paikassa tällä hetkellä, /OutputCSS/), jonka jälkeen tulostaa sivulle tämän uuden tiedoston.

Miten se toimii?

Kuvittele, että sinulla olisi sivu, jossa on joitakin tyylilehtien määritelmiä:

```
   1: <link type="text/css" rel="stylesheet" href="../../../build/logger/assets/logger.css"/>
```

```
   2: <link type="text/css" rel="stylesheet" href="../../../build/yuitest/assets/testlogger.css"/>        
```

```
   3: <style type="text/css">
```

```
   4: #container, #container2 {
```

```
   5:     width: 400px;
```

```
   6: }
```

```
   7:  
```

```
   8: .yui-carousel-element {
```

```
   9:     margin: 0;
```

```
  10:     padding: 0;
```

```
  11: }
```

```
  12:  
```

```
  13: .yui-carousel-element li {
```

```
  14:     border: none;
```

```
  15:     margin: 0;
```

```
  16:     padding: 0;
```

```
  17:     width: 100px;
```

```
  18: }
```

```
  19: </style>
```

Kuten näette, meillä on kaksi CSS-tiedoston määrittelyä ja tyylinen tunniste. Olisi kiva, jos voisimme yhdistää ja minimoida nämä...no... tässä miten minun pieni hakata ohjaus antaa sinun tehdä sen:

```
   1: <asp:CSSManager runat="server">
```

```
   2:         <link type="text/css" rel="stylesheet" href="~/build/logger/assets/logger.css"/>
```

```
   3:         <link type="text/css" rel="stylesheet" href="../../../build/yuitest/assets/testlogger.css"/>        
```

```
   4:         <style type="text/css">
```

```
   5:         #container, #container2 {
```

```
   6:             width: 400px;
```

```
   7:         }
```

```
   8:  
```

```
   9:         .yui-carousel-element {
```

```
  10:             margin: 0;
```

```
  11:             padding: 0;
```

```
  12:         }
```

```
  13:  
```

```
  14:         .yui-carousel-element li {
```

```
  15:             border: none;
```

```
  16:             margin: 0;
```

```
  17:             padding: 0;
```

```
  18:             width: 100px;
```

```
  19:         }
```

```
  20:         </style>
```

```
  21: </asp:CSSManager>
```

Yllä olevasta kuvasta näet, että käärimme CSS-määritelmät &lt;Asp:CSSManager&gt;…&lt;/asp:CSSManager&gt; Vielä yksi asia, tarkkaavainen on huomannut, että voin nyt käyttää ~/ in the href...it...se on mukava sivuvaikutus tästä menetelmästä... joten vältät hullun polun ylikulkujutut (../././).

Ilmeisesti tämä on vielä vähän rajallinen, se ei toimi Osittainen luottamus, ei käsittele useita skaaloja; sano, Site Level CSS, Page Level CSS ja Masterpages, jossa haluat useita lakanat eri sisältöä. Suunnitelma on jatkaa työtä tämän vähän aikaa ... joten aion lähes varmasti päivittää tämän pian.

Lähde seuraa

```
   1: using System;
```

```
   2: using System.Collections.Generic;
```

```
   3: using System.ComponentModel;
```

```
   4: using System.Text;
```

```
   5: using System.Web.UI;
```

```
   6: using System.Web.UI.HtmlControls;
```

```
   7: using System.IO;
```

```
   8: using System.Security.Cryptography;
```

```
   9: using Yahoo.Yui.Compressor;
```

```
  10:  
```

```
  11: namespace CSSManager
```

```
  12: {
```

```
  13:     [DefaultProperty("Text")]
```

```
  14:     [ToolboxData("<{0}:CSSManager runat=server></{0}:CSSManager>")]
```

```
  15:  
```

```
  16:     [ParseChildren(true, "cssFiles")]
```

```
  17:     public class CSSManager : Control, INamingContainer
```

```
  18:     {
```

```
  19:  
```

```
  20:         public const string FILE_PATH = "~/OutputCSS/{0}.css";
```

```
  21:  
```

```
  22:         public CSSManager() { }
```

```
  23:  
```

```
  24:         public List<HtmlGenericControl> CSSFiles
```

```
  25:         {
```

```
  26:             get;
```

```
  27:             set;
```

```
  28:         }
```

```
  29:  
```

```
  30:  
```

```
  31:         private StringBuilder combinedSheets = new StringBuilder();
```

```
  32:  
```

```
  33:         public string GetStyleSheet(string virtualPath)
```

```
  34:         {
```

```
  35:             string filePath = Context.Server.MapPath(virtualPath);
```

```
  36:             if (!string.IsNullOrEmpty(filePath))
```

```
  37:             {
```

```
  38:                 return File.ReadAllText(filePath);
```

```
  39:             }
```

```
  40:             return string.Empty;
```

```
  41:  
```

```
  42:         }
```

```
  43:  
```

```
  44:         public string CalculateFileHash(string filePaths)
```

```
  45:         {
```

```
  46:             MD5CryptoServiceProvider csp = new MD5CryptoServiceProvider();
```

```
  47:             byte[] pathBytes = csp.ComputeHash(System.Text.UTF8Encoding.UTF8.GetBytes(filePaths));
```

```
  48:             return BitConverter.ToUInt64(pathBytes, 0).ToString();
```

```
  49:  
```

```
  50:         }
```

```
  51:  
```

```
  52:         public void WriteFile(string textToWrite, string fileHash)
```

```
  53:         {
```

```
  54:             File.WriteAllText(Context.Server.MapPath(string.Format(FILE_PATH, fileHash)), textToWrite);
```

```
  55:         }
```

```
  56:  
```

```
  57:         public string CreateDatedFilePath(string filePath)
```

```
  58:         {
```

```
  59:             FileInfo fi = new FileInfo(Context.Server.MapPath(filePath));
```

```
  60:             if (fi.Exists)
```

```
  61:             {
```

```
  62:                 return fi.LastWriteTimeUtc.Ticks.ToString() + "#" + filePath;
```

```
  63:             }
```

```
  64:             return string.Empty;
```

```
  65:  
```

```
  66:  
```

```
  67:         }
```

```
  68:  
```

```
  69:         protected override void CreateChildControls()
```

```
  70:         {
```

```
  71:  
```

```
  72:             if (this.DesignMode == true)
```

```
  73:             {
```

```
  74:                 foreach (var file in CSSFiles)
```

```
  75:                 {
```

```
  76:                     string rel = file.Attributes["rel"];
```

```
  77:  
```

```
  78:                     string href = file.Attributes["href"];
```

```
  79:  
```

```
  80:                     if (rel.ToLowerInvariant() == "stylesheet")
```

```
  81:                     {
```

```
  82:                         file.Attributes["href"] = this.ResolveClientUrl(Context.Server.MapPath(href));
```

```
  83:                         this.Controls.Add(file);
```

```
  84:                     }
```

```
  85:  
```

```
  86:                 }
```

```
  87:             }
```

```
  88:             StringBuilder filePaths = new StringBuilder();
```

```
  89:             int i = 0;
```

```
  90:             foreach (var file in CSSFiles)
```

```
  91:             {
```

```
  92:                 string tagName = file.TagName.ToLowerInvariant();
```

```
  93:                 if (tagName == "link")
```

```
  94:                 {
```

```
  95:                     string rel = file.Attributes["rel"];
```

```
  96:                     string href = file.Attributes["href"];
```

```
  97:  
```

```
  98:                     if (rel.ToLowerInvariant() == "stylesheet")
```

```
  99:                     {
```

```
 100:                         string styleSheet = GetStyleSheet(href);
```

```
 101:                         if (!string.IsNullOrEmpty(styleSheet))
```

```
 102:                             combinedSheets.Append(styleSheet);
```

```
 103:                         filePaths.AppendFormat("{0}#", CreateDatedFilePath(href));
```

```
 104:                     }
```

```
 105:                 }
```

```
 106:                 else if (tagName == "style")
```

```
 107:                 {
```

```
 108:                     string inner = file.InnerHtml;
```

```
 109:                     combinedSheets.Append(inner);
```

```
 110:                     filePaths.Append("CSSSTYLE_" + i);
```

```
 111:                     i++;
```

```
 112:                 }
```

```
 113:  
```

```
 114:             }
```

```
 115:             string minimizedStyles = CssCompressor.Compress(combinedSheets.ToString(), 0, CssCompressionType.Hybrid);
```

```
 116:             string fileHash = CalculateFileHash(filePaths.ToString());
```

```
 117:             WriteFile(minimizedStyles, fileHash);
```

```
 118:  
```

```
 119:             HtmlGenericControl gen = new HtmlGenericControl();
```

```
 120:             gen.TagName = "link";
```

```
 121:             gen.Attributes.Add("href", this.ResolveClientUrl(string.Format(FILE_PATH, fileHash)));
```

```
 122:             gen.Attributes.Add("rel", "stylesheet");
```

```
 123:             this.Controls.Add(gen);
```

```
 124:         }
```

```
 125:  
```

```
 126:     }
```

```
 127: }
```