Visual Studio Add-in: Recycle all IIS application pools on build done

This is my 2nd visual studio-in. What it does is to recycle all application pools in IIS to make sure GAC is refreshed with newly built dlls.

There were a few things to tweak. This is an add-in for visual studio 2003, so it may not be suitable for vs 2005 or 2008 in some details.

  1. connectMode == ext_ConnectMode.ext_cm_Startup
    When the add-in wizard creates the skeleton code, ext_ConnectMode.ext_cm_UISetup is used. UISetup is only once when you set up the add-in, so the add-in is not loaded when you run this in debug-mode. Change it to …_Startup.
  2. _application.Solution.Projects
    In order to get projects I first tried ActiveSolutionProjects which worked perfectly fine in vs macro, but it did not work at all in add-in. ActiveSolutionProjects returned null if you build a solution. It returned only one project if you build a specific project. I used Solution.Projects and it worked as it is expected.

This is the code for recycling application pools.

private void RecycleAllApplicationPools()
{
DirectoryEntry appPools = new DirectoryEntry("IIS://localhost/W3SVC/AppPools");
_outputWindowPane.OutputString("-------------------------------------------\n");
_outputWindowPane.OutputString("Start recycling application pools\n");
foreach (DirectoryEntry appPool in appPools.Children)
{
appPool.Invoke("Recycle", null);
_outputWindowPane.OutputString(".");
}
_outputWindowPane.OutputString("\nRecycling is complete.\n");
}

The following is the full code

using System.DirectoryServices;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace ExtVS2003
{
using System;
using Microsoft.Office.Core;
using Extensibility;
using System.Runtime.InteropServices;
using EnvDTE;

#region Read me for Add-in installation and setup information.
// When run, the Add-in wizard prepared the registry for the Add-in.
// At a later time, if the Add-in becomes unavailable for reasons such as:
//   1) You moved this project to a computer other than which is was originally created on.
//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
//   3) Registry corruption.
// you will need to re-register the Add-in by building the MyAddin21Setup project
// by right clicking the project in the Solution Explorer, then choosing install.
#endregion

/// <summary>
///   The object for implementing an Add-in.
/// </summary>
/// <seealso class='IDTExtensibility2' />
[GuidAttribute("594C22F4-C9ED-40B1-9CC7-2D095D68AD97"), ProgId("ExtVS2003.Connect")]
public class Connect : Object, IDTExtensibility2, IDTCommandTarget
{
const string OUTPUTWINDOWGUID = "{1BD8A850-02D1-11D1-BEE7-00A0C913D1F8}";
private _DTE _application;
private AddIn addInInstance;
private Command _command;
private OutputWindowPane _outputWindowPane;
private BuildEvents _buildEvents;

/// <summary>
///        Implements the constructor for the Add-in object.
///        Place your initialization code within this method.
/// </summary>
public Connect()
{
}

/// <summary>
///      Implements the OnConnection method of the IDTExtensibility2 interface.
///      Receives notification that the Add-in is being loaded.
/// </summary>
///
<param term='application'>
///      Root object of the host application.
/// </param>
///
<param term='connectMode'>
///      Describes how the Add-in is being loaded.
/// </param>
///
<param term='addInInst'>
///      Object representing this Add-in.
/// </param>
/// <seealso class='IDTExtensibility2' />
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
int bitmapNo = 59;
_application = (_DTE)application;
addInInstance = (AddIn)addInInst;

SetBuildEvent();
SetOutputWindowPane();

if (connectMode == ext_ConnectMode.ext_cm_Startup)
{
object []contextGUIDS = new object[] { };
Commands commands = _application.Commands;
_CommandBars commandBars = _application.CommandBars;

// When run, the Add-in wizard prepared the registry for the Add-in.
// At a later time, the Add-in or its commands may become unavailable for reasons such as:
//   1) You moved this project to a computer other than which is was originally created on.
//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
//   3) You add new commands or modify commands already defined.
// You will need to re-register the Add-in by building the ExtVS2003Setup project,
// right-clicking the project in the Solution Explorer, and then choosing install.
// Alternatively, you could execute the ReCreateCommands.reg file the Add-in Wizard generated in
// the project directory, or run 'devenv /setup' from a command prompt.
try
{
_command = commands.AddNamedCommand(addInInstance, "ExtVS2003", "Recycle IIS App pools", "Reset IIS", true, bitmapNo,
ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled);
CommandBar commandBar = commandBars["Tools"];
CommandBarControl commandBarControl = _command.AddControl(commandBar, 1);
}
catch(Exception ex)
{
MessageBox.Show("Cant't place toolbutton, error: " + ex.Message, "error", MessageBoxButtons.OK);
}
}

}

private void SetOutputWindowPane()
{
OutputWindow outputWindow = (OutputWindow)_application.Windows.Item(Constants.vsWindowKindOutput).Object;
_outputWindowPane = outputWindow.OutputWindowPanes.Item(OUTPUTWINDOWGUID);
}

private void SetBuildEvent()
{
_buildEvents = _application.Events.BuildEvents;
_buildEvents.OnBuildDone += new _dispBuildEvents_OnBuildDoneEventHandler(_buildEvents_OnBuildDone);
}

/// <summary>
///     Implements the OnDisconnection method of the IDTExtensibility2 interface.
///     Receives notification that the Add-in is being unloaded.
/// </summary>
///
<param term='disconnectMode'>
///      Describes how the Add-in is being unloaded.
/// </param>
///
<param term='custom'>
///      Array of parameters that are host application specific.
/// </param>
/// <seealso class='IDTExtensibility2' />
public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
{
try
{
_command.Delete();
}
catch (Exception ex)
{
MessageBox.Show("Error in Disconnect: " + ex.Message, "Error", MessageBoxButtons.OK);
}

}

/// <summary>
///      Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
///      Receives notification that the collection of Add-ins has changed.
/// </summary>
///
<param term='custom'>
///      Array of parameters that are host application specific.
/// </param>
/// <seealso class='IDTExtensibility2' />
public void OnAddInsUpdate(ref Array custom)
{
}

/// <summary>
///      Implements the OnStartupComplete method of the IDTExtensibility2 interface.
///      Receives notification that the host application has completed loading.
/// </summary>
///
<param term='custom'>
///      Array of parameters that are host application specific.
/// </param>
/// <seealso class='IDTExtensibility2' />
public void OnStartupComplete(ref Array custom)
{
}

/// <summary>
///      Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
///      Receives notification that the host application is being unloaded.
/// </summary>
///
<param term='custom'>
///      Array of parameters that are host application specific.
/// </param>
/// <seealso class='IDTExtensibility2' />
public void OnBeginShutdown(ref Array custom)
{
}

/// <summary>
///      Implements the QueryStatus method of the IDTCommandTarget interface.
///      This is called when the command's availability is updated
/// </summary>
///
<param term='commandName'>
///        The name of the command to determine state for.
/// </param>
///
<param term='neededText'>
///        Text that is needed for the command.
/// </param>
///
<param term='status'>
///        The state of the command in the user interface.
/// </param>
///
<param term='commandText'>
///        Text requested by the neededText parameter.
/// </param>
/// <seealso class='Exec' />
public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
{
if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
{
if(commandName == "ExtVS2003.Connect.ExtVS2003")
{
status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled;
}
}
}

/// <summary>
///      Implements the Exec method of the IDTCommandTarget interface.
///      This is called when the command is invoked.
/// </summary>
///
<param term='commandName'>
///        The name of the command to execute.
/// </param>
///
<param term='executeOption'>
///        Describes how the command should be run.
/// </param>
///
<param term='varIn'>
///        Parameters passed from the caller to the command handler.
/// </param>
///
<param term='varOut'>
///        Parameters passed from the command handler to the caller.
/// </param>
///
<param term='handled'>
///        Informs the caller if the command was handled or not.
/// </param>
/// <seealso class='Exec' />
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if(commandName == "ExtVS2003.Connect.ExtVS2003")
{
RecycleAllApplicationPools();
handled = true;
return;
}
}
}

private void _buildEvents_OnBuildDone(vsBuildScope Scope, vsBuildAction Action)
{
if (IsBuildingGACProject())
{
RecycleAllApplicationPools();
}
}

private bool IsBuildingGACProject()
{
Regex GACRegex = new Regex("PJB.UI|PJB.Business", RegexOptions.IgnoreCase);
Projects projects = _application.Solution.Projects;

foreach (Project project in projects)
{
if (GACRegex.Match(project.Name).Success)
{
return true;
}
}
return false;
}

private void RecycleAllApplicationPools()
{
DirectoryEntry appPools = new DirectoryEntry("IIS://localhost/W3SVC/AppPools");
_outputWindowPane.OutputString("-------------------------------------------\n");
_outputWindowPane.OutputString("Start recycling application pools\n");
foreach (DirectoryEntry appPool in appPools.Children)
{
appPool.Invoke("Recycle", null);
_outputWindowPane.OutputString(".");
}
_outputWindowPane.OutputString("\nRecycling is complete.\n");
}
}
}

Visual Studio Add-in: Recycle all IIS application pools on build done

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