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

Image non disponible


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

Image non disponible


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 :

Image non disponible


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.

Image non disponible


Cette table contient les enregistrements suivants :

Image non disponible


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
Sélectionnez

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
Sélectionnez

public class WebDataServiceDeveloppez : DataService<developpezEntities>


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

Image non disponible


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
Sélectionnez

// 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
Sélectionnez

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

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

Image non disponible


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

ListView
Sélectionnez

<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ô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
Sélectionnez

<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
Sélectionnez

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 :

Image non disponible


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.