Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Abonnements

Roslyn : générer des InvokeActivity avec T4

Le titre peut paraître bizarre mais c’est un vrai besoin rencontré chez un client pour lequel je vais utiliser Roslyn.

Imaginez le scénario suivant : dans un projet, il y a des développeurs et des experts fonctionnels. Les experts fonctionnels doivent "développer" des Workflows. Les développeurs vont développer des méthodes qui seront utilisées dans les workflows.

Le problème avec ça c’est les InvokeActivity. Pour les utiliser, ils doivent connaîtrent la signature de la méthode pour spécifier les bons types des paramètres / résultat. Un autre problème c’est qu’il faut écrire manuellement le nom de la méthode avec potentiellement le risque de faute de frappe / mise à jour.

Les experts fonctionnels préfèreraient faire du drag and drop des activités dans le workflow.

Donc mon idée est d’encapsuler les InvokeActivity dans des Activity. Maintenant, ça peut être très pénible pour les développeurs de faire ces activités.

Pour cela, il serait plus simple que les développeurs décorent les méthodes en utilisant un Attribut et ils pourraient utiliser un T4 pour générer ces activités.

Le T4 utilise Roslyn pour récupérer les informations sur les méthodes.

Ce T4 va utiliser le ttinclude d’Entity Framework EF.Utility.CS.ttinclude qui intègre déjà la création de plusieurs fichiers depuis un T4 (dans mon casje veux un fichier par méthode).

<#@ include file="EF.Utility.CS.ttinclude"#>

Ensuite, le T4 référence les assemblies de Roslyn :

<#@ assembly name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Roslyn\v1.0\Roslyn.Compilers.dll"#>

<#@ assembly name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Roslyn\v1.0\Roslyn.Compilers.CSharp.dll"#>

<#@ assembly name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Roslyn\v1.0\Roslyn.Services.dll"#>

<#@ assembly name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Roslyn\v1.0\Roslyn.Services.CSharp.dll"#>

<#@ assembly name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Roslyn\v1.0\Roslyn.Services.VisualBasic.dll"#>

Le chemin vers la solution et le nom de projet sont spécifiés au début du T4. Donc maintenant, on peut charger la solution en utilisant Roslyn et récupérer les méthodes décorées avec l’attribut dans le projet spécifié.

var solution = Solution.Load(solutionPath);

var project = solution.Projects.First(p => p.AssemblyName == projectAssemblyName);

foreach (var document in project.Documents)

{

    //…

}

Ensuite, pour identifier les méthodes, on utilisera un SyntaxVisitor:

public class InvokeActivityAttributeVisitor : SyntaxVisitor<object>

{

    protected override object VisitCompilationUnit(CompilationUnitSyntax node)

    {

        foreach (var n in node.ChildNodes())

            Visit(n);

        return null;

    }

 

    protected override object VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)

    {

        foreach (var n in node.ChildNodes())

            Visit(n);

        return null;

    }

 

    protected override object VisitTypeDeclaration(TypeDeclarationSyntax node)

    {

        foreach (var n in node.ChildNodes())

            Visit(n);

        return null;

    }

 

    protected override object VisitMethodDeclaration(MethodDeclarationSyntax node)

    {

        if (node.Modifiers.Any(st => st.Kind == SyntaxKind.PublicKeyword) && node.Attributes.Any(a => a.Attributes.Any(a2 => Regex.IsMatch(a2.Name.GetFullText(), @"^(Roslyn.WF.ActivityGenerator.)?InvokeActivity$"))))

        {

            string methodName = node.Identifier.GetText();
            var returnTypeAsPredefinedTypeSyntax = node.ReturnType as PredefinedTypeSyntax;
            if (returnTypeAsPredefinedTypeSyntax == null || returnTypeAsPredefinedTypeSyntax.Keyword.Kind != SyntaxKind.VoidKeyword)
            {
                //…       
            }
            foreach (var parameter in node.ParameterList.Parameters)
            {
                //…       
            }

        }

    }

}

Maintenant le point important est de connaître le namespace et l’assembly des types utilisés dans les méthodes. Pour cela, on utilisera les symbols de compilation :

_syntaxTree = (SyntaxTree)_document.GetSyntaxTree();
_semanticModel = _document.Project.GetCompilation().GetSemanticModel(_syntaxTree);
var returnTypeSymbol = _semanticModel.GetSemanticInfo(node.ReturnType).Symbol;
string returnTypeAssemblyName = returnTypeSymbol.ContainingAssembly.AssemblyName.Name;
string returnTypeNamespaceName = returnTypeSymbol.ContainingNamespace.ToString();

Il faut également savoir si les paramètres sont en In/Out/InOut:

parameter.Modifiers.Any(st => st.Kind == SyntaxKind.RefKeyword) ? Direction.InOut : (parameter.Modifiers.Any(st => st.Kind == SyntaxKind.OutKeyword) ? Direction.Out : Direction.In)

Le reste du code est basique, utilisé pour générer les activités.

Vous pouvez télécharger le code ici.

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 :

Publié jeudi 20 octobre 2011 09:02 par Matthieu MEZIL

Classé sous : , ,

Commentaires

Pas de commentaires

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Les actualités de la semaine sur c2i.fr (14 mai - 20 mai) par Richard Clark le il y a 5 heures et 18 minutes

- Reactive Extensions : Consommer des services avec Rx Partie 3, les pièges à éviter par Léonard Labat le il y a 14 heures et 23 minutes

- SharePoint Blog Site, problème d’archives par Le Blog (Vert) d'Arnaud JUND le 05-20-2012, 13:09

- Soirée ALT.NET Mai - 3 présentations par #Rui le 05-18-2012, 11:59

- [ #SharePoint 2010][ #SQLServer 2012] AlwaysOn pour SharePoint (2/4) : Configuration (2e partie)… par Le blog de Patrick [MVP SharePoint] le 05-18-2012, 11:31

- Team Foundation Server 11: tous les trésors cachés du site d’équipe par Philess le 05-16-2012, 19:01

- [PowerShell 3] Télécharger et installer la documentation en ligne par Blog de SPBrouillet (Pierrick BROUILLET) le 05-16-2012, 17:36

- [#SharePoint 2010][#SQLServer 2012] AlwaysOn pour SharePoint (1/4) : Configuration (1ère partie)… par Le blog de Patrick [MVP SharePoint] le 05-16-2012, 12:10

- Job Day @MIC Brussels - .Net Developers on Mobile applications par Le Blog (Vert) d'Arnaud JUND le 05-15-2012, 20:26

- [SharePoint 2010] – SharePoint 2010, Windows (Server) 8 et des erreurs IIS sont dans une VM… par Blog de SPBrouillet (Pierrick BROUILLET) le 05-14-2012, 12:10