Techdays 2009 : Implémenter WPF, Silverlight et Azure .NET Service Bus avec Dynamics CRM (NAV201)
Vous avez peut être assisté à la session NAV201 - “Découvrez comment combiner des développements WPF, Silverlight et Azure avec l'architecture orientée services de Microsoft Dynamics CRM” présentée par Daniel Tizon au Techdays 2009, session où j’ai participé en grande majorité avec l’aide de Gregory OTT à la réalisation du contenu technique dans le cadre de nos activités à Winwise. La session au Techdays 2009 proposait la gestion des séminaires depuis une application WPF.
Un heure c’est relativement court quand on souhaite communiquer sur l’ensemble de l’architecture, c’est pourquoi j’ai souhaité revenir vers vous pour partager mon expérience sur la combinaison d’un développement externe avec CRM dans le cadre de la solution de réservation des salles, la thématique de mes précédents posts.
Dynamics CRM expose un web service CRM permettant d’étendre les possibilités du produit vers l’extérieur.
Pour ma part je pense qu’il est indispensable d’encapsuler le web service au sein d’un service WCF afin de :
- Permettre une exposition à l’aide de Service Bus.
- Proposer une couche de service applicative enrichie.
- Normaliser l’architecture service.
Voici l’architecture projet d’une implémentation WPF et/ou Silverlight autour de Dynamics CRM.
| 
| La solution contient :
Un projet WPF et Silverlight qui référence une couche de service WCF (CrmBusinessPlatform.Run)
Un projet d’interface, d’implémentation des interfaces, et d’exécution du service.
Un projet qui permet d’échanger des entités entre les différentes couches. (DataContract sur la classe, DataMember sur chaque propriétés)
Le projet Libraries établit une référence au service CRM.
|
Fonctionnalité PolicyRetriever :
L'exposition de mon clientaccesspolicy.xml par WCF pour Silverlight est décrit dans l'article suivant :
http://blogs.developpeur.org/davidrei/archive/2009/02/15/silverlight-wcf-exposer-le-clientaccesspolicy-xml-avec-wcf-et-rest.aspxStructure du service CrmBusinessPlatform:Le service suivant encapsule l'accès vers le web service CRM. Dans un soucis de performance de notre service, il est déclaré dans un contexte d'exécution unique
(
InstanceContextMode = InstanceContextMode.Single). En effet notre instance vers le webservice est ici toujours active d'une requête à une autre.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
[ServiceBehavior(Name = "Service", InstanceContextMode = InstanceContextMode.Single, Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class CrmBusinessPlatformServices : ICrmBusinessPlatform, IPolicyRetriever { private CrmService _myService; public CrmService CRMService { get { if (_myService == null) _myService = GetCrmService("CRM4"); return _myService; } }
#region ICrmBusinessPlatform Members #endregion #region IPolicyRetriever Members #endregion
private CrmService GetCrmService(string organizationName) { CrmAuthenticationToken token = new CrmAuthenticationToken(); token.OrganizationName = organizationName; CrmService crmService = new CrmService(); // Same Computer WCF // crmService.UseDefaultCredentials = true; // Other Computers crmService.UseDefaultCredentials = false; crmService.Credentials = new System.Net.NetworkCredential("Administrator", "P@ssw0rd", "CRM4"); crmService.CrmAuthenticationTokenValue = token;
return crmService; } } |
Récupérer la liste des salles :
Pour revenir avec la thématique abordée dans les précédents posts concernant la liste des salles dans CRM, nous pouvons dés lors ajouter la signature de la méthode suivante dans notre interface et l'implémenter comme ci-dessous :
Room étant un objet partagé par l'ensemble de notre solution.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public IEnumerable GetRooms() { QueryExpression query = new QueryExpression();
query.EntityName = "new_salle";
ColumnSet columns = new ColumnSet(); columns.Attributes = new string[] { "new_name", "new_salleid" }; query.ColumnSet = columns;
BusinessEntityCollection resultEntities = CRMService.RetrieveMultiple(query);
if (resultEntities != null && resultEntities.BusinessEntities != null) { foreach (new_salle n in resultEntities.BusinessEntities) { yield return new Room() { ID = n.new_salleid.Value, Name = n.new_name }; } } else yield break; } |
Enregistrer le service WCF sur .NET Service Bus d'Azure :
 |
Notre service peut alors démarrer via service bus. L'approche est intéressante car elle permet de s'affranchir des problématiques d'infrastructure dans l'entreprise. Celui-ci s'enregistre sur la plateforme service bus, puis d'un bout à l'autre la communication est rendu possible ici sur le binding NetTcpRelayBinding. Vous pouvez aussi utiliser le BasicHttpRelayBinding pour vos applications Silverlight. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
static void Main(string[] args) { #region Credentials
string solutionName = "X"; string solutionPassword = "X";
#endregion
// Définition de l'adresse du endpoint Uri address = new Uri(String.Format("sb://servicebus.windows.net/services/{0}/NAV201-WCF/", solutionName));
// Création de l'objet d'authentification pour le endpoint TransportClientEndpointBehavior userNamePasswordServiceBusCredential = new TransportClientEndpointBehavior(); userNamePasswordServiceBusCredential.CredentialType = TransportClientCredentialType.UserNamePassword; userNamePasswordServiceBusCredential.Credentials.UserName.UserName = solutionName; userNamePasswordServiceBusCredential.Credentials.UserName.Password = solutionPassword; // Création du serviceHost ServiceHost host = new ServiceHost(typeof(Service), address); host.AddServiceEndpoint(typeof(ICrmBusinessPlatform), new NetTcpRelayBinding(), "");
// Ajouter l'objet d'authentification service bus à tous les endpoints spécifiés en configuration foreach (ServiceEndpoint endpoint in host.Description.Endpoints) { endpoint.Behaviors.Add(userNamePasswordServiceBusCredential); }
// Ouverture du service host.Open();
Console.WriteLine("Service address: " + address); Console.WriteLine("Press [Enter] to exit"); Console.ReadLine();
// Fermeture du service host.Close(); } |
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :