Optimizarea site-urilor ASP.NET MVC cu Fiddler ,Yahoo Slow si Google Page Speed si Search Engine Optimization Toolkit

Disclaimer : Acest post se refera la un website obisnuit, la care nu ai acces la configurarea de pe server(de ex., nu ai acces la IIS Compression) si trebuie sa ti le faci singur

Marota mea favorita, www.infovalutar.ro, se incarca destul de greu prima oara. Asa incit a trebuit sa ii fac o optimizare. Site-ul fiind facut cu ASP.NET MVC, prima optimizare chioara am facut-o cu [OutputCache] pe controller. Asta cacheuia si pagina, si datele …tot. Ca sa vad cum cachuieste, am gasit un Html.Substitution cu care pot sa afisez chestii ne=cache-uite (modificat un pic, ca poate am nevoie sa scriu stringul EXACT asa cum este …):

public static object Substitute(this HtmlHelper html, MvcCacheCallback cb, bool Encode)
        {
            if (Encode)
            {
                html.ViewContext.HttpContext.Response.WriteSubstitution(
            c => HttpUtility.HtmlEncode(
                cb(new HttpContextWrapper(c))
            ));

            }
            else
            {
                html.ViewContext.HttpContext.Response.WriteSubstitution(
         c => (
             cb(new HttpContextWrapper(c))
         ));

            }
            return null;
        }

 

OK, apoi am inceput sa ma gindesc la optimizari … Mai intii imaginile, apoi css-urile + jscript, apoi redirect-urile . Asa ca am zis ca cel mai bine este sa incerc cu un tool – si primul ales este Fiddler. Asa ca am vazut redirecturi (301)la greu  .De ce le aveam ? pentru ca aveam probleme la controlere pentru uppercase/lowercase la argumente si m-am decis ca toate sa fie cu lowercase , asa incit pusesem in global.asax

protected void Application_BeginRequest(Object sender, EventArgs e)
       {
           // If upper case letters are found in the URL, redirect to lower case URL.
           if (Regex.IsMatch(HttpContext.Current.Request.Url.ToString(), @"[A-Z]") == true)
           {
               string LowercaseURL = HttpContext.Current.Request.Url.ToString().ToLower();

               Response.Clear();               
               Response.Status = "301 Moved Permanently";
               Response.AddHeader("Location", LowercaseURL);
               Response.End();
           }
       }

Asa ca am intervenit in site si am schimbat ca toate sa fie cu litere mici (un .ToLower() la linkuri a ajuns)

Dar am revenit la problema initiala: mai aveam nevoie sa fie cache-uite imaginile,css-urile si jscripturile. E adevarat, ma puteam uita in Fiddler(click pe fisier=>inspectors )

032811_Print Screen

sa vad care e cache-uita, care e zip-uita – dar aveam nevoie de un tool general. Asa ca , pentru mine , combinatia ideala a ajuns : Firefox + Firebug + Yahoo Slow + Google Page Speed. OK,daca vi le-ati instalat pe toate atunci puteti incepe cu yahoo Slow – si, ca sa ma dau bun iata cum arata la mine:

 

035121_Cursurile Banca Nationala a RomanieiBNR  Mozilla Firefox_active

Va rog sa observati ca am Grade A pentru “Small Site or Blog” . OK, ceea ce recomanda Yahoo Slow si nu faceam era:

  1. Put CSS at top
  2. Put Javascript at bottom
  3. Compress components with Gzip
  4. Make fewer HTTP requests.

1 si 2 sunt relativ usor – mai modifica site master-ul  si gata.

 

3.Cum facem Compress components with Gzip ? Am cautat rapid – si am gasit, in final, asta GZip and Deflate Compression Filter for ASP.Net MVC . Am pus-o, mergea bine pe masina mea, dar cum am pus-o in productie , cum a dat eroarea asta . Asa ca a trebuit sa renunt la OutputCache – si sa fac caching pe ASP.NET Cache – dar asta doar la datele din BD .Acum mergea perfect! Dovada : nu a mai aparut pagina la Yahoo Slow  – iar , inspectata cu fiddler => inspector , a aparut Gzip.

4.OK, acum era problema de optimizare a imaginilor – mai exact, vroiam ca imaginile sa ramine in cache-ul browser-ului, astfel incit sa nu se mai downloadeze inca o data. Pentru asta trebuia sa setez expiration la image  -dar cum, daca nu am acces la server ? Ca de obicei, se rezolva cu o indirectare: Sa zicem ca imaginile sunt in folder-ul flags. Atunci il pus sa treaca printr-un controller:

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("flags", "flags/{id}.ashx",
                new { controller = "imagini", action = "flags" });

//alte date        

}

Iar fiecare imagine se va prelungi cu un ashx ( adica .gif.ashx) :

<img width="30" height="20" src="/<% ="flags/" + curLoop.IDMoneda.ToLower() + ".gif.ashx"%>" />

In controller-ul respectiv pe actiunea flags, redam imaginea :

            Response.Cache.SetExpires(DateTime.Now.AddDays(300));//
            Response.Cache.SetCacheability(HttpCacheability.Public);
            Response.Cache.SetValidUntilExpires(false);
            Response.AddHeader("content-disposition", "inline; filename=" + filename);

             Response.ContentType = content;

Response.WriteFile(file);

OK, acum iarasi Fiddler si presto : imaginile erau cache-uite aproximativ 1 an.

Dar cum sa fac cu Jscriptul ca sa fie si compresat si cache-uit ? Pai – acelasi lucru – sa treaca printr-un Controller si sa ii aplic Gzip prin clasa CompressFilter.

Aici am avut cea mai mare problema : de acasa imi dadea ca js e compresat – la servici ca nu. Innebunisem – si totul s-a rezolvat cu

//proxy servers in between may cache            
Response.AppendHeader("Vary", "Accept-Encoding");

Bun, deja ma miscam mai usor  in sensul ca pagina, de la citiva bun kb ajunsese la a doua iteratie la < 10 (ma rog, cu reclame < 15)

image

Daca apasati pe Statistics o sa vedeti 2 grafice : una de la prima incarcare si una de la a doua incarcare (in care nu se mai incarca cache-ul de la prima)– Daca numarul de Http Requests si numarul de Kb este acelasi – atunci aveti o problema. La mine este 48 / 6 Requests – cu 84 / 13 Kb.

Daca ati facut pina aici  – e super! Acum sa mai aplicam doar Google Page Speed – acesta este doar cireasa de pe tort

image

Cu el am mai optimizat din imagini , m-am uitat ca

  1. puteam optimiza prin minify “There is 173.8kB worth of JavaScript. Minifying could save 4.7kB (2.7% reduction).” – ma rog, doar pentru primii veniti – ceilalti au oricum cache-ul…
  2. ca ar trebui sa fac “This page makes 43 parallelizable requests to infovalutar.ro. Increase download parallelization by distributing these requests across multiple hostnames:” – mda, si de unde bani  ? Si yahoo vorbeste de CDN-uri

OK, ultimul tool de care voiam sa va vorbesc este Search Engine Optimization Toolkit. Este o scula extraordinara pentru incepatorii ca mine, se integreaza de minune in VISTA . Il rulati odata pe site-ul vostru(din IIS,vedeti Scott http://weblogs.asp.net/scottgu/archive/2009/06/03/iis-search-engine-optimization-toolkit.aspx ) , puteti creea robots.txt, sitemap si vedea multe altele. Oricum, postul lui Scott http://weblogs.asp.net/scottgu/archive/2009/06/03/iis-search-engine-optimization-toolkit.aspx  spune tot – si face analiza chiar pe site-ul propriu! Nu spun pe www.infovalutar.ro cit mi-a gasit!

Oricum, daca faceti site-uri, e bine de avut in trusa de dezvoltator!

2 thoughts on “Optimizarea site-urilor ASP.NET MVC cu Fiddler ,Yahoo Slow si Google Page Speed si Search Engine Optimization Toolkit

  1. Multumesc.
    Ca remember, sa nu uit de whitespace removing – facut tot cu un action filter dupa http://madskristensen.net/post/A-whitespace-removal-HTTP-module-for-ASPNET-20.aspx
    dar codul corect este:

    public override void Write(byte[] buffer, int offset, int count)
    {

    byte[] data = new byte[count];
    Buffer.BlockCopy(buffer, offset, data, 0, count);
    string contentInBuffer = System.Text.Encoding.Default.GetString(data);

    contentInBuffer = Regex.Replace(contentInBuffer, @"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/", "");
    contentInBuffer = Regex.Replace(contentInBuffer, @"\s+", " ");
    contentInBuffer = Regex.Replace(contentInBuffer, @"\s*{\s*", "{");
    contentInBuffer = Regex.Replace(contentInBuffer, @"\s*}\s*", "}");
    contentInBuffer = Regex.Replace(contentInBuffer, @"\s*;\s*", ";");

    byte[] outdata = System.Text.Encoding.Default.GetBytes(contentInBuffer);
    _sink.Write(outdata, offset, outdata.GetLength(0));
    }

Leave a Reply to Iulian Ghisoiu - optimizare.biz Cancel reply

Your email address will not be published. Required fields are marked *