Créer une activité personnelle pour les workflows Sharepoint Designer
Date de publication : 02/09/2007
Par
Stephane Eyskens (Blog)
Le but de cet article est de montrer comment créer une activité personnelle utilisable dans l'assistant de workflow de Sharepoint Designer. Ceci montre d'une part
que Sharepoint Designer ne se restreint pas aux activités standard et d'autre part ouvre une porte vers des perspectives non négligeables.
I. Introduction
I-A. A quoi sert une activité personnelle?
II. Création de notre service web
II-A. Note sur la sécurité
III. Création de notre activité personnelle
III-A. Type de projet
III-B. Référencement du service web
III-C. Code de notre activité
III-C-1. Création d'une propriété de type DependencyProperty
III-C-2. Implémentation de la méthode ActivityExecutionStatus
III-D. Déploiement de l'activité dans la GAC
III-E. Mise à jour du web.config de Sharepoint
III-F. Renseignement de notre activité dans le WSS.ACTIONS ou dans un fichier .ACTIONS propre
III-F-1. via le fichier WSS.ACTIONS
III-F-2. via un fichier spécifique à notre action
IV. Création de notre workflow dans Sharepoint Designer
V. Plus loin avec les activités personnelles
V-A. Description des propriétés __Context, __ListId et __ListItem
V-B. Code permettant de transformer le champ cible choisi par l'utilisateur
V-C. Le code complet du fichier .ACTIONS
V-D. Comment tester notre activité opérant une transformation de chaîne?
VI. Téléchargement
I. Introduction
Dans cet article nous allons dans un premier temps créer une simple activité personnelle qui interroge un service web qui lui retournera une réponse. Nous utiliserons ensuite cette activité
dans un workflow que l'on créera avec Sharepoint Designer pour mettre à jour la colonne Title de la liste d'annonces de notre site lorsqu'une annonce est ajoutée.
Dans un deuxième temps, nous aborderons des concepts plus complexes en travaillant directement sur des éléments de listes via les propriétés __Context, __ListId et __ListItem
I-A. A quoi sert une activité personnelle?
Une activité personnelle sert à faire tout ce que les activités standard ne permettent pas de faire. On peut par exemple imaginer devoir interroger
Active Directory ou un service web ou décider de créer une entrée dans le gestionnaire d'évènements etc... au cours d'un workflow. Toutes ces actions ne sont
pas réalisables avec les activités standard. Il faut donc passer par une activité personnelle. Dès qu'une limitation quelconque est rencontrée, il est possible soit
de créer entièrement un workflow avec Visual Studio mais le coût de développement est élevé, soit de créer une activité personnelle le cas échéant, ce qui réduit
le coût de développement et est est plus efficace en terme de réutilisation.
De surcroît, cette activité ne se crée qu'une fois et peut être réutilisée par tous les workflows.
II. Création de notre service web
Le service web que nous créons pour cet article n'est qu'un prétexte servant à montrer l'interaction possible entre un workflow créé avec
Sharepoint Designer et les services web. Il ne fait donc rien de très enthousiasmant.
Je ne vais pas rentrer dans le détail concernant la création et l'utilisation d'un service web car ce n'est pas le but de cet article. D'autres
ressources traitant de ce sujet sont disponibles sur ce site. Je vais donc simplement exposer le code afin de vous montrer ce qui sera retourné par le service.
|
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public Service () {
}
[WebMethod]
public string GetAnswer() {
return "coucou";
}
}
|
Comme vous pouvez le constater, ce service n'expose qu'une web méthod qui retourne la chaîne de caractères coucou témoignant de la
bonne exécution de cette dernière. C'est donc cette chaîne de caractères qui servira à mettre à jour la colonne Title de notre liste d'annonces.
II-A. Note sur la sécurité
Dans cet exemple, mon service est accessible de manière anonyme, il sera donc interrogeable directement par un workflow s'exécutant au sein
de Sharepoint. Il est plus que probable qu'en situation réelle, vous ayez à utiliser la sécurité intégrée et à transmettre les informations de l'
utilisateur courant lors de l'interrogation du service et à éventuellement faire une impersonation. Ces concepts ne sont pas abordés dans cet article
III. Création de notre activité personnelle
III-A. Type de projet
Vous pouvez utiliser le type de projet standard dédié à la création d'une activité personnelle. Choisissez le modèle illustré par l'image
ci-dessous
Note: vous devez au moins disposer de la version 3.0 du framework dotnet.
III-B. Référencement du service web
Lorsque vous avez créé le projet, vous pouvez directement référencer le service en ajoutant une référence web et en renseignant l'url de votre service comme illustré ci-dessous.
III-C. Code de notre activité
III-C-1. Création d'une propriété de type DependencyProperty
Les propriétés vont nous permettre d'associer les valeurs en entrée et en sortie de notre workflow aux propriétés exposées dans l'assistant workflow de
Sharepoint Designer. Pour créer une de ces propriétés dans le code, il est aisé d'utiliser une snippet. Pour cela, dans votre fichier source, cliquez sur le bouton droit, ensuite Insert Snippet et ensuite
cliquez sur Workflow.
Ceci crée une propriété que vous pourrez renommer selon vos besoins.
Dans notre exemple, nous avons créé la propriété suivante
public static DependencyProperty WebServiceReturnValueProperty =
DependencyProperty.Register("WebServiceReturnValue", typeof(string), typeof(GetWsInfo));
[Description("Return value of the demo web service")]
[Category("User")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string WebServiceReturnValue
{
get
{
return (string)GetValue(WebServiceReturnValueProperty);
}
set
{
SetValue(WebServiceReturnValueProperty, value);
}
}
|
- Register permet d'enregistrer la propriété pour qu'elle soit connue par le workflow
- le premier typeof prend en paramètre le type de notre propriété (string, int, workflowcontext etc...)
- le deuxième typeof doit prendre en paramètre le nom de la classe principale
III-C-2. Implémentation de la méthode ActivityExecutionStatus
Pour que votre activité s'exécute, vous devez réécrire la méthode ActivityExecutionStatus de la classe de base.
try
{
momix.Service DemoService = new GetWebServiceAnswer.momix.Service();
WebServiceReturnValue = DemoService.GetAnswer();
DemoService.Dispose();
return ActivityExecutionStatus.Closed;
}
catch (Exception)
{
return ActivityExecutionStatus.Faulting;
}
|
III-D. Déploiement de l'activité dans la GAC
Notre activité étant une DLL, vous pouvez suivre les instructions stipulées dans
ce tuto section
Signature, GAC et construction d'un fichier bat car la marche à suivre est exactement la même.
III-E. Mise à jour du web.config de Sharepoint
Habituellement, lorsque l'on développe un contrôle personnel ou un webpart pour Sharepoint, il faut le référencer en tant que SafeControl dans le web.config. Cette fois, c'est une
autre section qu'il faut modifier.
Editez le web.config correspondant à votre application Sharepoint, localisez la section <System.Workflow.ComponentModel.WorkflowCompiler> et ajoutez-y ceci
|
<authorizedType Assembly="GetWebServiceAnswer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8986eea5ac14faeb"
Namespace="GetWebServiceAnswer" TypeName="*" Authorized="True" />
|
en remplaçant bien sûr la signature par celle de votre assembly.
III-F. Renseignement de notre activité dans le WSS.ACTIONS ou dans un fichier .ACTIONS propre
Afin que Sharepoint Designer liste notre activité dans la liste d'actions de l'assistant workflow, nous devons lui renseigner celle-ci dans
un fichier de configuration. Il est possible d'utiliser deux techniques différentes. On peut enregistrer l'action dans le fichier wss.ACTIONS ou dans
un fichier séparé. La deuxième option semble préférable dans le mesure où l'on ne risque pas d'induire une déstabilisation quelconque en ne modifiant pas le
fichier standard.
III-F-1. via le fichier WSS.ACTIONS
Le fichier WSS.ACTIONS se trouve dans le répertoire 12\TEMPLATE\1033\Workflow de votre installation Sharepoint. Pour ajouter une action
il faut modifier la section Actions et ajouter une action spécifique comme ceci
<Action Name="Get web service Info"
ClassName="GetWebServiceAnswer.GetWsInfo"
Assembly="GetWebServiceAnswer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8986eea5ac14faeb"
AppliesTo="all">
<RuleDesigner Sentence="Get information from web service (Output to %1)">
<FieldBind Field="WebServiceReturnValue" Text="WebServiceReturnValue" DesignerType="ParameterNames" Id="1"/>
</RuleDesigner>
<Parameters>
<Parameter Name="WebServiceReturnValue" Type="System.String, mscorlib" Direction="Out" />
</Parameters>
</Action>
|
Dans notre exemple, nous déclarons une règle dans laquelle nous lions le champ de sortie au paramètre de sortie WebServiceReturnValue. C'est celui-là
même qui stockera la réponse du service web. Le mot clé ParameterNames spécifie au designer que ce champ doit être considéré comme une variable.
III-F-2. via un fichier spécifique à notre action
La méthode est la même que pour le WSS.ACTIONS mais l'on spécifie notre XML dans un fichier à part.
<?xml version="1.0" encoding="utf-8" ?>
<WorkflowInfo>
<Actions Sequential="then" Parallel="and">
<Action Name="Get web service Info"
ClassName="GetWebServiceAnswer.GetWsInfo"
Assembly="GetWebServiceAnswer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8986eea5ac14faeb"
AppliesTo="all">
<RuleDesigner Sentence="Get information from web service (Output to %1)">
<FieldBind Field="WebServiceReturnValue" Text="WebServiceReturnValue" DesignerType="ParameterNames" Id="1"/>
</RuleDesigner>
<Parameters>
<Parameter Name="WebServiceReturnValue" Type="System.String, mscorlib" Direction="Out" />
</Parameters>
</Action>
</Actions>
</WorkflowInfo>
|
La seule différence par rapport à WSS.ACTIONS est que l'on déclare la section Actions puisqu'elle n'existe pas déjà comme c'est le cas dans WSS.ACTIONS
Que vous ayez choisi l'une ou l'autre méthode, vous devrez redémarrer IIS et rafraîchir Sharepoint Designer pour pouvoir visualiser l'activité dans la liste d'actions.
IV. Création de notre workflow dans Sharepoint Designer
La première étape consiste à créer le workflow, pour cela, ouvrez le site cible dans Sharepoint Designer et cliquez sur, File => New => Workflow
Donnez un nom à votre workflow et faites en sorte qu'il s'exécute lorsqu'une nouvelle annonce est créée.
Choisissez notre activité personnelle dans la liste d'actions.
Cliquez sur l'activité Build Dynamic String pour récupérer la valeur actuelle de la colonne Title et la concaténer avec la variable retournée par notre action "Get web service info" et envoyez le tout
dans une variable nommée New Title par exemple.
Ensuite, choisissez l'action Update List Item qui va nous permettre de mettre à jour la colonne Title avec la valeur stockée dans New Title
Cliquez ensuite sur Finish pour terminer le workflow. Vous pouvez ensuite créer une annonce dans votre liste d'annonce et le titre devrait être modifié et contenir le titre original plus la réponse du service web.
V. Plus loin avec les activités personnelles
Dans cette section, nous allons explorer plus avant grâce à un exemple simple les possibilités d'interaction entre une activité personnelle et l'assistant de création de workflow de Sharepoint Designer.
Par ailleurs, nous allons également voir comment récupérer/transformer les données de la liste sur laquelle est exécuté notre workflow.
L'exemple que nous allons développer est une activité personnelle qui permettra à l'utilisateur de créer un workflow dans Sharepoint Designer qui lui permettra de choisir
une colonne qui devra être transformée soit en minuscules soit en majuscules. Cet exemple simpliste permet de se familiariser avec certaines propriétés importantes.
V-A. Description des propriétés __Context, __ListId et __ListItem
- __Context Cette propriété est une instance de WorkflowContext et permet de récupérer le contexte dans lequel le workflow évolue. On peut via cette propriété récupérer le SPSite et le SPWeb
- __ListId Cette propriété représente le GUID de la liste à laquelle est attaché le workflow
- __ListItem Cette propriété représente l'ID de l'élément de la liste auquel est attaché le workflow
Vous l'aurez compris, c'est grâce à ces trois propriétés que l'on va pouvoir travailler sur l'élément de liste sur lequel est basé le workflow. Voici comment
elles sont déclarées dans le code.
public static DependencyProperty __ContextProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(StringActivity));
[Description("Workflow Context")]
[Category("String Transformation")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[ValidationOption(ValidationOption.Required)]
public WorkflowContext __Context
{
get
{
return ((WorkflowContext)(base.GetValue(StringActivity.__ContextProperty)));
}
set
{
base.SetValue(StringActivity.__ContextProperty, value);
}
}
public static DependencyProperty __ListItemProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("__ListItem", typeof(int), typeof(StringActivity));
[Description("ListItem")]
[Category("String Transformation")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[ValidationOption(ValidationOption.Required)]
public int __ListItem
{
get
{
return ((int)(base.GetValue(StringActivity.__ListItemProperty)));
}
set
{
base.SetValue(StringActivity.__ListItemProperty, value);
}
}
public static DependencyProperty __ListIdProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("__ListId", typeof(string), typeof(StringActivity));
[Description("Id of the list")]
[Category("String Transformation")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[ValidationOption(ValidationOption.Required)]
public string __ListId
{
get
{
return ((string)(base.GetValue(StringActivity.__ListIdProperty)));
}
set
{
base.SetValue(StringActivity.__ListIdProperty, value);
}
}
|
Ces propriétés ressemblent à n'importe quelles autres propriétés dotnet. Elles sont simplement préfixée d'attributs qui seront séralisés en XML et interprétés par
le designer. Voici comment elles sont déclarées dans le fichier .ACTIONS
<Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" />
<Parameter Name="__ListId" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="__ListItem" Type="System.Int32, mscorlib" Direction="In" />
|
Dans notre exemple, nous avons besoin de connaître le nom de la colonne de liste qui devra subir la transformation en majuscules ou en minuscules. Voici la propriété
correspondant à ce nom. Cette propriété sera affichée sous cette forme par l'assistant graphique de Sharepoint Designer
et voici le code Csharp correspondant
public static DependencyProperty FieldProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("Field", typeof(string), typeof(StringActivity));
[Description("Column to be transformed")]
[Category("String Transformation")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[ValidationOption(ValidationOption.Required)]
public string Field
{
get
{
return ((string)(base.GetValue(StringActivity.FieldProperty)));
}
set
{
base.SetValue(StringActivity.FieldProperty, value);
}
}
|
Voici à présent sa déclaration dans le fichier .ACTIONS
<FieldBind Field="Field" Text="Field" Id="1" DesignerType="writablefieldNames"/>
|
writablefieldNames permet de ne liste que les champs qui ne sont pas en lecture seule de la liste sur laquelle s'exécute le workflow. Pour la liste complète, vous pouvez
utiliser fieldNames
Voici enfin la dernière propriété, elle correspond au type d'opération que l'on veut appliquer, c'est à dire à une transformation en minuscules ou en majuscules.
Elle est représentée sous forme de liste dans Sharepoint Designer comme suit:
et voici son code Csharp
public static DependencyProperty FunctionProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("Function", typeof(string), typeof(StringActivity));
[Description("Function to apply")]
[Category("String Transformation")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[ValidationOption(ValidationOption.Required)]
public string Function
{
get
{
return ((string)(base.GetValue(StringActivity.FunctionProperty)));
}
set
{
base.SetValue(StringActivity.FunctionProperty, value);
}
}
|
Voici à présent sa déclaration dans le fichier .ACTIONS
<FieldBind Field="Function" Text="Function to apply" Id="2" DesignerType="Dropdown">
<Option Name="Uppercase" Value="Uppercase"/>
<Option Name="Lowercase" Value="Lowercase"/>
</FieldBind>
|
Dropdown permet de spécifier que la propriété doit être rendue sous forme de zone de liste. Les différentes options sont ensuite
listées une à une.
V-B. Code permettant de transformer le champ cible choisi par l'utilisateur
Lorsque le créateur du workflow aura spécifié le champ à transformer ainsi que l'opération à y appliquer, le code suivant fera en sorte d'exécuter
les instructions.
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
using (SPWeb ContextWeb = __Context.Web)
{
SPList TargetList = ContextWeb.Lists[new Guid(__ListId)];
SPListItem TargetItem = TargetList.GetItemById(__ListItem);
if (TargetList.Fields[Field].Type == SPFieldType.Text)
{
string CurrentValue = (TargetItem[Field] != null) ? TargetItem[Field].ToString() : "";
switch(Function)
{
case "Uppercase":
TargetItem[Field] = CurrentValue.ToUpper();
break;
case "Lowercase":
TargetItem[Field] = CurrentValue.ToLower();
break;
}
}
TargetItem.Update();
}
return ActivityExecutionStatus.Closed;
}
|
Tous les commentaires utiles sont dans le code. Toutefois, on pourrait y ajouter une gestion d'erreur. Il faut savoir qu'en cas de non gestion d'erreur explicite, si le workflow
rencontre un problème, il sera en statut "Error Occured" et des informations relatives à l'erreur pourront normalement être trouvées soit dans le gestionnaire d'évènements soit dans les fichiers
logs de Sharepoint que l'on trouve dans le répertoire <intallation Sharepoint>/12/Logs/
V-C. Le code complet du fichier .ACTIONS
Il est préférable de créer un fichier .ACTIONS indépendant, dans lequel vous pouvez insérer ce code
<?xml version="1.0" encoding="utf-8" ?>
<WorkflowInfo>
<Actions Sequential="then" Parallel="and">
<Action Name="Transform String"
ClassName="StringTransformations.StringActivity"
Assembly="StringTransformations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=eda78c3b825c364e"
AppliesTo="list"
Category="String Operations"
UsesCurrentItem="true">
<RuleDesigner Sentence="Transform %1 to be in %2">
<FieldBind Field="Field" Text="Field" Id="1" DesignerType="writablefieldNames"/>
<FieldBind Field="Function" Text="Function to apply" Id="2" DesignerType="Dropdown">
<Option Name="Uppercase" Value="Uppercase"/>
<Option Name="Lowercase" Value="Lowercase"/>
</FieldBind>
</RuleDesigner>
<Parameters>
<Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" />
<Parameter Name="__ListId" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="__ListItem" Type="System.Int32, mscorlib" Direction="In" />
<Parameter Name="Field" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="Function" Type="System.String, mscorlib" Direction="In" />
</Parameters>
</Action>
</Actions>
</WorkflowInfo>
|
V-D. Comment tester notre activité opérant une transformation de chaîne?
Pour tester le workflow, rien de plus simple (inspirez-vous de la section Création de notre workflow dans Sharepoint Designer. Voici donc en résumé les différentes
étapes à accomplir
- Ouvrez Sharepoint Designer sur le site cible et cliquez sur New => Workflow
- Faites démarrer le workflow sur l'ajout d'un élément
- Ajoutez un step, ajoutez une action en choisissant notre activité et choisissez le champ de la liste à convertir dans la zone "field"
- Sélectionnez ensuite la transformation à accomplir dans la zone "function"
- Cliquez sur Finish
- Allez dans votre site Sharepoint, ajoutez un élément dans votre liste et voyez si la valeur de la colonne cible a bien été transformée
VI. Téléchargement
Vous pouvez télécharger l'exemple de projet
ici. C'est l'exemple qui modifie la colonne choisie en majuscules ou minuscules.


Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur.
La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.