.Net Framework 4.5 http://blogs.ugidotnet.org/PietroLibroBlog/category/.Net Framework 4.5.aspx .Net Framework 4.5 it-IT Pietro Libro pietro.libro@libero.it Subtext Version 2.6.0.0 JSON.Merge http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/08/29/json.merge.aspx <p>Un’interessante novità introdotta con la versione 6.0 release 4 di Json.NET è la possibilità di eseguire il <em>Merge</em> (utilizzando 4 possibili “variazioni”) di oggetti <em>JObject</em> e <em>Jarray</em>. Un rapido esempio, tramite Web Api:</p> <pre class="brush: csharp;">[HttpPost] public void JsonStringPost([FromBody]string value) { JObject jCar = JObject.Parse(value); JObject jOptional = JObject.Parse(@"{Optionals :['Air Conditioned','Smoker'] }"); jCar.Merge(jOptional, new JsonMergeSettings() { MergeArrayHandling = MergeArrayHandling.Union }); string jsonFormat = jCar.ToString(); Car mergedCar = jCar.ToObject&lt;Car&gt;(); }</pre> <p>Dove <em>l’Action</em> “JsonStringPost” accetta una stringa tipo:</p> <p>"{ 'Brand': 'Ferrari','Model': 'f450 Modena','Optionals': [] }"</p> <p>Utilizzando, ad esempio il <em>Composer</em> di strumenti come <a href="http://www.telerik.com/fiddler" target="_blank">Fiddler2</a> possiamo invocare il servizio:</p> <a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/JSON.Merge_A854/image_5.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/JSON.Merge_A854/image_thumb_1.png" width="244" height="238" /></a> <p>Per ottenere una nuova istanza di <em>Car</em> con tutti gli <em>Optionals</em>:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/JSON.Merge_A854/image_7.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/JSON.Merge_A854/image_thumb_2.png" width="244" height="74" /></a></p> <p>Se il nostro servizio accetta direttamente un’istanza di oggetto invece di una stringa in formato JSON, il nostro codice cambia leggermente, come di seguito:</p> <pre class="brush: csharp;">[HttpPost] public void JsonObjectPost([FromBody] Car carByPost) { JObject jCar = JObject.FromObject(carByPost); JObject jOptional = JObject.Parse(@"{Optionals :['Air Conditioned','Smoker'] }"); jCar.Merge(jOptional, new JsonMergeSettings() { MergeArrayHandling = MergeArrayHandling.Union }); string jsonFormat = jCar.ToString(); Car mergedCar = jCar.ToObject<car>(); }</car></pre> <p>Dove utilizziamo il metodo <em>FromObject</em> della classe <em>JObject</em> invece di <em>Parse. </em>Utilizzando Fiddler, passando come <em>Body</em> del messaggio la stringa (senza i doppi apici ad inizio e fine stringa)</p> <p>{ 'Brand': 'Ferrari','Model': 'f450 Modena','Optionals': [] }</p> <p>Otteniamo (ovviamente) lo stesso risultato dell’invocazione precedente. E’ possibile modificare il comportamento di “Merge” utilizzando l’enumerazione <em>MergeArrayHandling. </em>La classe <em>Car </em>(C#) è descritta nell’esempio, è la seguente:</p> <pre class="brush: csharp;">public class Car { public string Brand { get; set; } public string Model { get; set; } public string[] Optionals { get; set; } }</pre> <p>La lista completa delle <em>features</em> aggiunte nel rilascio della versione 6.0 release 4 è disponibile <a href="http://james.newtonking.com/archive/2014/08/04/json-net-6-0-release-4-json-merge-dependency-injection" target="_blank">qui</a>.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101880.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/08/29/json.merge.aspx Fri, 29 Aug 2014 13:30:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/08/29/json.merge.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101880.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101880.aspx EF 6.1 : What&rsquo;s new (3) http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/27/ef-6.1-whatrsquos-new-3.aspx <p>Supporto a “.ToString()” e “String.Concat()”, un esempio:</p> <pre class="csharpcode">var queryConcat = from c <span class="kwrd">in</span> db.Vehicles <span class="kwrd">where</span> <span class="kwrd">string</span>.Concat(c.EngineSize, c.HP).Equals(<span class="str">"1600110"</span>) select c; var queryToString = from c <span class="kwrd">in</span> db.Vehicles <span class="kwrd">where</span> c.HP.ToString().Equals(<span class="str">"110"</span>) select c;</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Abbiamo due Query LINQ che filtrano i dati in base a condizioni su stringhe, la prima “tira fuori” tutti i veicoli dove la concatenazione dei valori delle proprietà “EngineSize” e “HP” è uguale a “1600110”, mentre la seconda esegue un filtro su di un valore intero convertio in stringa. Se proviamo ad eseguire il codice in un ambiente con EF 6.0 otteniamo un’eccezione a runtime in tutti e due i casi:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-3_7B13/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-3_7B13/image_thumb.png" width="244" height="223" /></a></p> <p>Con EF 6.1 le query sono eseguite correttamente:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-3_7B13/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-3_7B13/image_thumb_1.png" width="244" height="165" /></a></p> <p>Cosa succede dietro le quinte:</p> <pre class="csharpcode"><span class="kwrd">SELECT</span> [GroupBy1].[A1] <span class="kwrd">AS</span> [C1] <span class="kwrd">FROM</span> ( <span class="kwrd">SELECT</span> <span class="kwrd">COUNT</span>(1) <span class="kwrd">AS</span> [A1] <span class="kwrd">FROM</span> [DomusDotNet].[Vehicles] <span class="kwrd">AS</span> [Extent1] <span class="kwrd">WHERE</span> N<span class="str">'1600110'</span> = (<span class="kwrd">CASE</span> <span class="kwrd">WHEN</span> ([Extent1].[EngineSize] <span class="kwrd">IS</span> <span class="kwrd">NULL</span>) <span class="kwrd">THEN</span> N<span class="str">''</span> <span class="kwrd">ELSE</span> [Extent1].[EngineSize] <span class="kwrd">END</span> + <span class="kwrd">CAST</span>( [Extent1].[HP] <span class="kwrd">AS</span> nvarchar(<span class="kwrd">max</span>))) ) <span class="kwrd">AS</span> [GroupBy1] <span class="kwrd">SELECT</span> [GroupBy1].[A1] <span class="kwrd">AS</span> [C1] <span class="kwrd">FROM</span> ( <span class="kwrd">SELECT</span> <span class="kwrd">COUNT</span>(1) <span class="kwrd">AS</span> [A1] <span class="kwrd">FROM</span> [DomusDotNet].[Vehicles] <span class="kwrd">AS</span> [Extent1] <span class="kwrd">WHERE</span> N<span class="str">'110'</span> = <span class="kwrd">CAST</span>( [Extent1].[HP] <span class="kwrd">AS</span> nvarchar(<span class="kwrd">max</span>)) ) <span class="kwrd">AS</span> [GroupBy1]</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p>Da analizzare il funzionamento di “String.Concat(…)” con SQL Server 2012 per verificare la conversione in SQL con la funzione “nativa SQL” “<a href="http://technet.microsoft.com/en-us/library/hh231515.aspx" target="_blank">Concat</a>”.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101829.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/27/ef-6.1-whatrsquos-new-3.aspx Thu, 27 Mar 2014 10:04:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/27/ef-6.1-whatrsquos-new-3.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101829.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101829.aspx EF 6.1 : What&rsquo;s new (2) http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/20/ef-6.1-whatrsquos-new-2.aspx <p>Altra <em>feature </em>introdotta, l’attributo “IndexAttribute” che ci permette di definire un indice su una o piu’ colonne. Ad esempio, per creare un indice (di nome “IX_FreeDailyKm”) sulla proprietà “FreeDailyKm” del nostro modello, scriviamo:</p> <pre class="csharpcode">[Index(<span class="str">"IX_FreeDailyKm_Clustered"</span>, IsUnique = <span class="kwrd">false</span>, IsClustered = <span class="kwrd">false</span>)] <span class="kwrd">public</span> <span class="kwrd">int</span> FreeDailyKm { get; set; }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Mentre per creare un indice che insiste su due proprietà, è sufficiente utilizzare lo stesso nome come da esempio:</p> <pre class="csharpcode">[Index(<span class="str">"IX_Engine"</span>, 2)] <span class="kwrd">public</span> <span class="kwrd">string</span> EngineSize { get; set; } [Index(<span class="str">"IX_Engine"</span>, 1)] <span class="kwrd">public</span> <span class="kwrd">int</span> HP { get; set; }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Utilizzando <em>EF migrations</em> per aggiornare il database, avremmo:</p> <pre class="csharpcode">CreateIndex(<span class="str">"DomusDotNet.Vehicles"</span>, <span class="str">"FreeDailyKm"</span>, name: <span class="str">"IX_FreeDailyKm_Clustered"</span>); CreateIndex(<span class="str">"DomusDotNet.Vehicles"</span>, <span class="kwrd">new</span>[] { <span class="str">"HP"</span>, <span class="str">"EngineSize"</span> }, name: <span class="str">"IX_Engine"</span>);</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Quindi, a livello di database:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-2_EA92/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-2_EA92/image_thumb.png" width="244" height="55" /></a></p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101825.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/20/ef-6.1-whatrsquos-new-2.aspx Thu, 20 Mar 2014 17:49:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/20/ef-6.1-whatrsquos-new-2.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101825.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101825.aspx EF 6.1 : What&rsquo;s new (1) http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/20/ef-6.1-whatrsquos-new-1.aspx <p>Da qualche giorno è stata rilasciata in RTM la <a href="http://blogs.msdn.com/b/adonet/archive/2014/03/17/ef6-1-0-rtm-available.aspx" target="_blank">versione 6.1.0</a> di Entity Framework. Una delle novità piu’ interessanti è sicuramente la possibilità di utilizzare l’approcio  <em>Code First </em>partendo da un database esistente (potrebbe sembrare strano, ma se pensiamo ad un nuovo sviluppo potrebbe non esserlo). I “ferri” da utilizzare sono ovviamente  EF 6.0.1 e la nuova versione di EF Tools, “scaricabile” per VS 2012 e VS 2013 seguendo <a href="http://www.microsoft.com/en-us/download/details.aspx?id=40762" target="_blank">questo</a> link.</p> <p>Per un semplice test, apriamo VS 2013 (o 2012), magari creando un semplice progetto “Console” al quale aggiungiamo tramite NuGet i riferimenti a EF 6.0.1. Poi tasto destro sul progetto e “Add New Item”, e scegliamo “ADO.NET Entity Data model”:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-1_9B2C/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-1_9B2C/image_thumb_1.png" width="244" height="170" /></a></p> <p>Il testo di “Name” infuenzerà il nome della classe “DbContext” generata. Dalla scheramata successiva (“Entity Data Model Wizard”) scegliamo “Code First model from Database”:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-1_9B2C/image_6.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-1_9B2C/image_thumb_2.png" width="244" height="170" /></a></p> <p>Nella schermata successiva del Wizard verrà chiesta la connessione dati da utilizzare (eventualmente ne creiamo una nuova), nel mio caso, per i test ho utilizzato un DB di un evento “DomusDotNet”. L’ultimo passo è la scelta degli oggetti da “importare”:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-1_9B2C/image_8.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/EF-6.1--Whats-new-1_9B2C/image_thumb_3.png" width="244" height="219" /></a></p> <p>Dopo aver premuto “Finish” e qualche secondo di pazienza, VS aggiungerà all’alberatura del progetto, tutte le classi necessarie, una “buildata” per verificare che sia tutto a posto , e qualche riga di codice per verificare l’estrapolazione dati :</p> <pre class="csharpcode"><span class="kwrd">using</span> (CarRental db = <span class="kwrd">new</span> CarRental()) { System.Console.WriteLine(<span class="str">"There are {0} cars."</span>, db.Cars.Count()); System.Console.ReadKey(); }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101823.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/20/ef-6.1-whatrsquos-new-1.aspx Thu, 20 Mar 2014 12:42:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/20/ef-6.1-whatrsquos-new-1.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101823.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101823.aspx Dynamic Data Provider per EF6 released http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/03/dynamic-data-provider-per-ef6-released.aspx <p>Sono stati rilasciati in RTM, <em>ASP.NET Dynamic Data</em> e <em>EntityDataSource</em> per EntityFrameowrk 6. Per provare la nuova versione di <em>Dynamic Data</em> è sufficiente creare un nuovo progetto di tipo “ASP.NET Dynamic Data Entities Web Application”, ed installare tramite NuGet il package <em>Microsoft.AspNet.DynamicData.EFProvider</em>:</p> <p align="center"><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/3b52774302cc_7140/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; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/3b52774302cc_7140/image_thumb.png" width="244" height="33" /></a></p> <p>Eventualmente forziamo la scrittura dei <em>Template</em> (“A” per sovrascrivere tutto):</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/3b52774302cc_7140/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/3b52774302cc_7140/image_thumb_1.png" width="244" height="39" /></a></p> <p>Aggiungiamo in modalità <em>Code First</em> una semplice classe <em>Book </em>e relativo <em>DbContext</em>:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Book { <span class="kwrd">public</span> <span class="kwrd">int</span> Id { get; set; } <span class="kwrd">public</span> <span class="kwrd">string</span> Title { get; set; } <span class="kwrd">public</span> <span class="kwrd">string</span> Authors { get; set; } <span class="kwrd">public</span> <span class="kwrd">int</span> Pages { get; set; } } <span class="kwrd">public</span> <span class="kwrd">class</span> Db : DbContext { <span class="kwrd">public</span> DbSet&lt;Book&gt; Books { get; set; } <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnModelCreating(DbModelBuilder modelBuilder) { <span class="kwrd">base</span>.OnModelCreating(modelBuilder); } }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Nel <em>Global.asax</em> registriamo il nostro <em>DbContext</em>:</p> <pre class="csharpcode">DefaultModel.RegisterContext( <span class="kwrd">new</span> Microsoft.AspNet.DynamicData.ModelProviders.EFDataModelProvider(() =&gt; <span class="kwrd">new</span> Db()), <span class="kwrd">new</span> ContextConfiguration { ScaffoldAllTables = <span class="kwrd">true</span> });</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>F5, per vedere in azione il nostro <em>Data Site</em>:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/3b52774302cc_7140/image_6.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/PietroLibroBlog/Windows-Live-Writer/3b52774302cc_7140/image_thumb_2.png" width="244" height="156" /></a></p> <p>Discorso simile per l’utilizzo <em>dell’EntityDataSource</em> control.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101806.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/03/dynamic-data-provider-per-ef6-released.aspx Mon, 03 Mar 2014 10:06:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/03/03/dynamic-data-provider-per-ef6-released.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101806.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101806.aspx Windows Azure WebJobs (parte 4) http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/17/windows-azure-webjobs-parte-4.aspx <p>Per automatizzare tramite script il processo di creazione di un WebJob utilizzando <a href="http://msdn.microsoft.com/en-us/library/windowsazure/jj156055.aspx" target="_blank">Windows Azure Power Shell</a> (Windows PowerShell ISE), i principali comandi da utilizzare sono:</p> <ul> <li><em>Add-AzureAccount</em>, che ci permette di autenticarci utilizzando <a href="http://www.windowsazure.com/en-us/services/active-directory/" target="_blank">Active Azure Directory</a> </li> <li><em>Get-AzureWebsite</em>, per avere una panoramica dei WebSites legati alla <em>subscription</em> con la quale siamo collegati </li> <li><em>Get-AzureWebsiteJob</em>, il quale ritorna le informazioni sul WebJob specificato dal paramentro <em>Name</em>  </li> </ul> <p align="center"><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-4_C607/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; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-4_C607/image_thumb_1.png" width="244" height="70" /></a></p> <ul> <li> <em>New-AzureWebsiteJob</em>, il quale permette la creazione di un nuovo WebJob ed accetta in ingresso i seguenti parametri: <ul> <li><em>Name</em>, il nome del WebSite di riferimento </li> <li><em>JobName</em>, il nome del WebJob </li> <li><em>JobType</em>, la modalità di esecuzione del WebJob come descritto nel <a href="http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/05/windows-azure-webjobs-parte-1.aspx" target="_blank">primo post</a> relativo a questa serie </li> <li><em>JobFile</em>, il percorso dell’archivio compresso contenente tutti i file necessari all’esecuzione del Job </li> </ul> </li> <li><em>Remove-AzureWebsiteJob</em>, il quale rimuove il WebJob specificato ed necessita dei parametri: <em>Name</em>, <em>JobName</em> e <em>JobType</em> </li> </ul> <p>Per eseguire “Start&amp;Stop” del WebJob, possiamo utilizzare i comandi:</p> <ul> <li><em>Start-AzureWebsiteJob</em>, con parametri <em>Name</em>, <em>JobName</em> e <em>JobType</em> </li> <li><em>Stop-AzureWebsiteJob</em>, con parametri <em>Name</em> e <em>JobName</em> </li> </ul> <p>Se i comandi sopracitati non dovessero essere presenti nel tool (I WebJob sono in <em>Preview</em>) è sufficiente aggiornare la documentazione della guida:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-4_C607/image_6.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-4_C607/image_thumb_2.png" width="244" height="64" /></a></p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101780.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/17/windows-azure-webjobs-parte-4.aspx Mon, 17 Feb 2014 10:02:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/17/windows-azure-webjobs-parte-4.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101780.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101780.aspx Windows Azure WebJobs (parte 3) http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/11/windows-azure-webjobs-parte-3.aspx <p>Torniamo ancora sull’argomento “WebJobs” descrivendo brevemente le varie modalità di <em>Triggering</em>:</p> <ul> <li>Alla creazione di un nuovo <em>Blob</em> </li> <li>Alla ricezione di un nuovo <em>Queue Message</em> </li> <li>Esplicatamente tramite l’invocazione della funzione <em>Call</em> </li> </ul> <p>Nei post precedenti (<a href="http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/05/windows-azure-webjobs-parte-1.aspx" target="_blank">parte 1</a> e <a href="http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/06/windows-azure-webjobs-parte-2.aspx" target="_blank">parte 2</a>) abbiamo visto come attivare il <em>Trigger</em> del “WebJob” alla creazione di un nuovo <em>Blob</em> all’interno di un <em>container</em> specifico semplicemente utilizzando l’attributo <em>[BlobInput].</em> Con le stesse modalità é possibile eseguire il <em>Binding</em> di una funzione invocata dall’instanza di <em>JobHost</em> al ricevimento di un messaggio in un specifica coda (<em>Queue</em>) come da esempio:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> ProcessBobByQueueMessage([QueueInput(<span class="str">@"inputqueue"</span>)] <span class="kwrd">string</span> message, [BlobOutput(<span class="str">@"outputcontainer/resized_image.png"</span>)] Stream outputStream) { <span class="kwrd">if</span> (!message.Equals(<span class="str">"go"</span>)) <span class="kwrd">return</span>; CloudStorageAccount storageAccount = CloudStorageAccount.Parse( System.Configuration.ConfigurationManager.ConnectionStrings[<span class="str">"AzureJobsData"</span>] .ConnectionString); CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = blobClient.GetContainerReference(<span class="str">"inputcontainer"</span>); CloudBlob blob = container.GetBlobReference(<span class="str">"TestPicture"</span>); Stream inputStream = <span class="kwrd">new</span> MemoryStream(); blob.DownloadToStream(inputStream); ResizeImage(inputStream, outputStream); }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>La funzione “ProcessBobByQueueMessage” é invocata al momento che un messaggio contenente il testo “go” arriva nella coda denominata “inputqueue”, come nei casi precedenti, creiamo un nuovo <em>Blob</em> nel <em>container</em> “outputcontainer” con il nome di “resized_image.png”. Da notare che nel codice utilizziamo le clasi del namespace<em> Microsoft.WindowsAzure.StorageClient </em>per lavorare con le classi che rappresentano lo <em>storage</em> di Windows Azure. Per testare il tutto é sufficiente caricare il <em>Job</em> sul nostro Web Site di test o premere F5 e lavoare “in locale”. Tramite l’Azure Storage Explorer possiamo creare un nuovo messaggio con la dicitura “go” come da figura:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_2.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_thumb.png" width="244" height="176" /></a></p> <p>E nel <em>container</em> di output avremo:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_4.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_thumb_1.png" width="244" height="141" /></a></p> <p>Dal codice si evince come il nome del <em>Blob</em> di ouput (e di input) sia fissato, ma per un’applicazione reale questo non é un comportamento desiderabile, cosi’, sarebbe auspicabile avere un comportamento piu’ dinamico utilizzando (ad esempio) una classe “Custom” serializzata in JSON, contenente la definizione dei file (<em>Blob</em>) di <em>Input</em> ed <em>Output</em> e passata come messaggio testo alla coda, tradotto in codice:</p> <pre class="csharpcode"> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> ProcessBobByQueueCustomMessage([QueueInput(<span class="str">@"inputqueue"</span>)] ImageMessage message, [BlobOutput(<span class="str">@"outputcontainer/{OutputName}"</span>)] Stream outputStream) { CloudStorageAccount storageaccount = CloudStorageAccount.Parse( System.Configuration.ConfigurationManager.ConnectionStrings[<span class="str">"AzureJobsData"</span>] .ConnectionString); CloudBlobClient blobclient = storageaccount.CreateCloudBlobClient(); CloudBlobContainer container = blobclient.GetContainerReference(<span class="str">"inputcontainer"</span>); CloudBlob blob = container.GetBlobReference(message.InputName); Stream inputStream = <span class="kwrd">new</span> MemoryStream(); blob.DownloadToStream(inputStream); ResizeImage(inputStream, outputStream); }</pre> <p> </p> <p>Da notare l’utilizzo del <em>placeHolder </em>“{OutputName}” specificato nel percorso (<em>BlobPath</em>) ed accettato come argomento dall’attributo <em>BlobPath</em>, uguale alla proprietà omonima della classe <em>ImageMessage</em>, ed utilizzata per definire il nome del <em>Blob</em> di output in questo modo:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> ImageMessage { <span class="kwrd">public</span> <span class="kwrd">string</span> InputName { get; set; } <span class="kwrd">public</span> <span class="kwrd">string</span> OutputName { get; set; } }</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Per un giro di test è sufficiente creare un nuovo messagio con il testo seguente:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_6.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_thumb_2.png" width="244" height="122" /></a></p> <p>Ottenendo:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_8.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-3_DAA1/image_thumb_3.png" width="244" height="136" /></a></p> <p>Interessante è l’utilizzo dell’attributo [<em>NoAutomaticTrigger()</em>] che indica all’istanza di “JobHost” di non far scattare un particolare metodo (magari per evitare che il job venga attivato quando non tutte le condizioni necessiaro sono presenti). Questo attributo non va d’accordo con l’attributo <em>[QueueInput(…)]</em> in quanto a runtime solleva un’eccezione con il messaggio seguente: <em>“Can't have QueueInput and NoAutomaticTrigger on the same function.”.</em></p> <p>Per invocare programmaticamente una funzione è sufficiente utilizzare il metodo <em>Call()</em> della classe JobHost:</p> <pre class="csharpcode">host.Call(methodInfo);</pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Dove “methodInfo” puo’ essere facilmente calcolato tramite <em>Reflection</em>.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101771.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/11/windows-azure-webjobs-parte-3.aspx Tue, 11 Feb 2014 12:27:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/11/windows-azure-webjobs-parte-3.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101771.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101771.aspx Windows Azure WebJobs (parte 2) http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/06/windows-azure-webjobs-parte-2.aspx <p>Nella <a href="http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/05/windows-azure-webjobs-parte-1.aspx" target="_blank">prima parte</a> abbiamo visto come creare un’applicazione console ed utilizzarla per elaborare (ridimensionare) in modalità <em>Continuously</em> dei <em>Blob</em> contenenti immagini, caricati in un particolare <em>container</em> del nostro <em>storage</em>. L’applicazione non è stata fisicamente copiata su un Web Site di Azure, ma è stata eseguita “in locale” sfruttando gli <em>endpoint</em> allo <em>storage</em>. Per caricare il nostro processo su <em>Web Site</em> i passi da compiere sono pochi e semplici:</p> <ul> <li>Accedere al portale di Windows Azure (<a title="https://manage.windowsazure.com" href="https://manage.windowsazure.com">https://manage.windowsazure.com</a>)</li> <li>Se non presente, creare un nuovo Web Site:</li> </ul> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_1.png" width="244" height="108" /></a></p> <ul> <li>Aprire il <em>Web Site</em> e visualizzare la sezione “Configure”:</li> </ul> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_10.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_4.png" width="244" height="23" /></a></p> <ul> <li>Nella sottosezione “connection strings”, aggiungiamo la stringa di connessione “AzureJobsRuntime”:</li> </ul> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_12.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_5.png" width="244" height="45" /></a></p> <ul> <li>Visualizziamo la sezione “WebJobs”:</li> </ul> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_8.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_3.png" width="244" height="52" /></a></p> <ul> <li> <p>Prima di effettuare l’upload dell’eseguibile è necessario creare una cartella compressa contenente sia “.exe” che “.dll” necessari al corretto funzionamento dell’applicazione. E’ sufficiente creare un archivio “zip” partendo (ad esempio) dalla cartella Debug\Release del nostro progetto. A questo punto è sufficiente cliccare sul bottone “ADD”, assegnare un nome al nostro “WebJob”, specificare il percorso della cartella compressa ed infine la modalità di esecuzione:</p> </li> </ul> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_14.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_6.png" width="233" height="244" /></a></p> <ul> <li> <p>Una volta caricato il file compresso, dovremmo avere una situazione simile alla seguente:</p> </li> </ul> <p align="center"><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_16.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/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_7.png" width="244" height="43" /></a></p> <ul> <li> <p>Il <em>Job</em> caricato è in stato “STOP”, per entrare in “RUNNING” è ncessario cliccare l’icona con la dicitura “START” in fondo alla pagina:</p> </li> </ul> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_18.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_8.png" width="244" height="31" /></a></p> <ul> <li> <p>Per testare che tutto funzioni correttamente è sufficiente utilizzare il tool <a href="http://azurestorageexplorer.codeplex.com/" target="_blank">Azure Storage Explorer</a> come visto nella prima parte.</p> </li> </ul> <p>Se avessimo optato per un’esecuzione <em>On Demand</em> del <em>Job</em> ci saremmo trovati in una situazione di questo tipo:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_20.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/Windows-Azure-WebJobs-parte-2_7AF8/image_thumb_9.png" width="244" height="194" /></a></p> <p>Dove per eseguire il processo si rende necessario cliccare l’icona con la dicitura “RUN ONCE”. Se si vuole invece provare la versione <em>Scheduled</em> è necessario attivare il servizio “Windows Azure Scheduler” tra quelli presenti in questa pagina: <a title="https://account.windowsazure.com/PreviewFeatures" href="https://account.windowsazure.com/PreviewFeatures" target="_blank">https://account.windowsazure.com/PreviewFeatures</a></p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101766.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/06/windows-azure-webjobs-parte-2.aspx Thu, 06 Feb 2014 12:22:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/06/windows-azure-webjobs-parte-2.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101766.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101766.aspx Windows Azure WebJobs (parte 1) http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/05/windows-azure-webjobs-parte-1.aspx <p>Windows Azure mi appassiona veramente tanto e le nuove funzionalità  rilasciate (seppur in <em>alpha</em>) aumentano ancora di piu’  la voglia e volontà di adottare questa piattaforma. E’ il caso dei <em>WebJobs</em>, un nuovo SDK in versione <em>alpha</em> che permette di eseguire programmi e script ospitati nei <em>Web Site</em> di Windows Azure, “semplicemente” tramite upload di un file (ad esempio “.exe” o “.cmd” ) dato che tutto il “difficile” è onere del “WebJobs SDK”.</p> <p>Questa nuova <em>feature </em>permette di eseguire dei veri e propri <em>batch,</em> processi che normalmente impiegherebbero molto tempo per essere eseguiti, come ad esempio la riorganizzazione di file, invio di email, processamento di immagini o code (<em>Queue</em>). Un <em>batch </em>puo’ essere eseguito in tre modalità differenti:</p> <ul> <li>On-Demand (<em>a richiesta</em>) </li> <li>Continuously, il processo in background è sempre attivo “in attesa di fare qualcosa”, il <em>Trigger</em> per attivare il processo puo’ essere ad esempio la ricezione di un messaggio in una specifica coda oppure la creazione di un nuovo <em>Blob</em> </li> <li>Scheduled, vogliamo che il nostro processo esegua del lavoro ad una certa ora di uno o piu’ giorni della settimana (in modalità singola o ricorrente) </li> </ul> <p>Un piccolo scenario d’esempio: un task (sempre attivo) che <em>triggerato</em> al caricamento di un <em>Blob</em> (un file immagine) in uno specifico <em>container </em>(“inputcontainer”), lo elabora (ridimensiona l’immagine e ne cambia formato in “png”) e salva il <em>Blob</em> risultato in un altro <em>container</em> (“outputcontainer”).</p> <p>Per iniziare è sufficiente creare una nuova applicazione console C# ed aggiungere i <em>package</em> necessari traminte NuGet:</p> <p>PM&gt; Install-Package Microsoft.WindowsAzure.Jobs.Host –pre</p> <p>In <em>Program.cs</em> scriviamo il codice seguente:</p> <pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args) { JobHost host = <span class="kwrd">new</span> JobHost(); host.RunAndBlock(); } <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> ProcessJob([BlobInput(<span class="str">@"inputcontainer/{name}"</span>)] Stream inputStream, [BlobOutput(<span class="str">@"outputcontainer/{name}"</span>)] Stream outputStream) { <span class="kwrd">using</span> (Bitmap inputImage = <span class="kwrd">new</span> Bitmap(inputStream)) { Image outputImage = <span class="kwrd">new</span> Bitmap(200, 200); <span class="kwrd">using</span> (Graphics g = Graphics.FromImage(outputImage)) { g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.CompositingMode = CompositingMode.SourceCopy; g.PixelOffsetMode = PixelOffsetMode.HighQuality; <span class="kwrd">using</span> (ImageAttributes imageAttributes = <span class="kwrd">new</span> ImageAttributes()) { Rectangle destRect = <span class="kwrd">new</span> Rectangle(0, 0, 200, 200); g.DrawImage(inputImage, destRect, 0, 0, inputImage.Width, inputImage.Height, GraphicsUnit.Pixel, imageAttributes); } } System.Drawing.Imaging.ImageFormat pngFormat = <span class="kwrd">new</span> System.Drawing.Imaging.ImageFormat(ImageFormat.Png.Guid); outputImage.Save(outputStream, pngFormat); } }</pre> <p> </p> <p>E’ abbastanza intuitivo che il “lavoro sporco” del <em>Task</em> è eseguito dal codice presente in <em>ProcessJob</em>, il quale verrà attivato (<em>BlobInput</em>) ogni volta che un nuovo <em>Blob</em> verrà caricato in “inputcontainer”. L’output è definito dall’attributo <em>BlobOutput</em>, nello specifico la creazione di un nuovo Blob (immagine 200x200) nel container “outputcontainer”. Il codice di ridimensionamento è <em>out of scope</em>. Il nome del <em>Blob</em> in ingresso sarà uguale a quello di uscita in base al pattern specificato dal token “{name}”.</p> <p>Chi si occupa di gestire i <em>Bindings</em>, di rimanere in “ascolto” e dei <em>Trigger</em> è la classe <em>JobHost</em> che puo’ essere inizializzata come specificato nel <em>Main</em>. In questo caso si suppone che l’A<em>pp.config </em>contenga le definizione delle due <em>ConnectionStrings</em> necessarie rispettivamente per lavorare con lo <em>Storage</em> di Azure (“AzureJobsData”) e con le attività di logging (“AzureJobsRuntime”):</p> <pre class="csharpcode"> <span class="kwrd">&lt;</span><span class="html">connectionStrings</span><span class="kwrd">&gt;</span> <span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="AzureJobsRuntime"</span> <span class="attr">connectionString</span><span class="kwrd">="DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=ACCOUNT_KEY"</span><span class="kwrd">/&gt;</span> <span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="AzureJobsData"</span> <span class="attr">connectionString</span><span class="kwrd">="DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=ACCOUNT_KEY"</span><span class="kwrd">/&gt;</span> <span class="kwrd">&lt;/</span><span class="html">connectionStrings</span><span class="kwrd">&gt;</span></pre> <style type="text/css"><![CDATA[ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }]]></style> <p> </p> <p>Altrimenti è necessario specificare il nome delle due stringhe di connessione tramite costruttore della classe <em>JobHost</em>. Le due connessioni possono coincidere ed ovviamente per eseguire l’esempio è necessario modificarle secondo il proprio account, sostituendo i valori di ACCOUNT_NAME e ACCOUNT_KEY.</p> <p>Il metodo “RunAndBlock()” esegue il <em>Task</em> nello stesso <em>Thread</em> attivo, mentre per utilizzare un <em>Background Thread</em> è necessario invocare il metodo “RunOnBackgroundThread()” (che ritorna immediatamente il controllo al chiamante). </p> <p>Per testare il tutto possiamo premere F5 e dopo qualche secondo, se tutte le configurazioni sono corrette, dovremmo ottenere una <em>console</em> simile alla seguente:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_2.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/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_thumb.png" width="244" height="126" /></a></p> <p>Questo implica che il nostro Job è in attesa di “fare qualcosa”. Per lavorare con lo storage di Windows Azure possiamo scaricare il Tool <a href="http://azurestorageexplorer.codeplex.com/" target="_blank">“Azure Storage Explorer”</a>. Una volta installato e configurato è possibile esplorare e modificare il nostro storage, nel mo caso, inizailmente abbiamo una situazione simile alla seguente:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/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; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_thumb_2.png" width="244" height="176" /></a></p> <p>Dopo aver selezionato la voce “inputcontainer” nella lista “Container”, scegliamo la voce “New” nella lista dei comandi “Blob”, specifichiamo il nome del nuovo <em>Blob</em> e premiamo “Create Blob”:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_8.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/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_thumb_3.png" width="244" height="176" /></a></p> <p>Dalla lista dei <em>Blob</em> presenti selezioniamo quello appena creato e scegliamo la voce “View” per visualizzarne i dettagli:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_12.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/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_thumb_5.png" width="244" height="162" /></a></p> <p>Click su “Upload Image File” per caricare una nuova immagine ed attendere il completamento delle operazioni di upload. Rieseguendo la nostra applicazione, dopo qualche secondo, dovremmo ottenere una <em>console</em> di questo tipo:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_14.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/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_thumb_6.png" width="244" height="126" /></a></p> <p>A questo punto ”outputcontainer” dovrebbe contenere un <em>Blob</em> con lo stesso nome di quello di input e contenente un immagine di dimensione 200x200px:</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_16.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/PietroLibroBlog/Windows-Live-Writer/WebJobs_CCDC/image_thumb_7.png" width="244" height="135" /></a></p> <p>Nella seconda parte del post vedremo come caricare l’eseguibile direttamente in un nostro Web Site ospitato su Windows Azure.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101765.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/05/windows-azure-webjobs-parte-1.aspx Wed, 05 Feb 2014 18:32:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/02/05/windows-azure-webjobs-parte-1.aspx#feedback 2 http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101765.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101765.aspx ASP.NET Dynamic Data provider (preview) per EF6 http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/01/31/asp.net-dynamic-data-provider-preview-per-ef6.aspx <p>Rilasciato un aggiornamento per <em>ASP.NET DynamicData</em> e <em>DataSourceControl</em> per Entity Framework 6. Tutti i dettagli del caso sul <a href="http://blogs.msdn.com/b/webdev/archive/2014/01/30/announcing-preview-of-dynamic-data-provider-and-entitydatasource-control-for-entity-framework-6.aspx" target="_blank">blog originale</a>.</p><img src="http://blogs.ugidotnet.org/PietroLibroBlog/aggbug/101763.aspx" width="1" height="1" /> Pietro Libro http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/01/31/asp.net-dynamic-data-provider-preview-per-ef6.aspx Fri, 31 Jan 2014 10:23:00 GMT http://blogs.ugidotnet.org/PietroLibroBlog/archive/2014/01/31/asp.net-dynamic-data-provider-preview-per-ef6.aspx#feedback http://blogs.ugidotnet.org/PietroLibroBlog/comments/commentRss/101763.aspx http://blogs.ugidotnet.org/PietroLibroBlog/services/trackbacks/101763.aspx