Javascript http://blogs.ugidotnet.org/ainotame/category/Javascript.aspx Javascript it Roberto Sarati Subtext Version 2.6.0.0 Http performance in browsers (+Angular2) http://blogs.ugidotnet.org/ainotame/archive/2016/07/26/http-browser-performance-angular2.aspx <p>Prendendo spunto da ultime attività lavorative, vorrei evidenziare (molti lo sapranno) come il <strong>numero</strong> di chiamate http parallele eseguite da un browser (<u>browser != istanza di browser</u>) verso lo stesso server (stesso dominio) sia in numero finito e ridotto, e che la cosa possa peggiorare la performance del vostro applicativo web [<a title="http://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser" href="http://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser">http://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser</a>].</p> <p>Partiamo cronologicamente al contrario:</p> <h4>1 - Angular2</h4> <p>Angular2 è la nuova versione del framework di google, scritta in typescript, ed "enormemente" modulare; basti pensare che:</p> <ul> <li>ogni "view" può essere composta dalla definizione di “component" scritto in typescript (=&gt; js), un css e un html ad esso collegato. Questi possono essere embeddati nel file typescript, ma personalmente preferisco tenerli separati. </li> <li>angular promuove la modularizzazione, anche per questioni di performance dovute a shadow dom, change detecion stragegy.. (<a href="http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html)">http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html)</a> </li> <li>l’accoppiata di dependency injection di ng2 e l’import di moduli esterni con ES2015 è una __FIGATA PAZZESCA__. Ed ora si scrive molto più C#-like (interfacce, classi, ereditarietà ... il tutto per il single responsibility principle). </li> </ul> <p>Bene. Ottimo. Fantastico:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Open-Live-Writer/Http-browser-performance-Angular2_14936/many_requests.png"><img title="many_requests" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="many_requests" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Open-Live-Writer/Http-browser-performance-Angular2_14936/many_requests_thumb.png" width="564" height="107" /></a></p> <p>Il problema è semplice (e di facile risoluzione). Ci sono troppi file da caricare (650+) e… ogni browser può effettuare un massimo di connessioni verso lo stesso dominio (chrome per esempio un massimo di 6). <br />Tutte le chiamate http vengono dispacciate da questo numero limitato di connessioni, il che rende lungo (9+ secondi) il caricamento dell’applicativo (insieme ovviamente all’elevato numero di handshake).</p> <p>Soluzione semplice: <strong>BUILD</strong> (fatelo ‘sempre’ e, soprattutto, <u><em>pensateci in tempo</em></u>)</p> <p>Ad oggi vi sono numerosi strumenti per effettuare la build di un’applicativo web javascript (grunt, gulp, broccoli, webpack…), personalmente mi sto affezionando a webpack, con il seguente risultato:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Open-Live-Writer/Http-browser-performance-Angular2_14936/low_requests.png"><img title="low_requests" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="low_requests" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Open-Live-Writer/Http-browser-performance-Angular2_14936/low_requests_thumb.png" width="576" height="173" /></a></p> <p>Perfetto. Numero di richieste ridotte al minimo, quantità di dati ridotta, tempi di caricamento abbassati.</p> <h4>2 – Data recomposition</h4> <p>Un altro applicativo web a cui ho/sto lavorando, molto dinamico, permette ad ogni utente di comporre la sua UI in base alle proprie preferenze. <br />L’utente può decidere</p> <ul> <li>quanti grafici aggiungere alla pagina </li> <li>per ogni grafico, quante serie mostrare. </li> </ul> <p>A complicare le cose, i grafici vengono aggiornati in realtime. <br />Per rendere il tutto il più modulare e indipendente possibile, abbiamo architetturato l’applicativo in modo da recuperare ogni serie con una chiamata http separata. Massima flessibilità ma… alcuni dati:</p> <ul> <li>In media (a spanne) un utente apre 2-4 grafici per pagina </li> <li>ogni grafico ha 6 -12 serie scelte dall’utente </li> <li>un utente può aprire apre anche più tab con la stessa applicazione (anche 2 o 3 per pc) su diversi monitor (ok, il contesto è un pò particolare) </li> </ul> <p>Risultato:</p> <ul> <li>una connessione utilizzata da signalR (SSE) <u>per tab aperto</u> </li> <li>Le chiamate http, anche se su server è stata implementata una cache abbastanza intelligente, possono richiedere tempo per essere evase. Il tempo di risposta occupa la connessione, non permettendo ad altre serie di essere recuperate velocemente da parte del browser. </li> <li>E’ anche capitato (numero eccessivo di tab aperti) che un tab smettesse di recuperare dati da server finché l’utente non ne chiudesse un’altro. </li> </ul> <p>Soluzione: dipende. Come sempre non c’è una verità. Ci stiamo spostando verso la definizione di “view model” che incapsulino più serie, in modo tale da raggruppare e quindi recuperare più serie in un unica chiamata http. Parrebbe inoltre che i websocket non utilizzi connessioni http (<a title="https://samsaffron.com/archive/2015/12/29/websockets-caution-required" href="https://samsaffron.com/archive/2015/12/29/websockets-caution-required">https://samsaffron.com/archive/2015/12/29/websockets-caution-required</a>). Altre idee sono ben accette.</p> <p>I sistemi software sono complicati, e la conoscenza è oro.</p><img src="http://blogs.ugidotnet.org/ainotame/aggbug/102187.aspx" width="1" height="1" /> Roberto Sarati http://blogs.ugidotnet.org/ainotame/archive/2016/07/26/http-browser-performance-angular2.aspx Tue, 26 Jul 2016 01:10:46 GMT http://blogs.ugidotnet.org/ainotame/archive/2016/07/26/http-browser-performance-angular2.aspx#feedback 2 http://blogs.ugidotnet.org/ainotame/comments/commentRss/102187.aspx http://blogs.ugidotnet.org/ainotame/services/trackbacks/102187.aspx JsHint - Permettere variabili globali http://blogs.ugidotnet.org/ainotame/archive/2014/12/24/jshint-permettere-variabili-globali.aspx <p>Senza entrare nella discussione di quale lint-tool utilizzare per il verificare la “bontà” del codice js scritto, e poichè JsHint è incluso nel plugin di VS <a href="http://vswebessentials.com/">WebEssentials</a>, mi sono ritrovato a faccia a faccia con il seguente messaggio:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_thumb.png" width="222" height="33" /></a></p> <p>Tale messaggio indica chiaramente che la variabile “_” (<a href="https://lodash.com/">lodash</a> nel mio caso) è usata senza che essa venga precedentemente dichiarata. Da qui il mio pensiero è stato:</p> <ol> <li>Vero è che, di buona norma, occorrerebbe evitare di utilizzare variabili globali ed iniettarle tutte tramite injection, però è anche vero che ce ne sono un insieme ($, _, angular, toastr…) che sinceramente si fa “fatica” ogni volta definirle come parametro da iniettare (si, sono molto lazy).</li> <li>Perchè non esiste lo stesso problema con angular (anch’essa variabile globale)?</li> <li>E’ possibile in qualche modo nascondere questo messaggio di errore selettivamente per altre librerie?</li> </ol> <p>La risposta è ovviamente positiva e può essere risolta nei seguenti modi:</p> <ol> <li>All’inizio di <strong>ogni file .js</strong> che utilizza “_”, è possibile aggiungere la direttiva <font color="#005000">/*global _: false*/</font>, ovvero indica di non considerare “_” in quanto è definito nello scope globale</li> <li>Da visual studio, sotto il menù “WEB ESSENTIALS-Edit global JSHint settings” è possibile modificare le impostazioni utilizzate <strong>dall’utente corrente</strong>: <br /><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_thumb_1.png" width="244" height="59" /></a> <br />Il file “.jshintrc” è un file json che, tra le altre cose, definisce quali variabili sono considerate globali: <br /><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_8.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_thumb_3.png" width="361" height="49" /></a> <br />Ecco quindi il motivo per il quale “angular” non viene mostrato di default nei messaggi di JsHint. La sezione può essere quindi arricchita in modo da aggiungere altre librerie: <br /><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_10.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_thumb_4.png" width="293" height="74" /></a></li> <li>Nel punto precedente tutto funziona perfettamente eccetto che tale setting è a livello di utente e magari “Emix” è una variabile che si vorrebbe considerare globale solo in uno specifico progetto. Per ovviare al problema è possibile creare una copia del file “.jshintrc”, aggiungerla alla solution in modo da utilizzare un set di impostazioni specifiche per il singolo progetto/solution: <br /><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_12.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/5be5ad12b5c8_7A/image_thumb_5.png" width="244" height="98" /></a> <br />In questo modo inoltre, poichè il file è all’interno della solution, le impostazioni possono essere salvate su source control e quindi condivise tra tutti gli sviluppatori del team.</li> </ol><img src="http://blogs.ugidotnet.org/ainotame/aggbug/101921.aspx" width="1" height="1" /> Roberto Sarati http://blogs.ugidotnet.org/ainotame/archive/2014/12/24/jshint-permettere-variabili-globali.aspx Wed, 24 Dec 2014 01:47:32 GMT http://blogs.ugidotnet.org/ainotame/archive/2014/12/24/jshint-permettere-variabili-globali.aspx#feedback 8 http://blogs.ugidotnet.org/ainotame/comments/commentRss/101921.aspx http://blogs.ugidotnet.org/ainotame/services/trackbacks/101921.aspx ASP.NET AngularJS seed http://blogs.ugidotnet.org/ainotame/archive/2014/11/28/asp.net-angularjs-seed-project.aspx <p>Quando iniziai (un po’ di tempo fa a dire il vero) a voler provare/utilizzare AngularJS su alcuni progetti web, mi sono scontrato contro alcuni problemi tra i quali:</p> <ul> <li>Non voler cambiare “troppo” le tecnologie utilizzate e conosciute dal team (asp.net, webapi, sql server… e quindi niente node, mongo, php, gruntjs…), </li> <li>Utilizzare Visual Studio e avere una struttura chiara della solution, </li> <li>Creare una SPA, e non solo il motore di binding di ng per le singole view asp.net. </li> </ul> <p>Poichè ai tempi (mesi e mesi fa) non trovai un esempio/template che mi soddisfacesse appieno, in quanto:</p> <ul> <li>o veniva usato <u>nodejs</u> e niente vs </li> <li>o <u>l’organizzazione</u> dell’applicazione ng era a cura del developer </li> <li>o gli <u>script ng erano separati dalle view</u> (e per me è una cosa fastidiosa dopo un paio di esperienze tra cui anche la struttura di default di durandaljs) </li> </ul> <p>Ho creato un progetto su github, <a title="https://github.com/sierrodc/ASP.NET-MVC-AngularJs-Seed" href="https://github.com/sierrodc/ASP.NET-MVC-AngularJs-Seed">https://github.com/sierrodc/ASP.NET-MVC-AngularJs-Seed</a>, dove:</p> <ul> <li>viene utilizzato nuget solo per le libraries .net; ho scelto di non usarlo per i package js perchè altrimenti non avrei potuto organizzarli come segue <br /><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/ASP.NET-Angular-seed-project_1510F/image_4.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/ASP.NET-Angular-seed-project_1510F/image_thumb_1.png" width="189" height="244" /></a> <br />ovvero una sorta di struttura a strati con le librerie senza dipendenze in Ring0, e con Ring(N) dipendente da Ring(N-1) <br /></li> <li>è configurato angularjs e una semplice SPA con alcune features con la seguente struttura: <br /><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/ASP.NET-Angular-seed-project_1510F/image_6.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/ainotame/Windows-Live-Writer/ASP.NET-Angular-seed-project_1510F/image_thumb_2.png" width="244" height="232" /></a>  <br />dove: <ol> <li>emixApp.js definisce l’applicazione angularjs, impostando tutte le dipendenze e le regole di routing (forse lo estrarrò da qui), </li> <li>la cartella directives contiene tutte le directive custom, </li> <li>la cartella services contiene i servizi angular, in questo caso solo un proxy alle chiamate verso webapi </li> <li>la cartella pages che contiene le pagine che costituiscono la SPA, ogni pagina definita tramite coppia #pagina.html, pagina.js# <br /></li> </ol> </li> <li>tutte le librerie che ritengo utili (anche per una demo veloce) sono già incluse, configurate e utilizzabili; <br />Per una lista completa di librerie incluse faccio riferimento al file readme.md presente su repository (cercherò ti mantenerle il più possibile aggiornate). </li> </ul> <p>E dopo questa condivisione, ogni domanda, suggerimento  o critica è ben accetta.</p><img src="http://blogs.ugidotnet.org/ainotame/aggbug/101907.aspx" width="1" height="1" /> Roberto Sarati http://blogs.ugidotnet.org/ainotame/archive/2014/11/28/asp.net-angularjs-seed-project.aspx Fri, 28 Nov 2014 01:38:12 GMT http://blogs.ugidotnet.org/ainotame/archive/2014/11/28/asp.net-angularjs-seed-project.aspx#feedback 23 http://blogs.ugidotnet.org/ainotame/comments/commentRss/101907.aspx http://blogs.ugidotnet.org/ainotame/services/trackbacks/101907.aspx Webapi-like controllers in NodeJS+ExpressJS http://blogs.ugidotnet.org/ainotame/archive/2014/10/12/webapi-like-controllers-in-nodeexpress.aspx <p>Lavorando su un progetto ~MEAN (MongoDB + ExpressJS + AngularJS + nodeJS) mi sono chiesto: “perchè non creare un modulo di registrazione custom dei controller simile a quella delle webapi di asp.net”? da qui è nato il seguente modulo:</p> <p /> <!-- HTML generated using hilite.me --> <div style="overflow: auto; border-top: gray 0.1em solid; border-right: gray 0.1em solid; width: auto; background: #ffffff; border-bottom: gray 0.1em solid; padding-bottom: 0.2em; padding-top: 0.2em; padding-left: 0.6em; border-left: gray 0.8em solid; padding-right: 0.6em"> <table><tbody> <tr> <td> <pre style="margin: 0px; line-height: 125%"> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29</pre> </td> <td> <pre style="margin: 0px; line-height: 125%"><span style="font-weight: bold; color: #008800">var</span> path <span style="color: #333333">=</span> require(<span style="background-color: #fff0f0">'path'</span>); <span style="font-weight: bold; color: #008800">var</span> fs <span style="color: #333333">=</span> require(<span style="background-color: #fff0f0">'fs'</span>); <span style="font-weight: bold; color: #008800">var</span> config <span style="color: #333333">=</span> require(<span style="background-color: #fff0f0">'./config'</span>); <span style="font-weight: bold; color: #008800">var</span> _ <span style="color: #333333">=</span> require(<span style="background-color: #fff0f0">'lodash'</span>); <span style="font-weight: bold; color: #008800">var</span> getControllersInServerFolder <span style="color: #333333">=</span> <span style="font-weight: bold; color: #008800">function</span> (serverFolder) { <span style="font-weight: bold; color: #008800">if</span> (_.isEmpty(serverFolder)) { serverFolder <span style="color: #333333">=</span> config.settings.controllersFolder; } <span style="font-weight: bold; color: #008800">var</span> controllers <span style="color: #333333">=</span> []; <span style="font-weight: bold; color: #008800">var</span> fileSystemObjects <span style="color: #333333">=</span> fs.readdirSync(serverFolder); <span style="color: #888888">//read folder content</span> <span style="font-weight: bold; color: #008800">if</span> (_.isArray(fileSystemObjects)) { _.forEach(fileSystemObjects, <span style="font-weight: bold; color: #008800">function</span> (fso) { <span style="font-weight: bold; color: #008800">var</span> fsoFullPath <span style="color: #333333">=</span> path.join(serverFolder, fso); <span style="font-weight: bold; color: #008800">var</span> fsoStat <span style="color: #333333">=</span> fs.statSync(fsoFullPath); <span style="font-weight: bold; color: #008800">if</span> (fsoStat.isFile() <span style="color: #333333">&amp;&amp;</span> fso.endsWith(<span style="background-color: #fff0f0">'controller.js'</span>)) { controllers.push(require(path.relative(__dirname, fsoFullPath))); } <span style="font-weight: bold; color: #008800">else</span> <span style="font-weight: bold; color: #008800">if</span> (fsoStat.isDirectory()) { _.union(controllers, getControllersInServerFolder(fsoFullPath)); } }); } <span style="font-weight: bold; color: #008800">return</span> controllers; }; exports.getControllers <span style="color: #333333">=</span> getControllersInServerFolder;</pre> </td> </tr> </tbody></table> </div> <p /> <p>Quindi nello startup del server nodejs:</p> <!-- HTML generated using hilite.me --> <div style="overflow: auto; border-top: gray 0.1em solid; border-right: gray 0.1em solid; width: auto; background: #ffffff; border-bottom: gray 0.1em solid; padding-bottom: 0.2em; padding-top: 0.2em; padding-left: 0.6em; border-left: gray 0.8em solid; padding-right: 0.6em"> <table><tbody> <tr> <td> <pre style="margin: 0px; line-height: 125%">1 2 3</pre> </td> <td> <pre style="margin: 0px; line-height: 125%">_.forEach(require(<span style="background-color: #fff0f0">'controllers-manager'</span>)..getControllers(), <span style="font-weight: bold; color: #008800">function</span>(controller) { server.use(controller.path, controller.router); <span style="color: #888888">// register route into expressjs</span> });</pre> </td> </tr> </tbody></table> </div> <p>Ora i controller sono tutti quei files definiti nella cartella config.settings.controllersFolder (o sottocartelle) che terminano con ‘controller.js’ e hanno tutti la seguente struttura:</p> <!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><table><tr><td><pre style="margin: 0; line-height: 125%"> 1 2 3 4 5 6 7 8 9 10 11 12 13 14</pre></td><td><pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-weight: bold">var</span> express <span style="color: #333333">=</span> require(<span style="background-color: #fff0f0">'express'</span>); <span style="color: #008800; font-weight: bold">var</span> router <span style="color: #333333">=</span> express.Router(); <span style="color: #888888">//apply before any actions (check authorizations...)</span> router.use(<span style="color: #008800; font-weight: bold">function</span>(req, res, next) { next(); <span style="color: #888888">//go to next </span> }); router.get(<span style="background-color: #fff0f0">'/message'</span>, <span style="color: #008800; font-weight: bold">function</span>(req, res, next) { res.send({<span style="background-color: #fff0f0">'Hello world'</span>}); }); exports.path <span style="color: #333333">=</span> <span style="background-color: #fff0f0">'/api/sample'</span>; exports.router <span style="color: #333333">=</span> router; </pre></td></tr></table></div> <p>Facile, semplice e veloce.</p><img src="http://blogs.ugidotnet.org/ainotame/aggbug/101888.aspx" width="1" height="1" /> Roberto Sarati http://blogs.ugidotnet.org/ainotame/archive/2014/10/12/webapi-like-controllers-in-nodeexpress.aspx Sun, 12 Oct 2014 16:49:31 GMT http://blogs.ugidotnet.org/ainotame/archive/2014/10/12/webapi-like-controllers-in-nodeexpress.aspx#feedback 6 http://blogs.ugidotnet.org/ainotame/comments/commentRss/101888.aspx http://blogs.ugidotnet.org/ainotame/services/trackbacks/101888.aspx ASP.NET MVC4 [RC] - Bundles http://blogs.ugidotnet.org/ainotame/archive/2012/06/07/asp.net-mvc4-rc-bundles.aspx <p>Dalla beta di asp.net mvc4 sono stati fatti passi avanti nelle API riguardanti i Bundle.</p> <p><br /> Giusto per informazione, i bundle sono presenti in ASP.NET MVC4 (assembly System.Web.Optimization.dll) e servono per riunire e minificare gruppi di risorse css e js. Questo permette di ridurre il payload e ridurre le connessioni HTTP.<br /> Ci sono molte librerie che svolgono lo stesso compito (es <a href="http://combres.codeplex.com/">Combres</a>, <a href="http://getcassette.net/">Cassette</a> ...), ma per i pigri (e chi non vuole troppe dipendenze al di fuori dallo stack ms) ora è tutto integrato.</p> <p>Alcune novità rispetto alla beta:</p> <ul> <li><strong>Rimozione del metodo "</strong><font face="Arial"><strong>BundleTable.Bundles.RegisterTemplateBundles()"</strong><br /> Imho bene, tutto a favore di una registrazione manuale.dei bundle. Il template di asp.net mvc4 di default registra i js e css aggiunti automaticamente nel progetto.<br /> E' così possibile da un lato capire come vengono registrate le risorse dall'altro si possono aggiungere le proprie senza troppi problemi.<br /> Rimane disponibile (giustamente) il metodo "BundleTable.Bundles.EnableDefaultBundles()" che raggruppa js e css in base alla struttura a folder della progetto.</font></li> <li><strong>Dichiarazione nelle pagine dei bundle tramite @Script.Render(jspaths) e @Styles.Render(csspaths)</strong><br /> Eccellente. Rispetto a <font face="Arial">&lt;link href="@System.Web.Optimization.BundleTable.Bundle.ResolveBundleUrl("~/Content/boot/css")" rel="stylesheet" type="text/css" /&gt; è una manna dal cielo. Questo infatti ci permette di avere:<br />  - riduzione del codice scritto<br />  - possibilità di renderizzare più tag script o link in modo di avere risorse non compresse per debug (ottimo!).</font></li> <li>(segue) <strong>Il rendering delle risorse è stabilito con due modalità:</strong><br /> 1) Tramite Web.config verificando l'attributo debug=true (del tag compilation). Da osservare come questo venga rimosso in fase di publishing tramite web.config transformation (quindi in release le risorse vengono compattate e minificate automaticamente) mentre in fase di sviluppo questo è impostato di default a true e le ottimizzazioni non sono applicate.<br /> 2) Tramite chiamata al metodo BundleTable.EnableOptimizatoins=true/false.<br /> In ogni caso, imho, l'impostazione di default è ottima.</li> </ul> <p>Grazie agli ultimi due punti, la libreria optimization è finalmente utilizzabile in modo proficuo. Benone.</p><img src="http://blogs.ugidotnet.org/ainotame/aggbug/101044.aspx" width="1" height="1" /> Roberto Sarati http://blogs.ugidotnet.org/ainotame/archive/2012/06/07/asp.net-mvc4-rc-bundles.aspx Thu, 07 Jun 2012 18:20:22 GMT http://blogs.ugidotnet.org/ainotame/archive/2012/06/07/asp.net-mvc4-rc-bundles.aspx#feedback 1 http://blogs.ugidotnet.org/ainotame/comments/commentRss/101044.aspx http://blogs.ugidotnet.org/ainotame/services/trackbacks/101044.aspx Knockout containerless binding http://blogs.ugidotnet.org/ainotame/archive/2012/02/07/knockout-containerless-binding.aspx <p><t>In ambito XAML per mostrare una lista di elementi occorre impostare il datacontext di un ItemsControl ad una IEnumerable<t>. L’ItemsControl poi rendererizza la lista in base al DataTemplate specificato nella proprietà ItemTemplate. Per aggiungere oggetti nuovi ho sempre usato ItemTemplateSelector e/o CompositeCollection, ma la presenza di un container l’ho sempre considerata obbligatoria (correggetemi se sbaglio).</t></t></p> <p><t>Ho considerato l’assioma valido anche in Knockout, ma non è così. Con knockout è possibile scrivere un “contenitore fittizio” tramite commenti:</t></p> <p><t>&lt;!-- ko ... --&gt;<br /> &lt;!-- /ko --&gt;</t></p> <p><t>Tramite questa feature è possibile (come nel mio caso particolare) creare una tabella con un numero di colonne variabili:</t></p> <p><t /></p> <pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">table</span> <span class="attr">id</span><span class="kwrd">="classificationTable"</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">thead</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">tr</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;</span>Rank<span class="kwrd">&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;</span>Country<span class="kwrd">&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;</span>Full Name<span class="kwrd">&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <strong><span class="rem">&lt;!-- ko foreach: batteries --&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;</span>R<span class="kwrd">&lt;</span><span class="html">span</span> <span class="attr">data-bind</span><span class="kwrd">="text: $data"</span><span class="kwrd">&gt;&lt;/</span><span class="html">span</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <span class="rem">&lt;!-- /ko --&gt;<br /></span></strong> <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;</span>TOT<span class="kwrd">&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;/</span><span class="html">tr</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;/</span><span class="html">thead</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">tbody</span> <span class="attr">data-bind</span><span class="kwrd">="foreach: positions"</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">tr</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span> <span class="attr">data-bind</span><span class="kwrd">="text: rank"</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span> <span class="attr">data-bind</span><span class="kwrd">="text: country"</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span> <span class="attr">data-bind</span><span class="kwrd">="text: fullname"</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <strong><span class="rem">&lt;!-- ko foreach: regularShots --&gt;<br /></span> <span class="kwrd">&lt;</span><span class="html">td</span> <span class="attr">data-bind</span><span class="kwrd">="text: $data"</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span> <br /> <span class="rem">&lt;!-- /ko --&gt;<br /></span></strong> <span class="kwrd">&lt;</span><span class="html">td</span> <span class="attr">data-bind</span><span class="kwrd">="text: totalRegularPoints"</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;/</span><span class="html">tr</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;/</span><span class="html">tbody</span><span class="kwrd">&gt;<br /></span> <span class="kwrd">&lt;/</span><span class="html">table</span><span class="kwrd">&gt;</span></pre> <p>Comodo, utile, veloce.</p> <p>Ps: gli elementi &lt;td&gt; chiudeteli sempre con un tag &lt;/td&gt;, non scriveteli con un tags self-closing &lt;td data-bind="" /&gt; altrimenti KnockoutJs potrebbe dare qualche problemino (e <a target="_blank" href="http://dev.w3.org/html5/spec-author-view/syntax.html#syntax-start-tag">non solo lui</a>)</p><img src="http://blogs.ugidotnet.org/ainotame/aggbug/100755.aspx" width="1" height="1" /> Roberto Sarati http://blogs.ugidotnet.org/ainotame/archive/2012/02/07/knockout-containerless-binding.aspx Tue, 07 Feb 2012 00:09:47 GMT http://blogs.ugidotnet.org/ainotame/archive/2012/02/07/knockout-containerless-binding.aspx#feedback http://blogs.ugidotnet.org/ainotame/comments/commentRss/100755.aspx http://blogs.ugidotnet.org/ainotame/services/trackbacks/100755.aspx Knockout 2.0 released http://blogs.ugidotnet.org/ainotame/archive/2011/12/22/knockout-released.aspx <p><a></a><a></a>Anche se leggermente OT rispetto al mondo .net, notifico l'uscita di <a href="http://knockoutjs.com/">Knockout </a>v2.0.0; Per chi non sapesse cosa fosse, è un framework javascript che semplifica l'applicarazione del pattern MVVM (oramai noto in xaml) in javascript+html.</p> <p>Tra le nuove caratteristiche che ho notato velocemente, cito le seguenti:</p> <ul> <li><strong>ViewModel</strong>: negli esempi ora è rappresentato da una funzione (=oggetto)</li> <li><strong>Computed properties</strong>: ko.<font face="Arial">dependentObservable è deprecato, ora è preferibile utilizzare ko.computed.</font></li> <li><strong>Templating</strong>: poiché <a href="https://github.com/jquery/jquery-tmpl">jQuery.tmpl</a> non è più in sviluppo, è stato modificato il motore di templating. Ora si può usare il binding di tipo foreach e altre tecniche. Probabilmente questa è una delle breaking changes maggiori per questa release. [+-datatemplate in xaml]</li> <li><strong>Accesso a "DataContext" relativi</strong>: è possibile utilizzare $data (contesto corrente), $parent (contesto padre), $parents[i] (i-esimo ancestor), $root (contesto root) [+- relativesource findancestor in xaml]</li> <li><strong>Trottling</strong>: è possibile propagare una modifica del viewmodel alle altre proprietà (per esempio le computed properties) dopo un determinato periodo di tempo. Si può specificare con:<br /> ko.computed(function() {}).extend({trottle: 1000}); //attende 1000ms a ricalcolare la proprietà computed.</li> </ul> <p>Sono state aggiunte altre feature non citate e, osservando il forum ufficiale, è stato effettuato anche un discreto periodo di sviluppo per migliorare le prestazioni nei vari browser attualmente sul mercato.</p> <p>E io che 'odiavo' javascript...</p> <p> </p> <p> </p><img src="http://blogs.ugidotnet.org/ainotame/aggbug/100647.aspx" width="1" height="1" /> Roberto Sarati http://blogs.ugidotnet.org/ainotame/archive/2011/12/22/knockout-released.aspx Thu, 22 Dec 2011 02:09:14 GMT http://blogs.ugidotnet.org/ainotame/archive/2011/12/22/knockout-released.aspx#feedback http://blogs.ugidotnet.org/ainotame/comments/commentRss/100647.aspx http://blogs.ugidotnet.org/ainotame/services/trackbacks/100647.aspx