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 16: Exposing a WCF Service.

Article

Je m'éclate sur cette série où je mets à jour ma simple démo d'application métier du Mix 09. Dans cette partie, je voulais traiter un scénario qui est, je l'espère, assez fréquent. Le développeur écrit son application Silverlight en utilisant le modèle "RIA Services" et l'application rencontre un grand succès. Un si grand succès qu'il y a une forte demande pour exposer la logique de l'application via un service pour faciliter l'écriture de plein d'autres clients. C'est le genre de scénario qu'on voit apparaitre avec des applications comme Twitter et Sharepoint.

Cette démo nécessite les éléments suivants (tout est 100 % gratuit) :

  • Visual Studio 2008 SP1 (qui inclut SQL Server Express 2008) ;
  • Silverlight 3 RTM ;
  • .NET RIA Services July '09 Preview (facultatif pour cette partie de la démo).

Téléchargez aussi les fichiers de la démo complète, et jetez un œil à l'application en cours d'exécution.

Pour commencer, reprenons l'application des parties précédentes de la série et ajoutons-y un point d'accès WCF. Pour cet exemple, supposons qu'on veuille simplement fournir la possibilité d'obtenir et de définir les "sites" pour nos superhéros. Cela permettra à un paquet de gens de vous aider à trouver les superhéros.

Image non disponible

Dans les posts précédents, nous avions défini un DomainService :

 
Sélectionnez

[EnableClientAccess]
public class SuperEmployeeDomainService :
   LinqToEntitiesDomainService<NORTHWNDEntities>
{
   public virtual IQueryable<SuperEmployee> GetSuperEmployees()
   {
       return this.Context.SuperEmployeeSet
                  .Where(emp=>emp.Issues>100)
                  .OrderBy(emp=>emp.EmployeeID);
   }

   public virtual SuperEmployee GetSuperEmployee(int employeeID)
   {
       return this.Context.SuperEmployeeSet
                  .Where(emp => emp.EmployeeID == employeeID)
                  .FirstOrDefault();
   }
   
   public virtual void InsertSuperEmployee(SuperEmployee superEmployee)
   {
       this.Context.AddToSuperEmployeeSet(superEmployee);
   }
   
   public override void Submit(ChangeSet changeSet)
   {
       base.Submit(changeSet);
   }
   
   public virtual void UpdateSuperEmployee(SuperEmployee currentSuperEmployee)
   {
       var org = this.ChangeSet.GetOriginal(currentSuperEmployee);
       this.Context.AttachAsModified(currentSuperEmployee, org);
   }

et un client Silverlight.

Et nous avons créé une application Silverlight pour fonctionner avec :

Image non disponible

Dans cette partie, commençons par ajouter un simple service WCF à notre projet web :

Image non disponible

Nous pouvons ensuite définir notre contrat de service. Remarquez qu'il peut prendre la forme que l'on veut. Il n'a pas besoin d'être conforme en aucune manière à notre DomainService.

 
Sélectionnez

[ServiceContract]
public interface ISuperHeroSitesService
{
   [OperationContract]
   void SetSite(string superHeroName, string site);

   [OperationContract]
   string GetSite(string superHeroName);

   [OperationContract]
   IEnumerable<string> GetSuperHeroNames();
}

Ensuite, implémentons le service.

La façon la plus simple de faire ceci est d'utiliser l'infobulle :

Image non disponible
 
Sélectionnez

[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class SuperHeroSitesService : ISuperHeroSitesService
{

   SuperEmployeeDomainService domainService =   DomainServiceProxy.Create<SuperEmployeeDomainService>();

On commence ensuite à implémenter le service. Remarquez que je mets le service en mode de compatibilité ASP.NET, ce qui nous permet d'accéder aux informations de session d'ASP.NET pour gérer des choses comme l'authentification, etc. Ensuite, j'inclus les informations d'exception pour faciliter le débogage.

Enfin, je crée une instance de notre DomainService que j'utiliserai pour implémenter le service. Comme dans l'exemple ASP.NET MVC, on n'appelle pas explicitement le constructeur de SuperEmployeesDomainService, parce qu'on veut tirer parti du pipeline de validation. Nous appelons donc une méthode de fabrication (Factory Method) pour créer notre instance de SuperEmployeeService. Remarquez qu'avec la CTP actuelle, vous aurez besoin d'ajouter une référence à l'assembly DomainServiceExtensions.dll de cet exemple pour avoir cette fonctionnalité.

On commence ensuite à implémenter nos méthodes. GetSuperHeroNames() est assez simple. On récupère simplement tous les SuperHeros auxquels la classe DomainService nous permet d'accéder, et on renvoie simplement leurs noms.

 
Sélectionnez

public IEnumerable<string> GetSuperHeroNames()
{
   var q = domainService.GetSuperEmployees();
   return q.Select(emp => emp.Name);
}

C'est très similaire pour GetSite. Ici, on cherche l'employé en question et on renvoie son site.

 
Sélectionnez

public string GetSite(string superHeroName)
{
   var q = domainService.GetSuperEmployees();
   var employee = q.Where(emp => emp.Name.ToUpper() == superHeroName.ToUpper()).FirstOrDefault();
   return employee.Sites;
}    

Pour SetSite, j'ai défini une méthode dans mon DomainService pour gérer cette opération. Mais j'ai trouvé qu'il était plus générique d'avoir une méthode commune de DomainService qui prend l'ID plutôt que le nom.

 
Sélectionnez

[ServiceOperation]

public virtual void SetSite(int empId, string site)

{
   var employee = GetSuperEmployee(empId);
   employee.Sites = site;
   this.Context.SaveChanges();
}

Ensuite la méthode dans le service WCF était assez facile à implémenter :

 
Sélectionnez

public void SetSite(string superHeroName, string site)
{
  var q = domainService.GetSuperEmployees();
  var employee = q.Where(emp => emp.Name.ToUpper() == superHeroName.ToUpper())
           .FirstOrDefault();
  if (employee == null) throw new Exception(String.Format("Employee named '{0}' not found.",superHeroName));
  domainService.SetSite(employee.EmployeeID, site);
}

Nous avons maintenant un service fonctionnel.

Image non disponible

Créons maintenant une application en ligne de commande qui teste notre petit service. À ce stade, vous pourriez créer n'importe quel client arbitraire, que ce soit en ASP.NET, Windows Forms, ou même Java ou PHP.

Créons une application console :

Image non disponible

Nous devons maintenant ajouter une référence au service que l'on vient de créer :

Image non disponible

On écrit ensuite le code de notre client.

 
Sélectionnez

Console.WriteLine("List of all SuperHero names");
foreach (var name in context.GetSuperHeroNames())
{
   Console.WriteLine(name);
}
Image non disponible

Récupération du site pour un employé donné :

 
Sélectionnez

Console.WriteLine("'{0}' site is currently: '{1}' ", args[0], context.GetSite(args[0]));
Image non disponible

Définition du site pour un employé donné :

 
Sélectionnez

var site = string.Join(" ", args.Skip(1).ToArray());
Console.WriteLine("siting superhero '{0}' site to '{1}' ", args[0], site);
context.SetSite(args[0], site);
Image non disponible

Dans cet exemple, je vous ai montré comme "augmenter" votre application Silverlight basée sur .NET RIA Services pour offrir un service WCF personnalisé avec juste le contrat que vous voulez. Ce service peut être utilisé à partir de n'importe quel client.

Profitez-en !

Conclusion

Ceci conclut la seizième partie de cette série. La partie suivante expliquera comment faire évoluer une application.

Remerciements

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