LINQ oltre SQL e XML: creare un provider per l'integrazione con Live Search

4 pagine in totale: <<Indietro 1 2 3 [4]

Un'applicazione di test utile...

Questo piccolo WinForm consente di selezionare i parametri di base e invoca la query LINQ. Siccome la chiamata al web service può avere una certa latenza, la query LINQ è eseguita su un worker thread in modo da consentire alla finestra dell'applicazione di processare altri messaggi, inclusa l'opzione di cancellare la richiesta.

Può essere un'ispirazione utile per chi vuole usare LINQ in un applicazione ma non vuole bloccare la UI mentre la query viene eseguita.

Per ottenere il comportamento asincrono desiderato, creeremo un metodo di tipo FormDelegate che processi una stringa contente l'HTML da presentare in un browser control.

private delegate void FormDelegate(string htmlSnippet);
private FormDelegate formDelegate;
private Thread currentThread = null;

private string queryTerm = null;
private string source = null;
private string cultureInfo = null;

private bool cancel = false;

public Form1()
{
  InitializeComponent();
  trident.Url = new Uri("about:blank");
  sourceType.SelectedIndex = 0;

  formDelegate = new FormDelegate(UpdateSearchResults);
}

Il bello di avere un comportamento asincrono è che la UI resta attiva durante l'operazione, quindi la si può cancellare in qualunque momento.

private void button1_Click(object sender, EventArgs
{
  if (!cancel)
  {
    cancel = !cancel;
    button1.Text = "&Cancel";
    queryTerm = queryTerms.Text;
    source = sourceType.SelectedItem.ToString();
    cultureInfo = cultureInformation.SelectedItem.ToString();
    trident.Document.Window.Document.Body.InnerHtml = "Searching...";

    PerformAsyncSearchRequest();
  }
  else
  {
    cancel = !cancel;
    button1.Text = "&Execute";
    trident.Document.Window.Document.Body.InnerHtml = "Searching
      operation canceled";
    currentThread.Abort();
  }
}

Questa funzione è il cuore dell'invocazione asincrona: gestisce il worker thread, abortendo l'operazione se ce n'è una già in corso o preparando il worker per eseguire il metodo che contiene la chiamata a LINQ

private void PerformAsyncSearchRequest()
{
  if (currentThread != null && currentThread.IsAlive)
  {
    currentThread.Abort();
    currentThread.Join();
  }

  currentThread = new Thread(new ThreadStart(ProcessSearchRequest));
  currentThread.Start();
}

Questa funzione incapsula la chiamata a LINQ e verrà eseguita da un thread diverso dal thread della UI. Di conseguenza, l'applicazione potrà continuare a processare messaggi mentre la query viene eseguita, mantnendo la chiamata alla query cancellabile dalla UI.

private void ProcessSearchRequest()
{
  try
  {
    QueryableLiveSearchData<LinqSearchObject> LiveSearch = new
      QueryableLiveSearchData<LinqSearchObject>();

    var query = from result in LiveSearch
                where result.QueryTerm == queryTerm &&
                result.SourceSearch == source &&
                result.CulInfo == cultureInfo
                select new WebSearchResponse(result.Title,
                result.Description, result.Url);

    IAsyncResult r = BeginInvoke(formDelegate, DisplayResults(query));
  }
  catch (ThreadAbortException)
  {
    // Do Nothing.
  }
}

Questa è la funzione che il worker thread invoca quando ha eseguito la query ed i dati sono pronti per essere mostrati nella UI. Questa funzione viene eseguita dal UI thread attraverso la chiamata a BeginInvoke.

private string DisplayResults(IQueryable<WebSearchResponse> query)
{
  string htmlSnippet = "<table><tr><th colspan='3'>Results:</th></tr>";

  foreach (var q in query)
  {
    htmlSnippet += "<tr><td><a href='" + q.Url + "' target='_blank'>" +
      q.Title + "</a></td><td colspan='2'>" + q.Description +
      "</td></tr>";
  }

  htmlSnippet += "</table>";

  return htmlSnippet;
}

public class WebSearchResponse
{
  public string Title { get; set; }
  public string Description { get; set; }
  public string Url { get; set; }

  public WebSearchResponse(string t, string d, string u)
  {
    Title = t;
    Description = d;
    Url = u;
  }
}

Conclusioni

LINQ permette di estendere un potentissimo parser di espressioni per interagire con qualunque struttura che possa essere mappata in un oggetto.

In questo articolo, si è cercato di dare una chiave di lettura diversa per una caratteristica potentissima e rivoluzionaria che ha il potenziale per cambiare come tutti accediamo ai nostri dati.

Questo è un esempio abbastanza semplice, ma spero di avere messo in movimento molte idee, per altri servizi e data source nelle vostre applicazioni e nei vostri sistemi, che potrebbero giovare della semplicità e universalità di accesso offerta da LINQ.

La piccola applicazione di test può essere utilizzata come modello per qualunque form che voglia interrogare LINQ in modo asincrono. Non usatela su un server così com'è (la lunga serie di commenti all'articolo sulla concurrency di qualche settimana fa dovrebbe dare abbastanza spunti sul perchè)

Lo speciale completo su Visual Studio 2008, Windows Server 2008 e SQL Server 2008

4 pagine in totale: <<Indietro 1 2 3 [4]

Contenuti dell'articolo

Commenti
Dai un voto a questo articolo, ci aiuterà a migliorare il nostro sito (1 è il voto minimo, 5 il massimo).

Per procedere al rating dell'articolo devi essere autenticato.

Aggiungi un nuovo commento »»»
Per inserire un commento, devi registrarti alla nostra community.



TUTORIALS


IN EVIDENZA
MISC