Inviare dati con JSON da ASP.NET e richiederli in maniera asincrona usando jquery e AJAX

JSON (JavaScript Object Notation) è un formato compatto per lo scambio di dati molto adatto per applicazioni client/server, specialmente se si vuole ridurre l’utilizzo di banda.

Per poter inviare dati attraverso applicazioni .NET è sufficiente utilizzare quanto ci mette a disposizione .NET attraverso DataContractJsonSerializer (namespace System.Runtime.Serialization.Json).

Consideriamo, ad esempio, una classe come la seguente:

  public class SampleItem
  {
    public SampleItem()
    {
      Date = DateTime.Now;
      Number = new Random(DateTime.Now.Millisecond).Next(1, 101);
    }

    public DateTime Date { get; set; }
    
    public int Number { get; set; }
    
  }

In pratica ogni istanza di questa classe è creata con la data di creazione e un numero casuale tra 1 e 100.

Possiamo scrivere un semplice HttpHandler che ci risponda inviandoci una nuova istanza della classe SampleItem, serializzata secondo JSON, come nel codice seguente:

  using System.Web;
  using System.IO;
  using System.Runtime.Serialization.Json;
  using System.Text;
 
  public class GetData : IHttpHandler
  {

    public void ProcessRequest(HttpContext context)
    {
      var response = context.Response;
      var sample = new SampleItem();

      using (var ms = new MemoryStream())
      {
        var serializer = new DataContractJsonSerializer(typeof(SampleItem));
        serializer.WriteObject(ms, sample);
        context.Response.ContentType = "application/json";
        response.Write(Encoding.Default.GetString(ms.ToArray()));
      } 
    }

    public bool IsReusable
    {
      get
      {
        return false;
      }
    }    
  }

A questo punto non resta che preparare una semplice pagina web in grado di consumare questi dati. Ad esempio, una pagina con un pulsante di start che fa partire una richiesta asincrona e quindi un timer per ripetere la richiesta ogni 100ms. Il risultato verrà aggiunto ad una tabella, mentre un pulsante stop servirà a fermare le richieste.

Il codice HTML è il seguente:

    <input type="submit" value="Start" 
      onclick="startSampling();return false;" id="btnStart" />
    <input type="submit" value="Stop" 
      onclick="stopSampling();return false;" id="btnStop"
      disabled="disabled" />
    <table id="samplesTable">
      <tr>
        <th>
          Data
        </th>
        <th>
          Valore
        </th>
      </tr>
    </table>

Mentre il codice javascript ha le due funzionalità di start e stop:

    var timerId;

    function startSampling() {
      $('#btnStart').attr('disabled', 'disabled');
      $('#btnStop').removeAttr('disabled');
      getSample();
    }

    function stopSampling() {
      $('#btnStop').attr('disabled', 'disabled');
      $('#btnStart').removeAttr('disabled');
      if (timerId) {
        clearTimeout(timerId);
      };
    }

Lo stop, oltre ad abilitare lo start e disabilitare lo stop, blocca il timer ed evita che partano le successive richieste. Per inviare la richiesta si usa la funzione getSample:

    function getSample() {
      $.ajax({
        url: "/GetData.ashx",
        contentType: "application/json; charset=utf-8",
        responseType: "json",
        cache: false,
        success: OnComplete,
        error: OnFail
      });
      timerId = setTimeout('getSample()', 100);
    }

    function OnComplete(result) {
      addRow($('#samplesTable'), 
      getDateTimeFormatted(getDateFromAspNetString(result.Date)), result.Number);
    }

    function OnFail() {
      alert('Errore nella ricezione dei dati');
    }

Viene inviata una chiamata asincrona all’url corrispondente all’HttpHandler visto prima e, in caso di risposta, viene aggiunta una riga alla tabella. è necessario impostare il parametro cache a false, altrimenti

Seguono le funzioni javascript per aggiungere la riga e formattare la data in formato JSON / ASP.NET AJAX, come indicato qui:

    function addRow(table, date, value) {
      var newRow = '<tr><td>' + date + '</td><td class="value">' + value + '</td></tr>';
      table.each(function () {
        $(this).append(newRow);
      });
    }

    function getDateFromAspNetString(aspNetString) {
      var milliseconds = aspNetString.replace(
        /^\/Date\(([0-9]+)([+-][0-9]{4})?\)\/$/, 
        '$1');
      if (milliseconds != aspNetString) {
        return new Date(parseInt(milliseconds));
      }
    }

    function getDateTimeFormatted(date) {
      return getString(date.getDate(), 2) + '/' + getString(date.getMonth() + 1, 2) + '/' 
        + date.getFullYear() + ' ' + getString(date.getHours(), 2) + ':' 
        + getString(date.getMinutes(), 2) + ':' + getString(date.getSeconds(), 2) + '.' 
        + date.getMilliseconds();
    }

    function getString(number, chars) {
      n = String(number);
      while (n.length < chars) {
        n = "0" + n;
      }
      return n;
    }

In allegato il codice di esempio: JSonSample.zip (10,34 kb)

Generare classi .Net a partire da uno schema XSD con Xsd2Code

Xsd2Code è un comodo AddIn per Visual Studio per generare classi C# o VB.NET a partire da uno schema XML (XSD).

Rispetto al tool a linea di comando xsd.exe, Xsd2Code offre, oltre alla comodità di essere un AddIn, anche una serie di caratteristiche e personalizzazioni, tra cui:

  • supporto per generic e custom collection
  • generazione di attributi WCF (Data Contract, Data Member)
  • implementazione di INotifyPropertyChanged
  • serializzazione / deserializzazione
  • custom tool per la generazione automatica alla modifica dello schema

e altro ancora, tutti i dettagli sulla pagina CodePlex di Xsd2Code.

SendKeys: come simulare la pressione di tasti per un’applicazione

La classe SendKeys (namespace System.Windows.Forms) consente di simulare la pressione di tasti per un’applicazione attiva.

Per poter rendere attiva un’applicazione che sia in esecuzione, si può ricorrere al metodo AppActivate della classe Interaction, del namespace Microsoft.VisualBasic (che può essere referenziato anche in C#).

In questo modo, ad esempio, per simulare la pressione dei tasti sulla calcolatrice di Windows (calc.exe), possiamo usare i due metodi seguenti:

    private void SendKeysToCalc(string text)
    {
      ActivateCalc();
      SendKeys.SendWait(text);    
    }

    private void ActivateCalc()
    {
      Interaction.AppActivate("Calc");
    }

image

Ad esempio, possiamo creare una mini applicazione WPF che invia alla calcolatrice quello che scriviamo in una casella di testo e poi a parte i tasti per somma, sottrazione, moltiplicazione e divisione, così come raffigurata a lato.

Alcuni tasti devono essere inviati mediante appositi codici, sia perché non esiste un carattere che li rappresenti (tasto Enter, ad esempio, per cui è necessario inviare {ENTER} oppure ~), sia perché il carattere corrispondente rappresenta un’azione (tasto +, ad esempio, che corrisponde allo SHIFT). L’elenco completo è su MSDN.

Pertanto creiamo un progetto WPF e nella MainWindow mettiamo i controlli della figura precedente:

<Button Content="Send Keys" Height="23" HorizontalAlignment="Left" Margin="138,12,0,0" 
  Name="sendKeysButton" VerticalAlignment="Top" Width="75" Click="SendTextToCalc" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" 
  Name="textBoxKeys" VerticalAlignment="Top" Width="120" />
<Button Content="+" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" 
  Name="addButton" VerticalAlignment="Top" Width="19" Click="SendAddToCalc" />
<Button Content="-" Height="23" HorizontalAlignment="Left" Margin="37,41,0,0" 
  Name="subtractButton" VerticalAlignment="Top" Width="19" Click="SendSubtractToCalc"/>
<Button Content="*" Height="23" HorizontalAlignment="Left" Margin="62,41,0,0" 
  Name="multiplyButton" VerticalAlignment="Top" Width="19" Click="SendMultiplyToCalc"/>
<Button Content="/" Height="23" HorizontalAlignment="Left" Margin="87,41,0,0" 
  Name="divideButton" VerticalAlignment="Top" Width="19" Click="SendDivideToCalc" />
<Button Content="Enter" Height="23" HorizontalAlignment="Left" Margin="113,41,0,0" 
  Name="enterButton" VerticalAlignment="Top" Width="48" Click="SendEnterToCalc"/>

Mentre nel codice aggiungiamo gli handler per l’evento click dei singoli tasti:

    private void SendTextToCalc(object sender, RoutedEventArgs e)
    {
      SendKeysToCalc(textBoxKeys.Text);    
    }

    private void SendAddToCalc(object sender, RoutedEventArgs e)
    {
      SendKeysToCalc("{ADD}");
    }

    private void SendSubtractToCalc(object sender, RoutedEventArgs e)
    {
      SendKeysToCalc("{SUBTRACT}");
    }

    private void SendMultiplyToCalc(object sender, RoutedEventArgs e)
    {
      SendKeysToCalc("{MULTIPLY}");
    }

    private void SendDivideToCalc(object sender, RoutedEventArgs e)
    {
      SendKeysToCalc("{DIVIDE}");
    }

    private void SendEnterToCalc(object sender, RoutedEventArgs e)
    {
      SendKeysToCalc("{ENTER}");
    }

A questo punto basta avviare la calcolatrice ed il programma provvederà a simulare la pressione dei tasti sulla calcolatrice di Windows.

In allegato il codice di esempio, SendKeyTest.zip (25,86 kb)

XMLSampleGenerator: come generare un documento XML di esempio a partire da uno schema XML

Su MSDN ho trovato questo articolo che descrive XMLSampleGenerator, un tool per generare un file XML di esempio a partire da un dato schema XML (.xsd).

È possibile scaricare i sorgenti, utili anche da esempio di come navigare nello Schema Object Model, insieme ai quali è incluso un tool a linea di comando, XmlGen.exe, per generare XML da prompt di MS DOS utilizzando XMLSampleGenerator.

XML Schema Definition Tool (Xsd.exe)

XML Schema Definition Tool (Xsd.exe) è un tool da linea di comando di Visual Studio in grado di generare schemi XML (XSD) a partire da file XML o da file assembly (con estensione .exe o .dll), oppure classi a partire da file .xsd.

Ad esempio, dato un file albums.xml, attraverso il prompt dei comandi di Visual Studio possiamo scrivere:

xsd albums.xml

per creato un file albums.xsd, con lo schema utilizzato dal file .xml.

Poi possiamo scrivere:

xsd albums.xsd /c

per creare un file albums.cs, con il codice C# per oggetti che corrispondono allo schema XML.

Se invece abbiamo una libreria albums.dll, scrivendo:

xsd albums.dll
 

verrà creato un file schema0.xsd che rappresenta uno schema XML corrispondente alle classi presenti nell’assembly specificato.

Su MSDN la documentazione completa, comprensiva di esempi su come specificare attraverso un file XML dei parametri per il tool.

Snoop

Quando si lavora con WPF, Snoop è una utility essenziale, che consente di navigare nel visual tree e anche di cambiare al volo le proprietà. Praticamente indispensabile.

Come testare una connessione a un database

imageUna maniera molto semplice (e poco documentata) per poter testare una connessione ad un database consiste nel creare un file di testo, quindi rinominarlo cambiandone l’estensione in “.udl”.

 

A questo punto basta fare doppio click per far comparire una procedura guidata con cui possiamo inserire i parametri della connessione al database (provider, nome del server, dati per l’autenticazione, ecc. )

image13

 

Una volta inseriti i dati è possibile testare la connessione attraverso il tasto test connection.

Disinstallare o installare applicazioni in modalità provvisoria

In modalità provvisoria normalmente non è possibile installare o rimuovere applicazioni, poiché in tale modalità il servizio di Windows Installer non è abilitato a funzionare, né può essere avviato. A meno che non si vada ad aggiungere ed impostare correttamente un’apposita chiave del registro.

Si può fare con regedit, navigando fino a:

HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Minimal


per la modalità provvisoria senza supporto di rete, oppure fino a:

HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Network


per la modalità provvisoria con supporto di rete.

Qui si deve aggiungere la chiave MSIServer e per essa il valore Service.

image

A questo punto non resta che avviare il servizio di Windows Installer.

In alternativa, è possibile fare tutto da linea di comando (aprendo il prompt con privilegi di amministratore)

Per la modalità provvisoria senza rete:

REG ADD HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Minimal\MSIServer /VE /T REG_SZ /F /D "Service" 
net start msiserver


Mentre per la modalitò provvisoria con rete:

REG ADD HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Network\MSIServer /VE /T REG_SZ /F /D "Service" 
net start msiserver

 

Fonti: Symantec blog, bufferOverflow, Maurizio Condini – Defcon.it Blog