Training
Module
Validate Azure resources by using the ARM Template Test Toolkit - Training
Use the ARM Template Test Toolkit and apply it on your Azure Resource Manager templates to ensure the templates follow good practices before deployment.
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
This walkthrough will guide you through how to develop a rule template for URL Rewrite module. You will create a rule template that can be used to generate a rewrite rule that enforces usage of a particular domain for a web site.
Canonical Domain Name rule template can be used to simplify the creation of a rewrite rule that is used to enforce canonical domain name for a web site. Users can choose this template from the "Add rule(s)" dialog:
Then users can provide a domain name that they want to use:
After that the template will generate a rewrite rule as below:
Before proceeding with this walkthrough it is recommended to familiarize yourself with the basic concepts of IIS Manager extensibility by completing the tasks in the article "How to create a simple IIS Manager module".
The complete Visual Studio 2008 project for this rule template is available for download here.
To support remote management, all IIS Manager UI components are implemented by following a certain design pattern. A module's implementation consists of these parts:
All the user interface specific implementation resides on a client side, which may be a remote client machine. All functionality that actually makes changes to the IIS configuration is implemented as a service on a server side, thus ensuring that it has access to all server configuration API's. Client-side controls interact with the service via service proxy.
It is a good practice to implement rule templates by following the same pattern, so that the templates work when users create rules via IIS Remote Manager. The following sections describe how to implement rule template service and client.
First, you will need to create a module, is the main entry point in the client for all extensibility objects. To do that:
using System;
using Microsoft.Web.Management.Server;
using Microsoft.Web.Management.Client;
using Microsoft.Web.Management.Iis.Rewrite;
namespace CanonicalDomainTemplate
{
internal class CanonicalDomainModule: Module
{
protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo)
{
base.Initialize(serviceProvider, moduleInfo);
IExtensibilityManager extensibilityManager = (IExtensibilityManager)GetService(typeof(IExtensibilityManager));
extensibilityManager.RegisterExtension(typeof(RewriteTemplateFeature), new CanonicalDomainFeature(this));
}
}
}
This code initializes a new instance of a class CanonicalDomainFeature, which will implement the rule template functionality. The instance of this class is used to register an extension of type RewriteTemplateFeature, which is a type from which all rule templates are derived.
When defining a class that implements rule template you will need to derive this class from RewriteTemplateFeature class. It is a parent class that is used by all URL Rewrite rule templates.
using System;
using Microsoft.Web.Management.Client;
using Microsoft.Web.Management.Iis.Rewrite;
using System.Windows.Forms;
using System.Collections;
namespace CanonicalDomainTemplate
{
class CanonicalDomainFeature: RewriteTemplateFeature
{
private const string FeatureTitle = "Canonical Domain Name";
private const string FeatureDescription = "Creates a rewrite rule for enforcing canonical domain name for your web site";
public CanonicalDomainFeature(Module module)
: base(module, FeatureTitle, FeatureDescription, Resource.domain_icon16, Resource.domain_icon32)
{
}
public override void Run()
{
CanonicalDomainModuleServiceProxy serviceProxy =
(CanonicalDomainModuleServiceProxy)Connection.CreateProxy(this.Module,
typeof(CanonicalDomainModuleServiceProxy));
CanonicalDomainForm form = new CanonicalDomainForm(serviceProxy);
form.StartPosition = FormStartPosition.CenterParent;
if (form.ShowDialog() == DialogResult.OK)
{
Navigate(GetPageType("Rewrite"));
}
}
/// <summary>
/// Returns the main page for the specified module
/// </summary>
private Type GetPageType(string moduleName)
{
IControlPanel controlPanel = (IControlPanel)GetService(typeof(IControlPanel));
Module module = (Module)Connection.Modules[moduleName];
if (module != null)
{
ICollection pageInfos = controlPanel.GetPages(module);
foreach (ModulePageInfo pageInfo in pageInfos)
{
if (pageInfo.IsEnabled && !pageInfo.PageType.IsAssignableFrom(typeof(IModuleChildPage)))
{
return pageInfo.PageType;
}
}
}
return null;
}
}
}
This code does the following:
For a remote client to call a service it is necessary to provide a service proxy. To do that, add another file to your project called CanonicalDomainModuleServiceProxy.cs and change the code in it to look as below:
using System;
using Microsoft.Web.Management.Client;
using Microsoft.Web.Management.Server;
namespace CanonicalDomainTemplate
{
class CanonicalDomainModuleServiceProxy : ModuleServiceProxy
{
public void GenerateRule(string domainName)
{
Invoke("GenerateRule", domainName);
}
}
}
The actual service implementation for GenerateRule method will be added later.
Now, that all the IIS Manager client-side plumbing code is done, the remaining part is to design and implement the actual user interface for the rule template. To do that follow these steps:
Select the option Add New Item in the project menu. In the Add New Item dialog, select "Windows Form" and type in the name CanonicalDomainForm.cs:
Use Visual Studio windows forms designer to arrange controls on the form:
Switch to the code view and add the private member of the class that will contain a reference to a service proxy:
private CanonicalDomainModuleServiceProxy _serviceProxy;
In the same class modify the constructor code as below:
public CanonicalDomainForm(CanonicalDomainModuleServiceProxy serviceProxy)
{
_serviceProxy = serviceProxy;
InitializeComponent();
}
In the same class add the helper function that will call the service proxy to generate the rewrite rule with the parameters specified by a user:
private void GenerateRule(string domainName)
{
try
{
_serviceProxy.GenerateRule(domainName);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Add an event handler for when OK button is clicked. In the event handler code invoke the helper function GenerateRule, passing the content of the TextBox control as a parameter.
private void OnOkButtonClick(object sender, EventArgs e)
{
GenerateRule(_DomainTextBox.Text);
}
To implement a service you will need to create a module provider, which is an entry point for registration of modules in IIS Manager. To do that:
Create and configure another Visual Studio project by following steps described in tasks 1 and 2 from the article "How to create a simple IIS Manager module". Name the project as "CanonicalDomainTemplate".
Select Add References from the Project menu and add references to the following assemblies located in \Windows\System32\inetsrv:
Select the option Add New Item from the Project menu. In the Add New Item dialog box, select the Class template and type CanonicalDomainModuleProvider.cs as the name for the file.
Change the code so that it looks as below (do not forget to replace the PublicKeyToken with the public key token of the CanonicalDomainTemplate.Client.dll assembly)
namespace CanonicalDomainTemplate
{
internal sealed class CanonicalDomainModuleProvider : ModuleProvider
{
public override string FriendlyName
{
get
{
return Resource.ModuleFriendlyName;
}
}
public override Type ServiceType
{
get {
return typeof(CanonicalDomainModuleService);
}
}
public override ModuleDefinition GetModuleDefinition(IManagementContext context)
{
if (context != null && string.Compare(context.ClientUserInterfaceTechnology,
"System.Windows.Forms.Control", StringComparison.OrdinalIgnoreCase) != 0)
{
return null;
}
return new ModuleDefinition(Name, "CanonicalDomainTemplate.CanonicalDomainModule,
CanonicalDomainTemplate.Client,Version=1.0.0.0,Culture=neutral,
PublicKeyToken={your key}");
}
public override bool SupportsScope(ManagementScope scope)
{
return true;
}
}
}
This code creates a ModuleProvider that supports all types of connections (Server, Site and Application) and registers a client-side module called CanonicalDomainModule. Also it registers the type of the module service CanonicalDomainModuleService that is used on a server-side to generate rewrite rules.
To create a service for the rule template follow these steps:
using System;
using System.Collections.Generic;
using Microsoft.Web.Management.Server;
using Microsoft.Web.Administration;
namespace CanonicalDomainTemplate
{
class CanonicalDomainModuleService : ModuleService
{
[ModuleServiceMethod]
public void GenerateRule(string domainName)
{
string sectionPath = "system.webServer/rewrite/rules";
if (ManagementUnit.ConfigurationPath.PathType == ConfigurationPathType.Server)
{
sectionPath = "system.webServer/rewrite/globalRules";
}
ConfigurationSection rulesSection = ManagementUnit.Configuration.GetSection(sectionPath);
ConfigurationElementCollection rulesCollection = rulesSection.GetCollection();
ConfigurationElement ruleElement = rulesCollection.CreateElement("rule");
ruleElement["name"] = @"Canonical domain for " + domainName;
ruleElement["patternSyntax"] = @"Wildcard";
ruleElement["stopProcessing"] = true;
ConfigurationElement matchElement = ruleElement.GetChildElement("match");
matchElement["url"] = @"*";
ConfigurationElement conditionsElement = ruleElement.GetChildElement("conditions");
ConfigurationElementCollection conditionsCollection = conditionsElement.GetCollection();
ConfigurationElement addElement = conditionsCollection.CreateElement("add");
addElement["input"] = @"{HTTP_HOST}";
addElement["negate"] = true;
addElement["pattern"] = domainName;
conditionsCollection.Add(addElement);
ConfigurationElement actionElement = ruleElement.GetChildElement("action");
actionElement["type"] = @"Redirect";
actionElement["url"] = @"http://" + domainName + @"/{R:1}";
actionElement["appendQueryString"] = true;
rulesCollection.Add(ruleElement);
ManagementUnit.Update();
}
}
}
This code creates a rule for redirection to canonical domain.
Tip
to quickly get the code for generating rewrite rules use the Configuration Editor for IIS 7.0 and above, which is included in Administration Pack for IIS. Refer to this article for more information on how to generate code for creation of rewrite rules.
Once the rule template project has been successfully compiled and placed into the Global Assembly Cache, you will need to register it with IIS Manager by adding its information to administration.config file.
Open administration.config file located at \Windows\System32\inetsrv\config and add the following line to the <moduleProviders> section. Make sure to replace the PublicKeyToken:
<add name="CanonicalDomainName" type="CanonicalDomainTemplate.CanonicalDomainModuleProvider, CanonicalDomainTemplate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e4e6d0bc8fe7a06a" />
Note
By adding it only to the list of moduleProviders you are registering the module only for Server connections. If you want this module to be enabled for Site connections as well as application connections, add it to the following list:
<location path=".">
<module>
<add name="CanonicalDomainName" />
</module>
</location>
After these steps are done, you should be able to see the "Canonical Domain Name" rule template in the Add Rule(s) dialog of URL Rewrite module.
Training
Module
Validate Azure resources by using the ARM Template Test Toolkit - Training
Use the ARM Template Test Toolkit and apply it on your Azure Resource Manager templates to ensure the templates follow good practices before deployment.