.Libreria client NET (framework di ADO.NET Data Services)
ADO.NET Data Services include la libreria client .NET per le applicazioni che utilizzano .NET Framework e ADO.NET Data Services. La libreria client consente alle applicazioni di utilizzare i risultati del servizio dati come oggetti .NET. L'attraversamento delle associazioni viene gestito mediante oggetti CLR (Common Language Runtime).
La libreria client .NET utilizza il protocollo HTTP e il formato AtomPub ed è efficace per reti aziendali e ambienti Internet. Richiede solo una connettività di livello HTTP al servizio dati, direttamente o tramite proxy.
System.Data.Services.Client
Per utilizzare la libreria client, aggiungere un riferimento all'assembly System.Data.Services.Client nel progetto. La libreria client può essere utilizzata da qualsiasi tipo di progetto, inclusi Windows Form, Windows Presentation Foundation e progetti di siti Web.
I due costrutti principali della libreria client sono le classi DataServiceContext
e DataServiceQuery
. DataServiceContext
rappresenta il contesto runtime con un servizio dati specifico. Sebbene i servizi dati siano senza stato, non lo è il contesto e lo stato del client viene mantenuto tra le interazioni per supportare funzionalità quali la gestione di modifiche.
La classe DataServiceQuery
rappresenta una query su un archivio specificato mediante la sintassi URI di ADO.NET Data Services. Per eseguire una query e visualizzare i risultati in forma di oggetti .NET, enumerare l'oggetto query utilizzando, ad esempio, il costrutto foreach
in C# o For Each
in Visual Basic.
Per rappresentare ogni entità definita nel servizio dati come oggetto .NET, è necessario definire le classi corrispondenti per l'applicazione client. Un'opzione consiste nel definire manualmente le classi; l'altra è lo strumento DataSvcUtil.exe illustrato nell'intestazione successiva.
Nell'esempio seguente viene illustrata una definizione scritta a mano per la classe Address
basata su dati contenuti nel database di esempio AdventureWorks fornito con SQL Server 2005. Nell'esempio vengono utilizzati l'entità Address
e un piccolo segmento di codice che esegue una query sul servizio. Le proprietà della classe Address
restituita vengono visualizzate come output.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Services.Client;
namespace DataServiceClient
{
public class Address
{
public int AddressID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public DateTime ModifiedDate { get; set; }
public string PostalCode { get; set; }
public Guid rowguid { get; set; }
public int StateProvinceID { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
DataServiceContext ctx = new
DataServiceContext(new Uri("https://localhost:1492/AdvWksSales.svc/"));
// This example expects the user to enter
// an integer representing AddressID in textBox1.
DataServiceQuery<Address> query =
ctx.CreateQuery<Address>(
"SalesOrderHeader(45678)/Address");
StringBuilder output = new StringBuilder();
foreach (Address address in query)
{
output.Append("Id: " + address.AddressID +
" Line 1: " + address.AddressLine1 + "\r\n");
}
richTextBox1.Text = output.ToString();
}
Di seguito viene riportato l'output.
Id: 70 Address Line1: 1792 Belmont Rd. City: Monroe
Utilizzo dello strumento DataSvcUtil
L'approccio di scrittura manuale delle classi funziona in presenza di un piccolo numero di tipi, ma quando lo schema del servizio dati è più complesso, il numero e la dimensione delle classi da gestire diventa troppo complesso per la gestione manuale. Un'opzione migliore consiste nell'utilizzo dello strumento per la generazione di codice DataSvcUtil.exe incluso in ADO.NET Data Services. Lo strumento consente di generare classi .NET dalla definizione del servizio dati.
DataSvcUtil.exe è posizionato nella directory \WINDOWS\Microsoft.NET\Framework\v3.5. La riga di comando accetta un argomento: l'URL di base del servizio dati per il quale devono essere generati i tipi. Se, ad esempio, il servizio Northwind è in esecuzione nel server di sviluppo di Visual Studio all'indirizzo https://localhost:1234/Northwind.svc, la riga di comando per generare le classi sarà:
C:\Program Files\Microsoft Visual Studio 9.0\VC>"C:\WINDOWS\Microsoft.NET\Framework\v3.5\DataSvcUtil.exe"
/out:c:\northwind.cs /uri:https://localhost:1365/Northwind.svc
L'output del comando è un file C# che contiene una classe per ogni tipo di entità nel servizio dati. I tipi Visual Basic possono essere generati utilizzando l'opzione /language:VB
.
Le classi generate dispongono di membri rappresentanti associazioni e valori primitivi che facilitano la navigazione nel modello a oggetti.
LINQ to ADO.NET Data Services
Oltre alle query su un servizio dati in una chiamata a DataServiceContext.CreateQuery
, la libreria client .NET supporta query al servizio dati mediante LINQ (Language Integrated Query), come illustrato sotto l'intestazione Microsoft Data Web Client. Per ulteriori informazioni su LINQ, vedere LINQ to Entities. La libreria client gestisce le informazioni sul mapping dell'istruzione LINQ a un URI nel servizio dati di destinazione e sul recupero delle risorse specificate come oggetti .NET. Nell'esempio seguente viene illustrato come recuperare tutti i clienti presenti nella città di Londra con il set di risultati restituito ordinato in base al nome dell'azienda.
using System;
using System.Data.Services.Client;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(
new Uri("https://localhost:1365/Northwind.svc"));
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);
}
}
}
}
Nota |
---|
La sintassi LINQ consente di esprimere un set di query più ampio di quello consentito nella sintassi URI basata su REST (Representational State Transfer) utilizzata dai servizi dati. Se non è possibile eseguire il mapping della query a un URI nel servizio dati di destinazione, verrà generata un'eccezione. Per ulteriori informazioni su REST, vedere Servizi e semantica REST (framework di ADO.NET Data Services). |
Nota |
---|
Negli esempi contenuti in questa intestazione e nelle due successive viene utilizzato il database di esempio Northwind. È possibile scaricare il database di esempio Northwind dalla pagina Web https://go.microsoft.com/fwlink/?linkid=24758. |
Associazioni
Le associazioni tra oggetti vengono registrate e gestite dalla classe DataServiceContext
. È possibile caricare gli oggetti associati immediatamente o in base alle necessità. I caricamenti "immediato" e "differito" sono illustrati nell'argomento Querying Data as Objects and Shaping Query Results della documentazione ADO.NET Entity Framework. I formati URL sono descritti in Schema di indirizzamento semplice di dati con URI uniformi (framework di ADO.NET Data Services).
Per il caricamento di entità associate in base alle necessità, viene utilizzato il metodo LoadProperty
sulla classe DataServiceContext
. Nell'esempio seguente viene illustrato come rinviare il caricamento di entità Product
associate ad entità Category
.
using System;
using System.Data.Services.Client;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
DataServiceQuery<Categories> categories =
ctx.CreateQuery<Categories>("/Categories");
foreach (Categories c in categories)
{
Console.WriteLine(c.CategoryName);
ctx.LoadProperty(c, "Products");
foreach (Products p in c.Products)
{
Console.WriteLine("\t" + p.ProductName);
}
}
}
}
}
}
Nel caso in cui siano necessari oggetti associati in alcuni scenari e si desideri evitare la latenza aggiunta di una nuova richiesta per recuperarli, è possibile utilizzare l'opzione expand
all'interno dell'URL. La libreria client riconosce che i risultati includono sia entità di livello superiore che entità associate e le materializza tutte in forma di oggetto grafico. Questo caricamento è denominato immediato. Il caricamento immediato è simile all'esempio precedente ma carica i prodotti correlati in un solo round trip al servizio dati.
Nell'esempio seguente viene illustrata l'opzione di espansione che include i prodotti correlati alle categorie.
using System;
using System.Data.Services.Client;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
// get a single category
DataServiceQuery<Categories> categories =
ctx.CreateQuery<Categories>("/Categories(1)?$expand=Products");
foreach (Categories c in categories)
{
//Console.WriteLine(c.CategoryName);
richTextBox1.Text = c.CategoryName;
foreach (Products p in c.Products)
{
//Console.WriteLine("\t" + p.ProductName);
richTextBox1.Text = richTextBox1.Text +
"\r\n\t" + p.ProductName ;
}
}
}
}
}
Supporto di aggiornamento
Per creare una nuova istanza nel servizio dati, creare l'oggetto .NET, quindi chiamare AddObject
sull'istanza DataServiceContext
utilizzata passando l'oggetto e il set di entità di destinazione, come illustrato nel frammento di codice seguente.
using System;
using Microsoft.Data.WebClient;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
Categories cNew = new Categories();
cNew.CategoryName = "NewCategory1";
cNew.Description = "Add Item Test.";
ctx.AddObject("Categories",cNew);
ctx.SaveChanges();
}
}
}
Dopo la creazione o la modifica di un'entità nel servizio dati, il servizio restituisce una copia aggiornata dell'entità, includendo i valori di proprietà che potrebbero essere stati aggiornati come risultato di trigger nel database o chiavi generate automaticamente. Nella libreria client l'oggetto .NET viene aggiornato automaticamente con i nuovi valori.
Per modificare un'istanza di entità esistente, eseguire innanzitutto una query per l'oggetto, apportare le modifiche desiderate alle proprietà, quindi chiamare il metodo UpdateObject
per indicare alla libreria client di inviare un aggiornamento per l'oggetto.
Nota |
---|
Nell'esempio seguente viene utilizzata una classe di contesto |
Nell'esempio seguente viene illustrata la sintassi per l'aggiornamento mediante il metodo UpdateObject
.
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctxN =
new NorthwindEntities(
new Uri("https://localhost:1365/Northwind.svc"));
var c1 = (from c in ctxN.Categories
where c.CategoryName == "NewCategory1"
select c).First();
c1.CategoryName = "UpdatedCategory";
//ctxN.AttachTo("Categories", c1);
ctxN.UpdateObject(c1);
ctxN.SaveChanges();
}
}
}
Per eliminare un'istanza di entità, chiamare il metodo Delete
sull'oggetto DataServiceContext
.
Le modifiche vengono registrate nell'istanza DataServiceContext
ma non sono inviate immediatamente al server. Una volta terminato di apportare le modifiche necessarie per un'attività specificata, chiamare SaveChanges
per inviare tutte le modifiche al servizio dati.
Aggiornamenti di associazioni
L'infrastruttura di aggiornamento può inoltre gestire modifiche di associazione. È possibile modificare le associazioni tra oggetti .NET e riflettere tali modifiche nella libreria client sotto forma di operazioni di creazione o eliminazione di associazioni nell'interfaccia HTTP. Per illustrare questo scenario, nell'esempio seguente viene creato un oggetto Product
nel database Northwind, che viene quindi associato a un oggetto Category
esistente. Le categorie e i prodotti partecipano in un'associazione uno-a-molti; a un prodotto specificato corrisponde, pertanto, una specifica categoria. Nel codice seguente viene illustrato come utilizzare il metodo Add
per aggiungere un'associazione Product
a un oggetto Category
.
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(new Uri(https://localhost:1234/Northwind.svc));
var c1 = (from c in ctx.Categories
where c.CategoryName == "UpdatedCategory"
select c).First();
Products p = new Products();
p.ProductName = "TestProduct";
p.Discontinued = false;
p.QuantityPerUnit = "1";
p.ReorderLevel = 100;
p.UnitPrice = 1.1M;
p.UnitsInStock = 200;
p.UnitsOnOrder = 0;
ctx.AddObject("Products", p);
// Add binding between product and category
p.Categories = c1;
ctx.SetLink(p, "Categories", c1);
ctx.SaveChanges();
Console.ReadKey();
}
}
La gestione di modifiche ad oggetti grafici arbitrari con associazioni bidirezionali è un problema complesso; librerie avanzate, quali ADO.NET Entity Framework, offrono gestori di stati completi ed estremamente coerenti per la gestione di grafici parzialmente materializzati. La libreria client ADO.NET, d'altra parte, è progettata per un footprint di memoria minimo e fornisce solo le primitive necessarie per consentire il mapping di operazioni di servizio dati ad oggetti .NET.
Nel grafico seguente vengono illustrati le entità e gli stati di entità di origine e destinazione che richiedono vari metodi per l'aggiornamento delle associazioni. Seguire gli assi orizzontale e verticale per individuare i metodi che è consentito chiamare.
Destinazione → Origine ↓ |
null |
Added |
Modified |
Deleted |
Unchanged |
Added |
SetLink |
AddLink SetLink |
AddLink SetLink |
n/d |
AddLink SetLink |
Modified |
SetLink |
AddLink SetLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
Deleted |
SetLink |
n/d |
DeleteLink |
DeleteLink |
DeleteLink |
Unchanged |
SetLink |
AddLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
AttachLink funziona solo se lo stato di origine e destinazione è Unchanged e non salva in modo permanente le relazioni. Non utilizzare AddLink se non si desidera che una chiamata a SavingChanges salvi il collegamento.
Utilizzare objCtx.AddLink(prod, "Categories", c1)
se si dispone di una relazione tra Products
e Catagories
e la proprietà Products.Categories
è un insieme.
Utilizzare objCtx.SetLink(prod, "Categories", c1);
se Products.Cateories
è solo un riferimento.
Durante l'utilizzo di SaveChanges per un'entità di origine in stato Added
, una richiesta POST HTTP include i collegamenti ad altre entità che sono nello stato Modified o Unchanged.
Il metodo AttachLink crea un collegamento nello stato EntityStates.Unchanged
. Questo meccanismo consente agli utenti di creare un collegamento registrato dal contesto che non sarà inviato al server.
Autenticazione nella libreria client
La libreria client .NET utilizza il supporto .NET Framework per il protocollo HTTP. Fra le altre cose, l'infrastruttura del framework gestisce automaticamente gli schemi di autenticazione su HTTP quando viene indicato un set di credenziali.
Per impostazione predefinita, la libreria client non fornisce credenziali allo stack HTTP. È, tuttavia, possibile impostare la proprietà Credentials in DataServiceContext
in modo da puntare a un oggetto che implementi l'interfaccia ICredentials
. Per ulteriori informazioni sulle credenziali, vedere WebRequest.Credentials.
Interazioni asincrone con il servizio dati
Le applicazioni Web devono essere progettate per contenere una latenza fra client e server superiore a quella delle applicazioni eseguite in reti interne. L'utilizzo di interazioni asincrone con il server consente di mantenere attiva l'interfaccia utente mentre l'applicazione è in attesa di una risposta dal server.
In questa versione, la libreria client ADO.NET supporta la modalità operativa asincrona per molte operazioni disponibili nella classe DataServiceContext
, come il recupero e il salvataggio di modifiche. Nell'esempio seguente viene illustrato l'utilizzo nel codice dell'API asincrona della libreria client.
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(new Uri(https://localhost:51905/nw.svc));
DataServiceQuery<Customers> q = ctx.Customers;
q.BeginExecute(
delegate(IAsyncResult ar)
{
foreach (Customers c in q.EndExecute(ar))
{
Console.WriteLine(c.CompanyName);
}
},
null);
Console.ReadKey();
}
}
}
Vedere anche
Concetti
HttpWebRequest GET (framework di ADO.NET Data Services)
Creazione di servizi ADO.NET Data Services