Partager via


Bibliothèque cliente .NET (ADO.NET Data Services Framework)

ADO.NET Data Services Framework inclut la Bibliothèque cliente .NET pour les applications qui utilisent le .NET Framework et ADO.NET Data Services. Les applications qui utilisent la bibliothèque cliente fonctionnent avec des résultats qui proviennent du service de données sous la forme d'objets .NET. Le parcours d'association est géré par des objets CLR (Common Language Runtime).

La Bibliothèque cliente .NET utilise le protocole HTTP et le format AtomPub. Elle est particulièrement adaptée aux réseaux d'entreprise et aux environnements Internet. La seule condition requise est une connectivité de niveau HTTP au service de données, directement ou par le biais de proxys.

System.Data.Services.Client

Pour pouvoir utiliser la bibliothèque cliente, ajoutez une référence à l'assembly System.Data.Services.Client à votre projet. La bibliothèque cliente peut être utilisée à partir de tout type de projet, y compris Windows Forms, Windows Presentation Foundation, ainsi que les projets de site Web.

Les deux constructions principales de la bibliothèque cliente sont les classes DataServiceContext et DataServiceQuery. DataServiceContext représente le contexte d'exécution avec un service de données spécifié. Bien que les services de données soient sans état, ce n'est pas le cas du contexte ; c'est pourquoi l'état sur le client est conservé d'une interaction à l'autre afin de prendre en charge des fonctionnalités telles que la gestion des modifications.

La classe DataServiceQuery représente une requête contre le stockage spécifié à l'aide de la syntaxe d'URI ADO.NET Data Services. Pour exécuter une requête et obtenir les résultats sous la forme d'objets .NET, énumérez l'objet de requête, par exemple à l'aide de la construction foreach en C# ou For Each en Visual Basic.

Pour représenter chacune des entités définies dans le service de données en tant qu'objets .NET, des classes correspondantes doivent être définies pour l'application cliente. L'une des solutions consiste à définir les classes manuellement. L'autre solution consiste à utiliser l'outil DataSvcUtil.exe décrit dans la section suivante.

L'exemple suivant illustre une définition de la classe Address écrite manuellement, basée sur les données de l'exemple de base de données AdventureWorks fourni avec SQL Server 2005. Il utilise l'entité Address et un petit segment de code qui exécute une requête contre le service. Les propriétés de l'élément Address sont affichées en sortie.

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();
            


        }

La sortie est illustrée ci-dessous.

Id: 70 Address Line1: 1792 Belmont Rd. City: Monroe

Utilisation de l'outil DataSvcUtil

La solution consistant à écrire manuellement les classes convient pour un petit nombre de types, mais lorsque le schéma du service de données est plus complexe, la quantité et la taille des classes à maintenir sont trop élevées pour que ce travail puisse être effectué manuellement. Une meilleure option consiste à utiliser l'outil de génération de code DataSvcUtil.exe fourni avec ADO.NET Data Services. Cet outil génère des classes .NET à partir de la définition du service de données.

DataSvcUtil.exe se trouve dans le répertoire \WINDOWS\Microsoft.NET\Framework\v3.5\. La ligne de commande prend un argument : l'URL de base vers le service de données pour lequel des types doivent être générés. Par exemple, si le service Northwind s'exécute sur le serveur de développement Visual Studio à l'adresse https://localhost:1234/Northwind.svc, la ligne de commande permettant de générer des classes est la suivante :

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

La sortie de la commande est un fichier C# (des types Visual Basic peuvent être générés à l'aide du commutateur /language:VB) qui contient une classe pour chaque type d'entité dans le service de données.

Les classes générées ont des membres représentant des valeurs primitives et des associations qui facilitent la navigation parmi le modèle objet.

LINQ to ADO.NET Data Services

La bibliothèque cliente .NET prend en charge les requêtes de service de données avec LINQ (Language-Integrated Queries) en plus de l'interrogation d'un service de données dans un appel à DataServiceContext.CreateQuery, comme illustré sous l'en-tête Microsoft Data Web Client. Pour plus d'informations sur LINQ, consultez LINQ to Entities (en anglais). La bibliothèque cliente gère les détails liés au mappage de l'instruction LINQ à un URI dans le service de données cible et à l'extraction des ressources spécifiées en tant qu'objets .NET. L'exemple suivant montre comment extraire tous les clients dans la ville de Londres et retourner un jeu de résultats trié par nom de société.

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);
            }
        }
    }
}
NoteRemarque

L'ensemble de requêtes pouvant être exprimées dans la syntaxe LINQ est plus étendu que dans la syntaxe d'URI REST (Representational State Transfer) utilisée par les services de données. Une exception est levée si la requête ne peut pas être mappée à un URI dans le service de données cible. Pour plus d'informations sur REST, consultez Services et sémantique REST (ADO.NET Data Services Framework).

NoteRemarque

Les sections de cette section et des deux sections suivantes utilisent l'exemple de base de données Northwind. Vous pouvez télécharger l'exemple Northwind à partir du site Web à l'adresse suivante : https://go.microsoft.com/fwlink/?linkid=24758.

Associations

Le suivi et la gestion des associations entre les objets sont assurés par la classe DataServiceContext. Vous pouvez charger des objets associés de manière « anticipée » ou selon les besoins. Les chargements « anticipé » et « différé » sont discutés dans la documentation ADO.NET Entity Framework sous Querying Data as Objects and Shaping Query Results (en anglais). Les formats d'URL sont discutés dans Modèle d'adressage simple pour les données avec des URI uniformes (ADO.NET Data Services Framework).

Pour charger des entités associées selon les besoins, on utilise la méthode LoadProperty sur le DataServiceContext. L'exemple suivant montre comment charger en différé des entités Product associées à des entités 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);
                 }
              }
            }
        }
    }
}

Vous aurez peut-être besoin dans certains scénarios d'objets associés et souhaiterez éviter la latence liée à une demande supplémentaire nécessaire pour les extraire. Dans ce cas, vous pouvez utiliser l'option expand dans l'URL. La bibliothèque cliente reconnaît que les résultats incluent des entités de niveau supérieur et des entités associées et elles les matérialise toutes sous la forme de graphique d'objets. On appelle cela le chargement anticipé. Le chargement anticipé est semblable à l'exemple précédent, mais les produits connexes sont chargés en un seul aller-retour vers le service de données.

L'exemple suivant illustre l'option d'extension qui inclut des produits en rapport avec des catégories.

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 ;
                }
            }
        }
    }
}

Prise en charge de la mise à jour

Pour créer une instance dans le service de données, créez l'objet .NET puis appelez AddObject sur l'instance DataServiceContext utilisée, en passant l'objet et le jeu d'entités cible, comme illustré dans l'extrait de code suivant.

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();
        }
    }
}

Après qu'une entité a été créée ou modifiée dans le service de données, le service retourne une nouvelle copie de l'entité, y compris toute valeur de propriété ayant pu être mise à jour à cause de déclencheurs dans la base de données ou de clés générées automatiquement. La bibliothèque cliente met automatiquement à jour l'objet .NET avec ces nouvelles valeurs.

Pour modifier une instance d'entité existante, interrogez tout d'abord cet objet, apportez les modifications souhaitées à sa propriété, puis appelez la méthode UpdateObject pour indiquer à la bibliothèque cliente qu'elle doit envoyer une mise à jour pour cet objet.

NoteRemarque

L'exemple ci-dessous utilise une classe de contexte NorthwindEntities créée par l'outil de génération de code décrit plus haut et dérivée de DataServiceContext. Cette classe dérivée fournit des propriétés spécifiques au service afin de simplifier le codage par rapport au service.

L'exemple suivant illustre la syntaxe de mise à jour avec la méthode 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();
        }
    }
}

Pour supprimer une instance d'entité, appelez la méthode Delete sur l'objet DataServiceContext.

Les modifications sont suivies dans l'instance DataServiceContext mais ne sont pas envoyées au serveur immédiatement. Une fois que vous avez terminé d'effectuer les modifications requises pour une activité spécifiée, appelez SaveChanges afin de soumettre toutes les modifications au service de données.

Mises à jour d'associations

L'infrastructure de mise à jour peut également gérer les modifications d'associations. Il est possible de modifier les associations entre objets .NET et de faire en sorte que la bibliothèque cliente reflète ces modifications en tant qu'opérations de création ou de suppression d'association dans l'interface HTTP. Pour illustrer ce mécanisme, l'exemple suivant crée un Product dans la base de données Northwind et l'associe à une Category existante. Les catégories et les produits participent à une association un-à-plusieurs ; par conséquent, un produit spécifié possède une catégorie spécifique. Le code suivant montre comment utiliser la méthode Add pour ajouter une association Product à une 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 gestion des modifications apportées à des graphiques d'objets arbitraires avec des associations bidirectionnelles est un problème complexe ; il existe des bibliothèques avancées telles que l'ADO.NET Entity Framework qui offrent des gestionnaires d'état très riches et à cohérence élevée pour la gestion des graphiques matérialisés partiellement. La bibliothèque cliente ADO.NET, quant à elle, est conçue pour un faible encombrement mémoire et procure uniquement les primitives requises pour autoriser le mappage d'opérations de service de données à des objets .NET.

Le graphique suivant montre des entités sources et cibles et des états d'entités qui requièrent différentes méthodes de mise à jour d'association. Suivez les axes horizontal et vertical pour rechercher les méthodes qu'il est valide d'appeler.

Cible →

Source ↓

Null

Ajouté

Modifié

Supprimé

Inchangé

Ajouté

SetLink

AddLink

SetLink

AddLink

SetLink

n/a

AddLink

SetLink

Modifié

SetLink

AddLink

SetLink

AddLink

AttachLink

DeleteLink

SetLink

DeleteLink

AddLink

AttachLink

DeleteLink

SetLink

Supprimé

SetLink

n/a

DeleteLink

DeleteLink

DeleteLink

Inchangé

SetLink

AddLink

AddLink

AttachLink

DeleteLink

SetLink

DeleteLink

AddLink

AttachLink

DeleteLink

SetLink

AttachLink fonctionne uniquement si la source et la cible sont toutes deux à l'état inchangé. AttachLink ne conserve pas les relations. N'utilisez AddLink que si le résultat souhaité est qu'un appel à SavingChanges n'enregistre pas le lien.

Si vous avez une relation entre Products et Catagories et que la propriété Products.Categories est une collection, utilisez objCtx.AddLink(prod, "Categories", c1).

Si Products.Cateories est seulement une référence, utilisez objCtx.SetLink(prod, "Categories", c1);

Durant SaveChanges pour une entité source à l'état Added, une requête POST HTTP inclut des liens vers d'autres entités qui sont à l'état modifié ou inchangé.

La méthode AttachLink crée un lien à l'état EntityStates.Unchanged. Ce mécanisme permet aux utilisateurs de créer un lien suivi par le contexte qui ne sera pas envoyé au serveur.

Authentification dans la bibliothèque cliente

La bibliothèque cliente .NET utilise la prise en charge du .NET Framework pour le protocole HTTP. Entre autres choses, l'infrastructure du framework gère les modèles d'authentification sur HTTP automatiquement lorsqu'un ensemble d'informations d'identification est fourni.

Par défaut, la bibliothèque cliente ne fournit aucune information d'identification à la pile HTTP. Toutefois, vous pouvez définir la propriété Credentials dans DataServiceContext de sorte qu'elle pointe vers un objet qui implémente l'interface ICredentials. Pour plus d'informations sur les informations d'identification, consultez WebRequest.Credentials (en anglais).

Interactions asynchrones avec le service de données

Les applications Web doivent être conçues de façon à gérer une latence plus élevée entre le client et le serveur, comparé aux applications qui s'exécutent sur des réseaux internes. L'utilisation d'interactions asynchrones avec le serveur aide à conserver une interface réactive pendant que l'application attend de recevoir une réponse du serveur.

Dans cette version, la bibliothèque cliente ADO.NET prend en charge un mode d'opération asynchrone pour une grande partie des opérations disponibles dans la classe DataServiceContext, telles que l'extraction et l'enregistrement des modifications. L'exemple suivant montre comment l'API asynchrone de la bibliothèque cliente est utilisée dans le code.

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();
        }
    }
}

Voir aussi

Concepts

HttpWebRequest GET (ADO.NET Data Services Framework)
Création d'ADO.NET Data Services

Autres ressources

Entity Data Model