ADO.NET Data Service

Un'altra interessante componente disponibile con la CTP delle ASP.NET 3.5 Extension è la nuova infrastruttura per lo sviluppo di Web Data Service ADO.NET Data Service. Si tratta dell'evoluzione in prodotto della tecnologia incubazione denominata "Astoria" mostrata a MIX 07.

Il nuovo framework ha lo scopo di semplificare l'erogazione di sorgenti dati sul Web venendo incontro alla trasformazione che i siti internet stanno avendo nell'utilizzo di queste funzionalità.

I siti Web da semplici erogatori di interfacce HTML si stanno trasformando in erogatori di dati.  Con lo sviluppo di AJAX e delle applicazioni RIA si sta  passando da un approccio in cui dall'esecuzione del codice lato server si accedeva alle sorgenti dati utilizzate nei siti

 

image

 

ad un approccio in cui dal codice client che si esegue nel browser, si accede direttamente alle sorgenti dati via HTTP, genericamente attraverso un approccio REST

 

image

 

Il framework ADO.NET Data Service è uno strato costruito sopra l'Entity Framework che permette di rendere accessibile attraverso un URL con uno stile REST il modello E/R implementato (per approfondimenti sull'entity framework vi consiglio : https://msdn2.microsoft.com/en-us/library/aa697427(VS.80).aspx  e https://msdn2.microsoft.com/en-us/library/cc161164(printer).aspx  ). In realtà non permette esclusivamente di esporre modelli dell'Entity framework ma di qualunque entità che implementi l'interfaccia IQueryable <T> .

Oltre a fornire le componenti server per esporre via Http con stile REST il modello di entità, il framework offre due nuove API client per semplificare l'accesso ai dati esposti in questa modalità:

- Un libreria JavaScript che estende i namespace della Microsoft Ajax Library (namespace Sys.Data ed in particolare Sys.Data.DataService nella Script Library  MicrosoftAjaxDataService.js)

- una libreria .NET pensata per client sia silverlight che .NET Framework per desktop ( namespace Microsoft.Data.WebClient contenuto nelle Extension con particolare riferimento alle classi WebDataContext e WebDataQuery ).

 

Per poter analizzare più nel dettaglio il funzionamento del framework partiamo con l'implementare un semplice esempio basandoci sull'Entity Framework. In particolare partiremo con il creare un entity data model sul classico database Northwind per poi esporre con un servizio ADO.NET DataService le entità via http e poi accederci utilizzandole due librerie client citate.

I passi da implementare sono essenzilmente i seguenti:

- Creare il Progetto

- Creare l'Entity Model

- Creare il Data Service e Autorizzare gli accessi

Procediamo con la creazione di un nuovo Web Site. Dopo aver avviato il progetto, includiamo un elemento di tipo ADO.NET Entity Data Model lo connettiamo al classico database Nortwind , ottenendo un nuovo modello che utilizzeremo come base per l'esposizione del servizio di accesso ai dati.

 image

  image

 

 image

 

Aggiungiamo ora un elemento di tipo ASP.NET Data Service e lo colleghiamo al modello EDM appena creato  

image

 

ottenendo un servizio come quello che vediamo di seguito:

image

 

Si tratta di un servizio che utilizza WCF ed il nuovo supporto REST offerto da .NET 3.5 e attraverso una infrastruttura costruita sopra queste funzionalità basata sulla classe WebDataService, espone il nostro EDM che in questo caso è basata data context NorthwindEntities che abbiamo appena costruito con il tool dell'entity framework e che stiamo indicando con lo specifico generics previsto dalla classe:

.........

public class Northwind: WebDtataService <NorthwindModel.NorthwindEntities>

........

 

In realtà la classe WebDataService come abbiamo già detto è in grado di gestire qualunque modello che implementi l'interfaccia IQueryable <T>.

 

Per autorizzare l'accesso alle informazioni esposte dal servizio utiliziamo la classe di autorizzazione appositamente inserita nel servizio , aggiungendo al configurazione sul costruttore del servizio per ottenere l'accesso ai dati di tutti i clienti contenuti nel database nortwind su cui abbiamo costruito il nostro EDM.

Nel nostro piccolo esempio impostiamo l'accesso completo a tutte le risorse presenti nel modello esposto attraverso il servizio:

 

namespace SimpleDataService {

  public class Northwind : WebDataService<NorthwindEntities> {

       public static void InitializeService(IWebDataServiceConfiguration config) {

                  config.SetResourceContainerAccessRule("*", ResourceContainerRights.All);

                }

        }

   }

 

Per poter effettuare un test sul funzionamento del servizio è possibile inviare direttamente con un browser una richiesta GET del tipo seguente:

https://localhost:2759/WebSite1/Northwind.svc/Customers

con la quale otteniamo accesso ai dati di tutti i clienti. Oppure la seguente con cui otteniamo l'accesso ad uno specifico customer:

https://localhost:2759/WebSite1/Northwind.svc/Customers('alfki')

image

o ad esempio ai suoi ordini:

https://localhost:2759/WebSite1/Northwind.svc/Customers('alfki')/Orders

Per un introduzione sulla sintassi per ADO.NET DataService potete far riferimento a https://quickstarts.asp.net/3-5-extensions/adonetdataservice/SimpleAddressingSchemeForDataWithUniformURLs.aspx

Utilizzando la specifica sintassi prevista dal servizio si possono effettuare query e modifiche ai dati. In funzione del tipo di content type inviato nell'header http è possibile ottenere risposte con serializzazione XML o JSON.

 

E' possibile anche implementare dei Query Interceptors o Change Interceptor sul WebService per agganciare del nostro codice e gestire specifiche richieste di Query o modifiche. Ad esempio per intercettare e gestire le richieste di Query sui Customers del nostro esempio si dovrà aggiungere il seguente metodo:

 

[QueryInterceptor("Customers")]
      public IQueryable<Customers> OnQueryOrders(IQueryable<Customers> customerQuery)
    {

        return from o in customerQuery
               where o.ContactName ==HttpContext.Current.User.Identity.Name
               select o;

    }

 

che fornirà esclusivamente accesso a quei customer dove il contactname corrisponde al nome dell'utente che sta accedendo al servizio. Per il Change Interceptor si utilizzerà l'attributo [ChangeInterceptor("......")] sul metodo Interceptor.

Oltre agli Interceptor è possibile estendere il servizio con dei nostri metodi custom attraverso quello che viene definito un Service Operation. Per aggiungere una Service Operation basta implementare uno specifico metodo come di seguito:

 

[WebGet]
public IQueryable<Model.Customers> CustomersInCity(string cityName)
{
return from c in this.CurrentDataSource.Customers
where c.City == cityName
select c;
}

 

Renderlo accessibile con la configurazione delle autorizzazioni:

 

public static void InitializeService(IWebDataServiceConfiguration config)
{
...
config.SetServiceOperationAccessRule("CustomersInCity", ServiceOperationRights.All);
}

 

e potrà essere acceduto attraverso il seguente URL:

 

https://localhost:2759/WebSite1/Northwind.svc/CustomersInCity?cityName='Rome'

 

Non soltando è possibile esporre dati ma utilizzando delle Service Operetions è possibile anche sfruttare gli attributi [SingleResult] e [MimeType] per realizzare interessanti combinazioni come ad esempio l'esposizione di template HTML collegati ai dati contenuti nel modello:

 

[MimeType("text/html")]
[SingleResult]
[WebGet]
public IQueryable<string> WelcomePage()
{
return new string[]
{
"<html><head><title>Welcome</title></head>" +
"<body><h1>Welcome!</h1><p>Currently we have " +
this.CurrentDataSource.Customers.Count().ToString() +
" customers.</p></body></html>"
}.AsQueryable();
}

 

Accessibili poi con URL di questo tipo:

 

https://localhost:2759/WebSite1/Northwind.svc/WelcomePage/$value

Ad esempio è possibile anche creare dei Tempale XAML per Silverlight che possono essere direttamente valorizati con dei dati come nell'esempio precedente e poi caricati dinamicamente nell'applicazione RIA client chiamante utilizzando ad esempio una chiamata XmlHttpRequest con la funzione createfromxaml del plugin.

Abbiamo parlato prima delle due librerie client disponibili per l'accesso via JavaScript e via .NET. Per l'utilizzo AJAX sfruttiamo la libreria JS MicrosoftAjaxDataService.js che ci mette a dsiposizione la classe Sys.Data.DataService . Referenziando la libreria :

 

<asp:ScriptManager ID="ScriptManager1" runat="server">

  <Scripts>

             <asp:ScriptReference Name="MicrosoftAjaxDataService.js" />

    </Scripts>

</asp:ScriptManager>

 

è possibile utilizzare la libreria per effettuare un query sui dati come di seguito:

 

var northwindService = new Sys.Data.DataService("/Northwind.svc");

northwindService.query("/Customers", onSuccess, onFailure);

 

Dove onSuccess e onFailure sono rispettivamente i metodi invocati all'arrivo della risposta o in caso di errore :

 

function onFailure(error, context, operation) {

    $get("spanResults").innerHTML = "Error occurred in operation " + operation + ".";

}

 

function onSuccess(result, context, operation) { 

  // Get Customers list and put into a table.  

  var sb = new Sys.StringBuilder();

  sb.append("<table>");

var firstRowOutput = false;

for (idx in result) {

  var customer = result[idx];

  if (!firstRowOutput) { // Display the header row.

   sb.append("<tr>"); for (key in customer) {

            if (key != "__metadata") {

                         sb.append("<th>");

                         sb.append(key);

                         sb.append("</th>");

                  }

      }

sb.append("</tr>");

firstRowOutput = true;

} // Display the data.

sb.append("<tr>");

for (key in customer) {

  if (key != "__metadata") {

       sb.append("<td>");

       sb.append(customer[key]);

        sb.append("</td>");

       }

}

sb.append("</tr>");

}

sb.append("</table>");

$get("spanResults").innerHTML = sb.toString();

}

 

La classe mette poi a disposizione le funzionalità per effettuare update ed insert.

 

Come già in precedenza segnalato è disponibile anche un namespace client .NET (Microsoft.Data.WebClient) per poter accedere con maggiore semplicità da client managed ai dati esposti da un servizio ASP.NET Data Service .

Attraverso la classe WebDataContext si gestisce il contesto verso uno specifico servizio e con la classe WebDataQuery si rappresentano e si eseguono le query verso la sorgente dati rappresentata da un WebDataContext:

 

WebDataContext ctx = new WebDataContext(https://localhost:51905/nw.svc);

WebDataQuery<Customer> customers = ctx.CreateQuery<Customer>("/Customer");

foreach (Customer r in customers) {

    Console.WriteLine(c.CompanyName );

}

 

La CTP mette a disposizione anche un generatore di codice (WebDataGen.exe) che, partendo dai metadatid el servizio, ci genera un modello ad oggetti che ci permette di utilizzare LINQ per accedere al servizio:

 

\Program Files\Microsoft ASP.NET 3.5 Extensions\WebDataGen.exe" /mode:ClientClassGeneration /outobjectlayer:northwind.cs /uri:https://localhost:8090/Northwind.svc

 

Generato il modello con il tool è possibile utilizzare per accedere ai dati del servizio codice come il seguente:

 

using System;

using Microsoft.Data.WebClient;

using System.Linq;

using NorthwindModel;

 

namespace TestApplication {

class Program {

   static void Main(string[] args) {

       NorthwindEntities ctx = new NorthwindEntities(https://localhost:8090/Northwind.svc);

       ctx.MergeOption = MergeOption.AppendOnly;

        var q = from c in ctx.Customers where c.City == "London" orderby c.CompanyName select c;

        foreach (var cust in q) {

                  Console.WriteLine(cust.CompanyName);

              }

         }

     }

}

La classe NorthwindEntities deriva da WebDataContext e permette di gestire con LINQ un approccio tipizzato. 

Sono possibili anche operazioni di update,delete e insert.  L'autenticazione sul servizio avviene passando le credenziali con la classica interfaccia ICredentials.

 

Conclusioni

ADO.NET Data Service fornisce un nuova nuova sofisticata modalità per esporre , consumare sorgenti dati attraverso un approccio REST che consente di costruire con rapidità servizi in grado di supportare con efficacia le esigenze di accesso ai dati nei nuovi scenari Internet con particolare riferimento alle applicazioni RIA.

Per una introduzione alle funzionalità del servizio vi suggerisco il QuickStart online , il blog del team dove troverete anche le novità in arrivo , e segnalo inoltre  alcuni video realizzati sull'argomento:

 

ADO.NET Data Services - Surfacing Data

ADO.NET Data Services - Querying with URI's

ADO.NET Data Services - A Basic .NET Client

ADO.NET Data Services - A Basic AJAX Client

ADO.NET Data Services - A Basic Silverlight Client

        ADO.NET Data Services - Querying with LINQ

        ADO.NET Data Services - Query Interceptors

        ADO.NET Data Services - Service Operations