Traduction

Cet article est la traduction la plus fidèle possible de l'article original de Brad Abrams, Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 8: WCF Based Data Source.

Source de données basée sur WCF

Encore des mises à jour sur ma présentation Mix09 intitulée « building business applications with Silverlight 3 ».

Vous pouvez regarder

La démo requiert les éléments suivants (tout est 100 % gratuit) :

Vous pouvez, de plus, télécharger les fichiers de la démo complète...

Dans la démo originale j'ai démontré comment obtenir vos données d'une base de données directement de la couche web. Plusieurs clients en entreprise ont trouvé que leurs systèmes sont plus maintenables et sécurisés s'ils isolent l'accès à la base de données derrière un ensemble de services web, éventuellement dans une zone démilitarisée (DMZ). Cela signifie qu'aucune application ne communique directement avec la base de données. Pourtant il y a souvent un besoin d'ajouter une validation propre à l'application et la logique de l'application aussi bien que la mise en forme et l'agrégation de données dans la couche web.

Pour démontrer ceci, j'ai refactorisé l'application exemple de la première partie de cette procédure pas à pas afin d'accéder à ses données d'un service WCF plutôt que EF directement. Remarquez que tous les autres bouts de l'interface utilisateur sont restés les mêmes.

Image non disponible

Définir le service

Commençons par définir le service WCF. Dans une application réelle, ce service est défini par un autre groupe et vous êtes seulement autorisé à y accéder, pas à le modifier.

Faites un clic droit sur la solution et ajoutez un nouveau projet WCF Service Application. Je l'ai appelé MyApp.Service, mais vous pouvez choisir ce qui vous convient.

Image non disponible

D'abord, nous créons un modèle Entity Framework pour notre base de données... Cela est fait exactement de la même manière que dans la deuxième partie, mais cette fois ça fait partie de notre Service plutôt que dans la couche web. La démo fonctionnerait exactement de la même manière qu'importe la source de données que vous utilisez... EF était juste facile pour moi afin de débuter, ce n'est pas nécessaire pour ce scénario car nous encapsulons tout derrière une couche de services WCF.

Ensuite, nous définissons l'interface pour notre service

 
Sélectionnez
[ServiceContract]
public interface ISuperEmployeeService
{
 
   [OperationContract]
   IEnumerable<SuperEmployee> GetSuperEmployees(int page);
 
   [OperationContract]
    SuperEmployee GetSuperEmployee(int empId);
 
 
   [OperationContract]
   void UpdateEmployee(SuperEmployee emp);
 
}

Ensuite nous l'implémentons.

 
Sélectionnez
public IEnumerable<SuperEmployee> GetSuperEmployees(int page)
{
   using (var context = new NORTHWNDEntities()) {
   var q = context.SuperEmployeeSet
       .OrderBy(emp=>emp.EmployeeID)
       .Skip(page * PageSize).Take(PageSize);
   return q.ToList();
   }
}

Remarquez qu'ici nous mettons en œuvre la pagination en prenant un paramètre de page. Après un bref inventaire des services réels sur le net, j'ai trouvé ceci comme étant un modèle très commun. C'est très facile avec EF d'accéder uniquement à la page de données que nous voulons.

Consommer le service

Maintenant consommons ce service depuis la couche web. La raison pour laquelle nous le faisons c'est d'obtenir tous les bénéfices des RIA Services en termes de logique de validation, etc., et être en mesure de personnaliser et de s'arroger les données afin que la vue soit tout juste à point pour le client.

D'abord, nous définissons un type SuperEmployee qui est façonné de manière tout juste à point pour le client. Dans cet exemple simple, je l'ai laissé à peu près le même que l'a renvoyé le service, mais vous pouvez utiliser n'importe quelle forme que vous souhaitez.

Remarquez que nous utilisons des attributs pour spécifier les différentes validations que nous voulons qui soient effectuées sur ces données sur le client ET la couche web.

 
Sélectionnez
public class SuperEmployee
{
 
       [ReadOnly(true)]
       [Key]
       public int EmployeeID { get; set; }
   
 
       [RegularExpression("^(?:m|M|male|Male|f|F|female|Female)$", 
           ErrorMessage = "Gender must be 'Male' or 'Female'")]
       public string Gender {get;set;}
 
       [Range(0, 10000,
           ErrorMessage = "Issues must be between 0 and 1000")]
       public Nullable<int> Issues {get;set;}
 
       public Nullable<DateTime> LastEdit {get;set;}
 
       [Required]
       [StringLength(100)]
       public string Name {get;set;}
 
       public string Origin {get;set;}
 
       public string Publishers {get;set;}
 
       public string Sites {get;set;}
}

Ajoutons maintenant une référence au service que nous venons tout juste de créer.

Faites un clic droit sur le projet et sélectionnez Ajouter une référence de service (Add Service Reference.

Image non disponible


Maintenant nous modifions notre DomainService.

 
Sélectionnez
  1: public class SuperEmployeeDomainService : DomainService
  2:   {
  3:       SuperEmployeeServiceClient Context = new SuperEmployeeServiceClient();
  4:  
  5:       public IQueryable<SuperEmployee> GetSuperEmployees(int pageNumber)
  6:       {
  7:           return this.Context.GetSuperEmployees(pageNumber)
  8:                      .Where(emp => emp.Issues > 100)
  9:                      .OrderBy(emp => emp.EmployeeID)
 10:                      .Select(emp =>
 11:                          new MyApp.Web.SuperEmployee()
 12:                          {
 13:                              EmployeeID = emp.EmployeeID,
 14:                              Gender = emp.Gender,
 15:                              Issues = emp.Issues,
 16:                              LastEdit = emp.LastEdit,
 17:                              Name = emp.Name,
 18:                              Origin = emp.Origin,
 19:                              Publishers = emp.Publishers,
 20:                              Sites = emp.Sites,
 21:                          }).AsQueryable();
 22:       }

Remarquez qu'à la ligne 1, nous n'avons plus besoin de dériver de EFDomainService car il n'y a pas de code d'accès DAL dans la couche web maintenant que nous avons factorisé tout cela dans le service.

À la ligne 3, nous créons une instance du proxy de service web WCF.

À la ligne 5, vous pouvez voir que nous prenons un numéro de page- nous aurons besoin de passer cela depuis le client.

À la ligne 7 nous créons une simple requête LINQ pour modifier la forme des données que nous obtenons du service.

Dans le client Silverlight

Maintenant, pour consommer cela dans le client Silverlight c'est très facile... Nous apportons juste quelques modifications au Home.xaml que nous avons créé dans la deuxième partie...

 
Sélectionnez
  1: <riaControls:DomainDataSource x:Name="dds" 
  2:         AutoLoad="True"
  3:         QueryName="GetSuperEmployeesQuery"
  4:         LoadSize="20">
  5:  
  6:     <riaControls:DomainDataSource.QueryParameters>
  7:         <datagroup:ControlParameter ParameterName="pageNumber"
  8:                                     ControlName="pager"
  9:                                     RefreshEventName="PageIndexChanged"
 10:                                     PropertyName="PageIndex">                            
 11:         </datagroup:ControlParameter> 
 12:         
 13:     </riaControls:DomainDataSource.QueryParameters>
 14:  
 15:     <riaControls:DomainDataSource.DomainContext>
 16:         <App:SuperEmployeeDomainContext/>
 17:     </riaControls:DomainDataSource.DomainContext>
 18:  
 19:     <riaControls:DomainDataSource.GroupDescriptors>
 20:         <datagroup:GroupDescriptor PropertyPath="Publishers" />
 21:     </riaControls:DomainDataSource.GroupDescriptors>
 22:  
 23:  
 24:     
 25: </riaControls:DomainDataSource>
 26:  

Remarquez qu'à la ligne 7 nous obtenons le numéro de page de la méthode GetSuperEmployees() depuis le DataPager. Ceci est mis en place de manière telle que quand le DataPager change les pages, le DDS demande des données du serveur.

Si vous êtes attentif à toute la série de billets de blog, vous remarquerez que j'ai enlevé le tri et le filtrage pour cet exemple. J'ai fait cela parce qu'à la base vous êtes limité par l'expressivité de vos données en back-end. Si vos données en back-end ne prennent pas en charge le tri et le filtrage, alors il est difficile de le faire sur le client ! Vous pourriez faire de la mise en cache sur la couche web mais c'est un sujet pour un autre jour.

Comme un exercice amusant, supposons que vous puissiez changer la définition du service WCF, comment ajouteriez-vous le filtrage ? Vous pourriez suivre exactement le même schéma que nous utilisons pour la pagination. Ajoutez un argument au service WCF, ajoutez le même à la méthode de requête GetSuperEmployees() sur le serveur, ensuite ajoutez un autre ControlParameter au DDS obtenant ses données à partir d'un contrôle sur le formulaire. Assez facile! Faites-moi savoir si vous l'essayez.

L'étape finale consiste à lier le DataPager à une collection « shim », juste pour le faire progresser.  

 
Sélectionnez
  1: <data:DataPager x:Name="pager" PageSize="1" Width="379" 
  2:                 HorizontalAlignment="Left"
  3:                 DisplayMode="FirstLastPreviousNext"
  4:                 IsEnabled="True"
  5:                 IsTotalItemCountFixed="False"
  6:                 Margin="0,0.2,0,0">
  7:     <data:DataPager.Source>
  8:         <paging:PagingShim PageCount="-1"></paging:PagingShim>
  9:     </data:DataPager.Source>
 10: </data:DataPager>

Vous pouvez retrouver l'implémentation du PagingShim dans l'échantillon. (Merci à David Poll pour son aide dessus).

Appuyez sur F5, et nous avons quelque chose de cool ! Cela ressemble beaucoup à l'application précédente, mais celle-ci reçoit toutes ses données via WCF !

Image non disponible

Conclusion

Cet article conclut la partie sur les sources de données basées sur WCF. La neuvième partie de cette série d'articles sera consacrée à POCO en tant que source de données et au fournisseur d'authentification.

Remerciements

Je tiens ici à remercier Brad Abrams pour nous avoir autorisé à traduire son article.
Je remercie également ClaudeLELOUP pour sa relecture et ses propositions.