Rappel du contexte

Un exemple typique : une solution constituée de trois projets:

  • Application Silverlight (ainsi que le projet ASP.NET qui sert l'application Silverlight, qu'on ignore ici)
  • Librairie .NET des entités
  • Service web .NET / WCF

L'application Silverlight accède à des données - représentées dans des objets de la librairie d'entités - à partir du service web. Ces deux projets (Silverlight et service web) doivent donc référencer la librairie .NET des entités.

Le problème est que VS nous interdit de référencer un assemblage Silverlight.

La solution qui vient très rapidement à l'esprit est de créer la librairie des entités non pas à partir d'un projet .NET mais Silverlight. Cette solution fonctionne mais amène d'autres problèmes: si le projet est référencé dans un projet .NET, il peut y avoir des conflits entre les versions des assemblages des deux frameworks: System.Core, System.Xml... sont implémentés de la même façon mais dans des fichiers DLL différents. De tels conflits surviendront au moment de l'exécution, lors de l'utilisation d'un membre .NET qui n'est pas implémenté en Silverlight. Par ailleurs, référencer un assemblage Silverlight dans un assemblage .NET alors que cela n'est pas nécessaire me perturbe un peu, pas vous ?

Solution

Face à ce dilemne existentiel, j'ai cherché et trouvé cet excellent article de David Betz. Il fournit deux solutions. Une première qui s'apparente - selon moi - limite à du hack et qui consiste à décompiler en instructions IL les assemblages .NET et à les recompiler après modifications pour tromper VS. Peut-être que cette solution trouverait sa place dans de très gros projets, aussi je ne juge pas trop vite. Néanmoins, ce n'est pas cette approche que je retiens ici. La deuxième solution consiste à créer une copie du projet .NET en Silverlight (en fait, il est plus judicieux de faire l'inverse comme on le verra par la suite). Cette copie contient des liens vers les fichiers du premier projet. De cette façon, il n'y a pas réellement duplication de code. Ce sont les mêmes fichiers qui servent à compiler les DLL de versions différentes.

Pour bien appréhender l'une ou l'autre de ces solutions, il faut bien comprendre que du point de vue du code IL, rien ne permet de distinguer un assemblage Silverlight d'un assemblage .NET. Si le projet .NET n'utilise que des éléments implémentés dans le framework Silverlight, son code IL est parfaitement compatible avec un projet Silverlight. VS se base en fait uniquement sur la version des assemblages natifs (System.Core notamment) pour déduire qu'il s'agit d'un assemblage .NET et nous empêcher de le référencer dans un assemblage Silverlight (en fait, il vérifie l'inverse: s'il s'agit d'un projet Silverlight, en considérant que la version des DLL référencées correspond au framework 2.0.5). La première solution décrite en détails par David Betz consiste à tromper VS sur la version des références (puisque, par ailleurs, le code IL est compatible).

Donc...

Récapitulons: Silverlight est une autre plateforme qui implémente un sous-ensemble du framework .NET. Si l'on fait abstraction de la partie WPF, tout ce qui est développé en Silverlight est compatible en .NET: List<T>, IEnumerable<T>, etc.. mais évidemment pas ObservableCollection. C'est pour cette raison qu'il est, je pense, préférable d'implémenter la version de base du projet des entités en Silverlight. Ceci évite d'avoir à se soucier de ce qui est compatible en Silverlight à partir d'un code .NET.

La solution consiste donc à créer un nouveau projet correspondant à l'autre version. Par exemple, si le projet de base est Silverlight et se nomme "Entity", nous pourrions créer un projet .NET nommé "Entity.NET". Ensuite, il faut ajouter les fichiers du premier projet sous forme de liens. Dans VS, ceci se fait en ajoutant des "fichiers existants" au projet. Dans la boîte de dialogue qui permet de sélectionner les fichiers, au lieu de cliquer sur "Ajouter", il faut dérouler le bouton-liste et cliquer sur "Ajouter en tant que liens" ("Add as link" dans ma version). Si les fichiers contiennent des instructions using d'assemblages inutiles (tel System.Windows pour Silverlight), supprimez-les. Le code restant doit être compatible à la fois en .NET et Silverlight. Si tout va bien, le nouveau projet doit compiler correctement, comme le projet de base. Ces deux projets contiennent exactement le même code.

Enfin, référencez dans les projets Silverlight la version Silverlight du projet "Entity" (de l'exemple ci-dessus). Puis référencez dans les projets .NET (le service web par exemple) la version .NET "Entity.NET".

Quelques références

http://www.netfxharmonics.com/2008/12/Reusing-NET-Assemblies-in-Silverlight
http://msdn.microsoft.com/en-us/library/9f4t9t92(VS.80).aspx