<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://dotnetcampania.org/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net.aspx</link><description /><dc:language>en-US</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net.aspx</link><pubDate>Thu, 08 Apr 2010 20:05:05 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:25</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Current revision posted to Articoli by ilNero on 08/04/2010 22:05:05&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;lt;style&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;type=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;text/css&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span style="text-decoration: line-through; color: red;"&gt;@&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;import&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;url&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;(&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;http://www.gianlucaesposito.it/dotnetcampania/styles/shCore.css&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;)&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;;&lt;/span&gt;
&lt;span style="text-decoration: line-through; color: red;"&gt;@&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;import&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;url&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;(&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;http://www.gianlucaesposito.it/dotnetcampania/styles/shThemeDefault.css&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;)&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;;&lt;/span&gt;
&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://crockford.com/javascript/jsmin"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dojotoolkit.org/docs/shrinksafe"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dean.edwards.name/packer/"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a target="_blank" href="http://yuicompressor.codeplex.com/"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;" style="overflow:auto;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi :)&lt;/p&gt;
&lt;p&gt;
&lt;script type="text/javascript"&gt;
&amp;lt;!--
        SyntaxHighlighter.all();
// --&amp;gt;
&lt;/script&gt;
&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/9.aspx</link><pubDate>Thu, 08 Apr 2010 20:04:27 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:74</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 9 posted to Articoli by ilNero on 08/04/2010 22:04:27&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;href=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;http://www.gianlucaesposito.it/dotnetcampania/styles/shCore.css&amp;quot;&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;type=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;media=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;screen&amp;quot;&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;rel=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;Stylesheet&amp;quot;&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;/&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;href=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;http://www.gianlucaesposito.it/dotnetcampania/styles/shThemeDefault.css&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;&amp;lt;style&lt;/span&gt; type=&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;media=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;screen&amp;quot;&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;rel=&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;quot;Stylesheet&amp;quot;&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;/&lt;/span&gt;&lt;span style="text-decoration: line-through; color: red;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="background: SpringGreen;"&gt;&amp;quot;text/css&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span style="background: SpringGreen;"&gt;@&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;import&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;url&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;(&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;http://www.gianlucaesposito.it/dotnetcampania/styles/shCore.css&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;)&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;;&lt;/span&gt;
&lt;span style="background: SpringGreen;"&gt;@&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;import&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;url&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;(&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;http://www.gianlucaesposito.it/dotnetcampania/styles/shThemeDefault.css&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;#39;&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;)&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;;&lt;/span&gt;
&lt;span style="background: SpringGreen;"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;script type="text/javascript" src="http://www.gianlucaesposito.it/dotnetcampania/js/shCore.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://www.gianlucaesposito.it/dotnetcampania/js/shBrushCSharp.js"&gt;&lt;/script&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://crockford.com/javascript/jsmin"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dojotoolkit.org/docs/shrinksafe"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dean.edwards.name/packer/"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a target="_blank" href="http://yuicompressor.codeplex.com/"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi :)&lt;/p&gt;
&lt;p&gt;
&lt;script type="text/javascript"&gt;
&amp;lt;!--
        SyntaxHighlighter.all();
// --&amp;gt;
&lt;/script&gt;
&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/8.aspx</link><pubDate>Thu, 08 Apr 2010 20:02:31 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:73</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 8 posted to Articoli by ilNero on 08/04/2010 22:02:31&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&amp;lt;link href=&amp;quot;http://www.gianlucaesposito.it/dotnetcampania/styles/shCore.css&amp;quot; type=&amp;quot;text/css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;Stylesheet&amp;quot; /&amp;gt;
&amp;lt;link href=&amp;quot;http://www.gianlucaesposito.it/dotnetcampania/styles/shThemeDefault.css&amp;quot; type=&amp;quot;text/css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;Stylesheet&amp;quot; /&amp;gt;
&lt;script type="text/javascript" src="http://www.gianlucaesposito.it/dotnetcampania/js/shCore.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://www.gianlucaesposito.it/dotnetcampania/js/shBrushCSharp.js"&gt;&lt;/script&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://crockford.com/javascript/jsmin"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dojotoolkit.org/docs/shrinksafe"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dean.edwards.name/packer/"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a target="_blank" href="http://yuicompressor.codeplex.com/"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi :)&lt;/p&gt;
&lt;p&gt;
&lt;script type="text/javascript"&gt;
&amp;lt;!--
        SyntaxHighlighter.all();
// --&amp;gt;
&lt;/script&gt;
&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/7.aspx</link><pubDate>Thu, 08 Apr 2010 19:56:44 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:72</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 7 posted to Articoli by ilNero on 08/04/2010 21:56:44&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;p&gt;
&lt;span style="background: SpringGreen;"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;href=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;http://www.gianlucaesposito.it/dotnetcampania/styles/shCore.css&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;type=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;media=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;screen&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;rel=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;Stylesheet&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;/&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="background: SpringGreen;"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;href=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;http://www.gianlucaesposito.it/dotnetcampania/styles/shThemeDefault.css&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;type=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;media=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;screen&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;rel=&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;quot;Stylesheet&amp;quot;&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;/&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;gt;&lt;/span&gt;
&lt;script type="text/javascript" src="http://www.gianlucaesposito.it/dotnetcampania/js/shCore.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://www.gianlucaesposito.it/dotnetcampania/js/shBrushCSharp.js"&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://crockford.com/javascript/jsmin"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dojotoolkit.org/docs/shrinksafe"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dean.edwards.name/packer/"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a target="_blank" href="http://yuicompressor.codeplex.com/"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi :)&lt;/p&gt;
&lt;p&gt;
&lt;script type="text/javascript"&gt;&lt;span style="background: SpringGreen;"&gt;&amp;lt;!--&lt;/span&gt;
        &lt;span style="background: SpringGreen;"&gt;SyntaxHighlighter.all()&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;;&lt;/span&gt;
&lt;span style="background: SpringGreen;"&gt;/&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;/&lt;/span&gt; &lt;span style="background: SpringGreen;"&gt;-&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;-&lt;/span&gt;&lt;span style="background: SpringGreen;"&gt;&amp;gt;&lt;/span&gt;&lt;/script&gt;
&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/6.aspx</link><pubDate>Thu, 08 Apr 2010 18:35:09 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:71</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 6 posted to Articoli by ilNero on 08/04/2010 20:35:09&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://crockford.com/javascript/jsmin" target="_blank"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dojotoolkit.org/docs/shrinksafe" target="_blank"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dean.edwards.name/packer/" target="_blank"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.yahoo.com/yui/compressor/" target="_blank"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a href="http://yuicompressor.codeplex.com/" target="_blank"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre style="font-size:11px;overflow:auto;" class="brush: c-sharp;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi &lt;span style="text-decoration: line-through; color: red;"&gt;,&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;mentre&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;mi&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;godo&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;il&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;fresco&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;di&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;questo&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;temporalone&lt;/span&gt; &lt;span style="text-decoration: line-through; color: red;"&gt;estivo&lt;/span&gt; :)&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/5.aspx</link><pubDate>Thu, 08 Apr 2010 11:03:02 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:70</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 5 posted to Articoli by ilNero on 08/04/2010 13:03:02&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://crockford.com/javascript/jsmin"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dojotoolkit.org/docs/shrinksafe"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dean.edwards.name/packer/"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a target="_blank" href="http://yuicompressor.codeplex.com/"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;" style="font-size:11px;overflow:auto;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi, mentre mi godo il fresco di questo temporalone estivo :)&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/4.aspx</link><pubDate>Thu, 08 Apr 2010 11:02:08 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:69</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 4 posted to Articoli by ilNero on 08/04/2010 13:02:08&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://crockford.com/javascript/jsmin" target="_blank"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dojotoolkit.org/docs/shrinksafe" target="_blank"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dean.edwards.name/packer/" target="_blank"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.yahoo.com/yui/compressor/" target="_blank"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a href="http://yuicompressor.codeplex.com/" target="_blank"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre style="font-size:11px;" class="brush: c-sharp;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi, mentre mi godo il fresco di questo temporalone estivo :)&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/3.aspx</link><pubDate>Thu, 08 Apr 2010 11:01:46 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:68</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 3 posted to Articoli by ilNero on 08/04/2010 13:01:46&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://crockford.com/javascript/jsmin"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dojotoolkit.org/docs/shrinksafe"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dean.edwards.name/packer/"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a target="_blank" href="http://yuicompressor.codeplex.com/"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;" style="font-size:10px;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi, mentre mi godo il fresco di questo temporalone estivo :)&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/2.aspx</link><pubDate>Thu, 08 Apr 2010 10:57:56 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:67</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 2 posted to Articoli by ilNero on 08/04/2010 12:57:56&lt;br /&gt;
&lt;h2&gt;CSS e Javascript minification con ASP.NET&lt;/h2&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://crockford.com/javascript/jsmin" target="_blank"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dojotoolkit.org/docs/shrinksafe" target="_blank"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dean.edwards.name/packer/" target="_blank"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.yahoo.com/yui/compressor/" target="_blank"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a href="http://yuicompressor.codeplex.com/" target="_blank"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;"&gt;using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Yahoo.Yui.Compressor;

namespace DotNetCampania.Web.Handlers
{
	public class YUICompressor : IHttpHandler
	{
		private const int DEFAULT_CACHE_DURATION = 1440;
		private bool useCache = true;
		private bool noCompression = false;

		public bool IsReusable { get { return true; } }
		
		public void ProcessRequest(HttpContext context)
		{
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
			bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
			context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
			string filePath = GetFilePath();
			string fileExtension = Path.GetExtension(filePath);
			if (File.Exists(filePath))
			{
				context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
				switch (fileExtension)
				{
					case &amp;quot;.css&amp;quot;:
						context.Response.ContentType = &amp;quot;text/css&amp;quot;;
						if (!this.noCompression) 
							CompressCSS(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					case &amp;quot;.js&amp;quot; :
						context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
						if (!this.noCompression)
							CompressJavaScript(filePath);
						else
							HttpContext.Current.Response.WriteFile(filePath);
						break;
					default :
						context.Response.StatusCode = 404;
						break;
				}
			}
			else
			{
				context.Response.StatusCode = 404;
			}
			context.Response.Flush();
			context.Response.End();
		}
		
		private string GetFilePath()
		{
			string filePath = HttpContext.Current.Request.Url.AbsolutePath;
			filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
			filePath = HttpContext.Current.Server.MapPath(filePath);
			return filePath;
		}

		private void CompressCSS(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = CssCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}

		private void CompressJavaScript(string filePath)
		{
			if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
			{
				HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
				return;
			}
			object fileLock = new object();
			lock (fileLock)
			{
				StreamReader sr = new StreamReader(filePath, true);
				string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
				HttpContext.Current.Response.Write(compressed);
				if (this.useCache)
					HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
				sr.Close();
			}
		}
	}
}
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi, mentre mi godo il fresco di questo temporalone estivo :)&lt;/p&gt;</description></item><item><title>CSS e Javascript minification con ASP.NET</title><link>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/revision/1.aspx</link><pubDate>Thu, 08 Apr 2010 10:57:01 GMT</pubDate><guid isPermaLink="false">793b29df-8c2a-42d1-a022-8914441a68e5:66</guid><dc:creator>ilNero</dc:creator><comments>http://dotnetcampania.org/wikis/articoli/css-e-javascript-minification-con-asp-net/comments.aspx</comments><description>Revision 1 posted to Articoli by ilNero on 08/04/2010 12:57:01&lt;br /&gt;
&lt;p&gt;
        Chiunque abbia a che fare con la programmazione web si sar&amp;agrave; reso conto che l&amp;#39;utilizzo
        dei CSS, cos&amp;igrave; come l&amp;#39;utilizzo di framework javascript come jQuery, sia ormai praticamente
        uno standard de-facto.&lt;br /&gt;
        Per quanto riguarda i framework Javascript, questi vengono rilasciati costantemente
        sia in versione &amp;#39;sources&amp;#39; che in versione &amp;#39;minified&amp;#39;, lasciando per&amp;ograve; la scelta del
        minifier da utilizzare esclusivamente ai creatori/mantainer del framework.&lt;br /&gt;
        Purtroppo ho la smania di tenere costantemente tutto sotto controllo, ragion per
        cui negli ultimi mesi ho cominciato a studiare i vari software che operano la &lt;em&gt;minification&lt;/em&gt;.&lt;br /&gt;
        Sul web se ne trovano diversi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://crockford.com/javascript/jsmin"&gt;JSMIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dojotoolkit.org/docs/shrinksafe"&gt;the Dojo compressor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://dean.edwards.name/packer/"&gt;Dean Edwards&amp;#39; Packer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
        Su tutti, la mia attenzione si &amp;egrave; focalizzata molto su &lt;strong&gt;YUI Compressor&lt;/strong&gt;, che
        a detta dei suoi sviluppatori&lt;/p&gt;
&lt;p&gt;
        &lt;em&gt;The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher
            compression ratio than most other tools.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
        Dopo diversi test e diverse rilasci in produzione di fogli di stile e codice javascript
        minimizzato con questo tool, posso affermare di non aver mai riscontrato incompatibilit&amp;agrave;
        o problemi di sorta.&lt;br /&gt;
        L&amp;#39;unico grande difetto di questo tool &amp;egrave; il suo essere un tool da riga di comando,
        il che si traduce in una serie di step da eseguire in pre-produzione.&lt;br /&gt;
        Se da un lato, le modifiche a queste tipologie di file, sono rare, una volta raggiunta
        la fase di rilascio, &amp;egrave; pur vero che piccole migliorie vengono sempre apportate dopo
        il rilascio di una applicazione web.&lt;br /&gt;
        Stanco quindi di aprire frequentemente il prompt dei comandi, ho cercato una soluzione
        da inglobare direttamente nei progetti web, che riuscisse a minimizzare &lt;em&gt;on-the-fly&lt;/em&gt;
        i CSS e i JS.&lt;/p&gt;
&lt;p&gt;
        Animato dall&amp;#39;esigenza e dalla scoperta di questo porting per .NET &lt;a target="_blank" href="http://yuicompressor.codeplex.com/"&gt;YUI Compresso for .NET&lt;/a&gt;, ho buttato gi&amp;ugrave; questo semplice HttpHandler,
        capace di riconoscere le richieste giuste e rispondere con la versione minimizzata
        del file richiesto.&lt;/p&gt;
&lt;pre class="brush: c-sharp;"&gt;        using System;
        using System.Collections.Generic;
        using System.IO;
        using System.Linq;
        using System.Text;
        using System.Web;
        using Yahoo.Yui.Compressor;

        namespace DotNetCampania.Web.Handlers
        {
            public class YUICompressor : IHttpHandler
            {
                private const int DEFAULT_CACHE_DURATION = 1440;
                private bool useCache = true;
                private bool noCompression = false;

                public bool IsReusable { get { return true; } }
                
                public void ProcessRequest(HttpContext context)
                {
                    bool.TryParse(context.Request.QueryString.Get(&amp;quot;useCache&amp;quot;), out this.useCache);
                    bool.TryParse(context.Request.QueryString.Get(&amp;quot;noCompression&amp;quot;), out this.noCompression);
                    context.Response.ContentType = &amp;quot;text/plain&amp;quot;;
                    string filePath = GetFilePath();
                    string fileExtension = Path.GetExtension(filePath);
                    if (File.Exists(filePath))
                    {
                        context.Response.AddHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;filename=&amp;quot; + Path.GetFileName(filePath));
                        switch (fileExtension)
                        {
                            case &amp;quot;.css&amp;quot;:
                                context.Response.ContentType = &amp;quot;text/css&amp;quot;;
                                if (!this.noCompression) 
                                    CompressCSS(filePath);
                                else
                                    HttpContext.Current.Response.WriteFile(filePath);
                                break;
                            case &amp;quot;.js&amp;quot; :
                                context.Response.ContentType = &amp;quot;application/x-javascript&amp;quot;;
                                if (!this.noCompression)
                                    CompressJavaScript(filePath);
                                else
                                    HttpContext.Current.Response.WriteFile(filePath);
                                break;
                            default :
                                context.Response.StatusCode = 404;
                                break;
                        }
                    }
                    else
                    {
                        context.Response.StatusCode = 404;
                    }
                    context.Response.Flush();
                    context.Response.End();
                }
                
                private string GetFilePath()
                {
                    string filePath = HttpContext.Current.Request.Url.AbsolutePath;
                    filePath = filePath.TrimEnd(&amp;quot;.axd&amp;quot;.ToCharArray());
                    filePath = HttpContext.Current.Server.MapPath(filePath);
                    return filePath;
                }

                private void CompressCSS(string filePath)
                {
                    if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
                    {
                        HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
                        return;
                    }
                    object fileLock = new object();
                    lock (fileLock)
                    {
                        StreamReader sr = new StreamReader(filePath, true);
                        string compressed = CssCompressor.Compress(sr.ReadToEnd());
                        HttpContext.Current.Response.Write(compressed);
                        if (this.useCache)
                            HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
                        sr.Close();
                    }
                }

                private void CompressJavaScript(string filePath)
                {
                    if (this.useCache &amp;amp; HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()] != null)
                    {
                        HttpContext.Current.Response.Write((string)HttpContext.Current.Cache[HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString()]);
                        return;
                    }
                    object fileLock = new object();
                    lock (fileLock)
                    {
                        StreamReader sr = new StreamReader(filePath, true);
                        string compressed = JavaScriptCompressor.Compress(sr.ReadToEnd());
                        HttpContext.Current.Response.Write(compressed);
                        if (this.useCache)
                            HttpContext.Current.Cache.Add(HttpContext.Current.Request.Url.AbsolutePath.GetHashCode().ToString(), compressed, null, DateTime.MaxValue, new TimeSpan(0, DEFAULT_CACHE_DURATION, 0), System.Web.Caching.CacheItemPriority.Normal, null);
                        sr.Close();
                    }
                }
            }
        }
    &lt;/pre&gt;
&lt;p&gt;
        L&amp;#39;handler va ovviamente mappato nel web.config. Devo per&amp;ograve; fornire una doverosa annotazione:
        nel mio caso ho mappato le estensioni &lt;strong&gt;*.js.axd&lt;/strong&gt; e &lt;strong&gt;*.css.axd&lt;/strong&gt;. Questa
        scelta mi obbliga a dover fare attenzione nelle pagine .aspx o .html che creo, in
        quanto i riferimenti ai fogli di stile ed ai file javascript devono finire con questa
        estensione per essere processati. In un contesto di hosting condiviso (leggi Aruba),
        dove non ho possibilit&amp;agrave; di intervento sulle estensioni mappate in IIS, questa mi
        sembrava la scelta migliore. In contesti di maggior libert&amp;agrave; di mapping delle estensioni
        in IIS, sarebbe bastato mappare le estensioni .css e .js sull&amp;#39;engine di ASP.NET,
        e mappare le stesse estensioni sull&amp;#39;handler.&lt;/p&gt;
&lt;p&gt;
        Come si evince dal codice, l&amp;#39;handler utilizza anche la cache in modo da evitare
        di processare i singoli file ad ogni richiesta, ma solo quando strettamente necessario.&lt;/p&gt;
&lt;p&gt;
        Una ulteriore aggiunta potrebbe essere l&amp;#39;utilizzo di chiavi negli appSettings, in
        modo da controllare l&amp;#39;abilitazione globale dell&amp;#39;handler direttamente da web.config,
        ma lo lascio fare a voi, mentre mi godo il fresco di questo temporalone estivo :)&lt;/p&gt;</description></item></channel></rss>
