Dans le cadre d’un projet sur lequel je travaille, j’ai défini l’architecture et l’implémentation d’une Solution de type « Business Application », utilisant SQL Azure comme backend, Entity Framework 4.0 comme Data Access Layer, RIA Services comme couche services, et enfin Silverlight 4 comme partie UI.
C’est un chalenge très intéressant sur lequel j’ai travaillé, et je souhaitais pouvoir partager les points sur lesquels ont porté mon attention pour que tout cela fonctionne bien ensemble
Les « Retry policies » :
Pour ceux qui ne le savent pas, SQL Azure est nettement plus sensible au niveau connectivité qu’un backend SQL Server standard, du fait du nombre de bases SQL Azure que gère le cluster Azure.
Pour cela, Microsoft a donné des recommandations d’utilisation de SQL Azure utilisant des « Retry Policies »; ces Retry Policies vont permettre de tenter de reconnecter une connexion sous-jacente ou de soumettre « à nouveau » une requête en fonction de certains codes erreurs SQL correspondant à des cas de blocage de SQL Azure.
La AppFabric Customer Advicory Team (CAT) a mis à disposition une série de classes implémentant la gestion de ces erreurs avec SQL Azure (appelé Transient Fault Handling Framework for SQL Azure).
Dans le cadre de requêtes simples générées côté serveur en LINQ, on peut leur ajouter une jolie Retry Policy, mais les chose sont différentes lorsque Entity Framework gère cela lui-même.
Il n’est pas possible aujourd’hui d’intercepter toutes les requêtes générées par EF pour les encapsuler dans une Retry Policy (pas d’évènements ou de méthodes partielles pour cela); le mieux que l’on puisse faire est au moins de regarder sur chaque création de ObjectContext que la connexion soit bien effectuée comme sur cet article de la AppFabric « CAT » team.
Relations « Many to Many » avec Entity Framework 4 & RIA Services :
Un autre problème intéressant ici : Entity Framework 4 gère très bien le N-to-N relationship lors de l’import des tables dans le modèle EF. Même lorsqu’on crée le Domain Service contenant les entités liés en N-N à travers Visual Studio les « EntityCollection<T> » sont bien là… Mais lorsque l’on essaie d’accéder à cette collection coté Silverlight… Et bien rien, RIA Services ne supportes pas l’exposition de relations N-N.
La solution : changer quelque peu votre table de liaison N-N qui ne contient que les clé étrangères des entités qu’elle lie en lui ajoutant juste une colonne (un TimeStamp par exemple). Une update do modèle EF et hop une table en plus, qui du coup va nous permettre la navigation N-N côté Silverlight.
L’interaction devient du coup plus chargée (puisque impliquant une tale de plus), mais c’est tout de même mieux que ne pas pouvoir y accéder du tout !
Utilisation des EntityCollection<T>, de l’attribut [Composition] et problèmes de chargement de données :
Pour ce scénario, je vais prendre un exemple :
Dans cet exemple je vais volontairement utiliser le même DomainContext pour toutes les requêtes faites.
Prenons une table Customer et une table Order ; un Customer a donc plusieurs Orders (table Order qui contient en clé étrangère la primary key de Customer, un grand classique).
Nous chargeons une liste de Customers affiché dans une grille, sans remonter les Orders (pour de meilleures performances). Une fois le Customer sélectionné, nous affichons les détails de ce Customer, mais gardons l’affichage des éléments Orders pour un sous-écran.
Une fois sur ce sous-écran, nous chargeons les Orders de cet utilisateur depuis le même DomainContext.
Si vous voulez pouvoir ajouter et supprimer des éléments dans la propriété EntityCollection<Order> de notre Customer, il vous faudra d’abord charger les donnés de cette liste, puis marquer cette liste dans les metadatas de Customer comme [Composition] car :
- Si votre liste est vide, vous ne pourrez pas lui demander de supprimer un élément récupéré depuis une autre requête,
- Si vous essayer de supprimer un élément depuis cette liste sans l’attribut [Composition], même chargée, RIA Services va tenter de mettre la clé pointant sur votre objet Customer à vide, ce qui génèrera une erreur de contrainte de clé étrangère dans SQL Server…
Le fait de devoir charger l’objet entièrement depuis une liste, ou de recharger la totalité de l’objet, surtout si celui ci contient des dizaines de ces sous-écrans est un non-sens.
=> Je préfère garder cette partie simple (KISS approach): Je charge l’objet une fois, je charge ensuite dans une autre requête les sous éléments, et je les manipule directement sur le DomainContext en utilisant par exemple this.MyDomainContext.Orders.Remove(order);
Un point très intéressant à noter d’ailleurs : si vous utiliser un DomainDataSource qui utilise une requête sur la même entité que celle o~u s’effectue votre ajout/suppression, la requête sera automatiquement rejoué une fois votre SubmitChanges fait !!
Timestamps et StoreGeneratedPattern à travers RIA Services :
L’utilisation de Entity Framework au travers de RIA Services permet l’utilisation de l’Optimistic Locking de Entity Framework. cette vérification marche très bien, sauf pour l’insertion d’une nouvelle entit. L’erreur donnée est que le TimeStamp ne peut pas être vide…
Ce message ne devrait certes pas arriver, car c’est au moment de l’insert en base que doit être généré ce TimeStamp. Pour contourner le problème, il faut implémenter la méthode anonyme sur l’entité côté client Silverlight, et setter la valeur du TimeStamp :
public sealed partial class Customer
{
partial void OnCreated()
{
// TimeStamp set for insertion issue.
this._timeStamp = new byte[] { 0 };
}
}
Session State management et Windows Azure :
Lorsque l’on développe son application web en interne et que l’on utilise de multiples serveurs Web frontaux, on bascule le Session State généralement vers du SQL Server.
Pour le cas d’une solution Azure, de multiples solutions existent :
- SQL Azure, mais de manière non supportée, avec un sample ici,
- Azure Table Storage avec un provider présent dans les samples Azure,
- ou dans le AppFabric Caching Service.
Du fait du coup prohibitif de ce dernier, je choisirai probablement la solution 1 ou 2. Pour des raisons de simplicité et de support, mon choix s’est porté sur la deuxième solution, même si SQL Azure ne possède pas de SQL Agents qui vont automatiquement supprimer les sessions expirées.
SAF Framework pour simplifier la gestion de la sécurité des RIA Services :
Après quelques recherches sur le sujet de la sécurité et la validation d’accès aux méthodes exposés pas les Services RIA, je me suis dit que la majorité des cas pouvait être factorisé :
Autoriser le rôle « Manager » a avoir accès en Read/Write sur l’entité « Market »,
Interdire l’acccès au rôle « NormalUser » à l’édition de l’entité « Customer ».
Grâce au SAF Framework (Simple Authentication Framework), cela peut se faire en décorant d’attributs les metadatas de classes ou de méthodes :
[Grant(Roles=new[]{"Admin"}, Permissions = Permission.All)]
[Grant(Roles=new[]{"NormalUser"}, Permissions = Permission.View)]
public class Metadata
{
}
On peut même ici donner comme pour les rêgles de validation sur les metadatas des méthodes custom

Bonjour,
Je débute en silverlight (Développement d’une application avec VS 2010 et Silverlight 4) j’utilise une base SQL 2008 contenant des tables liées sous la forme One to Many. (Utilisateur vers Incidents et Site vers Incidents)
Au chargement des tables Utlisateur et Site pour la création des données tout fonctionne correctement.
Au chargement de la table Incidents pour gérer les incidents j’ai une inner exception sur le chargement de la requète « GetIncidents » concernant les colonnes non valides « Utilisateur.IDUtilisateur » et « Site.IDSite ».
Il semblerait que votre solution pourrait résoudre mon problème mais comme je débute je ne sais comment l’appliquer.
Pourriez-vous m’envoyer une application modèle afin que j’étudie la solution ou m’indiquer un lien vers une application identique.
Merci de votre réponse.
Cordialement.
Philippe
Bonjour Philippe,
As-tu utilisé Entity Framework pour faire ton modèle ? Si oui, lorsque tu fais une requête dans ton LinqToEntitiesDomainService sur 1 entité qui en contient d’autres, ton doit indiquer 2 choses:
ajouter l’attribut [Include] sur chacune des propriétés contenant de l’objet requété pour quelle puissent être retournées par la requête (ex: public class Incidents { [Include]public User Utilisateur {get; set; }
ajouter dans la méthode Query qui retourne tes entités incidents un apple à la méthode Include sur l’objet enfant (var query = this.ObjectContext.Incidents.Include(« Utilisateur »), la chaine de caractère en fin d’instruction devant être le nom de la propriété et non celui de la classe.
Bonjour,
Mon erreur venait de la déclaration des assignations entre les tables dans le projet, alors qu’il fallait que je les déclare dans la base SQL.
Merci de votre aide.
Philippe