A la découverte du BDC - Partie 2

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

0. Introduction

Dans cet article, nous allons voir comment écrire nos propres fichiers ADF.

Dans un premier temps, nous allons voir comment créer un fichier ADF « de base », mais cependant pleinement fonctionnel.

Ensuite, nous verrons comment améliorer notre fichier afin de rajouter des fonctionnalités à notre application, afin que cette dernière soit pleinement fonctionnelle, et qu'elle puisse être utilisée de manière optimale par nos utilisateurs finaux.

L'objectif de ce tutoriel est de créer une application qui va modéliser les ressources humaines de la société AdventureWorks, dont la base de données est fournie à titre d'exemple par Microsoft avec SQL Server, ou téléchargeable gratuitement sur CodePlex.

I. Pré requis

Les pré requis pour suivre ce tutoriel sont exactement les même que ceux de l'article précédent « A la découverte du BDC - Partie 1 » ;

De plus, cet article part du postulat que vous avez lu l'article précédent, que vous avez récupéré et installé les composants listés dans l'article précédent, et de manière générale, que suite à l'article précédent, vous vous êtes familiarisé avec les webparts du BDC et l'import d'un fichier ADF.

Si vous n'avez pas lu l'article précédent, je vous conseille vivement de le faire avant de poursuivre la lecture de celui-ci.

II. Préparation de notre environnement

Cet article se veut pédagogique et a pour objectif de familiariser le lecteur avec la création de fichier ADF, ainsi que de démystifier la complexité (inexistante) des fichiers ADF aux yeux du lecteur.

Partant de ce postulat, nous écrirons les fichiers ADF à la main, et chacun des bouts de code que nous utiliserons sera détaillé. Nous verrons très rapidement également quelques outils nous permettant de générer ces fichiers, mais l'objectif de cet article est encore une fois d'expliquer les éléments qui composent un fichier ADF au lecteur, afin que ce dernier puisse les prendre en main très facilement, aussi nous passerons très rapidement sur l'utilisation de ces outils.

Afin de nous faciliter la tache et éviter des erreurs de frappe inutiles, nous allons utiliser Visual Studio pour écrire nos fichiers ADF et sa fonctionnalité d'IntelliSense ; pour cela, nous allons récupérer nos schémas xsd spécifiques au BDC et les intégrer à Visual Studio.

Pour cela, rendez vous dans le répertoire « C:\Program Files\Microsoft Office Servers\12.0\Bin » et récupérez les fichiers bdcmetadata.xsd et bdcmetadataresource.xsd, puis collez les dans le répertoire « C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas» de Visual Studio (2008 ; si vous utilisez VS 2005, remplacez 9.0 par 8.0).

Chacun de ces fichiers correspond a 1 type de fichier ADF que nous pouvons écrire (il y a donc 2 types de fichiers ADF différents, nous les verrons ultérieurement.).

Dorénavant, lorsque vous créez des fichiers ADF utilisez l'un ou l'autre de ces 2 fichiers, suivant votre besoin.

III. Présentation des fichiers ADF

Comme nous l'avons vu dans l'article précédent, les fichiers ADF vont nous permettre de décrire un LobSystem que nous souhaitons intégrer à SharePoint, afin que ce dernier puisse s'y connecter et nous restituer les informations sur notre portail web.

Nous avons également vu qu'il existe 2 types de fichiers ADF, les fichiers modèles (utilisant le schéma bdcmetadata.xsd), qui vont nous permettre de décrire notre LobSystem à proprement parler, et les fichiers ressources (utilisant le schéma bdcmetadataresource.xsd) qui vont éventuellement venir compléter notre fichier modèle en y rajoutant des informations sur la localisation (gestion de la langue), des propriétés (comme par exemple les données à afficher par défaut) et des autorisations, au travers d'ACE appartenant à des ACLs.

image

Dans cet article, nous allons procéder par étapes ; Nous allons tout d'abord commencer par écrire un fichier ADF minimal, mais fonctionnel, puis nous verrons comment améliorer l'application ainsi créée et par la même occasion modifier notre ADF existant afin qu'il devienne plus élaboré ; nous terminerons enfin par la création d'un fichier ADF de ressource pour notre application.

IV. Ecriture de notre fichier adf de base

L'objectif de cette 1ère partie va être de réaliser un fichier ADF simpliste, nous permettant de récupérer tous les départements de la société AdventureWorks.

L'application correspondant à ce fichier et mise à disposition de nos utilisateurs à l'issue de cette phase est illustrée ci-dessous.

image

Sans plus tarder, commençons à travailler !

Ouvrez donc Visual Studio et créez un nouveau fichier xml que nous appelons « bdc.adworks.hr.xml ».

Dans la fenêtre propriétés, sélectionnez « schémas », puis cliquez sur les « . », ensuite sélectionnez « bdcmetadata.xsd » comme illustré ci-dessous

image

Puis cliquez sur Ok. Dorénavant, l'IntelliSense est configurée sur votre fichier.

image

A présent, rentrons dans le vif du sujet.

IV-A. Création de l'élément racine, le LobSystem.

L'élément LobSystem est l'élément racine de notre fichier.

C'est cet élément qui va permettre d'identifier le système que nous souhaitons modéliser.

Dans notre cas, nous souhaitons représenter des éléments présents dans une base de données, nous allons donc utiliser la définition suivante :

 
Sélectionnez
<LobSystem xmlns="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog" Type="Database" Version="1.0.0.0" Name="AdventureWorksHumanResources">
</LobSystem>

L'attribut xmlns va représenter le namespace utilisé par le BDC ; il est rajouté automatique à l'insertion de l'élément. Attention, cette valeur ne doit pas être modifiée !

L'attribut Type va nous permettre de spécifier quel type de source de données nous souhaitons attaquer ; ici, nous allons attaquer la base de données AdventureWorks, donc la valeur de l'attribut sera Database ; l'autre valeur possible est WebService.

L'attribut Version va surtout être utile au niveau SharePoint ; il va nous permettre de pouvoir travailler de manière itérative sur nos fichiers adf ; lorsque nous modifions notre fichier, si nous essayons de le réimporter sans au préalable supprimer l'application de notre infrastructure SharePoint, nous obtenons un message d'erreur.

image

Pour y remédier, il nous suffit d'incrémenter la version de notre fichier, et le tour est joué !

L'attribut Name va simplement nous permettre de nommer notre application.

A cette étape, si nous importons notre application, nous obtenons ceci :

image

Une fois que nous avons défini notre LobSystem, il va falloir que nous décrivions où se situent les données et comment y accéder ; c'est l'élément LobSystemInstance qui va s'en charger.

Grossièrement, un LobSystem c'est :

  • Une (ou plusieurs) LobSystemInstance, qui va nous permettre de spécifier les paramètres de connexion à notre source de données,
  • Des entités, que l'on peut considérer (notamment dans le cadre d'une base de données) comme des objets similaires aux tables ou aux vues,
  • Des associations, que l'on peut considérer (toujours dans le cadre d'une base de données) comme des relations entre tables.

Notre 1ère application sera donc composée d'une entité et d'une instance ; ultérieurement, nous ajouterons d'autres entités et modéliserons des associations.

IV-B. Création d'une instance de notre LobSystem.

Comme nous l'avons vu ci-dessus, nous allons utiliser l'élément LobSystemInstances pour décrire la manière de se connecter à notre LobSystem.

Le bout de code suivant, à insérer juste après l'élément LobSystem, se charge de cette opération.

 
Sélectionnez
<LobSystemInstances>
  <LobSystemInstance Name="AdventureWorksHumanResourcesWebInstance">
    <Properties>
      <Property Name="AuthenticationMode" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAuthenticationMode">PassThrough</Property>
      <Property Name="DatabaseAccessProvider" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAccessProvider">SqlServer</Property>
      <Property Name="RdbConnection Data Source" Type="System.String">.</Property>
      <Property Name="RdbConnection Initial Catalog" Type="System.String">AdventureWorks</Property>
      <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
    </Properties>
  </LobSystemInstance>
</LobSystemInstances>

L'élément LobSystemInstances va nous permettre de créer plusieurs instances ; Il existe cependant une contrainte à respecter lorsque nous travaillons avec plusieurs LobSystemInstances, c'est que toutes ces instances doivent avoir le même schéma. Il est donc impossible de représenter 2 instances différentes pour accéder à 2 bases de données différentes. L'objectif principal de travailler avec plusieurs instances est de spécifier des informations de connexion différentes.

L'élément LobSystemInstance représente donc une de ces instances ; l'attribut Name va permettre de nommer cette instance.

L'élément Properties va nous permettre de rajouter des propriétés au niveau de notre instance ; c'est notamment grâce à ces propriétés que nous allons pouvoir passer les paramètres de connexion. Ces propriétés auraient également pu être ajoutées directement dans un fichier ressource, cependant, étant donné que le fonctionnement de notre application dépend directement d'elles, nous allons les renseigner immédiatement.

Chacune des propriétés renseigne une information de connexion.

Ici, nous spécifions entre autre le type de serveur de base de données utilisé (ici SQL Server), le nom de notre Instance, et notre base de données.

Pour ceux d'entre vous qui ont l'habitude de travailler avec ado.net, ce bout de code doit vous paraitre familier.

Nous spécifions également La propriété AuthenticationMode, qui a ici la valeur PassThrough, ce qui spécifie à SharePoint de récupérer les informations utilisateur et de les passer directement à la source de données ; cette information est couplée avec la propriété Integrated Security qui vaut SSPI. Concrètement, lorsqu'un utilisateur va utiliser le BDC, SharePoint va transmettre directement à SQL Server les informations d'authentification windows de l'utilisateur ; ainsi, si au niveau SQL Server l'utilisateur a les autorisations nécessaires, il pourra accéder aux données depuis le BDC, sinon il recevra un message d'information.

Voila, notre instance est définie !

Passons maintenant à la création de notre entité.

IV-C. Création de l'entité département

Commençons donc par créer notre entité, juste en dessous de l'élément LobSystemInstances.

 
Sélectionnez
<Entities>
 	<Entity Name="Department">
    </Entity>
</Entities>

Nous venons de représenter notre entité, cependant elle est totalement vide.

Pour faire la corrélation avec notre source de données (ici SQL Server), et spécifier toute la logique avec laquelle nous allons récupérer notre entité, il va falloir créer une (ou plusieurs) méthodes.

Une méthode va contenir plusieurs informations :

  • La requête à exécuter nous permettant de ramener nos données,
  • La définition de nos données représentées par des paramètres
  • Les différentes variantes d'exécution de notre requête.

Si nous examinons la structure de la table départements dans la base de données, nous remarquons que nous avons 4 champs :

  • DepartementID, de type smallint (int16 en .net),
  • Name, de type nvarchar(50) (string en .net),
  • GroupName, de type nvarchar(50) (string en .net),
  • Et ModifiedDate, de type datetime (DateTime en .net).

Une requête comme la suivante devrait donc nous permettre de récupérer tous nos départements.

 
Sélectionnez
--sql.adworks.sql
--Connexion à la BD AdventureWorks
use AdventureWorks
go
--Récupération de tous les départements.
select DepartmentID, [Name] as [Service], GroupName as Department, ModifiedDate
from HumanResources.Department
go

Et voici d'ailleurs le résultat.

image

Grâce à ces informations, nous avons donc identifié toutes les informations nécessaires à la conception de notre entité ; notre requête SQL, notre paramètre de sortie, à savoir la table des départements, ainsi que la structure de notre table.

Voici le code complet de l'entité département.

 
Sélectionnez
<Entity Name="Department">
  <Methods>
    <Method Name="GetDepartments">
      <Properties>
        <Property Name="RdbCommandText" Type="System.String">
          select DepartmentID, [Name] as [Service], GroupName as 
             Department, ModifiedDate
          from HumanResources.Department
        </Property>
        <Property Name="RdbCommandType" Type="System.Data.CommandType">Text</Property>
      </Properties>
      <Parameters>
        <Parameter Direction="Return" Name="Departments">
          <TypeDescriptor TypeName="System.Data.IDataReader, System.Data, Version=2.0.3600.0, Culture=neutral, 
		  	PublicKeyToken=b77a5c561934e089" IsCollection="true" Name="DepartmentDataReader">
            <TypeDescriptors>
              <TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, Version=2.0.3600.0, Culture=neutral, 
			  	PublicKeyToken=b77a5c561934e089" Name="DepartmentDataRecord">
                <TypeDescriptors>
                  <TypeDescriptor TypeName="System.Int16" Name="DepartmentID"/>
                  <TypeDescriptor TypeName="System.String" Name="Service"/>
                  <TypeDescriptor TypeName="System.String" Name="Department"/>
                  <TypeDescriptor TypeName="System.DateTime" Name="ModifiedDate"/>
                 </TypeDescriptors>
               </TypeDescriptor>
              </TypeDescriptors>
            </TypeDescriptor>
          </Parameter>
        </Parameters>
        <MethodInstances>
          <MethodInstance Name="DepartmentFinderInstance" Type="Finder" ReturnParameterName="Departments" />
        </MethodInstances>
    </Method>
  </Methods>
</Entity>

Nous nous servons donc des propriétés pour passer notre requête ; à noter qu'ici nous nous servons d'une requête de type texte, mais nous aurions également pu passer par les procédures stockées et renseigner uniquement la procédure stockée ; nous le ferons ultérieurement.

Ensuite nous créons un paramètre de retour, qui sera utilisé pour stocker le résultat de notre requête, que nous appelons Départements.

Puis nous définissons le type de notre paramètre ; ici nous créons un datareader, puis un datarow et enfin dans le datarow chacune des colonnes de notre table. Nous utilisons un datareader, car le BDC va utiliser ADO.Net pour récupérer nos données, et avec ADO.net, on peut soit utiliser un datareader, soit passer par un dataset pour récupérer nos données.

Nous avons choisi ici de passer par un datareader, mais nous aurions pu passer également par un dataset.

Enfin, nous créons une methodInstance de type finder, qui va nous permettre de récupérer toutes les données de notre table.

Une methodInstance est une instance particulière de la méthode à laquelle elle appartient ; on peut la voir comme l'exécution de la méthode à laquelle elle appartient, en y rajoutant des paramètres. De cette façon, grâce aux methodInstances, on va pouvoir exécuter de plusieurs façon différentes une même méthode, mais en faisant varier les paramètres en entrée. Pour l'instant, nous ne passons pas de paramètres, donc nous ne sommes pas capable de voir la subtilité que se cache derrière ce principe, mais patience.

Voila, c'est terminé !

Nous venons donc de créer notre 1er fichier ADF.

Voici le code complet du fichier.

 
Sélectionnez
<!--Fichier bdc.adworks.hr.minimal.xml-->
<LobSystem xmlns="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog"
           Type="Database" Version="1.0.0.0" Name="AdventureWorksHumanResources">
  <LobSystemInstances>
    <LobSystemInstance Name="AdventureWorksHumanResourcesInstance"
                        DefaultDisplayName="AdventureWorks Human Resources Web Instance">
      <Properties>
        <Property Name="AuthenticationMode" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAuthenticationMode">PassThrough</Property>
        <Property Name="DatabaseAccessProvider" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAccessProvider">SqlServer</Property>
        <Property Name="RdbConnection Data Source" Type="System.String">.</Property>
        <Property Name="RdbConnection Initial Catalog" Type="System.String">AdventureWorks</Property>
        <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
      </Properties>
    </LobSystemInstance>
  </LobSystemInstances>
  <Entities>
    <Entity Name="Department">
      <Methods>
        <Method Name="GetDepartments">
          <Properties>
            <Property Name="RdbCommandText" Type="System.String">
              select DepartmentID, [Name] as [Service], GroupName as Department, ModifiedDate
              from HumanResources.Department
            </Property>
            <Property Name="RdbCommandType" Type="System.Data.CommandType">Text</Property>
          </Properties>
          <Parameters>
           <Parameter Direction="Return" Name="Departments">
              <TypeDescriptor TypeName="System.Data.IDataReader, System.Data, Version=2.0.3600.0, Culture=neutral,
			  	 PublicKeyToken=b77a5c561934e089" IsCollection="true" Name="DepartmentDataReader">
                <TypeDescriptors>
                  <TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, Version=2.0.3600.0, Culture=neutral, 
				  	PublicKeyToken=b77a5c561934e089" Name="DepartmentDataRecord">
                    <TypeDescriptors>
                      <TypeDescriptor TypeName="System.Int16" Name="DepartmentID"/>
                      <TypeDescriptor TypeName="System.String" Name="Service"/>
                      <TypeDescriptor TypeName="System.String" Name="Department"/>
                      <TypeDescriptor TypeName="System.DateTime" Name="ModifiedDate"/>
                    </TypeDescriptors>
                  </TypeDescriptor>
                </TypeDescriptors>
              </TypeDescriptor>
            </Parameter>
          </Parameters>
          <MethodInstances>
            <MethodInstance Name="DepartmentFinderInstance" Type="Finder" ReturnParameterName="Departments" />
          </MethodInstances>
        </Method>
      </Methods>
    </Entity>
  </Entities>
</LobSystem>

Vous pouvez dès à présent l'importer et le tester.

Comme illustré au début de ce paragraphe, voici le résultat obtenu.

image

En tant que développeurs, ce résultat, fruit de dur labeur, peut nous satisfaire ; cependant, d'un point de vue du client final, notre application, en l'état aura une durée de vie limitée.

En effet, elle offre uniquement une vue statique de l'information.

L'utilisateur souhaitant prendre connaissance des différents départements de l'entreprise, utilisera une seule fois notre application. Elle ne présente finalement que peu d'intérêt pour l'utilisateur final, ceci en partie dû au manque d'interaction entre notre application et le public ciblé.

Nous allons donc voir, dans la partie suivante, comment la rendre plus agréable et plus fonctionnelle afin de correspondre au réel besoin du public ciblé.

V. Amélioration de notre application

La 1ère chose qu'il serait intéressant de modifier, ce sont tous les noms qui apparaissent dans notre application ; pour l'instant, nous avons utilisé des noms « internes » (AdventureWorksHumanResources, LobSystemWebInstance, etc..) ; ces noms ne sont pas très parlant pour nos utilisateurs, alors donnons leur quelque chose qui soit compréhensible pour eux.

Vous me direz « c'est du détail », mais nos utilisateurs finaux savent parfois être si difficiles.

V-A. Modification des libellés.

Grossièrement, pour modifier nos libellés, il va falloir rajouter un attribut DefaultDisplayName la ou nous avons déjà rajouté un attribut Name.

Nous allons donc faire les choses d'en l'ordre.

Remplaçons ceci (au niveau des services partagés)

image

Par ceci

image

Grâce à cette ligne.

 
Sélectionnez
<LobSystem xmlns="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog" Type="Database" 
	Version="1.0.0.3" Name="AdventureWorksHumanResources" DefaultDisplayName="BDC - Application Ressources Humaines" >

Puis (au niveau du data type picker) remplaçons ceci

image

Par ceci

image

Respectivement grâce à ces lignes

 
Sélectionnez
<LobSystemInstance Name="AdventureWorksHumanResourcesInstance" DefaultDisplayName="Application RH - Instance Web">

Puis

 
Sélectionnez
<Entity Name="Department" DefaultDisplayName="Départements de l'entreprise">


Au niveau de nos champs, Ceci

image

Par ceci

image

En modifiant ces lignes

 
Sélectionnez
<TypeDescriptor TypeName="System.Int16" Name="DepartmentID"   
  DefaultDisplayName="ID"/>
<TypeDescriptor TypeName="System.String" Name="Service"   
  DefaultDisplayName="Service"/>
<TypeDescriptor TypeName="System.String" Name="Department"  
  DefaultDisplayName="Département"/>
<TypeDescriptor TypeName="System.DateTime" Name="ModifiedDate" 
  DefaultDisplayName="Date de dernière modification"/>

Tant que nous y sommes, nous pourrions penser à masquer également des colonnes comme ID et Date de dernière modification car ces colonnes ne sont pas directement utiles à nos utilisateurs finaux qu'est le personnel du service RH.

V-B. Masquer des colonnes

Pour masquer des colonnes, nous pouvons passer par la case configuration de notre Business Data List.

Pour cela, passons la page en mode édition ; un lien view apparait maintenant à droite de notre webpart.

image

Cliquons dessus, puis sur la page Edit View, dans la section columns, décochons ID et Date de dernière modification

image

Une fois ceci validé, nous obtenons un affichage plus sobre pour nos utilisateurs.

image

Une autre fonctionnalité, qui dans notre situation actuelle présente peu d'intérêt, mais ultérieurement va nous être utile dans le cadre de la récupération des employés, va être par exemple d'afficher dans une Business Data List toute la liste des employés en affichant par exemple uniquement leur nom et prénom, mais ensuite dans un Business Data Item, afficher plus d'information sur un seul employé.

image

Pour cela, il va nous falloir rajouter la possibilité de récupérer également 1 employé ; cette opération va être possible grâce à une methodInstance de type SpecificFinder.

V-C. Récupérer uniquement 1 département parmi toute une liste.

Comme signalé ci-dessus, pour récupérer 1 département, et surtout pouvoir l'afficher dans le business data item, il va nous falloir utiliser une methodInstance de type SpecificFinder.

Une méthode de type va avoir besoin d'une clé pour s'exécuter ; ici, notre clé sera le champ ID.

Grâce à une méthode de type SpecificFinder nous allons pouvoir exécuter une méthode du genre

 
Sélectionnez
--sql.adworks.sql 
--Récupération d'un seul département; méthode instance SpecificFinder.
select DepartmentID, [Name] as [Service], GroupName as Department, ModifiedDate
from HumanResources.Department
where DepartmentID like @ID

Tout à l'heure, nous avons parlé de la différence entre une méthode et une méthode instance ; une méthode est une sorte de signature, tandis qu'une méthode instance va être une implémentation de cette signature.

De plus, une méthode peut posséder plusieurs méthodes instances.

Ici, nous avons déjà une méthode GetDepartments; plutôt que d'en créer une 2ème, adaptons plutôt notre méthode existante pour afin de l'adapter à nos 2 besoins, la récupération de tous nos départements, et la récupération d'un département spécifique en fonction de son ID.

Commençons par adapter notre requête SQL ; la requête suivante vous nous permettre d'atteindre notre objectif.

 
Sélectionnez
--sql.adworks.sql 
-- Récupération à la fois de tous les départements, mais aussi d'un seul.
select DepartmentID, [Name] as [Service], GroupName as Department, ModifiedDate
from HumanResources.Department
where (DepartmentID >= @MinDepartmentID) AND (DepartmentID <= @MaxDepartmentID)

Nous savons ici que nous avons 16 départements, il nous suffit donc de fixer respectivement les valeurs de @MinDepartmentID et de @MaxDepartmentID à un nombre inférieur à 0 et un nombre supérieur à 16 pour récupérer la totalité de nos départements ; de même, en fixant la valeur de @MinDepartmentID et de @MaxDepartmentID au même nombre, nous récupérons le département portant cet identifiant.

Encore reste-t-il à pouvoir passer en paramètre l'identifiant. Tiens, paramètre, on en a déjà parlé tout à l'heure lorsque nous avons récupéré nos données ; pour réaliser cela, nous avons créé un paramètre de direction Return; et bien pour cela, nous allons créer 2 paramètres de direction In; ces paramètres seront donc utilisés par SharePoint pour passer la valeur (l'identifiant) de notre département à la requête SQL.

 
Sélectionnez
<Parameter Direction="In" Name="@MinDepartmentID">
  <TypeDescriptor TypeName="System.Int16" IdentifierName="DepartmentID" 
     AssociatedFilter="ID" Name="MinDepartmentID">
    <DefaultValues>
      <DefaultValue MethodInstanceName="DepartmentFinderInstance" Type="System.Int16">0</DefaultValue>
    </DefaultValues>
  </TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@MaxDepartmentID">
  <TypeDescriptor TypeName="System.Int16" IdentifierName="DepartmentID" AssociatedFilter="ID" Name="MaxDepartmentID">
    <DefaultValues>
      <DefaultValue MethodInstanceName="DepartmentFinderInstance" Type="System.Int16">999</DefaultValue>
    </DefaultValues>
  </TypeDescriptor>
</Parameter>

Ici, nous fixons également les valeurs par défaut pour notre méthode DepartmentFinderInstance.

De cette façon, lorsque la méthode Finder sera appelée pour récupérer tous nos départements, le code suivant sera exécuté.

 
Sélectionnez
--sql.adworks.sql 
-- Méthode FinderInstance
select DepartmentID, [Name] as [Service], GroupName as Department, ModifiedDate
from HumanResources.Department
where (DepartmentID >= 0) AND (DepartmentID <= 999)

Ce qui nous permet effectivement de récupérer tous les départements.

image

Nous pouvons d'ailleurs facilement le vérifier en utilisant l'outil SQL Server Profiler, qui va nous servir à intercepter toutes les requêtes qui arrivent directement sur notre serveur SQL. (Pour le démarrer, dans management Studio, cliquez sur Tools, puis SQL Server Profiler ; ensuite choisissez Nouvelle Trace, puis dans l'onglet Event Selection, sélectionnez uniquement StoredProcedures et TSQL).

image

De même, si nous essayons de récupérer le service principal du département R&D,

image

Nous remarquons que les 2 paramètres, prennent la même valeur, ce qui nous permet de récupérer un seul département.

image

Enfin, pour clôturer le tout et pouvoir utiliser notre Business Data Item de manière indépendante, il va nous falloir mettre en ouvre un filtre.

image

Voici donc le code notre filtre.

 
Sélectionnez
<FilterDescriptor Type="Comparison" Name="ID">
	<Properties>
		<Property Name="Comparator" Type="System.String">Equals</Property>
	</Properties>
</FilterDescriptor>

De plus, nous avons à présent la possibilité de spécifier la façon dont nous voulons que nos requêtes s'exécutent depuis la page Edit View ; nous pouvons utiliser le filtre ainsi créé pour filtrer nos recherches.

image

Vous voyez cependant que nous ne pouvons pas (encore) limiter le nombre de résultats retournés par notre requête ; même si plus bas sur la page Edit View, nous avons la possibilité, tout comme avec des listes SharePoint, de limiter le nombre de résultat affichés à l'écran,

image

Si notre requête doit nous retourner des millions de lignes, nous devrons attendre que la requête finisse de s'exécuter, ce qui peut prendre beaucoup de temps.

La prochaine étape va donc être de voir comment limiter le nombre de résultats retournés par notre requête.

V-D. Limiter le nombre de résultats retournés par une requête

A l'image de la récupération d'un seul élément qui est passée par la création d'un filtre et d'un paramètre, nous allons en faire de même pour limiter le nombre d'éléments.

Commençons par créer notre paramètre

 
Sélectionnez
<Parameter Direction="In" Name="@Limit">
  <TypeDescriptor TypeName="System.Int32" AssociatedFilter="Limit" Name="Limit">
    <DefaultValues>
      <DefaultValue MethodInstanceName="DepartmentFinderInstance" Type="System.Int32">9999</DefaultValue>
      <DefaultValue MethodInstanceName="DepartmentSpecificFinderInstance" Type="System.Int32">9999</DefaultValue>
    </DefaultValues>
  </TypeDescriptor>
</Parameter>

Par défaut, afin de récupérer tous nos éléments, nos fixons la limite à 9999 éléments, ce qui devrait nous permettre de récupérer nos 16 services et nous laisse une bonne marge de manouvre.

Créons ensuite le filtre correspondant

 
Sélectionnez
<FilterDescriptor Type="Limit" Name="Limit"/>


Et pour terminer, modifions notre requête en y rajoutant une clause top.

 
Sélectionnez
select top(@Limit) DepartmentID, [Name] as [Service], GroupName as Department, ModifiedDate
from HumanResources.Department
where (DepartmentID >= @MinDepartmentID) AND (DepartmentID <= @MaxDepartmentID)

Dorénavant, vous pouvez modifier le paramètre.

image

Et depuis le profiler, voici la requête que l'on voit passer.

image

Et si nous ne spécifions pas de filtre,

image

Il pourrait également être intéressant de donner à l'utilisateur la possibilité de filtrer ses éléments.

image

Pour cela, sur la page Edit View, il nous suffit de configurer le composant pour autoriser les filtres.

image

Pour l'instant, nous n'avons autorisé uniquement un filtre de type equals sur les identifiants, ce qui ne présente que peu d'intérêt du point de vue de l'utilisateur ; nous allons à présent rajouter un filtre qui va nous permettre de récupérer les départements & services par leur nom.

V-E. Récupérer des éléments grâce aux filtres.

Nous allons à présent voir comment autoriser nos utilisateurs à effectuer des requêtes en y précisant des filtres.

image

Pour cela, nous allons tout d'abord commencer par modifier notre requête SQL

 
Sélectionnez
--sql.adworks.sql
-- Ajout du filtre pour récupérer les départements et services.
select top(@Limit) DepartmentID, [Name] as [Service], GroupName as Department, ModifiedDate
from HumanResources.Department
where (DepartmentID >= @MinDepartmentID) AND (DepartmentID <= @MaxDepartmentID)
and ([Name] Like @Service) and (GroupName Like @Department)

Puis, nous allons rajouter un filterdescriptor de type wildcard,

 
Sélectionnez
<FilterDescriptor Type="Wildcard" Name="Service"/>
<FilterDescriptor Type="Wildcard" Name="Department"/>

Leur attacher des paramètres, afin de les récupérer pour exécuter notre requête.

 
Sélectionnez
<Parameter Direction="In" Name="@Service">
  <TypeDescriptor TypeName="System.String" AssociatedFilter="Service" Name="Service">
    <DefaultValues>
      <DefaultValue MethodInstanceName="DepartmentFinderInstance" Type="System.String">%</DefaultValue>
      <DefaultValue MethodInstanceName="DepartmentSpecificFinderInstance" Type="System.String">%</DefaultValue>
    </DefaultValues>
  </TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@Department">
  <TypeDescriptor TypeName="System.String" AssociatedFilter="Department" Name="Department">
    <DefaultValues>
      <DefaultValue MethodInstanceName="DepartmentFinderInstance" Type="System.String">%</DefaultValue>
      <DefaultValue MethodInstanceName="DepartmentSpecificFinderInstance" Type="System.String">%</DefaultValue>
    </DefaultValues>
  </TypeDescriptor>
</Parameter>

Et enfin pour terminer, nous allons spécifier quel est le caractère joker de notre LobSystem. Pour SQL Server, il s'agit de « % », nous allons donc le spécifier dans les propriétés de notre LobSystemInstance

 
Sélectionnez
<LobSystem xmlns="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog" 
	Type="Database" Version="1.0.0.19" Name="AdventureWorksHumanResources" DefaultDisplayName="BDC - Application Ressources Humaines">
  <Properties>
    <Property Name="WildcardCharacter" Type="System.String">%</Property>
  </Properties>

Si nous regardons la requête qui passe, nous pouvons nous rendre compte de l'utilisation qui en est fait.

image

Pour sélectionner un item, actuellement nous sommes obligés de renseigner son identifiant, ce qui n'est pas forcément une chose aisée.

image

Il serait par exemple plus intéressant pour eux de pouvoir sélectionner directement le service qui les intéresse.

image

Voyons donc comment réaliser cette opération.

V-F. Afficher des propriétés dans le data item picker

Pour rajouter des propriétés au data item picker, il nous suffit de renseigner une propriété au niveau de notre entité.

 
Sélectionnez
<Entity Name="Department" DefaultDisplayName="Départements de l'entreprise">
  <Properties>
    <Property Name="Title" Type="System.String">Service</Property>
  </Properties>

Ceci nous suffit à afficher le résultat vu au précédent paragraphe.

Cependant, il se peut que nous ayons besoin d'afficher plusieurs propriétés ; pour cela, au niveau du type descriptor, il nous suffit de mettre à true la propriété ShowInPicker.

 
Sélectionnez
<TypeDescriptor TypeName="System.String" Name="Department" DefaultDisplayName="Département">
  <Properties>
    <Property Type="System.Boolean" Name="ShowInPicker">true</Property>
  </Properties>
</TypeDescriptor>

Et voici le résultat.

image

De même, dorénavant, en modifiant le title dans la page edit view, il nous est possible d'offrir un menu ECB à nos utilisateurs afin qu'ils puissent exécuter les actions que nous leurs mettrons à disposition.

image

Voici donc le résultat.

image

Ceci clôt le sujet sur la customisation de nos entités.

A présent, nous avons donc une application qui nous permet de récupérer la liste de nos départements, et d'en afficher le détail, soit via une action, soit en utilisant les connexions de webparts. Nous avons également mis en place un certain nombre de paramètres qui nous permettre de mettre à disposition de nos utilisateurs une application réactive et « userfriendly ».

Nous allons à présent rajouter l'entité Employés.

Cette étape ne sera pas détaillée dans cet article, car cela revient grossièrement à refaire ce que nous avons déjà fait ici pour l'entité département ; néanmoins, je vous invite à regarder le fichier adf joint pour voir quels sont les quelques changements mineurs (comme par exemple l'utilisation d'une procédure stockée en lieu et place d'une requête texte).

Voici l'état de notre application après avoir ajouté cette entité :

image

En affichant le profil de notre collaborateur, nous obtenons plus de détail.

image

La prochaine partie de cette article va donc traiter des associations ; nous allons voir comment les mettre en ouvre pour rajouter de l'interactivité entre nos différents composants.

Remarque : Certains paramètres, propriétés , methodInstances , etc. . n'ont pas été mise en ouvre ici car ces dernières ne sont pas utilisables par les composants OOTB du BDC fournis et nécessite nt de passer par du développement ; je pense notamment à l'utilisation de methodInstances de type GenericInvoker qui vont nous permettre d'ajouter/modifier/supprimer des données directement dans notre backend . Nous les verrons dans un article ultérieur traitant de l'utilisation du modèle objet du BDC.

V-G. Récupération de nos employés à partir de nos départements.

Nous allons ici définir une association entre notre entité département et notre entité collaborateurs, afin de pouvoir récupérer nos collaborateurs en fonction de nos départements.

image

Pour cela, dans une de nos entités, il va falloir définir une nouvelle méthode

Voici le code de la méthode que nous avons défini pour implémenter notre association ; cette méthode a été rajoutée à l'entité Department.

 
Sélectionnez
<Method Name="GetEmployeesByDept">
  <Properties>
    <Property Name="RdbCommandText" Type="System.String">
 
Sélectionnez
uspGetEmployeesByDept
 
Sélectionnez
</Property>
    <Property Name="RdbCommandType" Type="System.Data.CommandType">
      StoredProcedure
    </Property>
  </Properties>
  <Parameters>
    <Parameter Direction="In" Name="@ID">
      <TypeDescriptor TypeName="System.Int16"
            IdentifierName="DepartmentID" Name="ID"/>
    </Parameter>
    <Parameter Direction="Return" Name="Employees">
      <TypeDescriptor TypeName="System.Data.IDataReader, System.Data, 
           Version=2.0.3600.0, Culture=neutral, 
           PublicKeyToken=b77a5c561934e089" IsCollection="true" 
           Name="EmployeeDataReader">
        <TypeDescriptors>
          <TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, 
               Version=2.0.3600.0, Culture=neutral, 
               PublicKeyToken=b77a5c561934e089" Name="EmployeeDataRecord">
            <TypeDescriptors>
              <TypeDescriptor TypeName="System.Int32" 
                   IdentifierEntityName="Employee" 
                   IdentifierName="EmployeeID" Name="EmployeeID" 
                   DefaultDisplayName="ID"/>
              <TypeDescriptor TypeName="System.String" Name="Secu" 
                   DefaultDisplayName="Securité Sociale"/>
              <TypeDescriptor TypeName="System.String" Name="LoginID" 
                   DefaultDisplayName="Login"/>
              <TypeDescriptor TypeName="System.String" Name="Name" 
                   DefaultDisplayName="Nom"/>
              <TypeDescriptor TypeName="System.String" Name="Phone" 
                   DefaultDisplayName="Téléphone"/>
              <TypeDescriptor TypeName="System.String" Name="Mail" 
                   DefaultDisplayName="Mail"/>
              <TypeDescriptor TypeName="System.String" Name="Manager" 
                   DefaultDisplayName="Responsable"/>
              <TypeDescriptor TypeName="System.String" Name="Title" 
                   DefaultDisplayName="Fonction"/>
              <TypeDescriptor TypeName="System.String" Name="Service" 
                   DefaultDisplayName="Service"/>
              <TypeDescriptor TypeName="System.String" Name="Department" 
                   DefaultDisplayName="Département"/>
              <TypeDescriptor TypeName="System.DateTime" Name="BirthDate" 
                   DefaultDisplayName="Date de Naissance"/>
              <TypeDescriptor TypeName="System.DateTime" Name="HireDate" 
                   DefaultDisplayName="Date d'embauche"/>
              <TypeDescriptor TypeName="System.String" Name="Shift" 
                   DefaultDisplayName="les 3 huits"/>
              <TypeDescriptor TypeName="System.Int16" Name="VacationHours" 
                   DefaultDisplayName="Heures de vacances"/>
              <TypeDescriptor TypeName="System.Int16" 
                   Name="SickLeaveHours" 
                   DefaultDisplayName="Heures de congé de maladie"/>
              <TypeDescriptor TypeName="System.DateTime" 
                   Name="ModifiedDate" 
                   DefaultDisplayName="Date de dernière modification"/>
            </TypeDescriptors>
          </TypeDescriptor>
        </TypeDescriptors>
      </TypeDescriptor>
    </Parameter>
  </Parameters>
</Method>

Ici nous définissons de manière classique notre méthode, comme nous l'avons fait jusqu'à présent ; nous définissons notre requête SQL à exécuter (ici une procédure stockée), puis nos paramètres d'entrée et de sortie ; nous aurions également pu définir des filtres, ca fonctionne de la même façon que ce que nous avons déjà réalisé.

Un point important à noter ici, est que dans notre paramètre de retour, nous retournons une autre entité, nos employés ; pour préciser cela, nous avons utilisé l'attribut IdentifierEntityName="Employee" lorsque nous avons défini l'identifiant de notre entité dans notre type de retour.

La seule différence à noter ici par rapport à une méthode « classique » est le fait que nous n'ayons pas besoin de définir de MethodInstance; en effet, la requête est exécutée lors de la sélection d'un item.

Ensuite, il ne nous reste plus qu'à définir notre association, juste en dessous de la balise </Entities>.

 
Sélectionnez
<Associations>
  <Association AssociationMethodEntityName="Department"
    AssociationMethodName="GetEmployeesByDept"
    AssociationMethodReturnParameterName="Employees"
    Name="GetEmployeesByDepartement">
    <SourceEntity Name="Department"/>
    <DestinationEntity Name="Employee"/>
  </Association>
</Associations>

V-H. Ajout de quelques actions

Les actions vont permettre à nos utilisateurs de réaliser des opérations supplémentaires sur nos données, ou autre, directement depuis l'interface graphique.

Il s'agit de simple url, qui peuvent avoir une portée locale, directement sur l'item, comme ci-dessous,

image

Et/ou une portée globale, et donc s'appliquer à toute la liste.

image

Voici le code utilisé pour définir chacune des actions Export To Excel et Send Mail.

 
Sélectionnez
<Actions>
  <Action Name="ExportToExcel" DefaultDisplayName="Export To Excel"
          IsOpenedInNewWindow="false" 
          ImageUrl="/_layouts/images/icxlsx.gif" 
          Url="/_layouts/BDCexpToXlsx.aspx" Position="3"/>
  <Action Name="SendMail" DefaultDisplayName="Send Mail"
          IsOpenedInNewWindow="false" Position="1" Url="mailto:{0}" 
          ImageUrl="/_layouts/1033/images/sendmail.gif">
    <ActionParameters>
      <ActionParameter Index="0" Name="Mail"/>
    </ActionParameters>
  </Action>
</Actions>

Ce bout de code est à placer dans l'entitéEmployee, sous la balise </Methods>.

Comme vous pouvez le constater, dans l'action accessible au niveau de l'item, nous avons précisé un paramètre en querystring '{0}' ; ce paramètre est ensuite relié au ActionParameter via la propriété Index, puis à un type descriptor correspondant à un des typeDescriptor du typeDescriptor Return de la méthode contenant l'instance de méthode specificfinder ; dans notre cas, il s'agit du mail.

 
Sélectionnez
<Method Name="GetEmployees">          
  <Parameter Direction="Return" Name="Employees">              
  	<TypeDescriptor TypeName="System.String" Name="Mail" DefaultDisplayName="Mail"/>
  	<MethodInstances>            
    	<MethodInstance Name="EmployeeSpecificFinderInstance" Type="SpecificFinder" ReturnParameterName="Employees" />
    </MethodInstances>
  </Method>

Comme vous avez pu le constater, il est très facile d'intégrer nos propres actions dans nos fichiers ADF.

A présent, il nous reste un dernier point à voir, les outils de génération de fichier ADF.

VI. Les outils de génération de fichier ADF.

Actuellement, il existe 2 outils de génération de fichier ADF, l'un fourni par Microsoft avec le SDK.

Vous avez un certain nombre d'exemple en ligne sur le site de la MSDN, comme par exemple celui-ci > http://msdn.microsoft.com/en-us/library/bb736296.aspx pour une base de données.

image

Le 2ème outil est le BDC Meta Man, que je n'ai pu tester que dans sa version developer.image

Il est cependant à noter que la version développeur du BDC Metaman connait beaucoup (trop ??)de limite.

Ces outils sont surtout intéressants dans la mesure où ils vont nous éviter d'écrire du code à la main et donc de gagner du temps ; cependant, si vous souhaitez utiliser au maximum les capacités du BDC, ou du moins écrire un certain nombre de scénarios avancés, interagissant avec les composant OOTB de SharePoint, il peut être intéressant de générer un fichier ADF 'de base' grâce à la puissance de ces outils, et ensuite d'éditer manuellement ce fichier afin d'y incorporer les fonctionnalités avancées que vous souhaitez mettre en ouvre.

VII. Points supplémentaires

VII-A. Les différentes méthodes de connexion

Jusqu'à présent, lorsque nous avons défini les méthodes de connexion à notre entité, nous avons à chaque fois configuré notre mode d'authentification à PassThrough.

 
Sélectionnez
<Property Name="AuthenticationMode" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAuthenticationMode">
	PassThrough
</Property>


Ce mode d'authentification nous permet de récupérer les identifiants de l'utilisateur actuel et de les utiliser pour authentifier notre utilisateur. De cette façon, seuls les utilisateurs autorisés pourront utiliser notre application pour récupérer les données.

Ce mode d'authentification fonctionne très bien . à condition d'avoir tous les services installés sur le même serveur. Dans notre cas par exemple, le serveur SQL auquel nous accédons est installé sur la même machine, et donc si l'utilisateur authentifié est autorisé à accéder au serveur SQL, il pourrait récupérer les données, sinon, il recevra un message d'erreur en essayant d'exécuter la requête.

Si cependant, notre serveur SQL était sur un serveur différent, à ce moment, en utilisant la méthode d'authentification Passthrough, on se retrouve confronté à la problématique du double hop : les informations d'authentification ne peuvent pas être transmises de serveur en serveur.

De meme, si le système auquel nous souhaitons accéder ne supporte pas l'authentification windows, notre méthode Passthrough ne présente pas non plus dans ce cas de figure plus d'intérêt.

Suite à la réflexion autour des 2 scénarios précédents, il convient de trouver une alternative.

Pour résoudre les problématiques énoncées ci-dessus, SharePoint nous propose une solution, qui est la possibilité d'utilisé le service Single Sign On (SSO) ou authentification unique.

Le service SSO de SharePoint, va nous permettre de nous authentifier une seule fois et ensuite de pouvoir accéder aux différents services sur différents serveurs, en étant directement authentifié, et résolvant par la même occasion les problèmes de double hop.

Le principe est très simple ; une fois authentifié, le service SSO va stocker les informations de connexion de l'utilisateur dans une base de données (de manière cryptée) ; puis à chaque fois que notre utilisateur essayera de se connecter, SSO ira vérifier si les informations de l'utilisateur sont présentes dans la base, et si oui, il les utilisera pour authentifier l'utilisateur. Si elles ne sont pas présentes, alors il s'agit de la 1ère authentification de l'utilisateur.

Par mi les modes d'authentification du BDC, nous allons pouvoir en utiliser 2 qui vont nous permettre de résoudre notre problématique énoncée plus haut, à savoir :

  • Comment utiliser le BDC et l'authentification Windows pour autoriser nos utilisateurs à accéder à une application qui se trouve sur un serveur distant ?
  • Comment utiliser le BDC et une authentification Login/mot de passe quelconque pour autoriser nos utilisateurs à accéder à une application (distante ou pas)?

Pour répondre à la 1ère question, nous allons pouvoir utiliser le mode d'authentification WindowsCredentials.

 
Sélectionnez
<Properties>
  <Property Name="AuthenticationMode" 
  	Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAuthenticationMode">WindowsCredentials</Property>
  <Property Name="SsoApplicationId" Type="System.String">AdventureWorks</Property>
  <Property Name="SsoProviderImplementation" Type="System.String"> 
  	Microsoft.SharePoint.Portal.SingleSignon.SpsSsoProvider,Microsoft.SharePoint.Portal.SingleSignon,Version=12.0.0.0, 
	Culture=neutral,PublicKeyToken=71e9bce111e9429c
  </Property>
  <Property Name="DatabaseAccessProvider" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAccessProvider">
	  SqlServer
  </Property>
  <Property Name="RdbConnection Data Source" Type="System.String">.</Property>
  <Property Name="RdbConnection Initial Catalog" Type="System.String">AdventureWorks</Property>
  <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
</Properties>

Et configurer le SSO pour utiliser l'authenfication Windows.

Pour configurer le SSO, le service Microsoft Sigle Sign-On doit être démarré sur le serveur Sharepoint adéquate ; puis, toujours depuis ce serveur, rendez vous sur la page Opération du site d'administration centrale, puis dans la section choisissez Manage Settings for single sign-on.

image

Sélectionnez ensuite Manage Server Settings for SSo, et configurez cette page de manière adéquate.

image

Ici nous sommes sur un serveur de test ; cepedant, je vous conseille ce lien pour configurer cette page en respectant les best practices.

Une fois validé, nous allons à présent configurer le SSO pour notre application, en sélectionnant « Manage Settings for enterprise application definitions », puis selectionner un nouvel élément.

image

Ici, nous allons donner le nom de l'item, une adresse de contact, et surtout, le nom que nous allons ensuite utiliser pour identifer notre application. Ce nom sera également à préciser dans notre fichier ADF ; de cette facon, Sharepoint saura faire la relation entre les 2 !

 
Sélectionnez
<Property Name="SsoApplicationId" Type="System.String">AdventureWorks</Property>


Puis, nous allons créer un compte générique, qui sera ensuite utilisé par tout le monde ; pour cela, nous allons sélectionner Group dans la section Account Type,

Et nous allons cocher la case Windows authentication dans le cas d'une authentification Windows ; dans le cas d'une authentification par login/mot de passe, nous n'aurions pas coché cette case ; c'est la seule différence qui existe entre les 2 modes au niveau du SSO ; au niveau du BDC, nous aurions tout simplement remplacer WindowsCredentials par RdbCredentials (pour un LobSytem de type base de données, Credentials si le type est web service) dans la propriété Authentication Mode.

Pour terminer avec la configuration de cette page, nous allons spécifier que nous allons renseigner un nom d'utilisateur et un mot de passe, en utilisant des masques pour ne pas afficher le mot de passe lorsque l'utilisateur le saisira.

Une fois cette page configurée, il ne nous reste plus qu'à préciser quel est le compte qui sera utilisé, et par qui.

Pour cela, depuis la page Manage settings for SSO, cliquons sur Manage account information for enterprise application definition

image

Choisissons tout d'abord quel item l'on va utiliser, ici, nous allons reprendre l'item créé précédemment, à savoir Generic User, puis, il faut à présent dire à quel groupe nous souhaitons le mapper ; ici, nous avons mappé notre « Generic user à tous les utilisateurs du domaine ; une fois cette opération effectuée, avant de valider, il va nous falloir définir le compte représenté par notre « Generic user » ; pour cela, il faut choisir Set, et non pas Done.

image

Ici, nous avons spécifié que notre « Generic User » devait utiliser les informations de compte de l'administrateur (nous sommes sur une machine de test !).

En validant, dorénavant, les opérations réalisées par les utilisateurs de nos applications BDC, portant l'identifiant AdventureWorks, et utilisant l'authentification WindowsCredentials, seront considérés par notre système comme étant des opérations réalisées par l'administrateur ! et donc meme des personnes n'ayant pas d'accès à SQL Server peuvent à présent voir les données qui y sont stockées. De plus, désormais, nous pouvons accéder à nos système distant ! Fini la problématique de double hop !

Nous aurions également pu utiliser l'authentification SQL Server pour accéder à notre système ; à ce moment, il aurait suffi de ne pas cocher Windows authentification.

image

Il existe un dernier mode d'authentification, qui est d'ailleurs celui appliqué par défaut par Sharepoint, si la propriété AuthenticationMode était manquante, il s'agit de RevertToSelf.

 
Sélectionnez
<Property Name="AuthenticationMode" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAuthenticationMode">RevertToSelf</Property>


Cette propriété va nous permettre d'emprunter l'identité du pool d'application de l'application sur laquelle on se situe ; encore faut-il que ce compte aie accès aux diverses ressources auxquelles nous nous connections via nos applications BDC.

VII-B. Travailler avec plusieurs LobSystemIntances

Nous avons précisé au début de cet article que le lobsystemIntance allait être utilisé pour passer nos information de connexion à notre système.

Au sein de notre application, nous allons pouvoir renseigner, et donc travailler avec des lobsysteminstances différents ,ce qui va nous permettre de passer des informations de connexion différentes, ou de se connecter à des serveurs différents.

Il existe cependant une contrainte très forte au niveau de nos différents LobSytemInstances :

  • Il faut absolument qu'ils aient la meme structure, de sorte que les entités modélisées par la suite apparaissent exactement de la meme facon dans chacune de nos instances.

Une fois cette contrainte respectée, nous pouvons donc passer plusieurs informations de connexions, via plusieurs LobSystemInstances.

 
Sélectionnez
<LobSystemInstance Name="HRWindowsCredentials" 
	DefaultDisplayName="Application RH - Authentification Windows via SSO">
  <Properties>
    <Property Name="AuthenticationMode"  Type="System.String">WindowsCredentials</Property>
    <Property Name="SsoApplicationId" Type="System.String">AdventureWorks</Property>
    <Property Name="SsoProviderImplementation" Type="System.String">
          Microsoft.SharePoint.Portal.SingleSignon.SpsSsoProvider,Microsoft.SharePoint.Portal.SingleSignon,
		  Version=12.0.0.0, Culture=neutral,PublicKeyToken=71e9bce111e9429c
    </Property>
    <Property Name="DatabaseAccessProvider" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAccessProvider">
		SqlServer
	</Property>
    <Property Name="RdbConnection Data Source" Type="System.String">.</Property>
    <Property Name="RdbConnection Initial Catalog" Type="System.String">AdventureWorks</Property>
    <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
  </Properties>
</LobSystemInstance>
    
<LobSystemInstance Name="HRCredentials" DefaultDisplayName="Application RH - Authentification Login/Mot de Passe">
  <Properties>
    <Property Name="AuthenticationMode" Type="System.String">RdbCredentials</Property>
    <Property Name="SsoApplicationId" Type="System.String">AdventureWorksSQL</Property>
    <Property Name="SsoProviderImplementation" Type="System.String">
          Microsoft.SharePoint.Portal.SingleSignon.SpsSsoProvider,Microsoft.SharePoint.Portal.SingleSignon,Version=12.0.0.0,
		  Culture=neutral,PublicKeyToken=71e9bce111e9429c
    </Property>
    <Property Name="DatabaseAccessProvider" Type="Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db.DbAccessProvider">
		SqlServer
	</Property>
    <Property Name="RdbConnection Data Source" Type="System.String">.</Property>
    <Property Name="RdbConnection Initial Catalog" Type="System.String">AdventureWorks</Property>
    <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
  </Properties>
</LobSystemInstance>

Il semblerait cependant que nous soyons limités à 2 instances par LobSystem ; en effet, lorsque nous essayons d'en ajouter plus, SharePoint nous remonte une erreur, tout d'abord au niveau de notre fichier adf,

image

puis au moment de l'import.

image

Une solution de contournement consisterait à cloner le fichier adf, et d'y modifier le nom, puis d'y ajouter des LobSytemInstances 2 par 2.

En utilisant, plusieurs LobSystemInstances, nous allons pouvoir utiliser notre application en poursuivant des objectifs différents ; par exemple, dans le cas de notre application, nous pourrions par exemple implémenter 2 LobSystemInstances, l'une récupérant les informations de compte de l'utilisateur (PassThrough), et permettant à nos utilisateurs de ne récupérer que les informations qu'il est autorisé à visualiser, et l'autre récupérant des informations d'un compte bases de données login/mot de passe (RdbCredentials), autorisé à accéder à toutes les données présentes dans notre base.

Par exemple, nos utilisateurs utiliseraient le 1er LobSytemInstance, tandis que l'on pourrait configurer l'indexation du BDC pour utiliser le 2nd LobSystemInstance.

De cette facon, nos utilisateurs récupèrent uniquement les informations qui leur sont destinés, tandis que la recherche récupèrera l'ensemble des informations.

Dans ce cas, on pourrait se dire qu'il y'a faille de sécurité dans la mesure ou finalement, nos utilisateurs pourraient donc passer par le service de recherche pour accéder à toutes les informations ; mais le BDC implémente aussi le mécanisme de security trimming (qu'il faudra explicitement mettre en place), ce qui signifie que malgré l'utilisation du service de recherche qui accès à tout le contenu, nos utilisateurs ne verront que les informations qu'ils sont autorisés à récupérer.

Si nous créons plusiseurs instances, elle n'apparaitrons pas au niveau des services partagés, qui nous montrent uniquement nos LobSystems ;

image

On les verra apparaitre par exemple au niveau du Business data type picker.

image

VIII. Conclusion

C'est ici que s'achève ce nouvel article traitant du BDC.

Dans ce 2ème volet, vous avez pu y découvrir quelques unes des fonctionnalités avancées du BDC, et surtout, vous avez désormais toutes les bases pour vos lancer dans l'écriture de vos propres fichiers ADF et la mise au point d'application utilisant les composants OOTB du BDC.

Dans le prochain article, nous allons voir comment créer un fichier ADF pour interroger des web services, et également l'écriture de fichiers ADF ressources.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2008 Dieudonné N'TAMACK. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.