settembre 2007 Entries
A tool to manage your blog categories and Technorati Tags

When I first decided to have a blog, I didn't have a clear idea of what I was going to talk about. It was supposed to be focused on .Net and programming topics, indeed, but figuring out a list of categories having only this in mind was extremely hard. I think that a lot of bloggers had (and keep having) the same experience and, sudden or later, almost everyone comes to the need to re-arrange post categories.

Things get much more complicated when you decide to start Technorati-tagging your post: doing it post per post is pretty easy, just a matter of adding a couple of links. Some WLW plugins can be helpful to mantain a certain coherence on the keywords you are tagging, but what about the old posts? Can you figure out how boring and time consuming tagging old posts can be? I'm sure you can. I tried to do that job, giving up just some minutes after and deciding that I did need a tool to deal with it.

Though, I made Blog Manager (if you have a better name to suggest, please do it, I know that "Blog Manager" is simply awful smile_teeth) which uses MetaWeblog API to interact with blog engines and let you arrange Categories and Technorati tags with all those fancy features a Windows Explorer-like UI has, like multiple selection.

All you need to do is setting up your connection credentials

fetch some posts from your blog

and change categories and tags using multi-selection on the listview and three-state CheckBoxLists on the left

After your work is done, just press the Save button on the toolbar to update your blog.

An important reminder: Technorati Tags feature use regular expressions to extract keywords from each post body. Although both I and my friend Simone Chiaretta did many tests and it seems to work as expected, be aware that it can potentially mess your post text. So, please, do a backup of your blog data (there's a built in backup/restore feature in Blog Manager too) before using it.

Oh... and please always remember that...

This application is provided as is. The copyright holder cannot be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.

Here you can find both source code (in VS2008 beta 2 format) and executables.

EDIT: This project has been moved to Google Code and renamed as Blog Commander

Technorati tags: ,
6 Comments Filed Under [ .Net 3.5 ]
[SOLVED] SubText e blocchi di Internet Explorer 7

Molti si sono lamentati di blocchi a IE7 visitando le pagine del mio blog. Chiedo scusa a tutti per il disagio, purtroppo non è stato semplice capirne l'origine.

Ho provato a togliere quanto di personalizzato avessi inserito, Script, HTML e CSS, ma IE7 andava in crash ogni qual volta visualizzassi un singolo post.

Ho cercato un po' su Google e ho visto che qualcun altro aveva il mio stesso problema, e finalmente mi sembra di aver risolto: *disabilitate la funzione CoComments* e non beccherete più maledizioni dai vostri lettori.

E comunque... cosa diavolo sono i CoComments??????

4 Comments Filed Under [ Misc ]
Volete organizzare tutti i Technorati Tags in pochi minuti?

Bene, allora la nuova versione di Blog Manager (il nome è uno schifo, lo so) fa per voi! Qualche post fa, se ricordate, vi ho raccontato di un piccolo tool realizzato dal sottoscritto che, grazie ad un'interfaccia simil-Explorer, consente di riorganizzare velocemente tutte le categorie del blog facendo uso dei MetaWeblog API.

Mi è sembrato così comodo che, dopo essere stato lì a compiacermi come un fesso (e senza cambiare le categorie), mi son detto: "ma perchè non fare lo stesso anche per i Technorati Tags, che son così pallosi da inserire nei post vecchi che ne sono sprovvisti? In questo modo potrei sfoggiare una rigogliosa Tag Cloud e il mondo sarebbe finalmente mio!!"

Da questo vero e proprio documento dei requisiti, ho partorito la versione 1.1, che offre uno stupendo e alquanto esplicativo Tab

Come funziona? Selezioniamo nella toolbar il numero di post da scaricare e poi click sul pulsante Download.

A quel punto, grazie ad una serie di Regex, tutti i tag contenuti nei post scaricati verranno elencati nella CheckedListBox in basso, mentre i post appariranno nella ListView a destra, con tanto di Tooltip con il contenuto.

Ora basta selezionare un po' di post, e spuntare i checkbox relativi ai tag desiderati e poi premere il button Salva sulla Toolbar in alto.

Attenzione! A differenza delle categorie, la funzione dei Technorati Tags lavora per forza di cose tramite regex, perchè devono essere estratte dal body del post; pertanto potrebbe esserci un certo margine di errore nel match del pattern utilizzato. Io l'ho provato in diversi casi e lo stesso ha fatto il bravo Simone Chiaretta che mi ha dato una mano con i test, e non abbiamo evidenziato problemi. Sarebbe comunque opportuno effettuare un backup dei post per sicurezza. Per chi, come me, ha un blog su uno spazio condiviso e non ha accesso al database, ci sono due alternative

  1. Se si utilizza Subtext, esportare i post su BlogML tramite l'apposita funzione nella sezione Admin;
  2.  Utilizzare le funzionalità di Backup e Restore (quest'ultimo spero di no smile_teeth) che si trovano in Blog Manager nel menu Tools.

Ovviamente, come per la volta precedente, vale la seguente regola ferrea:

Questo software è rilasciato gratuitamente "AS IS". L'autore (cioé il sottoscritto) non è in alcun modo tenuto a fornire assistenza né tantomeno potrà essere ritenuto responsabile per eventuali problemi inerenti il suo utilizzo. In altre parole, se vi si sminkia (questa volta con la "K") totalmente il blog o il sistema operativo, se un hacker accede al vostro conto in banca, ecc.ecc., non bussate alla mia porta!

E chi non è d'accordo, eviti di utilizzarlo. Cosa manca? Ah sì, i link: qui per i sorgenti (rigorosamente Visual Studio 2008 ma su .NET 2.0) e qui l'eseguibile.

Ogni feedback è prezioso come un litro di birra ghiacciata nel deserto.

Ciao smile_wink

Technorati tags: ,
LINQ = Expression Trees

Quando scriviamo interrogazioni con LINQ, non dobbiamo mai perdere di vista ciò che in realtà esse sono, ossia alberi di funzioni e Lambda expression. Per questa ragione, un qualcosa come

1 var customers = db.Customers 2 .Where(c => c.CompanyName.StartsWith("A")) 3 .Join(db.Orders, 4 (c => c.CustomerID), 5 (o => o.CustomerID), 6 (c, o) => new { c, o }) 7 .Where(co => co.o.ShippedDate != null) 8 .Select(co => co.c).Distinct();

è, grazie a puro syntactic sugar, equivalente a

1 var customersLinq = (from c in db.Customers 2 join o in db.Orders 3 on c.CustomerID equals o.CustomerID 4 where c.CompanyName.StartsWith("A") && 5 o.ShippedDate != null 6 select c).Distinct();

Lo snippet di cui sopra infatti, non è altro che un modo leggibile per disegnare un Expression Tree. Questo concetto, che può sembrare un internal come un altro e quindi generare dei "chi se ne frega" allo stesso modo di un trattato sulle tradizioni popolari indocinesi, ha in realtà un peso determinante almeno per un paio di ragioni.

Intanto l'elaborazione non viene eseguita finchè non si cicla sul resultset; e questo, nel caso di LINQ to SQL, tanto per fare un esempio, vuol dire che finché non scriviamo

1 foreach (var item in customers) 2 { 3 Console.WriteLine(item.CompanyName); 4 }

non parte nessuna query verso il DataBase.

Inoltre, e anche in virtù anche del punto precedente, le interrogazioni LINQ possono essere concatenate tra di loro:

1 var customersStartingWithA = from c in db.Customers 2 where c.CompanyName.StartsWith("A") 3 select c; 4 5 var customersWithUnshippedOrders = (from c in customersStartingWithA 6 join o in db.Orders 7 on c.CustomerID equals o.CustomerID 8 where o.ShippedDate != null 9 select c).Distinct();

L'esempio, relativo a LINQ to SQL, genera questa query SQL:

SELECT DISTINCT [t0].[CustomerID], .... FROM [dbo].[Customers] AS [t0] INNER JOIN [dbo].[Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID] WHERE ([t1].[ShippedDate] IS NOT NULL) AND ([t0].[CompanyName] LIKE @p0)

che condensa perfettamente il concetto che siamo riusciti a scindere nelle due più semplici interrogazioni. Ah, attenzione che non sempre l'engine di LINQ to SQL è così smart, alle volte vengono fuori query innestate non da poco smile_teeth

Ovviamente quanto detto è uno dei fondamenti della stessa tecnologia LINQ, pertanto non è limitata solo a LINQ to SQL, ma a tutte le possibili incarnazioni che essa ha all'interno di .Net 3.5.

Technorati tags: ,
Add Comment Filed Under [ .Net 3.5 ]
Un sito dove testare al volo le Regular Expression

Ce ne sono parecchi, questo mi è piaciuto particolarmente perchè usa AJAX per visualizzare in real-time i match.

Technorati tags:
Add Comment Filed Under [ Misc ]
Tre cosine che mi sono piaciute poco di LINQ to SQL

Ieri ne ho parlato tessendone le lodi, perchè tutto sommato reputo LINQ un buon ORM, che forse però soffre di qualche peccato di gioventù. Visto che per natura sono un po' rompiballe e non mi accontento mai, infatti, vi vengo a raccontare un paio di aspetti (anzi tre) che mi sono subito saltati all'occhio e che non mi sconfinferano granché.

Punto 1

Le entity (generate da un'ottimo designer, poco da dire) non sono serializzabili a causa delle dipendenze da EntitySet e EntityRef. Si tratta di una brutta limitazione, che non mi permette di esporle direttamente MBV con Remoting, tanto per fare un esempio, non mi permette di memorizzarle in un Session Server, non mi permette di scriverle nel ViewState se mi voglio fare del male (o se non lo memorizzo in pagina smile_wink) and so on...

Punto 2

Le query SQL prodotte sono a volte di dubbia ottimizzazione. Se ad esempio scrivo

1 var orders = from o in Orders where o.Customer.Id == 5;

LINQ mi spara una bella JOIN tra la tabella degli ordini e quella dei clienti, mentre invece la condizione potrebbe essere posta utilizzando esclusivamente la prima (come fa NHibernate):

SELECT [t0].[OrderID], ... altri fields ... FROM [dbo].[Orders] AS [t0] LEFT OUTER JOIN [dbo].[Customers] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID] WHERE [t1].[CustomerID] = @p0

Per ovviare a questo problema, l'unico modo è esporre una proprietà CustomerID anche nella classe Order, come d'altronde fa per default il designer. "Stilisticamente" non è il massimo, ma quantomeno, se generiamo il codice da designer di Visual Studio, il setter della proprietà CustomerID solleva un'eccezione se proviamo ad impostarne un valore diverso da quello di Order.Customer.ID.

Punto 3

Piccola premessa: in LINQ to SQL ogni associazione è lazy by design (ed è una best practice); ma attenzione a chiamare la Dispose di un oggetto DataContext se gli oggetti recuperati con esso non sono stati completamente inizializzati. Consideriamo ad esempio questo metodo:

1 public Customer GetCustomerById(int id) 2 { 3 using (MyDomainDataContext db = new MyDomainDataContext()) 4 { 5 // Recupero il customer dato il suo Id, ma attenzione: 6 // la collection customer.Orders è lazy loaded e quindi 7 // sarà inizializzata solo al primo accesso 8 return db.Customers.First(c => c.Id == id); 9 } 10 }

Ora, dato che la collection Orders, ancora non inizializzata, ha al suo interno una reference a *quello specifico* DataContext che l'ha creata; pertanto, accedere alla proprietà Orders al di fuori di questo metodo causerà una ObjectDisposedException. Fin qui me l'aspetto e lo trovo anche giusto. Attenzione però che, anche agganciando quel customer ad un altro DataContext tale reference non viene aggiornata e quindi si otterrà comunque un'eccezione.

Technorati tags: ,
Add Comment Filed Under [ .Net 3.5 ]
Pensierini della sera su LINQ to SQL

In questi giorni sto spulciando un pochino questo ORM e fino ad ora le mie impressioni sono senz'altro positive; LINQ to SQL, a mio modo di vedere, è un prodotto che ha dalla sua un'estrema produttività, almeno per un paio di ragioni:

  1. Intanto l'ottima integrazione con il designer di Visual Studio, che si interfaccia con la base dati e ci consente di modellare il dominio applicativo veramente in brevissimo tempo: la comodità del designer del DataSet applicata ad un Domain Model + ORM, praticamente il mio sogno smile_teeth
  2. La semplicità e la naturalezza di LINQ come linguaggio di interrogazione, che ci consente di comporre (già, comporre, magari ne parlerò in un altro post) query complesse in maniera estremamente intuitiva e soprattutto strong typed (anche se alle volte si è costretti a smanettare con le lambda expression).

Ora.. è vero che il dominio viene "sporcato" dagli attributes, che c'è EntitySet per le collection e non una semplice interfaccia e che NHibernate rullezza, ma il mio pensiero in merito è più o meno "chi se ne frega" smile_teeth

Giuro che non avrei mai pensato di scrivere quel "chi se ne frega" di una riga fa, ma c'è una ragione: credo che LINQ to SQL sia, al giorno d'oggi, una soluzione estremamente valida per tutte quelle applicazioni - e sono tante - che difficilmente vedranno una versione 2.0. Per questa ragione un paragone con NHibernate è un pochino fuorviante e mal posto: il target è diverso, al massimo paragoniamolo ad Active Record e comunque consideriamolo un ORM dall'approccio molto più easy e anche parecchio RAD. Questo giustifica anche il punto 1 in alto, che magari avrà fatto storcere il naso a quanti, come il sottoscritto d'altronde, sono convinti che le entity di dominio vadano modellate a prescindere dallo schema del database.

Ovviamente non è tutto rose e fiori, ci sono aspetti che non mi hanno convinto fino in fondo, ma di questo scriverò (spero di averne il tempo) domani.

Technorati tags: , ,
One Comment Filed Under [ .Net 3.5 ]
Un semplice tool per gestire le categorie sul blog

Ne avevo parlato un paio di giorni fa. Vorrei riorganizzare le categorie sul mio blog, eliminando quelle poco usate ed assegnando i relativi post ad altre (nuove e non), ma sono sempre stato frenato dal fatto che farlo il manager web può essere veramente noioso ed estenuante.

Domenica scorsa allora, con un po' di tempo libero, mi sono messo a realizzare una semplice applicazione Windows Forms che, facendo uso delle MetaWeblog API, semplificasse di molto il lavoro; fatto sta che ho prodotto questa cosina qui:

1) Dopo aver configurato le impostazioni di accesso dal menu opzioni...

2) è possibile visualizzare le categorie e recuperare un certo numero di post dal proprio blog

A questo punto, grazie anche alle possibilità di filtro e di selezione multipla, è facile e veloce modificare le associazioni Post-Categorie nella CheckBoxList a sinistra.

Una nota importantissima:

Questo software è rilasciato gratuitamente "AS IS". L'autore (cioé il sottoscritto) non è in alcun modo tenuto a fornire assistenza né tantomeno potrà essere ritenuto responsabile per eventuali problemi inerenti il suo utilizzo. In altre parole, se vi si sminchia totalmente il blog, il sistema operativo, se un hacker accede al vostro conto in banca, ecc.ecc., non bussate alla mia porta!

Ciò detto, a questo link trovate i sorgenti.

Ah.. per inciso, le mie categorie sono ancora lì dov'erano smile_teeth

Technorati tags: ,
4 Comments Filed Under [ Misc .Net 3.5 ]
XML-RPC e .NET

La scorsa domenica ho dedicato un paio d'ore di tempo alla realizzazione di un piccolo tool per la gestione delle categorie sul blog, di cui parlerò più approfonditamente tra un paio di giorni (appena riesco ad ultimarlo).

Come sa chiunque utilizzi abitualmente Windows Live Writer, SubText, il vecchio .Text e altri blog engine espongono una serie di servizi remoti chiamati MetaWeblog API (qui un piccolo white paper), raggiungibili all'URL

http://[blogurl]/services/metablogapi.aspx

Il protocollo utilizzato è XML-RPC (qui maggiori informazioni) ed è basato su uno standard di comunicazione estremamente più semplice dei Web Service tradizionali. Non trattandosi di SOAP, però, essi non sono direttamente utilizzabili all'interno di un'applicazione .NET tramite l'introduzione di una Web Reference.

Come fare dunque? Beh, Windows Live Writer ha un suo provider interno di interfacciamento; io, per evitare di riscrivere tutto, ho usato XML-RPC.Net, che è gratuito e funziona benone.

Per utilizzarlo è sufficiente creare un'interfaccia con i metodi desiderati, che devono essere poi mappati sulle corrispondenti procedure esposte dal servizio tramite un custom attribute:

1 public interface IMyService : IXmlRpcProxy 2 { 3 [XmlRpcMethod("nomeDelMetodoRemoto")] 4 string RemoteMethodThatReturnsAString(int parametro1, MyType parametro2); 5 }

Nel caso in cui i tipi coinvolti (siano essi parametri o valori di ritorno) siano tipi complessi, come MyType nello snippet precedente, è sufficiente definire opportune struct, avendo cura di esporne i relativi membri come field pubblici:

1 public struct MyType 2 { 3 public int booleanField; 4 public string stringField; 5 public OtherType complexField; 6 }

A questo punto, per invocare il servizio è sufficiente costruire un proxy ed eseguirne i metodi:

1 IMyService proxy = XmlRpcProxyGen.Create<IMyService>(); 2 proxy.Url = "http://urldelserivizio"; 3 string res = proxy.RemoteMethodThatReturnsAString(...parametri...);

La generazione dinamica del proxy avviene tramite Reflection.Emit, ed è quindi piuttosto veloce. A questo link trovate un esempio di utilizzo di XML-RPC.Net proprio per invocare le MetaWeblog API.

Sciaooo :-)

Technorati tags:
Add Comment Filed Under [ .Net 2.0 ]
Linq e Reflector

Il più grande punto di forza di Microsoft LINQ è senza dubbio quel syntactic sugar che ci permette di scrivere query simil-SQL, strong typed e direttamente all'interno del codice C# (o VB.NET che sia).

Supponiamo di voler recuperare, dagli assembly in memoria, l'elenco delle classi che iniziano per una data lettera. In C# 3.0 posso scrivere qualcosa tipo

   1:  var types =
   2:      from assembly in AppDomain.CurrentDomain.GetAssemblies()
   3:      from type in assembly.GetTypes()
   4:      where type.Name.StartsWith("C") && type.IsClass
   5:      select new { Namespace = type.Namespace, Name = type.Name };
   6:   
   7:  foreach (var type in types)
   8:  {
   9:      Console.WriteLine("{0} \t {1}", type.Namespace, type.Name);
  10:  }

In realtà, ciò che avviene under the hood, è che il compilatore si fa carico di trasformare codice di questo tipo in qualcosa che sia traducibile in IL, facendo uso intensivo di extension methods, anonymous types, ecc.

Il risultato di tutto ciò è che, disassemblando quanto compilato con Reflector, ciò che ci si trova davanti è qualcosa del tipo...

Reflector disassemble

Morale: da domani, attenzione ad aver sotto mano anche i sorgenti veri e propri, perché Reflector da solo non basterà più.

Technorati tags: ,
Add Comment Filed Under [ .Net 3.5 ]