Eseguire chiamate cross domain con jQuery e ASP.NET

di Daniele Bochicchio, in jQuery, ASP.NET 2.0, ASP.NET 3.5,

Durante lo sviluppo di applicazioni AJAX based, non è inusuale che si voglia tenere su un dominio specifico, esternamente al resto del sito, tutta la parte di API da invocare attraverso Javascript. Una soluzione di questo tipo, però, non è immediata da attuare come ci si aspetterebbe: per ragioni di sicurezza, Javascript ha una policy di cross domain molto restrittiva, a causa della quale è possibile invocare tramite XmlHttpRequest solo risorse dello stesso dominio. Questa limitazione, che tra l'altro emerge anche quando si vuole dare in uso uno script all'esterno, è chiamata same origin policy ed esiste per proteggere l'utente da attacchi XSS (Cross Site Scripting).

Esistono differenti tecniche per aggirare il problema, ognuna con i propri pregi e difetti; all'interno di questo script vedremo come risolverlo utilizzando jQuery e ASP.NET. Solitamente in questi casi lo scambio di informazioni con il server avviene utilizzando la serializzazione JSON, ma nel nostro caso supporremo che il servizio sia in grado di restituire direttamente il markup da visualizzare in pagina. In questo modo non si è costretti a gestire il parse della stringa JSON lato client ed è anche possibile sfruttare dei custom control ASP.NET per produrre il markup in maniera componentizzata.

L'idea alla base di questa tecnica è evitare totalmente l'uso di XmlHttpRequest, facendo in modo che il server produca uno script simile al seguente:

updateData('<div>Daniele</div>...');

La funzione updateData è definita nella pagina chiamante e contiene il codice di callback che, attraverso jQuery, è in grado di aggiornare effettivamente l'interfaccia (e in particolare il contenuto di un div) con il markup fornito come argomento e generato da remoto:

function updateData(results) {
  $("#dataContainer").html(results);
}

Sul client, l'invocazione del servizio remoto può avvenire in una qualsiasi fase del ciclo di vita della pagina successiva all'evento di load, utilizzando del codice Javascript simile al seguente:

$(document).ready(function() {loadData(1);});

function loadData(page) {
  var myScript=document.createElement("script");
  myScript.type="text/javascript";
  // questo è l'url del "servizio" remoto fatto con ASP.NET
  myScript.src="service.aspx?username=<%=Server.UrlEncode("Daniele")%>&p="+page;
  document.body.appendChild(myScript);
}

Nel nostro caso, al caricamento della pagina viene aggiunto dinamicamente un tag script che punta all'indirizzo service.aspx, che si occuperà di produrre l'output secondo il formato che abbiamo visto in precedenza; in questo modo non sussiste alcuna limitazione circa la provenienza della risorsa, quindi il servizio invocato può di fatto appartenere a qualsiasi dominio.

A questo punto, l'infrastruttura lato client è completata e possiamo iniziare ad esaminare quanto necessario lato server. L'idea è quella di realizzare una pagina ASP.NET e, tramite l'override del metodo Render, modificare la logica secondo cui essa produce il suo markup. In particolare, vogliamo essere in grado di recuperare l'output del solo controllo che ci interessa (un Repeater) e di utilizzarlo come argomento per la funzione Javascript updateData definita in precedenza. A causa della nostra implementazione client, è essenziale che non vengano restituiti caratteri come il ritorno a capo, o i tab, che non sarebbero gestiti correttamente.

protected override void Render(HtmlTextWriter writer)
{
  // creo gli oggetti necessari a leggere il codice HTML 
  string xHtml = String.Empty;
  System.IO.StringWriter stringWriter = new System.IO.StringWriter();
  HtmlTextWriter sourcecode = new HtmlTextWriter(stringWriter);

  try
  {
    // catturo il codice prodotto dal rendering
    FriendListRepeater.RenderControl(sourcecode);
    sourcecode.Flush();
    xHtml = stringWriter.ToString();
  }
  finally
  {
    sourcecode.Close();
    stringWriter.Close();
  }

  // lo ripulisco
  xHtml = xHtml.Replace("\r\n", " ").Replace("\t", " ");
  
  Response.Clear();
  // updateData è la funzione di callback nella pagina principale
  Response.Write("updateData('" + xHtml.Replace("'", "\\'") + "');");
  Response.End();
}

In questo modo, quando lo script viene richiamato, di fatto è in grado di passare dei nuovi dati alla pagina, che può a sua volta decidere esattamente come visualizzarli, bypassando del tutto il componente XmlHttpRequest e quindi la sua limitazione sulle chiamate cross domain.

Con i dovuti accorgimenti, è possibile applicare questa tecnica anche ad ASP.NET MVC, dove peraltro la fase di generazione dell'output è più semplice da "addomesticare".

Una piccola nota dal punto di vista della sicurezza: i dati inviati secondo questa tecnica sono visibili in chiaro a chiunque, e pertanto non è consigliata nel caso debbano trasitare informazioni sensibili. Inoltre, aggirando la protezione sulle chiamate cross domain, la pagina destinazione è potenzialmente esposta ad attacchi di tipo XSS.

All'interno del materiale allegato a questo script si trova un esempio completo, pronto da customizzare.

Per approfondimenti, si veda:

Introduzione al framework Javascript jQuery con esempi pratici di utilizzo
https://www.aspitalia.com/articoli/asp.net/javascript-jquery-overview.aspx

#157 - Serializzare e deserializzare in JSON con DataContractJsonSerializer
https://www.winfxitalia.com/script/157/Serializzare-Deserializzare-JSON-DataContractJsonSerializer.aspx

#590 - Catturare l'HTML del DataGrid di ASP.NET
https://www.aspitalia.com/script/590/Catturare-HTML-DataGrid-ASP.NET.aspx

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi