SharePoint 2007: BDC - Exemple Basique

Ce post fait partie d'une serie d'articles dédiés à la présentation du BDC (Business Data Catalog) ou Catalogue de Données Métier dans SharePoint 2007. Cette fonctionnalité n'est disponible qu'a partir de la version Entreprise et est plus complexe à maitriser qu'elle n'y parait.

Cet article n'aurait pu voir le jour sans l'aimable autorisation de Salik Malik (MVP C# et membre actif de la communauté SharePoint) qui m'a permis de le rendre disponible à la communauté francophone.

 

Comme je vous l'ai décrit précédemment, le BDC est un moyen d'alimenter MOSS Entreprise en données externes. Tout ce qui est accessible via ADO.NET ou par un Web Service peut être fourni à MOSS via BDC.

Ainsi en schématisant, on obtient :

Certains d'entre vous se demande peut être où est l'intérêt de ce BDC en question, car vous pourriez tout à fait faire la même chose en développant une webpart personnalisée (ce que vous verrez d'ailleurs dans les posts suivants). Mais dans ce cas là, vous manqueriez un point important, à savoir que le BDC est une solution qui ne nécéssite aucun développement. Tout ce dont vous aurez besoin est d'un gros fichier XML (très gros), certes bien compliqué et souvent très long à écrire, mais qui dit XML dit outils pour créer et maintenir ces méta données. Ainsi les développeurs pourront par la suite être libérés de cette tâche laborieuse. Ce genre d'outils a d'ailleurs déjà commencé à voir le jour avec par exemple le BDCMetaman.

Ainsi pour que le BDC puisse fonctionner (fournir MOSS en données externes), vous avez tout d'abord besoin de créer une application BDC. Le fichier XML contiendra toutes les informations nécessaires à l'application BDC et devra donc être importé dans le SSP approprié.

Une fois l'XML importé dans le SSP, celui-ci commencera à lire toutes les méta données concernant le LOBD (Line of Business Data) et les rendra accessible à de nombreux sites SharePoint, Applications, etc. .

Comme vous l'avez sûrement compris, l'XML contiendra des données permettant de dire au SSP où se trouve les données, comment y accéder, quels entités sont extraites, les paramètres, mais aussi les actions à entreprendre et les liens entre les différentes entités.

Mais assez d'explications théoriques et commençons par un exemple basique.

L'exemple suivant utilise la base de donnée Northwind et la table Customers. Je souhaite obtenir mes informations sur mon Customer via la requête SQL suivante :

SELECT CustomerID, ContactName, Address, City FROM Customers WHERE CustomerID = @CustomerID

Et voici le fameux XML qui en découle :

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<LobSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xsi:schemaLocation="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog BDCMetadata.xsd" 
           Type="Database" Version="1.0.0.0" Name="NorthWindApp" 
           xmlns="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog">
    <Properties>
        <Property Name="WildcardCharacter" Type="System.String">%</Property>
    </Properties>
    <LobSystemInstances>
        <LobSystemInstance Name="NorthWindTraders">
            <Properties>
                <!--AuthenticationMode can be set to PassThrough, RevertToSelf, RdbCredentials, or WindowsCredentials. -->
                <Property Name="AuthenticationMode" Type="System.String">PassThrough</Property>
                <Property Name="DatabaseAccessProvider" Type="System.String">SqlServer</Property>
                <Property Name="RdbConnection Data Source" Type="System.String">192.168.0.107\SQLSERVER</Property>
                <Property Name="RdbConnection Initial Catalog" Type="System.String">Northwind</Property>
                <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
                <Property Name="RdbConnection Pooling" Type="System.String">false</Property>
            </Properties>
        </LobSystemInstance>
    </LobSystemInstances>
    <Entities>
        <Entity EstimatedInstanceCount="100" Name="Customer">
            <!-- EstimatedInstanceCount is an optional attribute-->
            <Properties>
                <Property Name="ContactName" Type="System.String">ContactName</Property>
            </Properties>
            <Identifiers>
                <Identifier Name="CustomerID" TypeName="System.String" />
            </Identifiers>
            <Methods>
                <!-- Defines a method that brings back Customer data from the back-end database.-->
                <Method Name="GetCustomers">
                    <Properties>
                        <Property Name="RdbCommandText" Type="System.String">
                            SELECT CustomerID, ContactName, Address, City FROM Customers WHERE CustomerID = @CustomerID
                        </Property>
                        <Property Name="RdbCommandType" Type="System.Data.CommandType">Text</Property>
                        <!-- For database systems, can be Text, StoredProcedure, or TableDirect. -->
                    </Properties>
                    <FilterDescriptors>
                        <!-- Define the filters supported by the back-end method (or sql query) here. -->
                        <FilterDescriptor Type="Comparison" Name="CustomerID" >
                            <Properties>
                                <Property Name="Comparator" Type="System.String">Equals</Property>
                            </Properties>
                        </FilterDescriptor>
                    </FilterDescriptors>
                    <Parameters>
                        <Parameter Direction="In" Name="@CustomerID">
                            <TypeDescriptor TypeName="System.String" IdentifierName="CustomerID" 
                                            AssociatedFilter="CustomerID" Name="CustomerID">
                              <DefaultValues>
                                <DefaultValue MethodInstanceName="CustomerFinderInstance" Type="System.String">ALFKI</DefaultValue>
                              </DefaultValues>
                            </TypeDescriptor>
                        </Parameter>
                        <Parameter Direction="Return" Name="Customers">
                            <TypeDescriptor TypeName="System.Data.IDataReader, System.Data, Version=2.0.3600.0, 
Culture=neutral, PublicKeyToken=b77a5c561934e089
"
                                            IsCollection="true" Name="CustomerDataReader">
                                <TypeDescriptors>
                                    <TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, Version=2.0.3600.0, 
Culture=neutral, PublicKeyToken=b77a5c561934e089
"
                                                    Name="CustomerDataRecord">
                                        <TypeDescriptors>
                                            <TypeDescriptor TypeName="System.String" IdentifierName="CustomerID" Name="CustomerID">
                                                <LocalizedDisplayNames>
                                                    <LocalizedDisplayName LCID="1033">CustomerID</LocalizedDisplayName>
                                                </LocalizedDisplayNames>
                                            </TypeDescriptor>
                                            <TypeDescriptor TypeName="System.String" Name="ContactName" >
                                                <!-- Do not use the AssociatedFilter  attribute in return parameters.-->
                                                <LocalizedDisplayNames>
                                                    <LocalizedDisplayName LCID="1033">ContactName</LocalizedDisplayName>
                                                </LocalizedDisplayNames>
                                                <Properties>
                                                    <Property Name="DisplayByDefault" Type="System.Boolean">true</Property>
                                                </Properties>
                                            </TypeDescriptor>
                                            <TypeDescriptor TypeName="System.String" Name="Address">
                                                <LocalizedDisplayNames>
                                                    <LocalizedDisplayName LCID="1033">Address</LocalizedDisplayName>
                                                </LocalizedDisplayNames>
                                                <Properties>
                                                    <Property Name="DisplayByDefault" Type="System.Boolean">true</Property>
                                                </Properties>
                                            </TypeDescriptor>
                                            <TypeDescriptor TypeName="System.String" Name="City">
                                                <LocalizedDisplayNames>
                                                    <LocalizedDisplayName LCID="1033">City</LocalizedDisplayName>
                                                </LocalizedDisplayNames>
                                            </TypeDescriptor>
                                        </TypeDescriptors>
                                    </TypeDescriptor>
                                </TypeDescriptors>
                            </TypeDescriptor>
                        </Parameter>
                    </Parameters>
                    <MethodInstances>
                        <MethodInstance Name="CustomerFinderInstance" Type="Finder" ReturnParameterName="Customers" />
                    </MethodInstances>
                </Method>
            </Methods>
            <!-- Enter your Action XML here -->
        </Entity>
    </Entities>
</LobSystem>

Pour la mauvaise nouvelle, à moins d'acheter BDCMetaman, vous devrez écrire ce fichier vous même. Alors évidement il y a un schéma mais vous vous rendrez vite compte que très souvent le schéma n'est pas suffisant pour faire fonctionner le smilblick. Certains ont espoir avec la sortie de Orcas que cela s'arrange mais n'y croyez pas trop ! En attendant, il vaut écrire le fichier pas à pas pour éviter de faire trop d'erreurs d'un coup.

Bref si on regarde en détail l'XML ci-dessus, vous remarquerez plusieurs blocs donc un plus spécialement au début du fichier :

<LobSystemInstances>
    <LobSystemInstance Name="NorthWindTraders">
        <Properties>
            <!--AuthenticationMode can be set to PassThrough, RevertToSelf, RdbCredentials, or WindowsCredentials. -->
            <Property Name="AuthenticationMode" Type="System.String">PassThrough</Property>
            <Property Name="DatabaseAccessProvider" Type="System.String">SqlServer</Property>
            <Property Name="RdbConnection Data Source" Type="System.String">192.168.0.107\SQLSERVER</Property>
            <Property Name="RdbConnection Initial Catalog" Type="System.String">Northwind</Property>
            <Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
            <Property Name="RdbConnection Pooling" Type="System.String">false</Property>
        </Properties>
    </LobSystemInstance>
</LobSystemInstances>

Comme vous pouvez le voir, j'utilise l'authentification PassThrough qui signifie que la personne loguée sur le site SharePoint utilisera ses identifiants pour accéder à la base derrière le BDC. Ceci marchera si :

  • Vous utilisez Kerberos
  • Vous utilisez NTLM et que tout est sur la même machine. (bon plan pour les démos).

Un autre chose à laquelle vous devez prêter attention avec le mode d'authentification PassThrough est que lorsque Search essaye d'indexer les données du BDC, les identifiants de l'utilisateur vont être utilisés sur la base de donnée !! Mais la simplicité de l'approche ne la rend pas moins attrayante pour autant, de plus d’autres options existent comme RevertToSelf (où l'identité du pool d'application reprend la main), WindowsCredentials (SSO), RdbCredentials, etc.

Mais revenons au fameux XML, j'ai défini l'entité appelée Customer, qui a un identifiant appelé CustomerID (la clef primaire dans le monde du BDC) et une méthode appelée GetCustomers : 

SELECT CustomerID, ContactName, Address, City FROM Customers WHERE CustomerID = @CustomerID

L'XML contient aussi la définition d'un paramètre d'entrée (CustomerID) avec une valeur par défaut et une valeur de retour de type DataReader avec la représentation obligatoire de toutes les colonnes.

Finalement j'ai une MethodInstance de type Finder avec un paramètre de retour de type Customer. Le type de MethodInstance affecte comment la méthode sera utilisée, c'est à dire :

  • Finder retourne plusieurs entités.
  • SpecificFinder extrait une seule entité.
  • IDEnumerator est utilisé pour la recherche et retourne une liste d'ID
  • Scalar est une méthode qui retourne une seule valeur et non pas entités. Par exemple : Vous pouvez utilisez cette méthode pour récupérer le nombre total de vente à partir d'une date donnée.
  • Etc. N'hesitez pas à consulter le SDK à ce sujet.

Maintenant que le fichier XML est écrit, importez le dans le SSP en suivant les étapes suivantes :

  • Allez dans votre SSP
  • Cliquez sur "Business data catalog" puis "Import application definition"
  • Ouvrez le fichier XML comme votre "Application Definition File", choisissez d'importer comme "Model", et cliquer "Import"

Normalement, si vous avez tout configuré proprement (sécurité comprise) à la fois sur la base de donnée, sur le serveur SharePoint et sur le réseau, vous devriez voir un warning concernant une instance du type "SpecificFinder" qui n'est pas définie :

No method instance of type SpecificFinder defined for for application 'NorthWindApp', entity 'Customer'. Profile page creation skipped.

Disons que pour l'instant vous allez ignorer ce warning (vous disant grosso modo que certes vous pouvez récupérer une liste d'entités mais sans la méthode pour avoir les infos sur un en particulier, ça risque de ne pas vous servir à grand chose).

Mais bon, c'est un exemple basique donc ignorons ce message pour l'instant. On arrangera ça plus tard.

Désormais, tout est prêt à être testé, vous pouvez utilisez le BDC de la manière suivante :

  • Allez sur votre site SharePoint favori
  • Editez une page qui accepte les web parts
  • Ajoutez une webpart appelée "Business Data List" (Au besoin vous devrez activer cette web part via la web part gallery)
Normalement vous obtenez ceci :

 

  • Cliquer sur "Open the Tool Pane" ou "Modify Shared Web Part" sous le menu d'édition à droite
  • Dans le panneau d'outils, tapez "Customer (NorthWindTraders)" sous le champ "Type". Pensez à utiliser le petit bouton de validation à droite, histoire d'éviter les typos.

  • Appuyez sur le bouton "OK" et vous devriez avoir une web part qui ressemble à ceci :

  • Sortez du mode édition et tapez l'id d'un Customer, ALFKI par exemple.
  • Récuperez les données et vous devriez vous retrouvez avec la liste suivante.

Super !   

Dans le prochain post, nous améliorerons cet exemple en récupérant une liste complète d'entités.

 <Philippe/>

Publié vendredi 20 avril 2007 21:52 par phil
Classé sous , ,
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 :

Commentaires

About phil

Philippe Sentenac est Consultant SharePoint à Wygwam en région Parisienne. Il intervient essentiellement sur des missions liées à SharePoint (2007 et 2010 ) mais aussi autour du Web 2.0. Plus généralement, il s'intéresse à l'ASP.Net (MVC) , à Silverlight, et à tout ce qui est orienté Web en rapport avec les nouvelles technologies, qu'il pratique depuis 2006. Féru de développement, il est passionné par les problématiques de méthodologies et d'industrialisation du développement.

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01