Share via


Writing Action Classes

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies.
This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

For an action to be included in a recipe, it has to be defined in the Guidance Package configuration file. The following XML configuration code example shows how actions are defined.

<Actions>
<Action Name="GenerateMainClass" Type="Microsoft.Practices.RecipeFramework.VisualStudio.Library.Templates.TextTemplateAction, Microsoft.Practices.RecipeFramework.VisualStudio.Library"
Template="Text\Program.cs.t4">
<Input Name="Hello" RecipeArgument="HelloMessage" />
<Input Name="ClassName" RecipeArgument="ClassName"/>
<Input Name="TargetNamespace" RecipeArgument="TargetNamespace"/>
<Output Name="Content" />
</Action>
<Action Name="AddMainClass" Type="Microsoft.Practices.RecipeFramework.Library.Actions.AddItemFromStringAction, Microsoft.Practices.RecipeFramework.Library"
Open="true">
<!--Shows how to specify a property as a fixed value in config-->
<Input Name="Content" ActionOutput="GenerateMainClass.Content" />
<Input Name="TargetFileName" RecipeArgument="TargetFile" />
<Input Name="Project" RecipeArgument="CurrentProject" />
</Action>
</Actions>

Each action has a name, type attributes, zero or more input parameters, and zero or more output parameters. Input parameters are defined explicitly by using the <Input> element, or they can be included as custom attributes defined in the Action element. These custom attributes can be of any type, but they are usually strings. The Recipe Framework will attempt to convert the value specified to the property type. An example of this is the Template attribute in the GenerateMainClass action shown in the preceding code example.

An input element can get values from a recipe argument or from the output of a previous action defined in the same recipe. An action can produce one or more outputs that can be used as inputs for later actions called by the recipe. All inputs and outputs defined in the configuration file must correspond to public properties with input and output attributes in the Action class defined by the type.

Action classes can be derived from the following sources:

  • IAction interface. This is most commonly used for simple actions.
  • Action base class. This class is used when the Guidance Package author needs to site the Action as a component within the recipe container. This is done to access the services exposed by the parent (for example, the DTE object).
  • ConfigurableAction base class. This class is used to develop configurable actions in which the <Action> element in the Guidance Package configuration file can contain a key/value pair as attributes, in addition to <Input> and <Output> elements. In this case, the Recipe Framework creates an instance of the Action class specified in the Type attribute, and for each additional attribute that the Recipe Framework finds in the statement, it sets the property of that name to be the value specified. This requires the action to be written to include an input property that matches the name of the attribute in the <Action> element. If no such property is found, the attribute is ignored.

Note

Note: You can access custom attributes defined in the Action element either by defining the public property, or through the configuration service by retrieving the action full configuration information.

The following code example shows the code of the class AddItemFromStringAction.cs used in the AddMainClass action defined in the preceding code. Note that each input defined in the configuration file corresponds to a property. Also notice that one input (Content) corresponds to the output of the GenerateMainClass action, and that one input (Open) corresponds to the key/value pair specified in the configuration file.

using System; 
using System.Text; 
using Microsoft.Practices.ComponentModel; 
using EnvDTE; 
using System.Diagnostics; 
using System.IO; 
        
namespace Microsoft.Practices.RecipeFramework.Library.Actions 
{ 
  /// <summary> 
  /// The action creates a project item from a string passed to the action 
  /// in the Content input property. The other two input properties of the 
  /// action are (a) targetFileName - provides the name of the item file  
  /// and (b) Project - identifies the project where the item is created.  
  /// The action is designed to follow the T4Action.  
  /// </summary> 
  [ServiceDependency(typeof(DTE))] 
  public class AddItemFromStringAction : ConfigurableAction 
  { 
     #region Input Properties 
          
  private string content; 
  /// <summary> 
  /// The string with the content of the item. In most cases it is a class 
  /// generated using the T4 engine. 
  /// </summary> 
  [Input(true)] 
  public string Content 
  { 
    get { return content; } 
    set { content = value; } 
  } 
          
  private string targetFileName; 
  /// <summary> 
  /// Name of the file where the item is to be stored. 
  /// </summary> 
  [Input(true)] 
  public string TargetFileName 
  { 
    get { return targetFileName; } 
    set { targetFileName = value; } 
  } 
          
  private Project project; 
  /// <summary> 
  /// Project where the item it to be inserted. 
  /// </summary> 
  [Input(true)] 
  public Project Project 
  { 
    get { return project; } 
    set { project = value; } 
  } 
          
  private bool open = true; 
  /// <summary> 
  /// A flag to indicate if the newly created item should be shown 
  /// in a window. 
  /// </summary> 
  [Input] 
  public bool Open 
  { 
    get { return open; } 
    set { open = value; } 
  }   
    
     #endregion Input Properties 
    
     #region Output Properties 
    
  private EnvDTE.ProjectItem projectItem; 
  /// <summary> 
  /// A property that can be used to pass the created item to 
  /// a following action. 
  /// </summary> 
  [Output] 
  public EnvDTE.ProjectItem ProjectItem 
  { 
    get { return projectItem; } 
    set { projectItem = value; } 
  } 
    
     #endregion Output Properties 

  /// <summary> 
  /// The method that creates a new item from the input string. 
  /// </summary> 
  public override void Execute() 
  { 
    DTE vs = GetService<DTE>(true); 
    string tempfile = Path.GetTempFileName(); 
    using (StreamWriter sw = new StreamWriter(tempfile, false)) 
    { 
      sw.WriteLine(content); 
    } 
    
    projectItem = project.ProjectItems.AddFromTemplate(tempfile, 
    targetFileName); 
    if (open) 
    { 
        Window wnd = projectItem.Open(Constants.vsViewKindPrimary); 
        wnd.Visible = true; 
        wnd.Activate(); 
    } 
    File.Delete(tempfile); 
  } 
    
  /// <summary> 
  /// Undoes the creation of the item, then deletes the item 
  /// </summary> 
  public override void Undo() 
  { 
    if (projectItem != null) 
    { 
        projectItem.Delete(); 
    } 
  }
}

Note

Note: In some cases, you might define a recipe that does not call any actions (for example, a recipe that collects parameters for a template).

See also

Developing Actions | Raising Exceptions | Obtaining and Using Host Services