Présentation des nouveautés de WCF Data Services 1.5

Jean-Michel Ormes

Cet article vous présentera les nouveautés de WCF Data Services 1.5 (anciennement appelé ADO.NET Data Services), framework utilisé pour déployer des services de données sur le Web ou en intranet. Commentez

- Titre : Présentation des nouveautés de WCF Data Services 1.5

- Auteur : Jean-Michel Ormes

- Parution : 8 janvier 2010

- Mise à jour : 8 janvier 2010

- Licence : Copyright ® 2009 Jean-Michel Ormes. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Introduction

- 1. Prérequis

- 2. Liste des nouveautés de WCF Data Services 1.5

- 2-1. La liaison de données sous WPF et Silverlight 2

- 2-1-1. Création du service Web

- 2-1-2. Création du client WPF

- 2-2. Comptage des entités

- 2-3. Mappage personnalisé

- 2-4. Pagination contrôlée du côté serveur

- 2-5. Meilleure prise en charge du BLOB (Binary Large OBject)

- 2-6. Projection (requête SELECT)

- 3. Conclusion

Introduction

WCF Data Services est un framework permettant d'effectuer des requêtes sur des services de données disponibles sur le web ou en intranet. Les données sont transmises sous la forme de requêtes REST (Representational State Transfer), identifiées par des URL.

Les applications clientes utilisent bien souvent des requêtes HTTP (GET, POST, PUT et DELETE) afin de procéder aux différentes transactions. Les formats utilisés pour représenter et transporter ces données sont en général ceux que l'on retrouve dans des formats d'échange de données tels que JSON, AtomPub et surtout XML.

À travers cet article, nous aborderons les nouveautés qu'apporte la nouvelle version de WCF Data Services 1.5, par rapport à sa précédente mouture.

1 - Prérequis

Pour travailler avec WCF Data Services 1.5, plusieurs éléments devront être installés sur votre ordinateur :

1. Microsoft.NET Framework 3.5 SP1 disponible à cette adresse :
http://www.microsoft.com/downloads/details.aspx?displaylang=fr&FamilyID=ab99342f-5d1a-413d-8319-81da479ab0d7

2. Visual Studio 2008 SP1 ou Microsoft Visual Web Developer 2008 Express Edition ou une version ultérieure :
http://www.microsoft.com/downloads/details.aspx?FamilyID=fbee1648-7106-44a7-9649-6d9f6d58056e&displaylang=fr

3. ou encore
http://www.microsoft.com/downloads/details.aspx?FamilyID=fbee1648-7106-44a7-9649-6d9f6d58056e&displaylang=fr

4. La CTP2 d'ADO.NET Data Services v1.5 disponible à cette adresse :
http://www.microsoft.com/downloads/details.aspx?familyid=A71060EB-454E-4475-81A6-E9552B1034FC&displaylang=en

2 - Liste des nouveautés de WCF Data Services 1.5

2-1 - La liaison de données sous WPF et Silverlight 2

Première nouveauté : celle-ci concerne la liaison des données sous Windows Presentation Foundation et Silverlight 2. Désormais, il est possible de mettre à jour automatiquement les données de la source vers la cible, mais également dans le sens inverse.

2-1-1 - Création du service Web

Nous allons, par l'intermédiaire d'un exemple, créer un service de données Web et un client WPF qui nous permettra d'illustrer cette nouveauté.

On crée un nouveau site Web (Fichier > Nouveau > Projet) :

On choisit une application de service Web ASP.NET. Nous ajoutons ensuite un nouvel objet de type Service de données ADO.NET :

Nous pouvons à présent créer le modèle de données de notre service Web en ajoutant un objet de type ADO.NET Entity Data Model :

En cliquant sur [Ajouter], un assistant apparaît, proposant de générer un modèle à partir d'une base de données ou de créer un modèle vide. Pour cet exemple, j'ai opté pour la première solution en suivant les étapes proposées et en sélectionnant la table [Membre] de ma base de données.

Cette table contient les enregistrements suivants :

Une fois en possession de tous ces éléments, nous pouvons commencer à écrire notre application. Dans un premier temps, nous allons nous attaquer au code du service Web. Voici notre fichier [WebDataServiceDeveloppez.svc.cs], tel qu'il est à sa création :

WebDataServiceDeveloppez.svc.cs

namespace WebServiceDeveloppez
{
public class WebDataServiceDeveloppez : DataService</*TODO : placez ici le nom de votre
* classe source de donnÃ©es */>
{
// Cette mÃ©thode n'est appelÃ©e qu'une seule fois
// pour initialiser les srtatÃ©gies au niveau des services.
public static void InitializeService(IDataServiceConfiguration config)
{
//config.SetEntitySetAccessRule("*", EntitySetRights.All);
//config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
}
}
}

Il s'agit d'une classe qui dérive d'un service de données. La première balise de commentaires nous indique qu'il nous faut sélectionner la classe qui sera utilisée en tant que source de données. Ayant précédemment utilisé un modèle de données de type [ADO.NET Entity], la classe à utiliser sera [developpezEntities] :

developpezEntities

public class WebDataServiceDeveloppez : DataService<developpezEntities>

On peut lancer l'application pour constater que notre service est bien fonctionnel :

Nous allons maintenant nous intéresser à la suite du code de notre service. Celui-ci contient une méthode [InitializeService] qui permet de configurer les données qui seront visibles via le service :

InitializeService

// Cette mÃ©thode n'est appelÃ©e qu'une seule fois
// pour initialiser les srtatÃ©gies au niveau des services.
public static void InitializeService(IDataServiceConfiguration config)
{
//config.SetEntitySetAccessRule("*", EntitySetRights.All);
//config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
}

La méthode [SetEntitySetAccessRule] permet de configurer les droits d'accès à l'entité spécifiée tandis que la deuxième méthode [SetServiceOperationAccessRule] permet de configurer l'accessibilité aux services. Une fois ces méthodes configurées, on pourra voir apparaître les données :

SetEntitySetAccessRule et SetServiceOperationAccessRule

config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

2-1-2 - Création du client WPF

Nous allons maintenant créer un client WPF afin de consommer le service de données. Pour cela, on ajoute un projet de type WPF (Fichier > Ajouter > Nouveau projet) :

À ce projet, nous ajoutons un objet de type [ListView] que nous lierons à la table [Membre] :

ListView

<ListView ItemsSource="{Binding Membres}" Grid.Row="0"
IsSynchronizedWithCurrentItem="True" Name="listView">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Nom" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Width="100" Text="{Binding Nom}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="PrÃ©nom" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Width="100"  Text="{Binding Prenom}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="RÃ&#180;le">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Width="120" Text="{Binding Role}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>

Le [ListView] contient 3 colonnes (Nom, Prénom et Rôle) avec des champs éditables. Nous ajouterons également des [TextBox] (1 pour chaque information) qui feront office de "cibles" ainsi qu'un [Button] pour valider nos changements :

TextBox

<TextBox Grid.Row="0" Grid.Column="2"
Text="{Binding Nom}" Name="TextBox1" />

<TextBox Grid.Row="1" Grid.Column="2"
Text="{Binding Prenom}" Name="TextBox2" />

<TextBox Grid.Row="2" Grid.Column="2"
Text="{Binding Role}" Name="TextBox3" />

<Button Grid.Row="3"
Grid.Column="2"
HorizontalAlignment="Right"
Content="Valider"
Click="Button_Click"/>

On définira le code behind de la façon suivante :

Window1.cs

public partial class Window1 : Window
{
WebDataServiceDeveloppez.developpezEntities wds;
private HashSet<object> _modifiedEntities = new HashSet<object>();

public ObservableCollection<Membre> Membres { get; private set; }

public Window1()
{
InitializeComponent();

wds = new WebDataServiceDeveloppez.developpezEntities(
new Uri("http://localhost:1083/WebDataServiceDeveloppez.svc"));
this.Membres = new ObservableCollection<Membre>(wds.Membre);
this.DataContext = this;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
foreach (var membre in _modifiedEntities)
{
wds.UpdateObject(membre);
}

wds.SaveChanges();
_modifiedEntities.Clear();
}
}

Nous faisons appel à notre source de données, puis nous initialisons une collection d'objets de type [Membre] avec les informations fournies par la source. Dans l'événement [Click] du [Button], on met à jour la source de données. Si l'on compile le projet, on obtient la fenêtre suivante :

Si l'on modifie une information sur la source (ou la cible), la mise à jour est également faite sur la cible (ou la source).

2-2 - Comptage des entités

Il est désormais possible de déterminer le nombre d'entités d'une table selon les filtres que l'on désire appliquer. Il suffit d'ajouter l'attribut $count dans l'URI, la table sur laquelle on va filtrer ainsi que le filtre. Par exemple, le lien URI suivant renverra 3 :

http://localhost:1083/WebDataServiceDeveloppez.svc/Membre/$count?$top=3

D'autres exemples de requêtes :

Requête

Réponse

/Membre/$count

3

/Membre/$count?$top=100

3

/Membre/$count?$top=2

2

2-3 - Mappage personnalisé

Par défaut, WCF Data Services utilise le protocole AtomPub pour exposer les données sur le Web.

Dans la nouvelle version d'WCF Data Services 1.5, il existe une fonctionnalité que l'on appelle le mappage personnalisé. Celle-ci nous permet de mapper une propriété à un élément sans passer par AtomPub. Ceci est aussi bien valable pour un élément prédéfini (ex. : [Nom] ou [Prenom] dans la table [Membre]) que pour un élément personnalisé. De ce fait, on dispose d'informations supplémentaires dans notre service de données qui peuvent être interprétées par des clients à même de les comprendre.

2-4 - Pagination contrôlée du côté serveur

Lorsqu'un utilisateur soumet une requête qui risque de renvoyer une multitude de données du serveur, le service Web peut forcer une mise en page et ne retourner que les enregistrements désirés au client. Si la pagination est exécutée, un lien URI sera inclus dans la requête, permettant de diriger le client vers la prochaine page.

2-5 - Meilleure prise en charge du BLOB (Binary Large OBject)

Si une entité contient des données binaires, on peut les séparer en deux parties : les liens et les ressources. Les ressources représentent les données binaires actuelles tandis que les liens représentent les métadonnées et les informations supplémentaires des données binaires. On peut également effectuer des requêtes sur l'un ou l'autre.

2-6 - Projection (requête SELECT)

On peut effectuer une requête SELECT en ajoutant $select à notre URI. Ce nouvel attribut nous permet de spécifier les données de la table que l'on souhaite retourner. Par exemple, l'URI suivant ne renverra que le champ [Role] de la table [Membre] :

http://localhost:1083/WebDataServiceDeveloppez.svc/Membre?$select=Role

Pour retourner plusieurs champs, on utilise la virgule comme séparateur :

http://localhost:1083/WebDataServiceDeveloppez.svc/Membre?$select=Nom,Role

3 - Conclusion

Au cours de cet article, nous avons passé en revue les nouvelles fonctionnalités associées à WCF Data Services 1.5. Ce produit en est à sa première évolution, mais celles-ci apportent un peu plus de conforts aux développeurs.

J'aimerais simplement remercier les membres de l'équipe Dotnet de Développez qui m'ont aidé tout au long de la rédaction de cet article, plus particulièrement Thomas Levesque pour ses conseils et son expérience sur WPF, ainsi que Louis-Guillaume Morand, Melem et Wachter pour les corrections apportées à cet article.