为 URL 重写模块开发规则模板

作者:Ruslan Yakushev

本演练将指导你开发 URL 重写模块的规则模板。 你将创建一个规则模板,该模板可用于生成重写规则,该规则会强制使用网站的特定域。

模板概述

规范域名规则模板可用于简化重写规则的创建,该规则用于强制执行网站的规范域名。 用户可以从“添加规则”对话框中选择此模板:

Screenshot of Add rule(s) dialog with

然后,用户可以提供要使用的域名:

Screenshot of

之后,模板将生成重写规则,如下所示:

Screenshot of Edit Rule pane with sections for domain Name, URL, Conditions, and Action.

先决条件

在继续执行本演练之前,建议通过完成文章“如何创建简单的 IIS Manager 模块”中的任务来熟悉 IIS Manager 扩展性的基本概念。

规则模板的 VS2008 项目

此规则模板的完整 Visual Studio 2008 项目可从此处下载。

实现规则模板

为了支持远程管理,所有 IIS Manager UI 组件都遵循特定的设计模式来实现。 模块的实现包含以下部分:

  • 客户端用户界面和服务代理
  • 用于管理 IIS 配置的服务器端服务

所有特定于用户界面的实现都驻留在客户端上,可能是远程客户端计算机。 实际更改 IIS 配置的所有功能都作为服务在服务器端实现,从而确保它有权访问所有服务器配置 API。 客户端控件通过服务代理与服务交互。

一种良好做法是遵循相同的模式实现规则模板,以便在用户通过 IIS 远程管理器创建规则时,模板有效。 以下部分介绍如何实现规则模板服务和客户端。

实现客户端用户界面

创建模块

首先,需要创建模块,这是客户端中所有扩展性对象的主要入口点。 若要执行该操作:

  1. 按照“如何创建简单的 IIS Manager 模块”一文中的任务 1 和 2 中所述的步骤创建和配置 Visual Studio 项目。 将项目命名为“CanonicalDomainTemplateClient”。
  2. 项目菜单中选择添加引用 ,并添加对位于 \Windows\System32\inetsrv 中的Microsoft.Web.Management.dll 的引用:
  3. 再次选择 添加引用 并添加对位于 \Program Files\Reference Assemblies\Microsoft\IIS 中的Microsoft.Web.Management.Rewrite.Client.dll的引用。
  4. 再次选择“添加引用”并添加对 System.Windows.Forms.dll 的引用
  5. 从“项目”菜单中选择“添加新项”选项。 在“添加新项”对话框中,选择“”模板,然后键入 CanonicalDomainModule.cs 作为文件的名称。
  6. 更改代码,使其如下所示:
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)); 
        }
    }
}

此代码初始化类的新实例 CanonicalDomainFeature,这将实现规则模板功能。 此类的实例用于注册类型为 RewriteTemplateFeature 的扩展,这是从中派生所有规则模板的类型。

创建重写模板功能

定义实现规则模板的类时,需要从 RewriteTemplateFeature 类派生此类。 它是所有 URL 重写规则模板使用的父类。

  1. 在“项目”菜单中选择“添加新项”选项。 选择类模板并键入 CanonicalDomainFeature.cs 作为文件名。
  2. 更改代码,使其如下所示:
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;
        }
    }
}

此代码执行以下操作:

  1. 定义规则模板的名称和标题
  2. 将名称、标题和图标传递给基类构造函数,以便在“添加规则”对话框显示所有已注册的规则模板时使用这些名称、标题和图标
  3. 定义用于呈现模板用户界面的 Run() 方法,即基于 WinForm 的模式对话框 CanonicalDomainForm。 如果在对话框中单击“确定”按钮,则通过调用 Navigate() 方法刷新 URL 重写模块的主 UI 页面。
  4. 最后,它定义一个帮助程序函数 GetPageType,该函数用于获取指定模块的主页。

定义服务代理

若远程客户端要调用服务,则必须提供服务代理。 为此,请将另一个名为 CanonicalDomainModuleServiceProxy.cs 的文件添加到项目,并更改其中的代码,使其如下所示:

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);
        }
    }
}

稍后将添加 GenerateRule 方法的实际服务实现。

实现规则模板对话框

现在,所有 IIS Manager 客户端管道代码都已完成,其余部分为设计和实现规则模板的实际用户界面。 若要完成这些操作,请执行以下步骤:

  1. 在“项目”菜单中选择“添加新项”选项。 在“添加新项”对话框中,选择“Windows 窗体”并键入名称 CanonicalDomainForm.cs:
    Screenshot of Add New Item dialog with a Windows Form template selected.

  2. 使用 Visual Studio Windows 窗体设计器排列窗体上的控件:
    Screenshot of the new form in Visual Studio windows form designer.

  3. 切换到代码视图,并添加将包含对服务代理的引用的类的私有成员:

    private CanonicalDomainModuleServiceProxy _serviceProxy;
    
  4. 在同一类中,修改构造函数代码,如下所示:

    public CanonicalDomainForm(CanonicalDomainModuleServiceProxy serviceProxy)
    {
       _serviceProxy = serviceProxy;
       InitializeComponent();
    }
    
  5. 在同一类中添加将调用服务代理的帮助程序函数,以使用用户指定的参数生成重写规则:

    private void GenerateRule(string domainName)
    {
        try
        {
            _serviceProxy.GenerateRule(domainName);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
    
  6. 为单击“确定”按钮时添加事件处理程序。 在事件处理程序代码中调用帮助程序函数 GenerateRule,将 TextBox 控件的内容作为参数传递。

    private void OnOkButtonClick(object sender, EventArgs e)
    {
        GenerateRule(_DomainTextBox.Text);
    }
    

为规则模板实现服务

若要实现服务,需要创建模块提供程序,这是在 IIS Manager 中注册模块的入口点。 若要执行该操作:

  1. 按照“如何创建简单的 IIS Manager 模块”一文中的任务 1 和 2 中所述的步骤创建和配置另一个 Visual Studio 项目。 将项目命名为“CanonicalDomainTemplate”。

  2. 项目菜单中选择添加引用,并将引用添加到位于 \Windows\System32\inetsrv 中的以下程序集:

    1. Microsoft.Web.Administration.dll
    2. Microsoft.Web.Management.dll
  3. 从“项目”菜单中选择“添加新项”选项。 在“添加新项”对话框中,选择“”模板,然后键入 CanonicalDomainModuleProvider.cs 作为文件的名称。

  4. 更改代码,使其如下所示(请记得将 PublicKeyToken 替换为 CanonicalDomainTemplate.Client.dll 程序集的公钥令牌)

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;
        }
    }
}

此代码会创建一个 ModuleProvider,该模块支持所有类型的连接(服务器、站点和应用程序),并注册名为 CanonicalDomainModule 的客户端模块。 此外,它还会注册在服务器端用于生成重写规则的模块服务类型 CanonicalDomainModuleService

若要为规则模板创建服务,请执行以下步骤:

  1. 在“项目”菜单中选择“添加新项”选项。 选择类模板并键入 CanonicalDomainModuleService.cs 作为文件名。
  2. 更改代码,使其如下所示:
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();
        }
    }
}

此代码会创建一个规则,用于重定向到规范域。

提示

若要快速获取用于生成重写规则的代码,请使用 IIS 7.0 及更高版本的配置编辑器,该编辑器包含在 IIS 的管理包中。 有关如何生成代码以创建重写规则的详细信息,请参阅本文

向 IIS Manager 注册规则模板

成功编译规则模板项目并将其放入全局程序集缓存后,需要通过将其信息添加到 administration.config 文件,以将其注册到 IIS Manager。

打开位于 \Windows\System32\inetsrv\config 的 administration.config 文件,并将以下行添加到 <moduleProviders> 部分。 请确保替换 PublicKeyToken:

<add name="CanonicalDomainName" type="CanonicalDomainTemplate.CanonicalDomainModuleProvider, CanonicalDomainTemplate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e4e6d0bc8fe7a06a" />

注意

通过仅将它添加到 moduleProviders 列表,你会注册该模块以仅用于服务器连接。 如果希望为站点连接和应用程序连接启用此模块,请将其添加到以下列表:

<location path=".">
   <module> 
     <add name="CanonicalDomainName" />
   </module>
</location>

完成这些步骤后,应能够在 URL 重写模块的“添加规则”对话框中看到“规范域名”规则模板。