Developpez.com - Microsoft DotNET
X

Choisissez d'abord la catégorieensuite la rubrique :


Configuration du suivi de workflows avec le SQLTrackingService

Date de publication : 20/10/2008 , Date de mise à jour : 20/10/2008

Par Dieudonne N'Tamack (dnt91) (Blog)
 


               Version PDF   Version hors-ligne

0. Mise en place du service SQLTrackingService
I. Utilisation du service SQLTrackingService dans nos applications
I-A. Créer des profils de suivi
II. Conclusion

WF est livré avec un service de Tracking qui permet d'enregistrer les données de suivi directement depuis une base de données SQL Server.


0. Mise en place du service SQLTrackingService

Pour mettre en place ce service, il nous faut au préalable créer une base de données :

image
Ensuite, il nous faut récupérer et exécuter les scripts livrés avec le Framework 3.0 ; ces derniers se trouvent ici > C:\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN (remplacer éventuellement EN par FR).

Commençons par exécuter le script Tracking_Schema.sql ; Ce dernier va créer toutes les tables & vues nécessaires.

image
Ensuite exécutons le script Tracking_Logic.sql ; ce dernier va créer toutes les procédures stockées permettant d'interagir directement avec la base de données de Tracking.

image
Ca y'est, c'est terminé !

Maintenant, il ne nous reste plus qu'à voir comment utiliser ce service depuis notre workflow.


I. Utilisation du service SQLTrackingService dans nos applications

Pour cela, il nous suffit de rajouter un fichier de configuration à notre projet de workflow,

image
Et d'y rajouter les entrées suivantes, en fonction de vos informations de connexion :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="SQLTrackingService" connectionString="Data Source=.;Initial Catalog=WFTrackingDB;Integrated Security=True"/>
  </connectionStrings>
</configuration>
Puis d'ajouter le service de Tracking dans notre code, comme ceci :
[autres directives using]
using System.Configuration;
using System.Workflow.Runtime.Tracking;

namespace Coforcert.WF.Certif.WFChanges {
    class Program {
        static void Main(string[] args) {
            string connectionString = ConfigurationManager.ConnectionStrings["SQLTrackingService"].ConnectionString;
            using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                //Ajout du service SQLTrackingService
                workflowRuntime.AddService(new SqlTrackingService(connectionString));

            [Le reste du code ici]

            Console.Read();
        }
    }
}
Si vous exécutez le code, puis que vous analysez vos tables, vous verrez que ces dernières comportent un certain nombre d'informations.

Jusqu'à présent, WF enregistre toutes les données concernant les actions de nos utilisateurs, nos workflow et nos activités ; cependant, nous pouvons décider par exemple de ne conserver qu'un sous ensemble de ces informations ; pour cela, nous allons utiliser les profils de suivi ou Tracking Profiles.


I-A. Créer des profils de suivi

Les profils de suivi vont donc nous permettre de configurer notre service de Tracking pour n'enregistrer qu'un sous ensemble des informations que WF peut analyser dans notre datastore.

Pour cela, nous allons travailler essentiellement avec 3 objets : le TrackingProfile, le {Activity|User|Workflow}TrackingLocation et enfin le {Activity|User|Workflow}TrackPoint.

Le TrackingProfile va représenter notre profil à proprement parlé.

Le TrackingLocation va nous permettre de définir ce que nous voulons enregistrer ; par exemple, l'exemple suivant précise que nous ne souhaitons enregistrer que les activités qui sont en cours d'exécution ou qui sont fermées.
ActivityTrackingLocation activityLocation = new ActivityTrackingLocation(typeof(Activity));
activityLocation.ExecutionStatusEvents.Add(ActivityExecutionStatus.Executing);
activityLocation.ExecutionStatusEvents.Add(ActivityExecutionStatus.Closed);
Le TrackPoint quant à lui va être chargé de rassembler les TrackingLocation en vue de les transmettre au TrackingProfile, par exemple comme ci-dessous
ActivityTrackPoint activityPoint = new ActivityTrackPoint();
activityPoint.MatchingLocations.Add(activityLocation);

Profile.ActivityTrackPoints.Add(activityPoint);
Voici le code complet de notre méthode de création de profil.
static void CreateTrackingProfile(out TrackingProfile Profile) {
  Profile = new TrackingProfile();
  Profile.Version = new Version("1.0.0.0");

  ActivityTrackingLocation activityLocation = new     
        ActivityTrackingLocation(typeof(Activity)); 
  activityLocation.MatchDerivedTypes = true;         
  activityLocation.ExecutionStatusEvents.Add(
        ActivityExecutionStatus.Executing);
  activityLocation.ExecutionStatusEvents.Add(
        ActivityExecutionStatus.Closed);

  ActivityTrackPoint activityPoint = new ActivityTrackPoint();
  activityPoint.MatchingLocations.Add(activityLocation);

  Profile.ActivityTrackPoints.Add(activityPoint);
}
De même, les profils sont stockés en base.

Si vous observez les procédures stockées créées via les scripts fournis pour le service SQLTracking, vous remarquerez la présence de 2 procédures stockées, UpdateDefaultTrackingProfile et UpdateTrackingProfile, indiquant la présence de 2 tables pour gérer les informations de profil (DefaultTrackingProfile pour gérer le profil par défaut et TrackingProfile pour gérer les autres profils).

Il nous faut donc à présent enregistrer notre profil dans la base de données.

Malheureusement, WF ne fournit pas de structure prête à l'emploi pour réaliser ces actions, nous allons donc devoir utiliser nos bonnes veilles méthodes Ado.net.

Voici le code qui réalise ces opérations.
static void UpdateTrackingProfile(
          TrackingProfile Profile, string ConnectionString) {

  #region Sérialisation de notre Profil

  string trackingprofile = string.Empty;
  TrackingProfileSerializer serializer = new TrackingProfileSerializer();
  using (StringWriter writer = new StringWriter(
                    new StringBuilder(), CultureInfo.InvariantCulture)){
    serializer.Serialize(writer, Profile);
    trackingprofile = writer.ToString();
  }

  #endregion

  #region Enregistrement des données dans la base
            
  if (string.IsNullOrEmpty(ConnectionString)) 
    throw new Exception("la chaine de connexion ne peut être vide");
  using (SqlConnection connection = new SqlConnection(ConnectionString)) {
    SqlCommand uspUpdate = 
          new SqlCommand("dbo.UpdateTrackingProfile", connection);
    uspUpdate.CommandType = CommandType.StoredProcedure;
                
    SqlParameter typeFullName = 
          new SqlParameter("@TypeFullName", SqlDbType.NVarChar, 128);
    typeFullName.Direction = ParameterDirection.Input;
    typeFullName.Value = typeof(Coforcert.WF.Certif.WFChanges.Workflow1);

    SqlParameter assemblyFullName = 
          new SqlParameter("@AssemblyFullName", SqlDbType.NVarChar, 256);
    assemblyFullName.Direction = ParameterDirection.Input;
    assemblyFullName.Value = 
      typeof(Coforcert.WF.Certif.WFChanges.Workflow1).Assembly.FullName;

    SqlParameter version = 
          new SqlParameter("@Version", SqlDbType.VarChar, 32;
    version.Direction = ParameterDirection.Input;
    version.Value = "1.0.0.0";

    SqlParameter trackingProfileXml = 
          new SqlParameter("@TrackingProfileXml", SqlDbType.NText);
    trackingProfileXml.Direction = ParameterDirection.Input;
    trackingProfileXml.Value = trackingprofile;
                
    uspUpdate.Parameters.Add(typeFullName);
    uspUpdate.Parameters.Add(assemblyFullName);
    uspUpdate.Parameters.Add(version);
    uspUpdate.Parameters.Add(trackingProfileXml);

    connection.Open();uspUpdate.ExecuteNonQuery();
    connection.Close();
  }

  #endregion
}
Il ne nous reste plus qu'à créer notre Profile depuis la méthode Main ; pour cela, ajouton du code au début de la méthode, avant de créer notre workflow
static void Main(string[] args) {
  string connectionString = ConfigurationManager.
          ConnectionStrings["SQLTrackingService"].ConnectionString;

  #region Création de notre profil perso

  TrackingProfile Profile = null;
  CreateTrackingProfile(out Profile);
  UpdateTrackingProfile(Profile, connectionString);

  #region Le reste du code se trouve ici
   [. . .]
  #endregion
}
Avant d'exécuter ce code, voici le résultat que nous avions

image
Et après

image

Comme nous pouvons le constater, seuls les événements définis au niveau de notre profil sont enregistrés.

Pour récupérer les données depuis la base de données de suivi, WF nous fournit des objets très pratique comme le SQLTrackingQuery et les {Activity|Workflow|user}TrackingRecord, que nous avons utilisé comme ceci :
//Récupération des données pour analyse
SqlTrackingQuery query = new SqlTrackingQuery(connectionString);
SqlTrackingWorkflowInstance trackingInstance = null;
if (query.TryGetWorkflow(instance.InstanceId, out trackingInstance)) {
  #region Activity tracking

  Console.WriteLine("***Activity Tracking***");
  foreach (ActivityTrackingRecord record in 
                           trackingInstance.ActivityEvents) {
    Console.WriteLine("Activity Name : {0}", record.QualifiedName);
    Console.WriteLine("Activity Event Date Time : {0}", 
                           record.EventDateTime.ToString());
    Console.WriteLine("Activity Type : {0}", 
                           record.ActivityType.ToString());
    Console.WriteLine("Activity Status : {0}", 
                           record.ExecutionStatus.ToString());
    }
                        
    Console.WriteLine("*****************************************");

  #endregion

  #region Workflow tracking

  Console.WriteLine("***Workflow Tracking***");
  foreach (WorkflowTrackingRecord record in 
                          trackingInstance.WorkflowEvents) {
    Console.WriteLine("Activity Name : {0}", 
                          record.TrackingWorkflowEvent.ToString());
    Console.WriteLine("Activity Event Date Time : {0}", 
                          record.EventDateTime.ToString());
    }
                   
    Console.WriteLine("*****************************************");

  #endregion

  #region Activity tracking

  Console.WriteLine("***User Tracking***");
  foreach (UserTrackingRecord record in trackingInstance.UserEvents) {
    Console.WriteLine("Activity Name : {0}", record.QualifiedName);
    Console.WriteLine("Activity Event Date Time : {0}", 
                               record.EventDateTime.ToString());
    Console.WriteLine("Activity Type : {0}", 
                               record.ActivityType.ToString());
  }
  Console.WriteLine("*****************************************");
                      
  #endregion

II. Conclusion

Comme vous avez pu le constater au travers de cet article, il va être facile de mettre en place un service de Tracking, en utilisant le service SQLTrackingService.

De même, nous pouvons cibler de manière plus spécifique les données que nous allons analyser en utilisant les TrackingProfile.

Et enfin, pour monitorer nos données, nous pouvons faire appel aux objets SQLTrackingQuery et {Activity|Workflow|user}TrackingRecord nous exposent diverses méthodes/propriétés pour gérer nos données enregistrées.

Télécharger le fichier projet Visual Studio : ICI



               Version PDF   Version hors-ligne

Valid XHTML 1.1!Valid CSS!

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.

Responsable bénévole de la rubrique Microsoft DotNET : Hinault Romaric -