July 2007 - Posts
Come anticipato in questo post, ho scritto un semplice HttpHandler che costruisce il file XML sitemap rispondente alle specifiche Sitemap 0.90, basato sulla classe System.Web.SiteMap.
Per chi utilizza ASP.NET 2.0, può essere comodo implementare un HttpHandler che costruisca la sitemap a partire dal file con estensione .sitemap (utilizzato dalla classe System.Web.SiteMap). Tra l'altro, in caso di modifiche alla struttura del sito, si avrebbe in automatico la nuova sitemap, al massimo toccherà segnalarla nuovamente ai motori di ricerca.
Possiamo, inoltre, personalizzare il file .sitemap ed il codice dell'HttpHandler per fargli includere nella mappa del sito anche anche le pagine dinamiche.
Avevo già realizzato qualcosa del genere, pescando a piene mani da basandomi soprattutto su alcuni esempi di Andrea Boschin[1], come l'articolo indicato in questo post e il suo webcast su tecniche di Search Engine Optimization con ASP.NET 2.0.
Ho ripreso quel codice e guardando un po' in rete ho trovato che anche qualcun'altro ha già realizzato qualcosa del genere.
Vediamo pertanto come costruire l'HttpHandler.
Anzitutto bisogna considerare che il file .sitemap può contenere, per ciascun nodo, anche altri attributi personalizzati, che potremmo sfruttare per i nostri scopi.
Allora considerato un semplice sito web, possiamo scriverne il file Web.sitemap aggiungendo (facoltativamente) 3 parametri a ciascun nodo:
- LastChangeDate - rappresenta la data dell'ultima modifica della pagina, scritta secondo il formato W3C Datetime
- ChangeFrequency - è la frequenza stimata di modifica della pagina, può avere uno dei seguenti valori (autoesplicativi)
- always
- hourly
- daily
- weekly
- monthly
- yearly
- never
- Priority - è la priorità relativa della pagina, ossia quanto riteniamo importante quella pagina relativamente alle altre della sitemap, con valori da 0.0 a 1.0
Ad esempio un semplice file Web.sitemap
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns=http://schemas.microsoft.com/AspNet/SiteMap-File-1.0>
<siteMapNode url="~/Default.aspx" title="Home" description="Home Page">
<siteMapNode url="~/Profile.aspx" title="Profile" description="Company"/>
<siteMapNode url="~/Info.aspx" title="Info" description="Info"/>
</siteMapNode>
</siteMap>
diventa:
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/Default.aspx" title="Home" description="Home Page"
LastChangeDate="2006-04-26" Priority="0.9" ChangeFrequency="weekly" >
<siteMapNode url="~/Profile.aspx" title="Profile" description="Company"
LastChangeDate="2007-07-16T19:20:30+01:00" Priority="0.4"/>
<siteMapNode url="~/Info.aspx" title="Info" description="Info"
Priority="0.8" LastChangeDate="2007-07-16T19:20:40+01:00"
ChangeFrequency="yearly"/>
</siteMapNode>
</siteMap>
Si può realizzare un primo semplice HttpHandler con il codice seguente:
Namespace Handlers
Public Class SiteMapHttpHandler : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
Using writer As XmlWriter = _
XmlWriter.Create(context.Response.OutputStream)
writer.WriteStartElement("urlset", _
"http://www.sitemaps.org/schemas/sitemap/0.9")
Me.WritePageNode(writer, SiteMap.RootNode, _
context.Request.ApplicationPath)
writer.WriteEndElement()
End Using
End Sub
Private Sub WritePageNode(ByVal wr As XmlWriter, _
ByVal siteMapNode As SiteMapNode, ByVal appPath As String)
If siteMapNode IsNot Nothing Then
If siteMapNode.Url <> "" Then
SiteMapHttpHandler.WriteUrl(wr, siteMapNode)
End If
Dim child As SiteMapNode
For Each child In siteMapNode.ChildNodes
Me.WritePageNode(wr, child, appPath)
Next
End If
End Sub
Private Shared Sub WriteUrl(ByVal wr As XmlWriter, _
ByVal smp As SiteMapNode)
wr.WriteStartElement("url")
' parametro obbligatorio, presente come condizione per chiamare
wr.WriteStartElement("loc")
wr.WriteString(("http://www.miosito.it" & _
VirtualPathUtility.ToAbsolute(smp.Url)))
wr.WriteEndElement()
' parametri facoltativi, da controllare con delle regex
' sperando che siano giuste ;-)
Dim rx As Regex
rx = New Regex("^\d\d\d\d((-\d\d)|(-\d\d-\d\d(T\d\d\:\d\d(\:\d\d" & _
"(\.\d+)?)?(Z|(((\+)|(\-))\d\d\:\d\d)))?))?$", RegexOptions.Compiled)
If (smp.Item("LastChangeDate") <> "") AndAlso _
(rx.IsMatch(smp.Item("LastChangeDate"))) Then
wr.WriteStartElement("lastmod")
wr.WriteString(smp.Item("LastChangeDate"))
wr.WriteEndElement()
End If
rx = New Regex("^((always)|(hourly)|(daily)|(weekly)|(monthly)|" & _
"(yearly)|(never))$", RegexOptions.IgnoreCase Or RegexOptions.Compiled)
If (smp.Item("ChangeFrequency") <> "") AndAlso _
(rx.IsMatch(smp.Item("ChangeFrequency"))) Then
wr.WriteStartElement("changefreq")
wr.WriteString(smp.Item("ChangeFrequency").ToLower)
wr.WriteEndElement()
End If
rx = New Regex("^(0?\.\d)|((0|1)(\.0)?)$", RegexOptions.Compiled)
If (smp.Item("Priority") <> "") AndAlso _
(rx.IsMatch(smp.Item("Priority"))) Then
wr.WriteStartElement("priority")
wr.WriteString(smp.Item("Priority"))
wr.WriteEndElement()
End If
wr.WriteEndElement()
End Sub
Public ReadOnly Property IsReusable() As Boolean _
Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class
End Namespace
Basta registrare l'HttpHandler nel file web.config:
<httpHandlers>
<add path="sitemap.axd" verb="GET" type="Handlers.SiteMapHttpHandler"/>
</httpHandlers>
Il risultato è questo:
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.miosito.it/Default.aspx</loc>
<lastmod>2006-04-26</lastmod>
<changefreq>weekly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>http://www.miosito.it/Profile.aspx</loc>
<lastmod>2007-07-16T19:20:30+01:00</lastmod>
<priority>0.4</priority>
</url>
<url>
<loc>http://www.miosito.it/Info.aspx</loc>
<lastmod>2007-07-16T19:20:40+01:00</lastmod>
<changefreq>yearly</changefreq>
<priority>0.8</priority>
</url>
</urlset>
visualizzabile nel browser all'indirizzo http://www.miosito.it/sitemap.axd
Ovviamente tale file dovrà essere segnalato ai principali motori di ricerca e nel file robots.txt.
In un prossimo post proverò a personalizzare il codice per includere pagine generate dinamicamente.
View blog reactions
[1] Andrea Boschin ha da poco ricevuto il premio di MVP per ASP.NET. Quando l'ho saputo sono rimasto stupito, poiché ero convinto che lo fosse già da tempo, vista la qualità dei suoi interventi.
Le sitemap a cui ci si riferisce nel titolo servono ad informare i motori di ricerca su quali siano le pagine di un sito disponibili per la scansione e quindi per essere indicizzate. Contribuiscono, pertanto, ad un migliore posizionamento delle pagine del sito nei risultati delle ricerche.
Possono essere dei semplici file di testo, costituiti dall'elenco degli URL corrispondenti a ciascuna pagina. Oppure dei file XML, in cui ad ogni URL è possibile associare dei metadati, come la data dell'ultimo cambiamento, la frequenza con cui la pagina viene modificata o ancora l'importanza di tale pagina relativamente alle altre del sito.
Vagando per la rete mi sono imbattuto in questo post sul blog di Marco D'Angelo (che spesso si occupa di Community Server) e da lì ho appreso, con notevole ritardo[1], che Google, Yahoo e Live Search, ossia i più utilizzati motori di ricerca, supportano insieme lo stesso protocollo delle sitemap.
Un protocollo serve appunto a definire come deve essere fatto il file XML della sitemap, ed in genere dipende dallo specifico motore di ricerca. Quello descritto su sitemaps.org (Sitemap 0.90), per il fatto stesso di essere accettato e supportato dai prinicipali motori di ricerca, si propone come uno standard adottato a livello generale.
Chi come me utilizza ASP.NET 2.0 ha avuto a che fare con gli strumenti offerti dal framework per la navigazione del sito, come i comodi controlli Menu, SiteMapPath, ecc., basati sulla classe System.Web.SiteMap.
Per chi non lo sapesse, la classe System.Web.SiteMap contiene la rappresentazione della struttura di navigazione del sito, composta da una collezione gerarchica di nodi. A ciascun nodo corrisponde una pagina o una directory dell'applicazione. Il provider predefinito per questa classe è la classe XmlSiteMapProvider, che serve a recuperare le informazioni dalla sorgente dati, ossia, nel caso predefinito, da un file XML con estensione .sitemap (per approfondimenti si può partire da qui oppure da qui).
Può essere molto comodo, allora, riuscire a generare in automatico un file XML di sitemap, secondo le specifiche Sitemap 0.90, utilizzando la classe System.Web.SiteMap, eventualmente modificando il file .sitemap ed estendo il provider per SiteMap. E magari utilizzando un HttpHandler, ma questo sarà oggetto di prossimi post.
Technorati Tags:
sitemap,
asp.net,
seo View blog reactions
[1] La notizia risale al 15/11/2006
Ho appena finito l'upgrade di un notebook da XP a Vista. Sembra che tutto sia andato per il meglio, però mi era rimasto un piccolo problema, retaggio di un programmino per XP che lo rendeva graficamente simile a Vista. Avevo provveduto a disinstallare il programmino, ma l'icona dell'hard disk non risultava visibile. Non c'è però la possibilità di cambiare direttamente l'icona, né avevano effetto cambiamenti del tema.
Ho creato un collegamento all'hard disk e da lì ho potuto verificare che per l'icona si faceva riferimento ad un file non più esistente, poiché cancellato con la disinstallazione del programmino.
Cercando nel registro un riferimento a quel file ho trovato la chiave:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\DriveIcons
qui era specificata un'ulteriore chiave C e all'interno di essa il valore DefaultIcon con il percorso al file incriminato.
Per ripristinare il tutto è bastato eliminare la chiave DriveIcons. Probabilmente (ma non ho provato), si può fare anche il contrario, ossia aggiungere le chiavi ed un path ad un file .ico per impostare un'icona personalizzata per i drive.
Technorati Tags:
windows vista View blog reactions
In questo post Scott Guthrie illustra le nuove caratteristiche del debug di JavaScript in VS 2008 (anche nella versione Express), che semplificano significativamente la realizzazione di applicazioni web con AJAX.
Nello stesso post si trovano due link a post che spiegano come arrangiarsi se si usa VS 2005:
View blog reactions
Sto "usacchiando" Safari, da quando ho installato la 3.02 Beta si sta dimostrando stabile: non ho più sperimentato crash.
Le prime impressioni non sono ottime, ma neanche totalmente negative, anche se temo di essere poco obiettivo e condizionato ancora dalla pessime Beta 3 e Beta 3.01 (You never have a second chance to make a good first impression, figuriamoci alla terza).
Di seguito descrivo le mie impressioni analizzando nell'ordine i 12 punti che mi dovrebbero portare ad amare Safari, come illustrati sul sito.
- Prestazioni mozzafiato, a sua volta diviso in tre parti:
- lancio applicazione
probabilmente Superfetch si mette in mezzo per cui sul mio PC sia IE che Safari risultano veloci, ma il primo si avvia in meno tempo. Per una misura obiettiva dovrei usarlo per un po' di tempo alla pari e verificare quello che succede (troppo difficile...) - prestazioni html
Per quanto riguarda il caricamento delle pagine, non ho fatto misure, ma l'impressione è che Safari sia sensibilmente più veloce a visualizzarle. Non ritengo, tuttavia, che si tratti di un enorme vantaggio, poiché per questo aspetto influisce molto di più la larghezza di banda della connessione. - prestazioni javascript
Safari sembra più veloce anche per l'esecuzione di JavaScript, ma a parte l'impressione e un paio di test "ad occhio", non mi resta che fidarmi di quanto scritto sul sito, non avendo tempo di fare misure adeguate.
- Interfaccia utente elegante
L'interfaccia di Safari si presenta indubbiamente elegante e, di default, in una veste minimale. Sicuramente non è male, però appare un po' fuori contesto, come andare in un pub indossando un abito da sera. E mi disorienta un po', probabilmente perché ormai lavoro solo in ambienti Windows. Inoltre aggiungendo la barra dei tab e quella per la ricerca della pagina (vedi punti successivi 5 e 6) comincia a diventare meno minimalista.
Per quanto riguarda il rendering dei font, all'inizio la resa mi è sembrata proprio brutta. Però una volta abituato, devo dire che non è così male. Io continuo a preferire ClearType, però, sempre secondo i miei occhi (poco attendibili causa miopia), ho notato che da lontano si legge meglio in Safari che in IE.
Non tutti i siti vengono resi come in IE e Firefox, ma chissà di chi è la colpa. Purtroppo in Safari non funziona per niente Live Search, anzi il browser viene dirottato ad un altro URL (come pure in Opera). - Preferiti semplificati
Non ho provato Bonjour, per il resto niente di eclatante, un approccio leggermente diverso che può piacere come no. - Blocco finestre a comparsa
Ci sono ancora in giro browser che non bloccano i pop up? - Ricerca in linea
La ricerca all'interno della pagina appare subito molto carina: si digita nell'apposita casella e la pagina si oscura, lasciando in evidenza i risultati della ricerca. Dopo un po' di volte che la si usa, però, l'animazione sembra più un fastidio che una feature, ma anche qui può essere solo questione di abitudine. - Navigazione a pannelli
Chi non ce l'ha ancora? - SnapBack
Carino, comodo quando ci si perde nei meandri di un sito (io mi limitavo a troncare l'indirizzo per tornare all'home page). - Riempimento automatico moduli
Sinceramente non sono riuscito a provarlo, nel senso che non mi funziona. Ammesso che sia per colpa mia (non c'ho perso più di tanto tempo), non mi sembra comunque una feature innovativa. - RSS integrato
Anche qui funziona bene, ma non mi sembra una novità rispetto a quanto già si vede in giro. - Campi di testo ridimensionabili
Non so quanto possa essere utile la possibilità di ridimensionare i campi di testo su più righe, quando l'ho usata ho visto che spesso si incasina alquanto il layout della pagina. Comunque funziona. - Navigazione privata
Può essere comoda più che altro per computer pubblici o condivisi, per non lasciare tracce. Mi sembra anche più comodo di andare a cancellare a posteriori crononologia, moduli e file temporanei, finendo tra l'altro per cancellare tutto. Poiché non sembra una feature difficile da implementare, spero che sia "copiata" anche da altri. - Protezione
non ho fatto esperimenti per quanto riguarda la sicurezza, però da quello che ho letto e dalla velocità con cui Apple è stata costretta a due aggiornamenti in pochi giorni, l'impressione non è buona. Con lo sbarco su Windows la Apple non potrà più contare sulla security by minority e dovrà prestare più attenzione alla sicurezza. A meno che alla Apple non credano realmente a loro stessi quando dicono di ambire a conquistare rilevanti fette nel mercato dei browser.
Un ultimo appunto riguarda il motivo per cui ho installato Safari: per me è un'ottima cosa avere la possibilità di installarlo in ambiente Windows, così da poterci testare i siti su cui lavoro. Senza dover ricorrere a siti che fanno degli screenshot (lenti ed inutili per testare JavaScript ed Ajax). E senza essere costretto ad acquistare un Mac, che con un hardware più modesto (secondo alcuni) fa meglio di Vista, ma intanto questo hardware più leggero costa leggermente il doppio di un PC con Vista (cit. da paperino).
Purtroppo devo registrare che almeno per ora Safari per Windows non è la soluzione definitiva. Secondo quanto segnalato qui (grazie a Lorenzo Barbieri per il link), infatti, pare che ci siano dei problemi con il framework AJAX ASP.NET che si manifestano solo con Safari per Mac, mentre non ci sono in Safari per Windows, vanificando l'efficacia dei test. Speriamo che si risolva con la release definitiva (stiamo pur sempre parlando di una beta).
View blog reactions
Nel precedente post su Plugoo ho parlato della libreria JavaScript SWFObject. Questa piccola libreria consente l'inserimento di contenuto Adobe Flash in una pagina web attivo da subito, senza bisogno di click.
Ho scoperto questa libreria grazie ad una segnalazione di Paolo Ongari. Il suo post segnalava in realtà un controllo web che sfrutta la libreria swfobject.js, occupandosi di generare il codice JavaScript necessario. In questo modo è possibile utilizzare la libreria in ASP.NET senza scrivere una riga di codice JavaScript.
Per approfondimenti e per il codice sorgente (in C#): SWFObject Server Control for ASP.NET
View blog reactions
Si tratta di un gadget in flash che è possibile inserire in una pagina web (e quindi nel proprio blog).
Plugoo viene associato ad un account di IM e consente ad un visitatore della pagina di sapere se quell'account è on line e di contattarlo, come descritto qui. Il tutto senza rendere pubblico l'IM.
Per poter inserire Plugoo in una pagina, è necessario anzitutto creare un account sul sito e fornire il un contatto IM, potendo scegliere tra MSN Messenger, Yahoo Messenger, AIM, Google Talk, Jabber o ICQ.
Dopo aver espletato le solite formalità (e-mail di conferma con link), un nuovo contatto chiederà di essere aggiunto all'elenco dei contatti a cui consentire di inviare messaggi (ovviamente bisogna accettarlo). Inoltre verrà fornito il codice HTML da inserire nella pagina, del tipo:
<object type="application/x-shockwave-flash" id="plugoo"
data= "http://www.plugoo.com/plug.swf?go=ABCDEFGHIJ9"
width="160" height="300">
<param name="movie"
value= "http://www.plugoo.com/plug.swf?go=ABCDEFGHIJ9" />
<param name="allowScriptAccess" value="always" />
<param name="wmode" value="transparent" />
</object>
Sulla piattaforma di community server offerta da dotnetside, però, non è possibile inserire tale codice, poiché verrebbe codificato in HTML in questo modo:
<object type="application/x-shockwave-flash" id="plugoo"
data= "http://www.plugoo.com/plug.swf?go=ABCDEFGHIJ9"
width="160" height="300">
<param name="movie"
value= "http://www.plugoo.com/plug.swf?go=ABCDEFGHIJ9" />
<param name="allowScriptAccess" value="always" />
<param name="wmode" value="transparent" />
</object>
E quindi non sarebbe eseguito, ma solo visualizzato nella pagina.
L'unico punto a disposizione di un utente con restrizioni per inserire codice senza che venga codificato in HTML è la sezione raw headers della dashboard. Possiamo allora piazzare lì del codice JavaScript che si occuperà di inserire il nostro object nel DOM della pagina.
Visto che si deve scrivere comunque del codice JavaScript, perché non sfruttare la libreria JavaScript SWFObject? Oltre a facilitarci il compito, ci consente di evitare il noioso "clicca per attivare questo oggetto" al visitatore della pagina, unendo l'utile al "dilettante"
, come direbbe un mio amico.
Pertanto ho "appoggiato" una copia del file swfobject.js (su un qualsiasi spazio raggiungibile via web con URL) ed ho aggiunto al raw header il codice per includerla:
<script type="text/javascript" src="http://miospazioweb.it/swfobject.js" />
Sempre nella stessa sezione ho aggiunto la funzione JavaScript che svolgerà il compito di aggiungere l'oggetto flash al DOM:
<script type="text/javascript">
function AddPlugoo() {
var plugoo = new SWFObject('http://www.plugoo.com/plug.swf?go=ABCDEFGHIJ9',
'', '160', '300', '6', '');
with (plugoo) {
addParam('movie', 'http://www.plugoo.com/plug.swf?go=ABCDEFGHIJ9');
addVariable('allowScriptAccess', 'always');
addVariable('wmode', 'transparent');
write('plugoocontainer');
}
}
</script>
Perché lo script funzioni, è necesario inserire un tag div identificato dall'id "plugoocontainer" in un punto qualunque di una pagina web. Ad esempio, nella sezione news della dashboard di CS si può scrivere:
<div id="plugoocontainer" style="width: 160px; height: 300px;"></div>
La funzione deve essere chiamata necessariamente al termine del caricamento della pagina. Il div "plugoocontainer", infatti, potrebbe non essere stato ancora caricato nel browser, che darebbe errore e interromperebbe l'esecuzione del codice.
In pratica servirebbe scrivere nella pagina:
<body onLoad="AddPlugoo">
ma non potendo agire a questo livello, è necessario un altro po' di JavaScript (sempre nella sezione raw header della dashboard):
<script type="text/javascript">
if (window.attachEvent) {
window.attachEvent("onload", AddPlugoo);
} else {
window.addEventListener("load", AddPlugoo, false);
}
</script>
A questo punto, dopo aver salvato le impostazioni, nella pagina compare il riquadro con Plugoo. Si può anche notare che è già attivo, senza bisogno di cliccare una volta sull'oggetto.
Il tutto funziona senza problemi con IE6 e IE7, Firefox 2.0.0.4, Opera 9.21 e Safari 3.02 Beta.
P.S.: grazie a paperino per avermi segnalato Plugoo e a Vito per le dritte su CS e i test on line
View blog reactions
Qualche giorno fa ho scritto questo post sulla formattazione delle date in .NET, poiché ho sempre problemi a ricordarmi le giuste stringhe di formattazione.
A tal proposito, questo post di Scott Guthrie segnala un comodissimo cheatsheet PDF da scaricare in cui ci sono tutte le possibili stringhe di formattazione (standard e custom) per numeri e date in .NET.
Sempre dello stesso autore, qui è possibile trovare altri utili cheatsheet in PDF per .NET
Technorati Tags:
.net,
asp.net View blog reactions
Stamattina stavo effettuando per conto di un mio cliente l'installazione di un software che prevede una modulo server e più moduli client su diversi PC all'interno della stessa LAN. Poiché i PC su cui effettuare l'installazione hanno tutti come sistema operativo Windows Vista Home Premium ed ero stato preavvisato da un collega su possibili problemi di compatibilità, ho chiamato l'Help Desk di chi produce il software per chiedere lumi. Ebbene, la risposta è stata: "Per la parte client non ci sono problemi, mentre per quanto riguarda il server, Vista non è ancora compatibile con il nostro software".
Questo fa il paio con quanto mi è stato detto un paio di mesi fa da un operatore dell'assistenza Telecom Italia, dopo che un tentativo di installazione del modem ADSL fornito da Telecom usando il CD allegato aveva provocato un BSOD su Vista: "Vista non è ancora pronto per il nostro modem".
(BTW, secondo voi perché Telecom Italia ha scelto di utilizzare i "bellissimi" e "versatili" modem Pirelli? per le prestazioni elevate, per i bassi costi o forse c'è qualche altra spiegazione?)
Che dire, magari hanno ragione loro. Come sviluppatore non potrei che rallegrarmene: mi basta che il software che scrivo sia certificato "It works on my machine" o "It works by accident", invece che perdere tempo con specifiche e altra robaccia (tra l'altro neanche tanto nuova). Se poi sul PC del cliente non va, che faccia ricorso a Microsoft che non ha adeguato il suo SO al mio software.
View blog reactions