venerdì 3 luglio 2009
Un ora fa ho scritto una mail al mio fornitore di hardware, chiedendo alcuni prezzi di box esterni per RAID sata. Dopo un’oretta vado a rivedere gmail per vedere se mi ha risposto. La risposta non è arrivata, ma vedo questo.
Secondo me è anche per questo che Google è veramente avanti.
alk.
martedì 16 giugno 2009
Personalmente non posso vivere senza fiddler, ed un’altra prova della potenza di questo tool la trovate qui, nel blog dell’Ace Team, in cui viene mostrato come fiddler possa anche registrare il traffico producendo poi un bel Web Test che potete includere in visual studio. Il processo è un po macchinoso, ma in alcune situazioni può pagare decisamente la fatica spesa.
alk.
Tags: Testing
lunedì 15 giugno 2009
Nei tip precedenti si è visto come comunicare con il server con la chiamata getJSON e restituiendo dalla pagina aspx un oggetto .net serializzato JSON. In molte situazioni è comunque conveniente formattare l’html direttamente lato server. Grazie a jQuery caricare parti di pagina dinamicamente è un gioco da ragazzi.
Lo script del tip 8 è il seguente.
$(function() {
$('[id=btnGetData]').log('button').click(function() {
var button = this;
var code = $('[id=txtCode]').val();
$('.result').load(
'/Tip8/CustomerService.aspx [id=thecontent]',
{
Code: code
});
return false;
});
});
Come si può vedere per cambiare il contenuto del div principale non si fa altro che chiamare la funzione load(). In questo caso il primo parametro è la url che restituisce i dati seguita da uno spazio e poi da un selettore opzionale (in questo caso [id=thecontent]) che va ad individuare un elemento della pagina restituita dalla chiamata. Come si può notare in questo caso non c’è bisogno di una callback, perchè jQuery va direttamente a sostituire il contenuto restituito dalla chiamata all’elemento su cui si è invocata la funzione load. Lato server la pagina CustomerService ora è cosi fatta
<body>
<form id="form1" runat="server">
<div id="thecontent">
<h1>Customer
<asp:Label ID="id" runat="server" Text="Label"></asp:Label></h1><br />
<b>Name:</b><asp:Label ID="Name" runat="server" Text="Label"></asp:Label><br />
<b>ContactName:</b><asp:Label ID="ContactName" runat="server" Text="Label"></asp:Label><br />
<b>Address:</b><asp:Label ID="Address" runat="server" Text="Label"></asp:Label><br />
</div>
</form>
</body>
</html>
In questo caso ho creato un po di html, lato codice non si fa altro che popolare il contenuto delle label, il risultato è il seguente.
Come si può vedere il contenuto della pagina CustomerSErvice viene sostituito al div originale. Per maggiori dettagli potete leggere il mio terzo articolo su jQuery pubblicato su ugi.
Alk.
Tags: jQuery
lunedì 25 maggio 2009
Nel codice relativo all’esempio del tip 7 è stato aggiunto un controllo di questo tipo per simulare eccezioni che si verificano nella pagina del servizio.
String code = Request["Code"];
if (code.StartsWith("B", true, null))
throw new ArgumentException("Error in parameter");
In questo caso quando si richiedono i dati di un cliente il cui codice inizia per B viene lanciata una eccezione. Il problema in questo caso è che lasciando il codice javascript del tip 6, si ha un spiacevole inconveniente. Quando si richiede un cliente con codice che inizia con B, viene impostato lo stato di attesa come spiegato nel tip precedente, ma purtroppo l’interfaccia rimane cosi, bloccata, senza che lo stato di attesa se ne vada.
Questo avviene perchè nel caso di eccezione la pagina aspx restituisce il classico messaggio di eccezione.
jQuery tenta di convertire questo HTML in JSON ma non riesce, e per questo non richiama la funzione callback specificata nella getJSON. Purtroppo questo comporta avere una pagina che rimane in uno stato non utilizzabile.
La soluzione risiede negli eventi callback ajax esposti da jQuery. La chiamata getJSON è infatti una delle tante offerte da jQuery per utilizzare funzionalità ajax, e per questo condivide un set di funzionalità standard, come ad esempio la possibilità di utilizzare eventi specifici relativi alle chiamate ajax. Questi eventi possono risolvere questo problema in maniera molto elegante
$(function() {
$('.maindiv')
.ajaxStart(function() {
console.log('ajaxStart');
$(this).log('this ajaxStart').setwait();
})
.ajaxError(function(event, request, settings) {
console.log('ajaxError');
$(this).log('this ajaxError').clearwait();
})
.ajaxSuccess(function(evt, request, settings) {
console.log('ajaxSuccess');
$(this).log('this ajaxSuccess').clearwait();
});
$('[id=btnGetData]').log('button').click(function() {
var button = this;
var code = $('[id=txtCode]').val();
$.getJSON(
'/Tip7/CustomerService.aspx',
{
Code: code
},
function(result) {
//Here result object has the same properties as Customers
var showresult;
for (p in result)
showresult += p + ': ' + result[p] + '<br />';
$('.result').html(showresult);
});
return false;
});
});
Come si può notare, nella prima parte sono stati attaccati al div principale alcuni eventi ajax, con l’aggiunta di qualche funzione di log per firefox che aiuta a capire quando vengono lanciati. Nel primo, ajaxStart, viene impostato lo stato di attesa, mentre in ajaxError e ajaxSuccess viene semplicemente rimosso lo stato di attesa. In questo modo sia in caso di successo, che in caso di fallimento, lo stato di attesa per il div principale viene sempre impostato correttamente.
alk.
Tags: jQuery
giovedì 21 maggio 2009
Nel tip5 ho mostrato come interrogare il server con getJSON, per questo tip ho semplicemente aggiunto nella pagina CustomerService.aspx una istruzione Thread.Sleep(3000) per fare attendere tre secondi il rendering della pagina. Lo scopo è simulare una operazione lunga.
In situazioni in cui la risposta del server non può essere stimata (praticamente sempre), è necessario mostrare all’utente un qualche segnale che l’operazione è in corso, in modo che non possa più premere nel bottone, ma soprattutto sia avvertito visualmente che il sistema non è bloccato ma sta facendo qualche cosa.
Questa operazione è cosi frequente che è stata implementata come plugin nel file jqueryext.js, le due estensioni si chiamano quindi setwait() e clearwait(), rispettivamente per impostare uno stato di attesa per un div e riportare il div alla situazione originaria.
(function($) {
$.fn.setwait = function(options) {
var settings = $.extend({
slidecss: 'waitindicatormasx',
imagecss: 'waitindicator',
waitoffset: 200
}, options || {});
La prima parte della funzione è la classica dichiarazione di plugin jQuery, la funzione $.extend( serve invece per comporre due oggetti, e verrà spiegata in dettaglio in un prossimo tip.
var context = this;
// debugger;
context[0].timer = setTimeout(function() {
var position = context.position();
var thediv = context;
var innerslide = $('<div style="width:' + thediv.width() + 'px; height:' + thediv.height() + 'px" class="' + settings.slidecss + '" />')
.css('opacity', 0.5);
var progress = $('<div style="width:' + thediv.width() + 'px; height:' + thediv.height() + 'px" class="' + settings.imagecss + '"/>');
thediv.prepend(innerslide)
thediv.prepend(progress);
context[0].innerslide = innerslide;
context[0].progress = progress;
}, settings.waitoffset);
return this;
Il resto della funzione non fa altro che creare un timer con la funzione setTimeout. In questo modo lo stato di attesa viene impostato solo allo scadere del timer, che per default è impostato a 200 millisecondi; grazie a questo piccolo offset, se il server risponde prima di 200 millisecondi lo stato di attesa non viene mai impostato. Grazie a jQuery lo stato di attesa viene impostato creando un nuovo div, impostandone le dimensioni al div target, sovrapponendolo al div originale con una opacità dello 0.5. In questo modo il contenuto originale del div si schiarisce perchè viene visualizzato sotto un div con sfondo bianco e opacita 50%, poi viene inserito un altro div con al centro una immagine gif animata per mostrare l’attesa.
La funzione clearwait non fa altro che controllare se il timer è scaduto, in caso contrario semplicemente lo annulla, altrimenti rimuove i due div. Gli stili base dei due div sono fatti cosi, ma possono essere modificati
.waitindicatormasx
{
position: absolute;
background-color: White;
z-index: 2;
}
.waitindicator
{
position: absolute;
background-image: url(Images/ajax-loader3.gif);
background-repeat: no-repeat;
background-position:center;
z-index: 3;
}
è importante il posizionamento assoluto per sovrapporsi al div originale, per il resto si può magari cambiare il colore, tipo il classico giallino.
Ora che si è creata questa funzione, usarla è banale.
$(function() {
$('[id=btnGetData]').log('button').click(function() {
var button = this;
var code = $('[id=txtCode]').val();
$('.maindiv').setwait();
$.getJSON(
'/Tip6/CustomerService.aspx',
{
Code: code
},
function(result) {
//Here result object has the same properties as Customers
$('.maindiv').clearwait();
var showresult;
for (p in result)
showresult += p + ': ' + result[p] + '<br />';
$('.result').html(showresult);
});
return false;
});
});
Come si può vedere il div identificato dalla classe “maindiv” viene posto in stato di attesa alla pressione del bottone, nella funzione callback la prima cosa che si fa è rimuovere lo stato di attesa, e poi modificare il div con i nuovi dati. La pagina principale ora è fatta cosi
<div class="maindiv">
<asp:TextBox ID="txtCode" runat="server"></asp:TextBox>
<asp:Button ID="btnGetData" runat="server" Text="Button" />
<div class="result">
</div>
</div>
Tutti i controlli sono racchiusi nel div mainDiv, premendo il bottone per la ricerca si può notare come tutto il contenuto sia schiarito e grazie al div sovrapposto, è impossibile cliccare ancora nel tasto e quindi fare più richieste.
Grazie al fatto di avere incluso la funzionalità in un plugin, usarla è solo questione di due righe di codice.
alk.
Tags: jQuery
martedì 19 maggio 2009
Nel precedente tip è stato mostrato come chiamare in maniera asincrona una pagina del server, e farsi restituire dati in formato json. Nell’esempio mostrato si è semplicemente chiamata una funzione che restituisce l’utente correntemente loggato.
In situazioni reali è sicuramente necessario passare parametri alla pagina in questione, questo può essere tranquillamente fatto tramite il secondo parametro di getJSON. Supponiamo di avere una pagina CustomerService che permette di restituire un oggetto Customers del database northwind dato un suo id. Il codice lato server è il seguente
String code = Request["Code"];
using (Northwind ctx = new Northwind())
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Response.Write(
serializer.Serialize(
ctx.Customers
.Where(c => c.CustomerID == code).FirstOrDefault()));
Response.End();
}
Grazie ad Entity Framework il recupero dell’oggetto è veramente banale. Ora si crei una pagina Customers.aspx con il seguente contenuto.
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/jQuery/jquery-1.3.2.js" />
<asp:ScriptReference Path="~/jQuery/jqueryext.js" />
<asp:ScriptReference Path="~/scripts/Tip5/GetData.js" />
</Scripts>
</asp:ScriptManager>
<div>
<asp:TextBox ID="txtCode" runat="server"></asp:TextBox> <asp:Button ID="btnGetData" runat="server" Text="Button" />
<div class="result" ></div>
</div>
Una semplice textbox dove inserire il codice, un bottone per effettuare la richiesta al server ed infine un div vuoto dove inserire il risultato, a questo punto non rimane alrto da fare che esaminare lo script GetData.js che aggiunge a questa pagina le funzionalità richieste.
$(function() {
$('[id=btnGetData]').log('button').click(function() {
var button = this;
var code = $('[id=txtCode]').val();
$.getJSON(
'/Tip5/CustomerService.aspx',
{
Code: code
},
function(result) {
//Here result object has the same properties as Customers
var showresult;
for (p in result)
showresult += p + ': ' + result[p] + '<br />';
$('.result').html(showresult);
});
return false;
});
});
Il codice è veramente semplice, prima di chiamare la pagina grazie alla funzione jQuery val si recupera il contenuto della textbox, poi come secondo parametro della funzione getJSON viene passato un oggetto javascript composto da una serie di coppie (proprietà, valore) che costituiscono i parametri che verranno passati alla pagina. Nell’esempio la pagina richiede solamente un parametro chiamato Code, per questo il parametro viene definito come { Code : code }.
Il risultato è un oggetto Customer di Entity Framework, e viene brutalmente rappresentato all’interno di un div iterando tra le sue proprietà. In tip successivi vedremo come gestire in maniera migliore la rappresentazione lato client degli oggetti restituiti dalle chiamate ajax.
alk.
Il codice lo trovate qui.
Tags: jQuery
sabato 16 maggio 2009
Nel precedente tip è stato mostrato come dialogare con il server tramite un semplice webservice asmx. Sebbene questo modo di procedere sia molto intuitivo, comporta spesso un overhead causato dal file javascript generato dal server per permettere la chiamata del servizio. Nel precedente esempio infatti potete vedere, come oltre ai normali script, venga restituito al client il file http://localhost:21963/MyService.asmx/js che contiene tutto il codice per permettere l’invocazione del webservice.
jQuery mette a disposizione modi molto più intelligenti di dialogare con il server, in particolare la funzione getJSON che permette di effettuare una chiamata ad una url che restituisce i dati in formato json. Se controllate nel sorgente potrete vedere nella cartella tip4, una pagina aspx chiamata Servicepage.aspx il cui codice è veramente semplice.
public partial class ServicePage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Response.Write(serializer.Serialize(Membership.GetUser()));
Response.End();
}
}
Come potete notare grazie alla classe JavaScriptSerializer è possibile restituire al chiamante un qualsiasi oggetto (in questo caso il MembershipUser) in formato json. Se chiamate direttamente la pagina potete infatti osservare cosa viene restituito.
{"UserName":"admin","ProviderUserKey":"5f7b1fdb-0322-4cab-96d8-c1c3771f414d","Email":"a@nablasoft.com"
,"PasswordQuestion":null,"Comment":null,"IsApproved":true,"IsLockedOut":false,"LastLockoutDate":"\/Date
(-6816268800000)\/","CreationDate":"\/Date(1242062048000)\/","LastLoginDate":"\/Date(1242470020860)\
/","LastActivityDate":"\/Date(1242470194907)\/","LastPasswordChangedDate":"\/Date(1242062048000)\/","IsOnline"
:true,"ProviderName":"SqlProvider"}
Sebbene questa stringa sia di difficile lettura, è semplicemente la serializzazione json dell’oggetto MembershipUser, ecco quindi che nella pagina tip4/auth.aspx basta referenziare lo script scripts/tip4/auth.js che non fa altro che recuperare tramite jQuery tutte le info sull’utente attualmente loggato.
$(function() {
$('.askname').log('button').click(function() {
var button = this;
$.getJSON('/Tip4/ServicePage.aspx', {}, function(result) {
//Here result object has the same properties as MembershipUser
$(button).siblings('.userdata').text(
'UserName:' + result.UserName + ' Email:' + result.Email );
});
});
});
Grazie alla getJSON si può invocare una pagina ed impostare come callback, una funzione anonima il cui unico parametro è l’oggetto restituito dalla pagina. L’aspetto importante è che nella callback si accede direttamente alle proprietà dell’oggetto MembershipUser come la result.UserName e result.Email. Tutto questo grazie al fatto che javascript è un linguaggio dinamico ;) e quindi può riscostruire l’oggetto dalla stringa json senza problemi.
Il vantaggio di questo approccio è evitare di passare al client file js inutili e anche in questo caso dato che la pagina che restituisce i dati è una normalissima pagina aspx, potete usare Session, Membership, proteggere la pagina con i ruoli, etc etc.
alk.
Il codice è scaricabile da qui.
Tags: jQuery
venerdì 15 maggio 2009
La potenza di jQuery risiede principalmente nel rendere semplice manipolare un oggetto complesso come il DOM. La chiave di jQuery è quindi quella di dialogare con il server, invocando operazioni ed aggiornando l’interfaccia, senza effettuare postback ed inviando solamente i dati minimali.
Esistono molti modi per dialogare con il server, ad esempio grazie ad asp.net ajax è semplicissimo invocare una funzione contenuta in un webservice .asmx. Il vantaggio di usare un asmx è che potete direttamente inserirlo nel sito, in questo modo anche la security standard di asp.net vi protegge dall’uso indesiderato. Se ad esempio chiedete il servizio con la richiesta
http://localhost:21963/Login.aspx?ReturnUrl=%2fMyService.asmx
Il server vi chiede correttamente la login perché il servizio è protetto, quindi abbiamo la stessa garanzia di sicurezza di una normale pagina. Supponiamo ora di avere nel servizio la funzione:
[WebService(Namespace = "http://blogs.ugidotnet.org/rgm/jQueryTip/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public string GetLoggedUser()
{
return Membership.GetUser().UserName;
}
}
Come vedete non è altro che un webservice standard che può essere chiamato da client grazie all’attributo ScriptService, e l’unica funzione presente recupera l’utente attualmente loggato, a questo punto grazie allo ScriptManager di asp.net ajax si può chiamare questa funzione da javascript , ecco il codice della pagina Auth1.aspx
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/jQuery/jquery-1.3.2.js" />
<asp:ScriptReference Path="~/jQuery/jqueryext.js" />
<asp:ScriptReference Path="~/scripts/Auth1.js" />
</Scripts>
<Services>
<asp:ServiceReference Path="~/MyService.asmx" />
</Services>
</asp:ScriptManager>
<div>
<input type="button" class="askname" value="loggedusername" ></input>
<input type="text" class="askname" ></input>
</div>
</form>
</body>
Come si può vedere ci sono solamente due controlli, un bottone ed una texbox, ma sono controlli html, senza attribute runat=”server”, e quindi sono completamente ignorati da asp.net.Ora si vuole creare una funzione che alla pressione del bottone, metta nella textbox il nome dell’utente loggato.
Notate come nello scriptmanager sia stato inserito un riferimento al webservice precedentemente mostrato e sono stati inclusi gli script javascript, i primi due sono la libreria jQuery ed una libreria di estensioni, il terzo è lo script che realizza la logica della pagina.
(function() {
$('.askname').log('button').click(function() {
SampleSite.MyService.GetLoggedUser(
function(result, context, method) {
$(context).siblings('input').val(result);
},
function(error, context, method) {
alert('Exception during the save.');
}, this);
});
});
Come si può vedere basta aggiungere un handler click() al bottone, alla pressione dello bottone si chiama quindi il webservice, proprio come se la classe del webservice fosse definita nel javascript (in effetti lo script manager vi genera uno script con tutta la definizione). La chiamata accetta tutti i parametri della funzione originale (in questo caso nessuno), e di seguito tre parametr:, la funzione da chiamare in caso di successo, quella da chiamare in caso di fallimento ed un oggetto che viene ripassato alle precedenti due funzioni nel campo context. In caso di successo non si fa altro che individuare la textbox grazie alla funzione jQuery siblings, e modificarne il contenuto. Come si può vedere il bottone premuto, era stato passato come ultimo parametro alla funzione GetLoggedUser(), per cui lo ritroviamo nel parametro context delle funzioni di callback.
Il codice è contenuto qui.
Alk.
Tags: jQuery asp.net ajax
martedì 12 maggio 2009
Dato che jQuery ha moltissime funzioni ed opzioni, spesso è facile perdersi. Avere l’intellisense è quindi un aiuto veramente indispensabile a volte. Fortunatamente Visual Studio 2008 include l’intellisense per javascript, è sufficiente scaricare l’apposito file di documentazione. In giro per la rete trovate molti file per intellisense, io uso questo (http://www.infobasis.com/sandpit/jQuery-Intellisense/jQuery-vsdoc.js) che è aggiornato alla versione 3.
Per utilizzare l’intellisense non serve molto, basta copiare il file direttamente in una cartella di progetto e referenziarlo in un commento in questo modo
Un altro utile strumento sono le refcartz, quella di jQuery la trovate qui, si tratta di un pdf di sei paginette in cui sono racchiuse tutti i selettori standard, più qualche tip. Una volta stampate costituiscono una quick reference veramente interessante.
alk.
Tags: jQuery
lunedì 11 maggio 2009
siderata l’importanza sempre maggiore che jQuery riveste per gli sviluppatori web, vorrei condividere qualche piccolo tip appreso qua e la, non so quanto riuscirò a mantenere la continuità, visto gli impegni sempre più pressanti di questo periodo lavorativo. I buoni propositi ci sono tutti :D.
Iniziamo con il tip più importante, come fare log con la firebug di firefox. Ecco un estensione per poter effetturare il dump di un wrapped-set nella firebug
(function($) {
$.fn.log = function(msg) {
if (typeof (console) == "undefined") {
console = { log: function() { } };
}
if (console) {
console.log("%s: %o", msg, this);
}
return this;
}
})(jQuery);
La sintassi può apparire un po cervellotica, ma è la modalità standard di scrivere estensioni per jQuery, in modo da poter usare il $ all’interno della funzione, ma mantenere allo stesso tempo la compatibilità in caso di conflitto con altre librerie.
Questa funzione si utilizza in maniera veramente semplice, come ogni plugin che si rispetti è concatenabile, questo significa che potete selezionare un wrappedset, poi chiamare il log e poi continuare a utilizzare il wrapped set. Ecco un esempio di utilizzo
$('.hierarchicmaindiv input[id=btnSearch]').log('searchdiv')
.click(function() {
con questa istruzione seleziono tutti i bottoni con id btnSearch dentro un elemento che ha come stile hierarchicmaindiv, poi chiamo il log e successivamente proseguo attaccando gli eventi, in questo modo però in firebug mi trovo:
Per ogni log ho una riga che mi dice gli elementi selezionati, la cosa interessante è che se clicco sopra l’elemento, firebug mi porta immediatamente nel sorgente della pagina relativo all’elemento selezionato. Se invece mi posiziono con il mouse sopra l’elemento, firebug mi evidenzia nella pagina l’elemento selezionato.
Soprattutto agli inizi quando non si ha troppa familiarità con i selettori è fondamentale visualizzare cosa si è selezionato, la funzione log è quindi la soluzione migliore.
Alk.
Tags: jQuery