Untitled

Random thoughts about everything and nothing

How to: Adding coordination to your GAT action execution

with 2 comments

At some point during GAT action execution, one might need some sort of conditional processing. 

For instance, depending on some choices made during the gathering wizard, some actions won’t be executed.

In the example I’ll be using, the user is prompted to fill in two messages.  Next to these, two checkboxes will indicate if the corresponding message will be displayed (not much of a show-stopper there…;-)).

And the story goes

First, have a look at the recipe involved.  Your typical “HelloWorld” recipe revisited.

<Recipe Name="HelloWorldRecipe" Bound="false">     

<Caption>Say a message</Caption> 
<Description>Accepts a message as input and shows a message box with it.</Description> 
<HostData> 
  <Icon ID="1046"/> 
  <CommandBar Name="Item"/> 
</HostData> 
<Arguments> 
  <Argument Name="Message1" />     <Argument Name="Message2" /> 
  <Argument Name="MessageOption1" Type="System.Boolean"></Argument> 
  <Argument Name="MessageOption2" Type="System.Boolean"></Argument> 
</Arguments> 
<GatheringServiceData> 
  <Wizard xmlns="http://schemas.microsoft.com/pag/gax-wizards" SchemaVersion="1.0"> 
  <Pages> 
    <Page> 
      <Title>Collect message to show</Title> 
      <LinkTitle>Provide a message that will be used by the HelloWorldAction.</LinkTitle> 
      <Help>You shouldn't need a lot of help!</Help> 
      <Fields> 
        <Field ValueName="Message1" Label="Message1" /> 
        <Field ValueName="Message2" Label="Message2" /> 
        <Field ValueName="MessageOption1" Label="Show Message 1" /> 
        <Field ValueName="MessageOption2" Label="Show Message 2" /> 
      </Fields> 
    </Page> 
  </Pages> 
  </Wizard> 
</GatheringServiceData> 
<Actions CoordinatorServiceType="Demo.ExperimentalPackage.Coordinators.ConditionalMessageCoordinator,ExperimentalPackage"> 
  <Action Name="ShowHelloWorldMessage1" Type="Demo.ExperimentalPackage.Actions.HelloWorldAction, ExperimentalPackage" 
  MessageCondition="$(MessageOption1)" 
  > 
    <Input Name="HelloMessage" RecipeArgument="Message1" /> 
  </Action> 
  <Action Name="ShowHelloWorldMessage2" Type="Demo.ExperimentalPackage.Actions.HelloWorldAction, ExperimentalPackage" 
  MessageCondition="$(MessageOption2)" 
  > 
  <Input Name="HelloMessage" RecipeArgument="Message2" /> 
  </Action> 
</Actions> 
</Recipe>
Just to cover the basics…

  1. Two string arguments (Message1 and Message2) will be filled with the actual messages.
  2. Two boolean arguments (MessageOption1 and MessageOption2) will keep the associated “should-we-show-the-message” value.
  3. The previous arguments will be displayed and filled in through a standard wizard page.
  4. After the wizard the ConditionalMessageCoordinator class kicks off to provide conditional processing execution. 

[ServiceDependency(typeof(DTE))] 
[ServiceDependency(typeof(IActionExecutionService))] 
[ServiceDependency(typeof(IDictionaryService))] 
public class ConditionalMessageCoordinator : SitedComponent, IActionCoordinationService

The ConditionalMessageCoordinator class itself derives from the SitedComponent class and implement the IActionCoordinationService interface.

The ServiceDependency attributes informs the configuration manager that this class needs to instantiate DTE, IActionExecutionService and IDictionaryService instances.

private DTE _DTE; 
/// <summary> 
/// When implemented by a class, allows descendants to 
/// perform processing whenever the component is being sited. 
/// </summary> 
protected override void OnSited() 
{ 
  base.OnSited(); 
  _DTE = GetService<DTE>(true); 
}

An EnvDTE instance will be set during the OnSited() method, whereas the coordination logic is stored in the Run() method. 

/// <summary> 
/// Runs the coordination logic, using the configuration data specified in the configuration file 
/// and the the MessageOption arguments. 
/// </summary> 
/// <param name="declaredActions">Actions defined in the package configuration file for the currently executing recipe.</param> 
/// <param name="coordinationData">The configuration data used to setup the coordination.</param> 
public void Run(Dictionary<string, Microsoft.Practices.RecipeFramework.Configuration.Action> declaredActions, 
    XmlElement coordinationData) 
{ 
    IActionExecutionService execucteService = GetService<IActionExecutionService>(true); 
    IDictionaryService dictionaryService = GetService<IDictionaryService>(true); 
    ExpressionEvaluationService evaluator = new ExpressionEvaluationService();    int amountCompleted = 0;    
    try 
    { 
        foreach (Action action in declaredActions.Values) 
        { 
            amountCompleted++; 
            _DTE.StatusBar.Progress(true, "Displaying messages", amountCompleted, declaredActions.Values.Count);             bool execute = (action.AnyAttr == null || action.AnyAttr.Length == 0);    
            if (!execute) 
            { 
                foreach (XmlAttribute att in action.AnyAttr) 
                { 
                    if (att.Name.Equals("MessageCondition", StringComparison.OrdinalIgnoreCase)) 
                    { 
                        execute = (bool)evaluator.Evaluate(att.Value, new ServiceAdapterDictionary(dictionaryService)); 
                        break; 
                    } 
                } 
            }   
            if (execute) 
            { 
                execucteService.Execute(action.Name); 
            } 
        }        
    } 
    finally 
    { 
        _DTE.StatusBar.Progress(false, "", 0, 0); 
    } 
}

Here we loop through the available configured actions and check if the MessageCondition attribute is filled in.  If so, we’ll evaluate the value (I.e. MessageOption1 or MessageOption2). 

Note that it wouldn’t hurt to add some additional checks here 🙂

If the MessageCondition attribute is available AND the corresponding value was set to true, the action will be executed through the IActionExecutionService instance.

Note also, that while we loop through the available actions, we will update the StatusBar with our progress.

And to finish this off, here are the “using statements” which were used…

#region Using Statements     

using System;     

using System.Collections.Generic;     

using System.Text;     

using EnvDTE;     

using Microsoft.Practices.RecipeFramework.Services;     

using System.ComponentModel.Design;     

using Microsoft.Practices.ComponentModel;     

using System.Xml;     

using Microsoft.Practices.RecipeFramework.Configuration;     

using Microsoft.Practices.RecipeFramework.Library;     

#endregion
Advertisements

Written by Michael

November 21, 2007 at 1:26 am

2 Responses

Subscribe to comments with RSS.

  1. well, hi admin adn people nice forum indeed. how’s life? hope it’s introduce branch 😉

    cwxwwwxdfvwwxwx

    December 25, 2008 at 12:20 am

  2. Terrific work! This is the kind of info that are meant to be shared across the
    web. Disgrace on Google for now not positioning this publish upper!
    Come on over and discuss with my site . Thanks =)

    online bachelor's degree

    April 25, 2013 at 6:19 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: