If broken it is, fix it you should

Using the powers of the debugger to solve the problems of the world - and a bag of chips    by Tess Ferrandez, ASP.NET Escalation Engineer (Microsoft)

Creating a UI Module For IIS7 to watch Current Requests

Creating a UI Module For IIS7 to watch Current Requests

  • Comments 14

A while back I posted about Failed Request Tracing in IIS 7 and I mentioned the command appcmd list requests which lists the requests that are currently executing in the process...

I was playing around a bit with UI Modules in IIS7, you know the ones that show up in the Features view when you open up a site in IIS 7...

UIModules1

... and I decided to create one that displays the requests that are currently executing...

CurrentRequests

This is a step-by-step of how I created it, along with a few notes about things to think about when creating them.  The sample should be seen as a proof-of-concept and although you are welcome to use this sample I will advice that it is not tested and doesn't have much in terms of error handling etc.  I just wanted to show how I went through it so you can make your own more interesting UI modules.

1. Creating and setting up the Project in Visual Studio

2. Implementing the essential parts of a UI module

  • Module
  • ModuleProvider
  • ModulePage

3. Some notes about the Microsoft.Web.Administration and Microsoft.Web.Management namespaces

4. Assigning a custom Icon to the UI Module

5. Installing/Configuring the UI Module

Creating and setting up the Project in Visual Studio

Note: make sure that you run Visual Studio as an administrator, otherwise you will not be able to perform certain actions like GACing the dll or edit the inetsrv Administration.config file

1. Create a new class library (C#) in Visual Studio .Net 2005 or 2008, call it CurrentRequestsUI

2. Remove Class1.cs as we will not be using this

3. Add references to Microsoft.Web.Administration.dll and Microsoft.Web.Management.dll in the c:\windows\system32\inetsrv directory.  These dlls contain the classes needed to implement the Module, ModuleProvider and ModulePage as well as the classes needed to retreive the requests.

4. Sign the assembly.  UI Modules need to be added to the GAC so we need to set up signing by:

a) In the project properties on the "Signing" tab, check the box "Sign the assembly"

b) In the dropdown box for the "Choose a strong name key file" select <new>, call the file MyKey.snk, and uncheck the checkbox "Protect my key file with a password"

c)  under the "Build Events" tab in the project properties add the following to the "Post-build event command line"

 

CALL "%VS90COMNTOOLS%\vsvars32.bat" > NULL
gacutil.exe /if "$(TargetPath)"

 

this will add the assembly to the GAC when you build.  Note that on 2005 you would have to change the path to be %VS80COMNTOOLS% rather than %VS90COMNTOOLS%

5. Under the "Debug" tab in project properties set the "Start Action" to start the external program c:\windows\system32\inetsrv\InetMgr.exe so that you automatically open the IIS manager when you start debugging.

Implementing the essential parts of a UI module

The most basic UI Modules consist of three parts:

a class deriving from Microsoft.Web.Management.Client.Module where we initialize the module and register the page we want to show when users access it.  Here we have to override and implement the Initialize method which runs when the Module is initialized.

a class deriving from Microsoft.Web.Management.Server.ModuleProvider where we set up some basic information about the Module.  Here we have to override and implement the ServiceType property (which returns the type of Module Service that is associated with the module provider), the SupportsScope method (where you decide in which scope eg. Application, Site, Server etc. your module will be valid), and the GetModuleDefinition method (which returns a ModuleDefinition with some information about the module).

a class deriving from Microsoft.Web.Management.Client.Win32.ModulePage which contains the UI and most of the functionality of our module.  The ModulePage is essentially a windows forms, and you can use the same controls on a module page as you can on a windows form.

RequestModule

1. Add a new class to the project called RequestModule and make it derive from Module

2. Include the namespaces Microsoft.Web.Management.Client, Microsoft.Web.Management.Server and System.Windows.Forms

3. Override and implement the Initialize method like this...

 

using System;
using Microsoft.Web.Management.Client;
using System.Windows.Forms;
using Microsoft.Web.Management.Server;

 

namespace CurrentRequestsUI
{
    internal class RequestModule : Module
    {
        protected override void Initialize(IServiceProvider serviceProvider, Microsoft.Web.Management.Server.ModuleInfo moduleInfo)
        {
            base.Initialize(serviceProvider, moduleInfo);
            //register the Module Page - RequestPage
            IControlPanel controlPanel = (IControlPanel)GetService(typeof(IControlPanel));
            ModulePageInfo modulePageInfo = new ModulePageInfo(this, typeof(RequestPage), "Current Requests", "Displays the current requests in all worker processes");
            controlPanel.RegisterPage(modulePageInfo);
        }
    }
}

 

In this method we create a new ModulePageInfo and use it to register the RequestPage that we will create later with the controlPanel in IIS 7.  "Current Requests" will be the title of the UI Module in the features view, and when you hover over it you will see the tooltip "Displays the current requests in all worker processes". 

RequestModuleProvider

1. Add a new class to the project called RequestModuleProvider and make it derive from ModuleProvider

2. Include the namespace Microsoft.Web.Management.Server

3. Override the ServiceType property so that it returns null since we don't have an associated Module service

4. Override the SupportsScope method to return true indicating that we support all scopes, i.e. that it should be visible both at the Application, Site and Server level.  If you want it to only be visible at the Application level you can use

return (scope == ManagementScope.Application);

5. Override the GetModuleDefinition method to

return new ModuleDefinition(Name, typeof(RequestModule).AssemblyQualifiedName)

The whole class should look like this:

 

using System;
using Microsoft.Web.Management.Server;

 

namespace CurrentRequestsUI
{
    class RequestModuleProvider : ModuleProvider
    {
        public override Type ServiceType
        {
            get { return null; }
        }
        public override ModuleDefinition GetModuleDefinition(IManagementContext context)
        {
            return new ModuleDefinition(Name, typeof(RequestModule).AssemblyQualifiedName);
        }
        public override bool SupportsScope(ManagementScope scope)
        {
            return true;
        }
    }
}

 

RequestPage

1. Add a new class called RequestPage that derives from ModulePage

2. Include the namespaces System.Windows.Forms, Microsoft.Web.Administration and Microsoft.Web.Management.Client.Win32

3. To be able to work with the form in the designer you can temporarily change it so that it derives from Form, just make sure to change it later.

4. While it is temporarily deriving from Form, double click on the class file to open it in the designer and add the following controls from the toolbox

a) a DataGridView called dgRequests

b) a Button called btnRefresh

5. Change the properties of the controls so that they look approximately like the Current Requests picture at the top of this post.  Here are the values I changed

Control Property Value
RequestPage Size 734;427
dgRequests Coulmns Process ID
URL
Client IP
Time Elapsed (ms)
  Location 12;12
  Size 693;341
btnRefresh Location 630;368
  Size 75;23
  Text Refresh

6. At the top of the class definition for RequestPage add the following code to create a new ServiceManager that we can use to retrieve the requests.

 

Microsoft.Web.Administration.ServerManager manager = new ServerManager();

 

7. Add a method to the class called UpdateUI() that displays the requests that are currently executing

 

private void UpdateUI()
{
    dgRequests.Rows.Clear();

 

    foreach (WorkerProcess w3wp in manager.WorkerProcesses)
    {
        string ProcID = w3wp.ProcessId.ToString();

        foreach (Request request in w3wp.GetRequests(0))
        {
            string[] row0 = { ProcID, request.Url, request.ClientIPAddr, request.TimeElapsed.ToString() };
            dgRequests.Rows.Add(row0);
        }
    }
}

 

This method cycles through the worker processes provided by the ServiceManager, and for each one of the processes we grab the current requests and display them in the dgRequests gridview.

8. In the forms designer, double click on the Refresh button to create a btnRefresh_Click eventhandler and call UpdateUI() from this eventhandler

 

private void btnRefresh_Click(object sender, EventArgs e)
{
    UpdateUI();
}

 

Each time the refresh button is clicked we will update the grid with the current status of the requests.

9. Create a constructor for RequestPage() and make it call InitializeComponent() and UpdateUI() so that the requests datagrid is populated when we open the UI Module

 

public RequestPage()
{
    InitializeComponent();
    UpdateUI();
}

 

10. Change the class again so that it derives from ModulePage

And that is pretty much all there is to writing a simple UI Module, now we just have to build the project and configure IIS 7 to use it.

Some notes about the Microsoft.Web.Administration and Microsoft.Web.Management namespaces

The Microsoft.Web.Management namespaces is where all the classes relating to setting up the modules etc. are stored.  The Microsoft.Web.Administration namespaces on the other hand are much more interesting in my opinion since this is where we can get to all the process and administration information that we can get to with the appcmd command.

To get to most of the information, you first create a new ServerManager and from this you can get to the Sites, ApplicationPools and WorkerProcesses.  Once you have a WorkerProcess, Site or ApplicationPool you can get and set their properties as you would with appcmd.  You can also get a little more crazy and for example get all the ApplicationDomains in a workerprocess and unload a given ApplicationDomain, or get the list of application pools and start, stop or set some of the recycling options on them.  Or for that matter, why not read from the failed request tracing logs.

Assigning a custom Icon to the UI Module

If you want to get fancy you can add your own custom icon to the page module as described in this post by Vijay.

Installing/Configuring the UI Module

Before we can use the UI Module we have to register it with IIS 7 and this is a two step process...

1. Open c:\windows\system32\inetsrv\config\Administration.config in your visual studio instance

2. Under <ModuleProviders> add the following line...

 

<add name="CurrentRequestsUI" type="CurrentRequestsUI.RequestModuleProvider, CurrentRequestsUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=269f1cc1a4bf892b" />

 

3. Browse to c:\windows\assembly (the GAC), locate CurrentRequestsUI, right click to view the properties of it to get the PublicKeyToken and replace the PublicKeyToken above with your PublicKeyToken.

4. Under <modules> in Administration.config add

 

<add name="CurrentRequestsUI" />

 

Now you are all set, and if you open InetMgr.exe and look at one of your applications you should now be able to see the "Current Requests" icon in the features view...

CurrentRequestsIcon

And if you open the feature you should be able to see your current requests (provided that you have any)...

CurrentRequests

Note ::1 in the Client IP column means localhost, for any other requests you should see proper IP addresses.

If you come up with or know about some cool/useful UI Modules, feel free to link to them in the comments... There are some really good ones in the download section of http://www.iis.net if you are interested as well...

Laters,

Tess

PS! I have attached my sample project to this post.

Attachment: CurrentRequestsUI.zip
  • Thanks you, now i can look at my server in real time to see what is happening,

  • Can it be used with IIS 6.0 or need to have IIS 7?

  • Great stuff.  

    To answer K, it will not work in IIS 6.

    My question is how is this different that the list currently executing requests feature in the UI?

    -b

  • The answer is, its not different:), I just didnt know about this feature.  Thank you very much for pointing it out

    For the rest of you, this is under the "worker processes" feature, accessible from the server node.

  • Link Listing - August 30, 2008

  • My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. Busy week this week so this is a quick all at once version. Greg Duncan posted a link to release announcement for XamlPadX 4.0 . Sasha

  • Hi. I'm a student from Spain and I'm doing my  Final-Year Project about IIS7 .  I am writing to you to tell you about my problem with this.  I have created and installed a new module for this server, and it works correctly, but the proccesses that arrive at the server, are not being listed and I don't know why.

    This module have been installed by means of  writing these two lines in the file "administration.config".

    <add name="CurrentRequestsUI" type="CurrentRequestsUI.RequestModuleProvider, CurrentRequestsUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=269f1cc1a4bf892b" />

    <add name="CurrentRequestsUI" />

    Could you help me with this?  Do I need to do something more to install the module?

    Kind regards and thanks in advance

  • if i recall correctly the requests only appear if you are looking in the view for the virtual directory that the requests are comming in to...

  • Hello looks good, can you help me get the Microsoft.Web.Management.dll?

    Tnx

    Eitan

  • If you have IIS 7 installed you will have it in the in the c:\windows\system32\inetsrv directory.  If not, the article doesn't apply since this only works in IIS7

  • Thank you for posting the instructions, they were very helpful.  I am having one issue though.  I am currently having an issue using the command within the Build Events:

    CALL "%VS100COMNTOOLS%\vsvars32.bat" > NULL

    gacutil.exe /if "$(TargetPath)"      

    I changed from VS90 to VS100 because I am using Visual Studio 2010 Ultimate.  When I go to C:/Windows/assembly  (the GAC) CurrentRequestsUI is not listed.  I'm currently using IIS 7.5 though I believe that should not effect how this assembly is displayed.      

  • I forgot to mention that my Build output displays " Assembly successfully added to the cache"

  • Sorry for the many comments, but I found out that because I set the Target framework to .NET Framework 4 it placed the assembly into C:\Windows\Microsoft.NET\assembly\GAC_MSIL rather then C:\Windows\assembly

  • I have IIS 7.5 and am using Visual Studio 2010 (Windows 7 64 bit).  I cannot seem to get any Custom UI Modules to show up within the IIS Manager.  The assembly is listed in the GAC and I changed the publicKeyToken within the administration.config.  I also tried to use your source and that did not work either.  I checked the Event Viewer to see if there were any errors, but there are none that have to do with IIS (other than me running iisreset). Any advice to get the UI Module to show up within IIS Manager?

Page 1 of 1 (14 items)
Leave a Comment
  • Please add 3 and 2 and type the answer here:
  • Post