为 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 重写模块的“添加规则”对话框中看到“规范域名”规则模板。