IIS7 Managed Extensibility: Client UI Integration


In the preceding posts we implemented the HttpModule, the configuration section and the server module including the server service – the last part of the integration story is the UI.

UI integration consists of three parts:

  • UI elements
  • The service proxy that is used by the UI to talk to the server service
  • A module that registers the UI with the IIS GUI

Let’s start with the proxy. The proxy provides an interface for the UI to read and write configuration. The proxy then marshals the requests to the IIS management server who in turn does the real work. You call the server methods you implemented in the service via the ModuleServiceProxy base class. The proxy for our ServerHeader feature looks like this:

class ServerHeaderModuleProxy : ModuleServiceProxy

{

    public PropertyBag GetConfiguration()

    {

        return (PropertyBag)base.Invoke(“GetConfiguration”, new object[0]);

    }

 

    public void SetConfiguration(bool enabled, string headerValue)

    {

        base.Invoke(“SetConfiguration”, new object[] { enabled, headerValue });

    }

}

For the UI elements you have several choices of how to integrate with the GUI. If you inspect the several feature settings pages you can spot several general types of UIs – dialogs, lists, property grids and features with sub-features (e.g. authentication). Depending on which type of UI you want, you derive from one of these base classes:

          ModulePage
offers only the most basic services, no standard UI support

          ModuleDialogPage
similar to a dialog, provides apply, cancel and refresh functionality, e.g. Session State, Directory Browsing

          ModulePropertiesPage
uses a property grid, e.g. Compilation, Pages & Controls

          ModuleListPage
uses a list view, useful for collections, e.g. Connection Strings, Handlers

I chose to use a ModuleDialogPage. This gives you a dialog that you can populate with standard WinForms controls. By implementing some of the base class methods you get nice support for the standard Apply/Cancel/Refresh UI elements in the IIS GUI. The complete class is a lot of code (mostly related to standard UI stuff), so I will only show you the important parts of it (the complete solution can be downloaded when the series is complete).

The easiest way is to start with a WinForms Form so that you can use the designer to layout your dialog. Afterwards copy the control declarations and InitializeComponent() to your ModuleDialogPage derived class. Furthermore you need access to the service proxy to issue calls to the configuration service. So your class would look similar to this:

class ServerHeaderPage : ModuleDialogPage

{

    private ServerHeaderModuleProxy _serviceProxy;

 

    // UI

    private System.Windows.Forms.CheckBox _chkEnabled;

    private System.Windows.Forms.Label _lblHeaderValue;

    private System.Windows.Forms.ComboBox _cmbHeaderValue;

 

    // state

    bool _enabled;

    string _headerValue;

 

    public ServerHeaderPage()

    {

        InitializeComponent();

    }

 

    private ServerHeaderModuleProxy ServiceProxy

    {

        get

        {

            if (this._serviceProxy == null)

            {

                this._serviceProxy = (ServerHeaderModuleProxy)

                    base.CreateProxy(typeof(ServerHeaderModuleProxy));

            }

            return this._serviceProxy;

        }

    }
}

Next you need two methods to read and write configuration – this is as simple as calling the corresponding methods on your proxy class, e.g.

private void ReadConfig()

{

    PropertyBag bag = ServiceProxy.GetConfiguration();

 

    _enabled = _chkEnabled.Checked = (bool)bag[0];

    _headerValue = _cmbHeaderValue.Text = (string)bag[1];

}

 

private void WriteConfig()

{

    ServiceProxy.SetConfiguration(_chkEnabled.Checked, _cmbHeaderValue.Text);

}

The base class also offers support for asynchronous operations. This helps keeping the UI responsive when you exchange more complex data or have a slow connection. Remodeling the WriteConfig() method to async looks like this:

private void WriteConfig()

{

    base.StartAsyncTask(“writing configuration…”,

        OnWriteConfigDoWork,

        OnWriteConfigCompleted);

}

 

void OnWriteConfigDoWork(object sender, DoWorkEventArgs e)

{

    ServiceProxy.SetConfiguration(_chkEnabled.Checked, _cmbHeaderValue.Text);

}

 

void OnWriteConfigCompleted(object sender, RunWorkerCompletedEventArgs e)

{

    if (e.Error != null)

    {

        this.DisplayErrorMessage(e.Error, Resource.ResourceManager);

    }

}

To help the GUI to enable/disable the Apply/Reset/Cancel labels you also have to implement methods that signal the host that settings have changed. The methods are called OnActivated/HasChanges/CanApplyChanges and ApplyChanges/CancelChanges. This mainly boils down to keeping two versions of the configuration data – the original and the read one – and to signal the GUI if changes have been done. You should also hook up control change event handlers to the UI controls to update the status in realtime.

The last step is to register the UI with the IIS manager. This is done in a Module derived class, and this is btw the type you specified in ModuleProvider.GetModuleDefinition(). The main job of this class is to get a reference to the IIS manager control panel and to register the UI in one (or more) of the available categories.

class ServerHeaderModule : Module

{

    protected override void Initialize(

      IServiceProvider serviceProvider, ModuleInfo moduleInfo)

    {

        base.Initialize(serviceProvider, moduleInfo);

       

        // get access to the control panel

        IControlPanel panel = (IControlPanel)

            serviceProvider.GetService(typeof(IControlPanel));

 

        // create a module description (name, icon, description etc)

        ModulePageInfo info = new ModulePageInfo(

            this,

            typeof(ServerHeaderPage),

            “ServerHeader”,

            “Allows to change the Server Response Header”,

            Resource.ServerHeaderIcon,

            Resource.ServerHeaderIcon);

       

        // register in the security category

        panel.RegisterPage(ControlPanelCategoryInfo.Security, info);

       

        // register in the IIS category

        panel.RegisterPage(ControlPanelCategoryInfo.Iis, info);

    }

 

    public override Version MinimumFrameworkVersion

    {

        get

        {

            return Module.FxVersion20;

        }

    }

}

The assembly implementing these classes needs to be registered in the GAC.

So that’s it – we now have a full blown IIS7 feature. The code that is needed is mostly boilerplate and I hope this walkthrough is helpful when building your own IIS features. In the next post I will talk about the general solution infrastructure, how many assemblies you should use and which class goes where.

 

This entry was posted in Uncategorized. Bookmark the permalink.

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