• Come un abito cucito su misura, i nostri progetti software uniscono le potenzialità di tecnologie innovative alle specifiche esigenze del cliente.

    Showcase progetti
  • Analizziamo e razionalizziamo con il cliente i processi e le attività della propria azienda, per poi seguirlo nella scelta delle giuste strategie IT da adottare.

    Le nostre competenze
  • Crediamo nelle potenzialità di un percorso formativo che unisca forti basi teoriche e metodologiche ad una continua applicazione pratica di quanto si apprende.

    Dettaglio dei corsi
  • Progettiamo e sviluppiamo sistemi e progetti basati su dispositivi mobile consumer (iPhone, Windows Phone 7 Series), industriali (Windows CE) e custom (basati su microcontrollori 8/16/32 bit).

    Approfondimenti
 

Esportare gli sms di iPhone con Entity Framework, SQLite e FileHelpers

March 31, 2010 11:13 by M.Poponi

Domenica scorsa ho avuto bisogno di esportare in un file gli SMS presenti nel mio fido iPhone. "Niente di più semplice", ho pensato, abituato alla Nokia PCSuite, "ci sarà una comoda funzione di iTunes che lo fa".

Errore.

iTunes non permette di esportare gli SMS presenti nell'iPhone! cercando un po' su google, ho trovato una schiera di programmi non free che lo fanno, addirittura alcuni siti che lo fanno online, entrambe le soluzione inaccettabili: non ho voglia di spendere soldi per una funzione che dovrebbe essere fornita gratuitamente e non ho voglia di uploadare i miei SMS personali su un sito che non conosco. Mi sono un po' documentato, ho scoperto qualcosa di utile e ne è uscita fuori un'applicazioncina che esporta gli sms e un'esperienza didatticamente interessante.
Ecco come ho fatto.
Premessa: Non è possibile estrarre gli SMS direttamente da un iPhone (legalmente). Quel che si deve fare è passare per il backup di iTunes.

I passi:

1) backuppare l'iphone con iTunes

2) andare sulla cartella %appdata%\Apple Computer\MobileSync\Backup\

3) c'è una sola cartella qui dentro, chiamata con un numero GUID-like. esplorare questa cartella, e individuare due files: 3d0d7e5fb2ce288813306e4d4636395e047a3d28.mddata è un db SQLite che contiene gli SMS 31bb7ba8914766d4ba40d6dfb6113c8b614be442.mddata è un db SQLite che contiene i contatti

4) utilizzare un qualche strumento SQLite che permette di leggere i db. Vi consiglio http://code.google.com/p/sqlite-manager/, una utilissima estensione per FireFox.

Il primo DB ha una tabella, message, che contiene i veri e propri SMS. La struttura di tale tabella è:

 messages

i campi più interessanti sono:

address: contiene il numero di telefono da cui/ verso il quale è stato inviato l'sms
date: timestamp UNIX della data di invio
flags: 2 se è un SMS in ingresso, 3 se è un SMS in uscita
text: il testo del messaggio

5) se invece dei numeri di telefono vogliamo sapere il nome dei contatti con cui abbiamo scambiato gli sms, occorre aprire l'altro DB. questo basterebbe per esportare gli SMS. contacts

 

In ABPerson troviamo tutti i nostri contatti, in ABMultivalue i numeri di telefono (e altre info), facendo la join ABMultivalue.record_id=ABPerson.ROWID.

 

Tra l'altro lo stesso sqlite manager può esportare i dati contenuti nella tabella, ma noi siamo sviluppatori, quindi facciamo un'applicazioncina! 

 

Strumenti:

1) volendo utilizzare per l’accesso ai dati Entity Framework, ho dovuto cercare un provider di accesso a SQLite che lo supportasse.  La scelta è caduta su System.Data.SQLite: http://sqlite.phxsoftware.com/ 

2) volendo esportare i dati, ho optato per un vecchio amore che mi ha fatto risparmiare innumerevoli ore di lavoro negli anni: FileHelpers

L’applicazione:

La realizzazione dell’applicazione è stata davvero istantanea:

1) Ho installato System.Data.SQLite

2) Ho creato un’applicazione Winforms, aggiunto i riferimenti a System.Data.SQLite, System.Data.SQLite.Linq e FileHelpers

3) Ho aggiunto al server explorer due connessioni di tipo SQLite ai due files/db di cui abbiamo parlato sopra

4) Ho creato due modelli di Entity Framework: Entities che contiene le tabelle relative agli SMS e Contacts che contiene, be’… lo avete capito.

5) Nella form principale ho aggiunto una lista che conterrà i contatti (lbContacts), un Menu per le funzionalità di esportazione, una DataGridView per contenere i messaggi.

6) Ho scritto una classe per trasportare i dati dei contatti:

   1: public class PersonDTO
   2:   {
   3:       public string Person { get; set; }
   4:        
   5:       public string Address{ get; set; }
   6:       
   7:   }

7) Una semplice funzioncina che all’avvio carica i dati dei contatti che hanno SMS, ripulisce i numeri di telefono da ‘+’ e spazi, estrae i nomi e li mette nella ListBox:

   1: public void LoadAddressess()
   2:        {
   3:            Entities ent  = new Entities();
   4:            var addresses = (from  m in ent.message select  new {address= m.address.Replace(" ","").Replace("+","")}).Distinct();
   5:  
   6:            Contacts cont = new Contacts();
   7:            var numbersContacts = from d in cont.ABPerson
   8:                                  join v in cont.ABMultiValue on d.ROWID equals v.record_id
   9:                                   select new {person = (d.First??"") + " " + (d.Last??""), number = v.value.Replace(" ","").Replace("+","")};
  10:  
  11:                              
  12:  
  13:            var smartAddresses= from nc in numbersContacts.ToList() join m in addresses.ToList()
  14:                                                           on nc.number equals m.address
  15:                                                           select new PersonDTO() {Person=nc.person , Address=m.address}
  16:            ;
  17:            lbAddresses.DisplayMember = "Person";
  18:            lbAddresses.DataSource = smartAddresses.ToList();
  19:             
  20:        }
  21:        private void Form1_Load(object sender, EventArgs e)
  22:        {
  23:            LoadAddressess();
  24:  
  25:  
  26:        }

 

8) Ho creato un DTO per contenere gli SMS:

   1: [FileHelpers.DelimitedRecord("|")]
   2:    public class SMSDTO
   3:    {
   4:        private string numero;
   5:        private string inOut;
   6:        [FileHelpers.FieldConverter(FileHelpers.ConverterKind.Date,"dd-MM-yyyy HH:mm:ss")]
   7:       
   8:        private DateTime dataOra;
   9:        private String testo;
  10:       
  11:    public string Numero
  12:        {
  13:            get { return numero; }
  14:            set { numero = value; }
  15:        }
  16:        public DateTime DataOra
  17:        {
  18:            get
  19:            {
  20:                return dataOra;
  21:            }
  22:            set { dataOra = value; }
  23:        }
  24:  
  25:        public string Testo
  26:        {
  27:            get { return testo; }
  28:            set { testo = value; }
  29:        }
  30:  
  31:        public string InOut
  32:        {
  33:            get { return inOut; }
  34:            set { inOut = value; }
  35:        }
  36:  
  37:       
  38:    }

 

Tanto che c’ero :) ho aggiunto due attirbuti che dicono a FileHelpers che voglio esportare i dati in un file a campi delimitati dal pipe (‘|’) e che voglio che la data sia nel formato italiano.

 

9) A questo punto è banale scrivere una funzioncina che ottiene gli SMS relativi al numero selezionato nella lista, e una che invece ottiene tutti gli SMS

   1: public IEnumerable<SMSDTO> GetSelectedSms()
   2:         {
   3:             Entities ent = new Entities();
   4:             string address = ((PersonDTO) lbAddresses.SelectedItem).Address;
   5:             var messages = (from m in ent.message where m.address.Replace(" ", "").Replace("+", "") == address select new {m.address, m.date, m.text, m.flags });
   6:  
   7:             return from m in messages.ToList()
   8:                    select
   9:                        new SMSDTO()
  10:                            {
  11:                                Numero =m.address,
  12:                                DataOra   = ConvertTimestamp((double) m.date),
  13:                                Testo = m.text,
  14:                                InOut = m.flags == 2 ? "in " : "out"
  15:                            };
  16:         }
  17:         public IEnumerable<SMSDTO> GetAllSms()
  18:         {
  19:             Entities ent = new Entities();
  20:             
  21:             var messages = (from m in ent.message  select new { m.address, m.date, m.text, m.flags });
  22:  
  23:             return from m in messages.ToList()
  24:                    select
  25:                        new SMSDTO()
  26:                        {
  27:                            Numero = m.address,
  28:                            DataOra = ConvertTimestamp((double)m.date),
  29:                            Testo = m.text,
  30:                            InOut = m.flags == 2 ? "in " : "out"
  31:                        };
  32:         }

le date devono essere convertite da Unix ad un formato più maneggevole, per questo basta una funzioncina semplice semplice:

   1: private static DateTime ConvertTimestamp(double timestamp)
   2:   
   3:      {
   4:   
   5:          return (new DateTime(1970, 1, 1, 0, 0, 0, 0)).AddSeconds(timestamp).ToLocalTime();
   6:  
   7:      } 

10) A questo punto basta solo collegare il binding della DataGridView al cambio di selezione della lista per vedere i dati,

   1: private void lbAddresses_SelectedIndexChanged(object sender, EventArgs e)
   2:       {
   3:           IEnumerable<SMSDTO> SMS = GetSelectedSms();
   4:  
   5:           dgvMessages.DataSource = SMS.ToList();
   6:       }

e collegare il click di due voci di menu per esportare i dati selezionati o tutti i dati in un file, con l’incredibile FileHelpers:

   1: private void exportSelectedToolStripMenuItem_Click(object sender, EventArgs e)
   2:        {
   3:            ExportSMS( GetSelectedSms()  );
   4:        }
   5:        private void exportAllToolStripMenuItem_Click(object sender, EventArgs e)
   6:        {
   7:            ExportSMS(GetAllSms());
   8:        }
   9:  
  10:  
  11:        private void ExportSMS(IEnumerable records)
  12:        {
  13:            FileHelpers.DelimitedFileEngine engine = new DelimitedFileEngine(typeof(SMSDTO));
  14:            SaveFileDialog sfd= new SaveFileDialog();
  15:            sfd.DefaultExt = ".csv";
  16:            sfd.FileName = "export.csv";
  17:            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  18:            { 
  19:                engine.WriteFile(sfd.FileName,records);
  20:            }
  21:        }

e abbiamo finito!

Conclusioni:

Abbiamo visto come sia possibile utilizzare Entity Framework con SQLite in modo semplice ed efficace, come l’esportazione su file sia immediata con FileHelpers e come questo possa essere utilizzato per l’esportazione dei propri SMS da un backup iPhone.

Buon divertimento!!!


Currently rated 4.7 by 3 people

  • Currently 4.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Logging delle eccezioni con ELMAH, un’introduzione

December 15, 2009 18:04 by M.Poponi

C'è solo una cosa di cui siamo sicuri quando scriviamo un qualunque software: prima o poi accadrà un'eccezione.
Accadrà perchè il software senza bachi non esiste, o perché la bella ma imprevedibile sistemista ha spento il DB, o solo perché l'utente ne sa una più del diavolo.
Gestire le eccezioni a volte non basta, o semplicemente ci è sfuggito quel caso, quel try, quell'inezia che dalla pancia del nostro programma rimbalza direttamente in faccia all'utente. Con la temuta paginona di errore di ASP.NET.
E' necessario quindi, specialmente in ambito web, avere una strategia un po' più sofisticata della semplice pagina di errore di .NET per la gestione o, almeno, per la rendicontazione e la registrazione di quanto è successo. Per capire dove, a chi e possibilmente, perché.
In questo post introdurremi i primi rudimenti dell'utilizzo di un tool open source, ELMAH, che ha come scopo proprio questo: fornire un framework semplice, potente e versatile per il logging e l'archiviazione delle eccezioni generate da un software ASP.NET.
In breve, le features principali di ELMAH sono
-logging automatico delle eccezioni non gestite
-logging delle eccezioni segnalate
-filtraggio delle eccezioni loggate
-utilizzo non intrusivo: basta aggiungere le dll di supporto, modificare il web config della nostra applicazione, e il gioco è fatto
-logging su diversi media: in RAM, su SQL server, Oracle, Acess, sql lite, XML...
-notifiche email degli errori
-report automatico: una pagina web permette di vedere la lista degli errori, i dettagli e persino la pagina errore originale.
-feed RSS degli errori, post su twitter (!) delle eccezioni

Per illustrare l'uso di questo semplice quanto potentissimo componente la cosa migliore è installarlo ed usarlo passo passo. Allegato a questo post trovate il semplice progetto ASP.NET 3.5 che andremo a costruire. Potete scaricare il progetto cliccando qui.

 

1) creiamo una semplice applicazione Web.


l'applicazione avrà una pagina con tre buttons e un link. 
Il primo bottone creerà un'eccezione di index out of bounds, non gestita. Questo è un errore tipico che magari può sfuggirci e, per i motivi più vari, non essere gestito e "finire" in faccia all'utente.

Il secondo istanzierà una classe contenuta in una class library, tenterà l'accesso ad un db utilizzando una stringa di configurazione errata, con eccezione non gestita. Anche in questo caso vedremo come l'eccezione verrà salvata.
Il terzo bottone tenterà anch'esso l'accesso al db, ma l'eccezione verrà gestita. Vedremo come registrare comunque in elmah l'avvenuto problema.

il semplice codice che realizza questi errori è il seguente

   1: protected void Button1_Click(object sender, EventArgs e)
   2:       {
   3:           int[] arr = new int[2];
   4:           arr[0] = 1;
   5:           arr[2] = 100;       
   6:  
   7:       }
   8:       protected void Button2_Click(object sender, EventArgs e)
   9:       {
  10:           liberia lib = new liberia();
  11:           lib.Accedi();
  12:  
  13:  
  14:       }
  15:  
  16:       protected void Button3_Click(object sender, EventArgs e)
  17:       {
  18:           try
  19:           {
  20:               liberia lib = new liberia();
  21:               lib.Accedi();
  22:           }
  23:           catch (ApplicationException ex)
  24:           {
  25:               Response.Write("si è verificata un'eccezione nell'accesso al db");
  26:               Elmah.ErrorSignal.FromCurrentContext().Raise(ex);  
  27:           }
  28:       }


Il link punterà ad una pagina inesistente, per vedere come vengono gestiti anche errori non direttamente generati dal codice.

Eseguendo l’applicazione e cliccando sul primo bottone, ci troveremo davanti alla normale pagina di errore di ASP.NET:

errore1

per prima cosa, ancora prima di installare ELMAH, per evitare che l'utente veda la pagina standard di errore, possiamo creare una nostra pagina in cui comunichiamo che si è verificata una eccezione, error.htm, e impostarla nel web.config come pagina di destinazione in caso di eccezione non gestita, utilizzando il seguente codice:

   1: <customErrors mode="On" defaultRedirect="error.htm">
   2: </customErrors>


per maggiori info sul tag customErrors si può vedere qui http://msdn.microsoft.com/en-us/library/h0hfz6fc.aspx

2) Installiamo  Elmah
Per iniziare dobbiamo scaricare l'ultima versione disponibile di ELMAH, facendo attenzione all'ambiente di destinazione, se è a 64 o 32 bit.
Troviamo la distribuzione qui:  http://code.google.com/p/elmah/

Nella distribuzione troviamo molti files. Un demo standalone che permette di testare le potenzialità di ELMAH e alcune cartelle con dentro i binari. Prendiamo i binari contenuti in bin\net-3.5\Release

e copiamoli nella directory \bin della nostra applicazione.

Aggiungiamo le references agli assembly elmah.dll e sqllite.

3) configuriamo ELMAH e cominciamo a loggare…

A questo punto, per utilizzare ELMAH basta configurare opportunamente il web.config.

Nel file di distribuzione è presente un file di configurazione generico, da cui possiamo “rubare” la configurazione del nostro web.config.

Nel nostro caso scegliamo di salvare gli errori generati su file XML. Questa è una situazione comoda per poter avere gli errori in un formato gestibile a posteriori. Se è possibile possiamo anche pensare di utilizzare SQLlite, o addirittura sql server. Quest’ultima opzione è sicuramente più potente e versatile, ma chiediamoci: se l’eccezione è proprio l’impossibilità di accedere al SQL Server, dove andrà a finire l’eccezione? :)

Come in ogni situazione, scegliamo fra le varie possibilità a disposizione quella che più si confà al problema che stiamo studiando. La potenza di ELMAH si vede anche dal fatto che possiamo cambiare idea in ogni momento, semplicemente riscrivendo il file di configurazione.

Pochi passi ci portano ad avere ELMAH funzionante:

aggiungiamo la sectionGroup nelle configSections

   1: <configuration>
   2:   <configSections> 
   3:     <sectionGroup name="elmah">
   4:           <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
   5:           <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
   6:         </sectionGroup>

 

aggiungiamo la vera e propria sezione di configurazione, in cui diciamo ad ELMAH di loggare su file XML, nella cartella virtuale /logs della nostra applicazione (ovviamente avremo già creato tale cartella):

 

   1: <elmah>
   2:     <!-- errorLog type="Elmah.SQLiteErrorLog, Elmah" connectionStringName="ELMAH.SQLite" /-->
   3:      
   4:     <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/logs" />
   5:   </elmah>

 

aggiungiamo ELMAH agli httphandlers e modules. Segnatamente, nel codice che segue, l’ultima riga degli handlers e le ultime due dei modules:

   1: <httpHandlers>
   2:   <remove verb="*" path="*.asmx" />
   3:   <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
   4:   <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
   5:   <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false" />
   6:   <add verb="POST,GET,HEAD" path="public/elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
   7: </httpHandlers>
   8: <httpModules>
   9:   <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  10:   <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
  11:   <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
  12:  
  13: </httpModules>

in particolare nella riga

   1: <add verb="POST,GET,HEAD" path="public/elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />

 

diciamo che la pagina in cui vogliamo vedere i report di errore generati sarà la pagina \public\elmah.axd.

Questo se vogliamo poter accedere da non autenticati ad una cartella che in questo caso abbiamo chiamato \public\ che è liberamente accessibile. Chiaramente sarebbe meglio che questa cartella avesse un nome meno ovvio… L’utilità è quella di poter accedere remotamente al report degli errori anche quando l’errore si verifica proprio nel controllo degli utenti.

Dovremmo quindi, se scegliamo di percorrere questa strada, creare una cartella \Public settando opportunamente le politiche di controllo degli accessi. Non dobbiamo creare alcun file particolare al suo interno, segnatamente non è necessario creare elmah.axd.

4) Fatto. Sentito niente?

A questo punto abbiamo la nostra applicazione che logga ogni errore. L’utente finale vedrà solo l’educatissima pagina error.htm, in cui ci scusiamo dell’errore avvenuto. Ovviamente potremmo anche utilizzare una pagina aspx che riprende una eventuale MasterPage, per rendere l’esperienza ancora più indolore.

Se premiamo i bottoni e clicchiamo sul link, sbirciando nella directory \logs vedremo 4 files:

   1: 15/12/2009  17.02            12.789 error-2009-12-15160210Z-f82885d7-74eb-41c8-bc54-e4d72639f51c.xml
   2: 15/12/2009  17.03            15.605 error-2009-12-15160300Z-fa4ecb0c-2d4f-4f85-9a56-f7672cf4bc5e.xml
   3: 15/12/2009  17.03            15.601 error-2009-12-15160305Z-1fe0f86d-454b-4cc4-a357-1fb4bc4aa1a1.xml
   4: 15/12/2009  17.03             7.247 error-2009-12-15160324Z-13e498bf-87c2-4fce-8af9-e10fc312de81.xml

 

che sono i quattro files xml contenenti tutti i dati degli errori avvenuti.

navigando invece sulla pagina \public\elmah.axd avremo un report interattivo degli errori avvenuti:

report

la cosa interessante è che oltre all’ora, all’utente e al tipo di errore, cliccando su details si hanno tutte le informazioni di contesto e di debug che possiamo sperare di avere, dallo stack completo dell’errore a tutte informazioni di contesto http, dal viewstate completo per arrivare perfino alla pagina di errore originale.

conclusioni

Questo post non dà che un assaggio delle potenzialità di ELMAH. Soprattutto la possibilità di innestare in un’applicazione già esistente, senza alcun cambiamento invasivo al codice, di un framework potente e utilissimo per il logging degli errori.

Una volta capito come utilizzare ELMAH e apprezzata la potenza e la facilità d’uso, si potrà approfondirne lo studio e utilizzarne le funzioni più approfonditamente, per esempio leggendo questo articolo: http://code.google.com/p/elmah/wiki/DotNetSlackersArticle.

Buon lavoro e come sempre buon divertimento.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

incremento automatico della versione in Visual Studio

December 10, 2009 17:42 by M.Poponi

 

C'è un tool che ho cominciato ad usare e di cui non riesco più a fare a meno. La necessità che avevo era quella di avere in maniera automatica, ma controllata, l'incremento del versioning dei miei progetti, sia web, che library che winforms.
Ho scoperto per caso questo add-in per visual studio:
http://team.sfi.vn/post/Build-Version-Increment-Add-In-Visual-Studio.aspx

una volta installato, riavviando visual studio avremo un nuovo item nel menu Tools:

menu

questo comando aprirà una finestra moltro scarna, nel cui albero di sinistra troveremo la nostra solution e i nostri progetti, e nel pannello di destra le varie opzioni per il progetto scelto:

finestra

 

Le opzioni più importanti sono quelle del Versioning Style. Per ognuna delle cifre della versione possiamo scegliere fra una nutrita lista di opzioni, da None, che non cambia il numero (per esempio la major  generalmente è legata a stadi di rilascio, più che di build) a cifre come il giorno dell’anno, il mese, o un semplice incremento.

Si può specificare quale versione incrementare, o se l’incremento avviene al build, al rebuild o sempre.

una possibile configurazione, per esempio è la seguente:

dettaglio

una volta impostato, il tool provvederà automaticamente a modificare (con preventivo checkout se necessario) il file assemblyinfo.cs, come per esempio nel codice che segue:

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.9344.10.2")]
[assembly: AssemblyFileVersion("1.9344.10.2")]

a questo punto avremo in maniera automatica e flessibile incrementato ad ogni build la versione del nostro progetto.

semplice, efficace ed utile.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5