Condividi tramite


.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);
            }
        }
    }
}
NoteNota

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).

NoteNota

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.

NoteNota

Nell'esempio seguente viene utilizzata una classe di contesto NorthwindEntities creata dallo strumento per la generazione di codice precedente e derivata da DataServiceContext. Questa classe derivata fornisce le proprietà specifiche del servizio per semplificare la codifica dello stesso.

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

Altre risorse

Entity Data Model