domenica 30 giugno 2013

.NET- Eseguire un task alla compilazione di un progetto

Richiamare un task, di una Dll esterna, all'atto di compilazione dei un progetto .NET in visual Studio è una cosa abbastanza semplice. In particolare, la scorsa settimana, mi sono dovuto informare su questo argomento perché volevo lanciare la minificazione di tutti i file javascript del progetto, a compilazione avvenuta.
Siccome non ero sicuro di quali librerie usare per la minificazione,  tra YUI Compressor di Yahoo e quelle delle Ajax Minification o quello che verrà, ho pensato di creare un mio task, che al momento usa le librerie della YUI ma in futuro potrebbe cambiare. Questa "Black Box" viene richiamata, all'atto della compilazione dei miei progetti Web.

Step 1 - Creazione task
  1. Create un nuovo progetto "Class Library" in Visual Studio.
  2. Create il vostro Task:

    public class MyTask : Microsoft.Build.Utilities.Task
        {
          
            public override bool Execute()
            {
               
                /* Do Something */
    
                return true;
            }
        }
  3. Compilate.

Step 2 - Lanciare i Task dopo ogni compilazione
  1. Create un progetto "Web Application"
  2. Tasto Destro del mouse sul progetto
  3. Selezionate "Unload Project"

  4. Tasto Destro del mouse sul progetto 
  5. Selezionare "Edit [Nomeprogetto].csproj"

  6. Inserire queste righe nel file di progetto, avendo cura di sostituire "MyTaskNameSpace" con il namespace del task e "c:\temp\MyTaskNameSpace.dll" con il path corretto della vostra dll :

    <UsingTask TaskName="MyTaskNameSpace.MyTask" AssemblyFile="c:\temp\MyTaskNameSpace.dll">
    </UsingTask>
    <Target Name="AfterBuild">
          <MyTask>
          </MyTask>
    </Target>
  7. Compilate.



giovedì 27 giugno 2013

MVC4 - Bundles - problema memoria

Buonasera a tutti.

Scrivo questo posto perché ho notato che le funzionalità di minificazione dei file javascript, fornite dalla Dll System.Web.Optimization, sono molto costose in termini di risorse di memoria. In particolare, su un applicativo in produzione, la sola minificazione dei file javascript allocava 50Mb di memoria RAM, a fronte di un insieme di file che pesano si e no 2Mb.

Ho spiegato come minificare file javascript e css in questo articolo :
MVC4 Minificazione file Javascript e CSS (Creazione Bundle)

Ora ecco un caso pratico:

Ho provato a creare un progetto MVC 4, con templates Razor.

Nel progetto base vengono creati 3 bundle per i javascript.

Ogni bundle richiamato (es. @Scripts.Render("~/bundles/jquery")) fà aumentare la memoria consumata di ca. 4Mb. Nella mia applicazione i Javascript sono diversi e quindi è probabile che sia per quello che arrivo a consumare 50Mb.

La cosa mi lascia molto perplesso perché a fronte di pochi Kb di script vengono allocati alcuni Mb in memoria.
Nella mia realtà aziendale, dove sullo stesso server sono installati diversi siti, questo è un problema non indifferente.

Credo che a questo punto l'unica soluzione sia quella di minificare e mergiare  i file in fase di compilazione e mettere il link diretto al file minificato nelle pagine. Purtroppo così allungo i tempi di produzione/bug fixing e aumentano le possibilità di errore (pubblicando solo i file non minificati e lasciando all'helper "Scripts" l'operazione di minificazione e merge, ho la certezza di quale file stia usando il sito e ho la possibilità di debuggare eventuali errori presenti solo in produzione).

Dopo alcune prove credo di aver isolato il problema.
Il consumo di memoria deve essere legato alle Trasformazioni, ovvero al processo dii minificazione, perchè sostituendo nella creazione dei bundle

System.Web.Optimization.ScriptBundle

con

System.Web.Optimization.Bundle

i file javascript vengono accodati in un unico file, non avviene la minificazione e la memoria utilizzata è quasi trascurabile.


Consiglio quindi di procedere in questo modo:


  • minificare i file javascript alla compilazione, magari utilizzando le librerie di "YUI Compressor" o "Ajax Minifier"
  • usare i bundle delle "System.Web.Optimization", senza la parte di minificazione "on the fly"

Spero di esservi stato utile.

---------------------

Luca Dalsass
Solution Architect and Development Manager at Totalcom Srl



sabato 22 giugno 2013

.NET - Errori comuni - Concatenazione di stringhe

Buongiorno a tutti.
oggi volevo condividere con voi uno di quegli "errori" che comunemente si commettono nella programmazione .NET. La concatenazione di stringhe. Spesso, per distrazione o per fretta, la concatenazione di stringhe viene fatta in ambiente .NET usando l'operatore "+". Il risultato che si ottiene è ovviamente quello desiderato, ma potrebbe avere gravi ripercussioni sulle performance del nostro applicativo. Mi spiego meglio:


  • Nel framework .NET le stringhe sono oggetti IMMUTABILI e pertanto le operazioni di modifica ad esse applicate non modificano la stringa di partenza, ma ne creano una nuova.
  • L'oggetto che deve essere usato per la manipolazione delle stringhe è "System.Text.StringBuilder", il quale non lavora con stringhe, ma con Stream di dati.

provate a creare una Console Application e sostituire il metodo main con il seguente:


 static void Main(string[] args)
        {
            /* test with + operator */
            DateTime start = System.DateTime.Now;

            string resultString = string.Empty;

            for (int i = 0; i < 50000; i++)
            {
                resultString += "123456789abcdefghilmnopqrstuvz";
            }
            TimeSpan t = (System.DateTime.Now - start);

            Console.WriteLine(string.Format("Test with + operator. Time : {0}:{1}:{2}:{3}", t.Hours, t.Minutes, t.Seconds, t.Milliseconds));


            /* Test with StringBuilder */
            start = System.DateTime.Now;

            StringBuilder resultStringBuilder = new StringBuilder();

            t = (System.DateTime.Now - start);
            
            for (int i = 0; i < 50000; i++)
            {
                resultStringBuilder.Append("123456789abcdefghilmnopqrstuvz");
            }

            Console.WriteLine(string.Format("Test with StringBuilder. Time : {0}:{1}:{2}:{3}", t.Hours, t.Minutes, t.Seconds, t.Milliseconds));

            Console.ReadLine();
        }


il risultato ottenuto sul mio computer è il seguente:


Senza parole vero?


venerdì 21 giugno 2013

I programmatori possono sbagliare

Ciao a tutti.

anche i migliori sbagliano, quindi anche chi come me che uno tra i migliori non è, può sbagliare dannazione. Mi sono preso 3 giorni di ferie. Tre stupidi giorni di ferie e due voucher di un e-commerce non sono partiti, facendo sì che il cliente gridasse allo scandalo, partissero mail verso i superiori dei superiori dei superiori.... ecc ecc ecc.
Mi sono arrabbiato. Soprattutto con me stesso, per non aver previsto tutte le situazioni possibili, per non aver fatto tutti i test possibili.
Ma può un povero programmatore vivere nel terrore di non poter andare in ferie, altrimenti "chissà cosa succede.." o coscio del fatto che "mentre sei via non c'è nessuno che abbia conoscenza dei progetti che hai seguito.."?

Ora sono più tranquillo. In fondo i problemi, almeno per la mia esperienza, sono sempre gli stessi:

  • i programmatori sono umani e pertanto possono sbagliare
  • i progetti sono spesso "svenduti" e quindi non si ha il budget per sviluppare con calma, fare i test e magari lavorare a coppie, di modo che gli errori del singolo siano sempre corretti dal partner.

e poi ho trovato un link, che mi hanno molto tranquillizzato :)

Buone ferie

mercoledì 12 giugno 2013

Serializing and deserializing classes in C#

When we send data to a different system, is usual to use xml formats. If we use C # as a programming language, there are some framework methods that help us a lot. In the version 3.5 of the framework we can use the "exstension Method" and can equip any class of additional methods, in relation to the type.
Combining the two things you can write methods for serializing and deserializing classes and make them generic.
For example:

With the following "Extension Method"


        /// <summary>
        /// Serializes to XML.
        /// </summary>
        /// <param name="value">The object to serialize.</param>
        /// <returns>
        /// a XElement rappresenting the class serialization
        /// </returns>
        public static XElement SerializeToXML(this object value)
        {
            XmlSerializer x = new XmlSerializer(value.GetType());
            XDocument doc = new XDocument();
            using (XmlWriter xw = doc.CreateWriter())
            {
                x.Serialize(xw, value);
                xw.Close();
            }
            return doc.Root;
        }


        /// <summary>
        /// Deserializes the specified string to an object of type T.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value containing an xml.</param>
        /// <returns>
        /// an object of type T
        /// </returns>
        public static T Deserialize<T>(this string value)
        {
            XElement xElement = XElement.Parse(value);

            return xElement.Deserialize<T>();

        }

        /// <summary>
        /// Deserializes the specified string to an object of type T.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value containing an xml.</param>
        /// <returns>
        /// an object of type T
        /// </returns>
        public static T Deserialize<T>(this XElement value)
        {
            XmlSerializer x = new XmlSerializer(typeof(T));
            T result;
            using (XmlReader xr = value.CreateReader())
            {
                result = (T)x.Deserialize(xr);
                xr.Close();
            }
            return result;
        }









In this way, you'll just have to serialize a class writing







MyClass a = new MyClass();

XElement xml = a.SerializeToXML();
MyClass b = xml.Deserialize<MyClass>(xml)

Extract the first characters of a text.

Good morning to everybody

What I propose today is a simple function to extract the first characters of a text.
Even in this simple function we have some requirements:

  • must be extracted whole words only.
  • if the text exceeds the size you want, we have to append some points of suspension.
  • the suspension points contribute to the number of desired characters.

Here's the function:


  public string GetAbstract(string text, int maxCharacters)
        {
            if (String.IsNullOrEmpty(text))
            {
                return string.Empty;
            }
            else    if (text.Length < maxCharacters)
            {
                return text;
            }
            else
            {
                string textToEsamine = text.Substring(0, maxCharacters);

                int lastSpacePosition = textToEsamine.LastIndexOf(" ", textToEsamine.Length);

                if (lastSpacePosition > 0)
                {
                    return textToEsamine.Substring(0, lastSpacePosition) + "...";
                }
                else
                {
                    /* devo troncare la parola */
                    return textToEsamine.Substring(0, maxCharacters - 3) + "...";
                }
            }
        }



If we really want to esagereare we can also create an extension method for object "String".
In this way we can easily extract text from each string.


public static class Extensions
    {
  public static string GetAbstract(this string text, int maxCharacters)
        {
            if (String.IsNullOrEmpty(text))
            {
                return string.Empty;
            }
            else    if (text.Length < maxCharacters)
            {
                return text;
            }
            else
            {
                string textToEsamine = text.Substring(0, maxCharacters);

                int lastSpacePosition = textToEsamine.LastIndexOf(" ", textToEsamine.Length);

                if (lastSpacePosition > 0)
                {
                    return textToEsamine.Substring(0, lastSpacePosition) + "...";
                }
                else
                {
                    /* devo troncare la parola */
                    return textToEsamine.Substring(0, maxCharacters - 3) + "...";
                }
            }
        }
}

Enjoy!

martedì 11 giugno 2013

Estrarre le prime lettere di un testo

Buongiorno a tutti.

Quello che vi propongo oggi è una semplice funzione per estrarre i primi caratteri di un testo.
Anche in una funzione così semplice debbono essere tenuti presenti alcuni requisiti:


  • devono essere estratte solo parole intere
  • se il testo supera la grandezza desiderata devono essere accodati dei punti di sospensione.
  • i punti di sospensione concorrono al conto del numero di caratteri



Ecco la funzione:



  public string GetAbstract(string text, int maxCharacters)
        {
            if (String.IsNullOrEmpty(text))
            {
                return string.Empty;
            }
            else    if (text.Length < maxCharacters)
            {
                return text;
            }
            else
            {
                string textToEsamine = text.Substring(0, maxCharacters);

                int lastSpacePosition = textToEsamine.LastIndexOf(" ", textToEsamine.Length);

                if (lastSpacePosition > 0)
                {
                    return textToEsamine.Substring(0, lastSpacePosition) + "...";
                }
                else
                {
                    /* devo troncare la parola */
                    return textToEsamine.Substring(0, maxCharacters - 3) + "...";
                }
            }
        }



Se vogliamo proprio esagereare possiamo anche crearne un extension method per l'oggetto "String".
In questo modo possiamo estrarre un testo da ogni stringa.


public static class Extensions
    {
  public static string GetAbstract(this string text, int maxCharacters)
        {
            if (String.IsNullOrEmpty(text))
            {
                return string.Empty;
            }
            else    if (text.Length < maxCharacters)
            {
                return text;
            }
            else
            {
                string textToEsamine = text.Substring(0, maxCharacters);

                int lastSpacePosition = textToEsamine.LastIndexOf(" ", textToEsamine.Length);

                if (lastSpacePosition > 0)
                {
                    return textToEsamine.Substring(0, lastSpacePosition) + "...";
                }
                else
                {
                    /* devo troncare la parola */
                    return textToEsamine.Substring(0, maxCharacters - 3) + "...";
                }
            }
        }
}

Divertitevi!

domenica 9 giugno 2013

MVC4 Minificazione file Javascript e CSS (Creazione Bundle)

Buongiorno a tutti

oggi vorrei condividere con voi una delle funzionalità da me più apprezzate, introdotte con la versione 4 del framework MVC: La minificazione dei file javascript e CSS. Aggregare e minificare i file javascript e CSS statici delle nostre applicazioni Web è una cosa buona e giusta. Già da tempo esistevano librerie .NET e non per fare questo, oggi, scaricando il pacchetto MVC4, ne ritroviamo una nuova.

Come prima cosa sappiate che dovrete usare Visual Studio 2010 o 2012.
Scaricate il pacchetto dal seguente indirizzo:

http://www.asp.net/mvc/mvc4

Una volta installato il pacchetto potrete creare facilmente un nuovo progetto Web, con framework MVC4.



Il progetto che verrà creato avrà una cartella "packages", con tutte le dll "Nuove", da poter includere nel vostro progetto. La libreria che fornisce le funzionalità per aggregare e minificare i file statici è la

    System.Web.Optimization

Per semplicità esaminiamo i file che sono presenti nel progetto base "ASP.NET MCV4 Web Applicazion".
In questo progetto troviamo i file javascript nella cartella "Scripts" e i file CSS nella cartella "Content".

La prima cosa da fare è capire come funzionano e come modificare i "Bundle". Questi "Bundle" sono degli insiemi di file. Aprite il file Global.asax e troverete la seguente riga

    BundleConfig.RegisterBundles(BundleTable.Bundles);

La funzione "RegisterBundles" contiene la creazione dei "Bundle":

// For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                        "~/Scripts/jquery-ui-{version}.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.unobtrusive*",
                        "~/Scripts/jquery.validate*"));

            // Use the development version of Modernizr to develop with and learn from. Then, when you're
            // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                        "~/Scripts/modernizr-*"));

            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

            bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                        "~/Content/themes/base/jquery.ui.core.css",
                        "~/Content/themes/base/jquery.ui.resizable.css",
                        "~/Content/themes/base/jquery.ui.selectable.css",
                        "~/Content/themes/base/jquery.ui.accordion.css",
                        "~/Content/themes/base/jquery.ui.autocomplete.css",
                        "~/Content/themes/base/jquery.ui.button.css",
                        "~/Content/themes/base/jquery.ui.dialog.css",
                        "~/Content/themes/base/jquery.ui.slider.css",
                        "~/Content/themes/base/jquery.ui.tabs.css",
                        "~/Content/themes/base/jquery.ui.datepicker.css",
                        "~/Content/themes/base/jquery.ui.progressbar.css",
                        "~/Content/themes/base/jquery.ui.theme.css"));
        }

Questi Bundle vengono richiamati nel file di Layout (Razor o ASP.NET) dagli Helper "Scripts" e "Styles":

        @Styles.Render("~/Content/css")
        @Scripts.Render("~/bundles/modernizr")

Questi Helper scrivono nell'html un output diverso, a seconda che l'applicazione sia configurata per essere eseguita in "Debug" o "Release". In Debug verranno richiamati TUTTI i file del bundle, singolarmente e non minificati. In Ralease i file dei Bundle verranno restituiti come un unico file, minificato. Il link al file conterrà inoltre un parametro "v", che varierà se uno dei file inclusi nel Bundle sarà variato. Questo assicurerà che gli utilizzatori del sito scarichino sempre l'ultima versione dei file statici.


ATTENZIONE

  • Al momento, i Bundle ignorano i file se è presente solo la versione minificata (file con estensione .min.js )
  • Al momento se sono presenti le due versioni di un file, quella minificata e quella non minificata, il Bundle include la versione minificata.


Spero che questo articolo vi sia stato d'aiuto.
Buon divertimento!

sabato 8 giugno 2013

Utilizzare i file di risorsa .NET nel javascript

Buongiorno a tutti

oggi vorrei condividere un idea che ho trovato e sviluppato per utilizzare i file di risorse all'interno dei file javascript. La soluzione prevede l'utilizzo dei file di risorse che l'ambiente di sviluppo .NET mette a disposizione.

Negli ultimi tempi, date le nuove tendenze in fatto di sviluppo web, mi sono ritrovato a dover scrivere montagne di file javascript. Le applicazioni che sono solito sviluppare utilizzano interfacce multilingua, quindi mi sono ritrovato a sperimentare diverse soluzioni, per poter restituire dei messaggi all'utilizzatore, nella lingua in cui ha scelto di usare la mia applicazione.

Per massimizzare la resa delle mie applicazioni, in relazione al javascript, mi sono posto i seguenti obbiettivi:


  • separare il codice javascript in file statici, di modo che il browser lo possa scaricare e mettere nella sua cache
  • separare le traduzioni file diversi, uno per lingua, di modo che l'utilizzatore debba sempre scaricarsi solo il file con le traduzioni per la lingua scelta.


Vediamo come procedere, passo passo

Creare un'applicazione Web. Nel mio caso ho utilizzato il framework MVC, con template Razor.




Aggiungere i file di risorse per le traduzioni. Nel mio caso ho aggiunto un file "Translation.resx" per la lingua principale e un file Translation.de.resx per la lingua tedesca.




Volendo utilizzare questi file in una pagina del sito potremmo mododamente scrivere


Resources.Global.MyResourceName


Per poter fare lo stesso in un file javascript occorre fare ancora qualche passaggio.
Aggiungete un controller all'applicazione. Nel mio caso ho aggiunto un controller "Scripts"



Modificate il codice del metodo Index, come segue. In pratica non dovete fare altro che passare alla vista il codice della lingua corrente.


 public ActionResult Index()
        {
            var cultureInfo = new System.Globalization.CultureInfo((Request.RequestContext.RouteData.Values["id"] ?? "it").ToString());

            return View(cultureInfo);
        }


Modificate la vista Index come segue. Quello che la vista genererà sarà un oggetto Javascript, con tatnte proprietà, quante sono le risorse presenti nel file "Translations.resx"

@model System.Globalization.CultureInfo
@using System.Linq
@using System.Collections.Generic

ResourcesClass = function () {

    GlobalClass = function () {
      return {
            @{var allResources = Resources.Global.ResourceManager.GetResourceSet(System.Globalization.CultureInfo.InvariantCulture, true, true);
              var localizedResources = Resources.Global.ResourceManager.GetResourceSet(Model, true, true);
             }

            @foreach (System.Collections.DictionaryEntry invariantEntry in allResources)
            {
                var entry = invariantEntry;
                foreach(System.Collections.DictionaryEntry localizedEntry in localizedResources)
                {
                    if (localizedEntry.Key == invariantEntry.Key)
                    {
                        entry = localizedEntry;
                    }
                }
                
                @entry.Key<text> : '</text>@Html.Raw(entry.Value.ToString().Replace("'", "\\'"))<text>',</text>@System.Environment.NewLine
            }
        }
    }

    var iGlobalManager = new GlobalClass();

    return {
        Global: iGlobalManager
    };
}


var Resources = new ResourcesClass();



Aggiungete alla masterpage del vostro sito questa riga, con la quale richiamate il risultato della action index del controller Scripts, come fosse un file javascript.


<script src="/Scripts/Index/@System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName"></script>


A questo punto il gioco è fatto. Nei vostri file javascript potete accedere alle risorse dei file resx, esattamente come da una pagina web.

window.load = function()
{
alert(Resources.Global.MyResourceName)
}


Spero che questo articolo possa esservi d'aiuto!