面向 IIS 7.0 开发人员的端到端扩展性示例

作者:Saad Ladki

IIS 7 及更高版本采用完全模块化的体系结构,基于丰富的扩展性 API 构建。 这使得开发人员能够轻松添加、删除内置 IIS 组件,甚至用手工制作的组件替换内置 IIS 组件,特别适合任何给定的网站。 将代码深入插入 IIS 核心管道并用以前不可能的方式扩展 IIS 从未如此简单。

举几个例子:只需编写几行代码,开发人员就能编写提供新身份验证和授权方案的模块或处理程序,对传入请求进行运行时或安全分析并检查响应。 但为了提供真正的附加价值,这些模块必须可通过编程接口、命令行工具和用户界面进行管理。

本白皮书提供了如何使用自定义请求处理程序扩展 IIS Web 服务器的端到端示例。 其中介绍了如何为此处理程序的配置添加 API 和命令行支持,以及如何将用户界面模块写入 IIS 管理界面。

该解决方案已在 Windows Vista 和 Windows Server® 2008 Beta 3 上进行测试。 Windows Server 2008 最终版本推出后,它将会更新。

功能集

  • 托管处理程序将版权消息插入图像文件
  • 版权消息功能是配置驱动的,使用新的 IIS 配置系统
  • 配置可以架构化,并可供配置 API、WMI 脚本和 IIS 命令行工具访问
  • 用户界面扩展模块允许通过 IIS 用户界面配置版权消息功能

先决条件

若要执行本文档中的步骤,必须安装以下软件:

ASP.NET

通过 Windows Vista 控制面板安装 ASP.NET。 选择“程序”-“打开或关闭 Windows 功能”。 然后打开“Internet Information Services”-“万维网服务”-“应用程序开发功能”,选中“ASP.NET”。

如果你有 Windows Server 2008 内部版本。 打开“服务器管理器”-“管理角色”并选择“Web 服务器(IIS)”。 单击“添加角色服务”。 在“应用程序开发”下,选中“ASP.NET”。

还必须安装“IIS 管理脚本和工具”,才能利用 IIS 中的 WMI 扩展性。 为此,请选择“程序”-“打开或关闭 Windows 功能”。 然后打开“Internet Information Services”-“Web 管理工具”,选中“IIS 管理脚本和工具”。

如果你有 Windows Server 2008 内部版本,请打开“服务器管理器”-“角色”,然后选择“Web 服务器(IIS)”。 单击“添加角色服务”。 在“Web 管理工具”下,选中“IIS 管理脚本和工具”。

Visual C# Express Edition 或 Visual Studio 2005

对于用户界面模块,需要一个 C# 开发工具。 如果你没有 Visual Studio 2005,请免费下载 Visual Studio

处理用户帐户控制问题

Windows Vista 用户帐户保护会从访问令牌中删除管理员权限。 默认情况下,你无权访问 IIS 配置和内容位置。 若要解决此问题,我们建议使用提升的命令提示符来阅读本文。

若要启动提升的命令提示符,请转到“开始”菜单,单击“所有程序”-“附件”。 右键单击“命令提示符”,然后单击“以管理员身份运行”。 确认提升权限提示。

场景

以下示例动态修饰我们的 Web 服务器提供的图像,并在左下角显示版权信息,如图 1 所示。

Screenshot of the web page displaying an image of snow covered rocky mountains on the backdrop of a cloudy sky.
图 1:操作中的图像版权模块

我们使用托管代码来开发修饰图像的处理程序。 作为示例的一部分,我们还指定了该处理程序的配置并将其存储在 IIS 配置存储中。 最后,我们将为 IIS 管理器开发一个用户界面插件。

只需将架构文件复制到 IIS 架构目录即可扩展 IIS 配置存储。 架构声明了新配置部分的名称及其属性、类型和默认值。 对于本示例,我们声明一个名为 imageCopyright 的新配置部分。 它位于 system.webServer 配置组中。 其属性为:

  • 用于启用或禁用 imageCopyright 功能的布尔标志
  • 包含版权消息的字符串属性
  • 指定版权消息颜色的颜色属性

架构声明

将以下架构定义保存为 %windir%\system32\inetsrv\config\schema 中的 imagecopyright.xml:

<configSchema>
    <sectionSchema name="system.webServer/imageCopyright">
        <attribute name="enabled" type="bool" defaultValue="false" />
        <attribute name="message" type="string" defaultValue="Your Copyright Message" />
        <attribute name="color" type="string" defaultValue="Red"/> 
   </sectionSchema>
</configSchema>

如果收到“访问被拒绝”消息,则表明你未从提升的命令提示符执行此操作。 添加架构文件后,需要在 applicationhost.config 文件中声明该架构。 将以下 XML 添加到 %windir%\system32\inetsrv\config\applicationhost.config

<configSections>
...
<sectionGroup name="system.webServer">
<section name="imageCopyright"  overrideModeDefault="Allow"/>
...    
</sectionGroup>
</configSections>

对其进行配置

该过程已完成。 可以通过命令行或者直接在 applicationhost.config 或 web.config 中设置新的配置设置。试试看。 打开命令行界面,然后输入以下命令:

<system.webServer>
    <imageCopyright />
</system.webServer>

输出显示配置部分已被识别,并具有默认配置:

%windir%\system32\inetsrv\appcmd set config -section:system.webServer/imageCopyright 

/color:yellow /message:"Copyright (C) Contoso.COM" /enabled:true

现在通过 appcmd.exe 添加配置设置,例如

%windir%\system32\inetsrv\appcmd set config -section:system.webServer/imageCopyright 

/color:yellow /message:"Copyright (C) Contoso.COM" /enabled:true

通过运行以下命令检查配置是否已保存:

%windir%\system32\inetsrv\appcmd list config -section:system.webServer/imageCopyright

查看保存的配置:

<system.webServer> 
    <imageCopyright enabled="true" message="Copyright (C) Contoso.COM" color="yellow" />
</system.webServer>

使 imageCopyright 配置可脚本化

注意

使 imageCopyright 处理程序配置可用于 WMI 脚本是可选操作。 可以直接转到“步骤 2 – 核心扩展性:图像版权处理程序”,而不影响其余步骤。

要使 imageCopyright 处理程序配置可用于 WMI 脚本,请完成以下步骤:

  • 安装 IIS WMI 支持
  • 创建 imageCopyright.mof 文件
  • 将 imageCopyright.mof 文件包含到 webadministration.mof 中并编译 WMI 架构文件
  • 编写并执行脚本

安装 IIS WMI 支持

IIS 的默认安装不包含 WMI 脚本组件。 必须添加它们。

在 Vista 客户端 SKU 上安装 WMI 支持

通过 Windows Vista 控制面板安装“IIS 管理脚本和工具”。 选择“程序”-“打开或关闭 Windows 功能”。 然后打开“Internet Information Services”-“Web 管理工具”,选中“IIS 管理脚本和工具”。

在 Windows Server 2008 SKU 上安装 WMI 支持

如果你有 Windows Server 2008 内部版本,请打开“服务器管理器”-“角色”,然后选择“Web 服务器(IIS)”。 单击“添加角色服务”。 在“管理工具”下,选中“IIS 管理脚本和工具”。

创建 imageCopyright.mof 文件

WMI 属性的架构声明与上一步骤中 IIS 属性的架构声明非常相似。 WMI 架构在 .mof 文件中声明,由名为 mofcomp 的工具编译。 Mofcomp 将架构声明添加到 WMI 存储库。

用于添加架构信息的任务

打开记事本实例并将以下行复制到其中:

#pragma AUTORECOVER
#pragma namespace("\\\\.\\Root\\WebAdministration")
[            
    dynamic : ToInstance ToSubClass,
    provider("WebAdministrationProvider") : ToInstance ToSubClass,
    Description("imageCopyright Section") : ToSubClass,
    Locale(1033) : ToInstance ToSubClass,
    factory_clsid("{901a70b2-0f7a-44ea-b97b-1e9299dec8ca}"),
    section_path("system.webServer/imageCopyright"),
    SupportsUpdate
]
 
class imageCopyright : ConfigurationSection
{      
    [
        read: ToSubClass ToInstance,
        write: ToSubClass ToInstance,
        DefaultValue("False"): ToSubClass ToInstance,
        Description("To be written"): ToSubClass ToInstance
    ]
    boolean Enabled;
  
    [
        read: ToSubClass ToInstance,
        write: ToSubClass ToInstance,
        DefaultValue("Your Copyright Message"): ToSubClass ToInstance,
        Description("Copyright Message"): ToSubClass ToInstance
    ]
    string Message;

    [
        read: ToSubClass ToInstance,
        write: ToSubClass ToInstance,
        DefaultValue("Yellow"): ToSubClass ToInstance,
        Description("Color of Copyright Message"): ToSubClass ToInstance
    ]
    string Color;
};

架构声明包含与上一步骤中的 imageCopyright.xml 相同的条目,即配置设置的名称和类型及其默认值。 将文件另存为 %windir%\system32\inetsrv\imageCopyright.mof

编译 WMI 架构文件

通过执行以下命令编译 imageCopyright.mof

mofcomp webadministration.mof

WMI 脚本

Mofcomp 已将 imageCopyright 架构添加到 WMI 存储库。 通过编写 IIS WMI 提供程序脚本来设置 IIS 配置设置。 以下是示例:

任务

打开记事本实例并将以下行复制到其中。 将文件另存为 SetCopyrightConfig.vbs:

Set oIIS = GetObject("winmgmts:root\WebAdministration")        
Set oSection = oIIS.Get("ImageCopyright.Path='MACHINE/WEBROOT/APPHOST/Default Web Site',Location=''")
oSection.Enabled = true
oSection.Message = "Copyright (C) IIS7 Team - Date: " & date
oSection.Color = "White"
oSection.Put_

这是连接到 IIS WMI 提供程序的标准 WMI 脚本。 它获取指定位置(“默认网站”)的配置部分并更改其值。 Put_ 调用将更改保存到磁盘。

如果你执行该脚本,它会将带有当前日期的版权消息添加到 %systemdrive%\inetpub\wwwroot\web.config 中。 请看一看。

接下来,添加图像版权处理程序本身。

处理程序是当请求匹配特定模式(通常是文件扩展名)时执行的一段代码。 例如,以 .ASP 结尾的请求将映射到 ASP.DLL。 在 IIS 6.0 中,必须编写 ISAPI 扩展来处理具有特定文件扩展名的请求。 ASP.NET 还允许处理文件扩展名,但前提是首先将请求映射到 ASP.NET。 在 IIS 中,可以处理任意文件扩展名,而无需涉及 ASP.NET。 在本示例中,我们将处理扩展名为 .JPG 的请求。 操作方法如下:

创建内容目录

创建一个内容目录,例如 c:\inetpub\mypictures,并将选择的一些数字图片复制到其中。 确保这些文件是扩展名为 .JPG 的图像文件。

注意

为简单起见,此处显示的代码示例不包括非图像文件的错误处理代码。

在新目录下创建一个名为 App_Code 的子目录:例如 c:\inetpub\mypictures\App\_Code

创建 mypictures 应用程序

可以通过 IIS 管理控制台创建一个指向 c:\inetpub\mypictures 的应用程序,但还有更有趣的方法可以实现此目的。 通过 appcmd 创建新应用程序。 以下命令在“默认网站”上创建名为“mypictures”的应用程序,其物理路径为 c:\inetpub\mypictures

%windir%\system32\inetsrv\appcmd add app -site.name:"Default Web Site"

-path:/mypictures -physicalPath:%systemdrive%\inetpub\mypictures

由于我们想要查看复制到该目录中的 JPG 文件,因此需要启用目录浏览。 通过 IIS 管理控制台执行此操作,或者采用更有趣的方法并使用 appcmd。 下面演示如何通过 appcmd 将目录浏览设置为 true:

%windir%\system32\inetsrv\appcmd set config "Default Web Site/mypictures"

 -section:directoryBrowse -enabled:true

如果请求 http://localhost/mypictures,你会看到一个包含图片的目录列表。

开始编写代码

现在编写实际的图像处理代码。 编写几行 C# 代码即可得到结果:使用以下代码作为参考,将其另存为 App_Code 目录中的 imagecopyrighthandler.cs,例如 c:\inetpub\mypictures\App\_Code\imagecopyrighthandler.cs

#region Using directives
using System;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using Microsoft.Web.Administration;
#endregion
  
namespace IIS7Demos
{
    public class imageCopyrightHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            ConfigurationSection imageCopyrightHandlerSection = 
                WebConfigurationManager.GetSection("system.webServer/imageCopyright");
  
            HandleImage(    context,
                            (bool)imageCopyrightHandlerSection.Attributes["enabled"].Value,
                            (string)imageCopyrightHandlerSection.Attributes["message"].Value,
                            (string)imageCopyrightHandlerSection.Attributes["color"].Value                            
                        );
        }
  
        void HandleImage(   HttpContext context,
                            bool enabled,
                            string copyrightText,
                            string color
                        )           
        {
            try
            {
                string strPath = context.Request.PhysicalPath;
                if (enabled)
                {
                    Bitmap bitmap = new Bitmap(strPath);
                    // add copyright message
                    Graphics g = Graphics.FromImage(bitmap);
                    Font f = new Font("Arial", 50, GraphicsUnit.Pixel);
                    SolidBrush sb = new SolidBrush(Color.FromName(color));
                    g.DrawString(   copyrightText,
                                    f,
                                    sb,
                                    5,
                                    bitmap.Height - f.Height - 5
                                );
                    f.Dispose();
                    g.Dispose();
                    // slow, but good looking resize for large images
                    context.Response.ContentType = "image/jpeg";
                    bitmap.Save(
                                        context.Response.OutputStream,
                                        System.Drawing.Imaging.ImageFormat.Jpeg
                                     );
                    bitmap.Dispose();
                }
                else
                {
                    context.Response.WriteFile(strPath);
                }
            }
            catch (Exception e)
            {
                context.Response.Write(e.Message);
            }
        }
  
        public bool IsReusable
        {
            get { return true; }
        }
    }
}

上面的代码执行以下操作:

  • 读取配置
  • 调用 HandleImage

HandleImage 执行以下操作:

  • 从位图创建图形对象
  • 使用配置的值创建字体对象
  • 将消息绘制到位图中

若要使用 Microsoft.Web.Administration 类,必须添加对 IIS 管理 API 程序集的引用。 为此,请打开 %systemdrive%\inetpub\mypictures\web.config 并添加以下条目:

<system.web>
    <compilation>
      <assemblies>
        <add assembly="Microsoft.Web.Administration, Version=7.0.0.0, 
Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/>
      </assemblies>
    </compilation>
</system.web>

还可以将处理程序编译成程序集并将其放入 mypictures/bin 中。 如果你这样做,则不必将 Microsoft.Web.Administration 程序集添加到 web.config 文件中。

处理程序配置

如果请求了 .JPG 文件,则只需告知 IIS 调用新处理程序即可。 通过 IIS 管理控制台或使用 appcmd 执行此操作:

appcmd set config "Default Web Site/mypictures/" -section:handlers 

/+[name='JPG-imageCopyrightHandler',path='*.jpg',verb='GET',type='IIS7Demos.imageCopyrightHandler']

上面的 appcmd 命令仅在 /mypictures 目录中配置新处理程序。 由于处理程序条目位于集合中,因此必须使用 +[] 语法。 必须将 add 元素添加到集合时,始终使用此语法。 处理程序配置的元素为:

name

可以是任何唯一名称。 该名称仅用于唯一标识处理程序。

path

告知 IIS 何时执行此处理程序。 *.JPG 告知 IIS 对所有以 .JPG 结尾的文件执行此处理程序。 如果使用 foo*.JPG 作为路径,则此处理程序仅执行以 foo 开头的 JPG 文件。

谓词

为执行此处理程序而必须匹配的逗号分隔 http 谓词列表。 在本示例中,我们只想在 GET 请求传入时执行该请求。

type

请求匹配时应执行的类的托管类型。 它由命名空间和 App_Code 目录中的 IHttpHandler 派生类组成。

最后一个要点

在开始测试受版权保护的图像之前,请确保执行请求的 IIS 工作进程获取所做的架构更改。 将 imageCopyright.xml 文件添加到架构目录时,工作进程可能已经在运行。 如果发生这种情况,你会在 imagecopyrightconfig.cs 中收到配置异常。 作者在编写此文时就遇到了此问题,花费了相当长的时间才予以解决。

只需回收应用程序池即可解决此问题:

appcmd recycle AppPool DefaultAppPool

该过程已完成。 如果现在请求 http://localhost/mypictures/<imageOfYourChoice>.jpg),你会看到版权消息。

选项:

  • 可以通过 appcmd 或直接编辑 web.config 文件来更改版权消息选项
  • 可以通过为不同的扩展名添加相同的处理程序,将 imageCopyright 处理程序映射到其他图像类型,例如 BMP 或 GIF。 示例:
appcmd set config "Default Web Site/mypictures/" -section:handlers /+[name='BMP-imageCopyrightHandler',path='*.bmp',verb='GET',type='IIS7Demos.imageCopyrightHandler']

差不多可以收尾了。 我们已经通过几行代码扩展了 IIS 核心服务器;无需编写任何代码就扩展了 IIS 配置系统,并免费获得了命令行支持。 现在让我们通过 IIS 管理控制台配置我们的 imageCopyright 处理程序。

通过以下任务做到这一点:

  • 在 Microsoft Visual Studio 或 Microsoft Visual C# Express 中创建项目,以便可以在 IIS 管理控制台内使用程序集
  • 创建模块提供程序
  • 创建一个读取和设置 imageCopyright 属性的模块。

创建项目

若要为 InetMgr 创建扩展性模块,需要创建一个 DLL 项目(也称为类库项目)。 该 DLL 需要强命名,以便可以在 GAC(全局程序集缓存)中注册,这是 IIS 管理控制台使用的模块的要求。

步骤

  1. 单击“开始”,然后单击“程序”并运行 Microsoft Visual Studio 2005 或 Microsoft Visual C# 2005 Express Edition。

  2. 在“文件”菜单中,选择“新建项目”选项。

  3. 在“新建项目”对话框中,选择“类库”作为项目类型,键入 imageCopyrightUI 作为项目名称,然后单击“确定”。

    Screenshot of New Project dialog box with Class Library selected and image Copyright U I entered in the Name filed as the name of the project.
    图 2:“新建项目”对话框

  4. 删除默认添加的文件 Class1.cs,因为我们不会使用它。

  5. 使用“项目”菜单中的“添加新引用”选项,添加对位于 \Windows\system32\inetsrv 目录中的 Microsoft.Web.Management.dll 的引用。 这是一个 DLL,其中包含为 IIS 管理控制台创建模块所需的所有扩展性类。

  6. 使用“项目”菜单中的“添加新引用”选项,添加对位于 \Windows\system32\inetsrv 目录中的 Microsoft.Web.Administration.dll 的引用。 这是一个 DLL,其中包含读取配置(用于写入 IIS 配置)所需的所有配置类。

  7. 由于我们将使用代码来创建基于 WinForms 的 UI,因此我们还需要添加对 System.Windows.Forms.dll 的引用;为此,请再次使用“项目”菜单中的“添加新引用”选项,在 .NET 程序集列表中选择 System.Windows.Forms.dll 和 System.Web.dll。

  8. 在 InetMgr 中使用库的要求之一是需要在 GAC 中将其注册。 为此,我们需要确保我们的 DLL 是强命名的(有时称为签名)。 Visual Studio 提供了一种简单方法来创建新名称并为项目选择名称,为此,请使用“项目”菜单选择“imageCopyrightUI 属性”选项。

  9. 在“签名”选项卡中,选中“对程序集进行签名”。

  10. 在“创建强名称密钥”中,键入 imageCopyrightUI 作为密钥名称,然后取消选中“使用密码保护我的密钥文件”复选框。 单击“确定”。

    Screenshot of Create Strong Name Key dialog box displaying image Copyright U I entered as Key file name and password created and confirmed.
    图 3:创建强名称对话框

    签名选项卡显示:

    Screenshot of Signing tab with image Copyright U I dot s n k selected in the Choose a strong name key file field.
    图 4:VS 项目签名选项卡

  11. 由于我们希望程序集位于 GAC 中,因此需要添加一些生成后事件,以便每次编译时它都会自动添加到 GAC 中。 当我们添加新功能时,这会使调试和更改变得非常简单。 为此,请选择“生成事件”选项卡,并添加以下“生成后事件”命令行

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

    Screenshot of Post Build Event command line populated with code.
    图 5:VS 生成后事件选项卡

    (可选)如果使用的是 Microsoft Visual Studio 2005(这不适用于 Visual C# Express Edition),请正确设置调试以使用 F5 运行代码。 为此,请转到项目属性,选择“调试”选项卡并将其设置为启动外部程序,同时选择 \windows\system32\inetsrv\inetmgr.exe

    Screenshot of Debug tab set to Start external program action.
    图 6:调试选项卡

  12. 最后,关闭项目属性,选择“文件”菜单中的“全部保存”选项,然后单击“确定”。

    现在,使用“生成”菜单下的“生成解决方案”编译项目。 这会自动生成 DLL 并将其添加到 GAC 中。

创建模块提供程序

与 IIS 核心服务器和 IIS 配置系统一样,IIS 用户界面也是可自定义和模块化的。 IIS 用户界面是一组可以删除或替换的功能模块。 每个 UI 模块的入口点是模块提供程序。 所有模块提供程序的列表可以在 <modules> 部分的 %windir%\system32\inetsrv\Administration.config 中找到。

首先,创建 imageCopyrightUI 模块提供程序。

步骤

  1. 从“项目”菜单中选择“添加新项”选项。 在“添加新项”对话框中,选择“类”模板,然后键入 imageCopyrightUIModuleProvider.cs 作为文件名。

    Screenshot of Add New Item dialog box with Class template selected and the Name field populated with image Copyright U I Module Provider dot c s.
    图 7:添加新项对话框

  2. 更改代码,使其如下所示:

    using System;
    using System.Security;
    using Microsoft.Web.Management.Server;
        
    namespace IIS7Demos           
    {
        class imageCopyrightUIProvider : ModuleProvider
        {
            public override Type ServiceType              
            {
                get { return null; }
            }
    
            public override ModuleDefinition GetModuleDefinition(IManagementContext context)
            {
                return new ModuleDefinition(Name, typeof(imageCopyrightUI).AssemblyQualifiedName);
            }
    
            public override bool SupportsScope(ManagementScope scope)
            {
                return true;
            }
        }            
    }
    

    此代码创建一个支持所有类型的范围(服务器、站点和应用程序)的 ModuleProvider,并注册一个名为 imageCopyrightUI 的客户端模块。 为了仅在应用程序级别显示模块,SupportsScope 函数如下所示:

    public override bool SupportsScope(ManagementScope scope)
    {
        return (scope == ManagementScope.Application) ;
    }
    

创建 UI 模块

模块是客户端中所有扩展性对象的主入口点。 它有一个名为 Initialize 的主方法。 所有操作在此方法中发生。

步骤

  1. 在“项目”菜单中选择“添加新项”选项。

  2. 选择“类”模板并键入 imageCopyrightUI.cs 作为文件名。 更改代码,使其如下所示:

    using System;
    using System.Windows.Forms;
    using Microsoft.Web.Management.Client;
    using Microsoft.Web.Management.Server;
    
    namespace IIS7Demos
    {
        internal class imageCopyrightUI : Module
        {
            protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo)
            {
                base.Initialize(serviceProvider, moduleInfo);
                IControlPanel controlPanel = (IControlPanel)GetService(typeof(IControlPanel));
                ModulePageInfo modulePageInfo = new ModulePageInfo(this, typeof(imageCopyrightUIPage), "Image Copyright", "Image Copyright");
                controlPanel.RegisterPage(modulePageInfo);
            }
        }              
    }
    

    在上面的代码中,我们指定了 UI 模块列表中条目的文本,以及用户单击此文本时应显示的单个页面的类型。

剩下的操作就是编写页面本身了。

创建模块页面

在此任务中,你将创建最基本的模块页面。 ModulePage 是框架提供的基类,用于创建新的用户界面。 框架提供了四种不同的类,它们非常有用,具体取决于尝试生成的方案。

  • ModulePage。 此基类仅提供最基本的服务,根本不提供特殊的用户界面。 InetMgr 中包含的所有功能都不是直接从此类派生的。
  • ModuleDialogPage。 此基类提供与对话框类似的语义,包括任务列表中的“应用”和“取消”链接,并提供可重写的特定方法来处理此常见任务。 它还自动处理“刷新”和其他功能。 从此页面派生的功能示例包括“计算机密钥”、“管理服务”等。
  • ModulePropertiesPage。 此基类提供类似于 Visual Studio 属性网格的 UI,其中所有属性都显示在分层网格式控件中。 其示例包括 CGI、ASP、.NET 编译等。
  • ModuleListPage。 当你需要显示项列表时,此基类非常有用。 它包括一个 ListView 控件,可用于显示设置并自动提供搜索、分组和视图。 示例包括“应用程序设置”、“模块”、“工作进程”等。

步骤

  1. 从“项目”菜单中选择“添加新项”选项。

  2. 在“添加新项”对话框中,选择“类”模板,然后键入 imageCopyrightUIPage.cs 作为文件名。 更改代码,使其如下所示:

    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    using Microsoft.Web.Management.Client.Win32;
    using Microsoft.Web.Administration;
    using Microsoft.Web.Management.Client;
    using Microsoft.Web.Management.Server;
    namespace IIS7Demos
    {
        public sealed class imageCopyrightUIPage : ModulePage
        {
            public string message;
            public bool featureenabled;
            public string color;
    
            ComboBox _colCombo = new ComboBox();
            TextBox _msgTB = new TextBox();
            CheckBox _enabledCB = new CheckBox();
            public imageCopyrightUIPage()
            {
                this.Initialize();
            }
            protected override void OnActivated(bool initialActivation)
            {
               base.OnActivated(initialActivation);
               if (initialActivation)
               {
                    ReadConfig();
                    UpdateUI();
                }
            }
    
            void UpdateUI()
            {
                _enabledCB.Checked = featureenabled;
                int n = _colCombo.FindString(color, 0);
                _colCombo.SelectedIndex = n;
                _msgTB.Text = message;
            }
    
            void Initialize()
            {
                Label crlabel = new Label();
                crlabel.Left = 50;
                crlabel.Top = 100;
                crlabel.AutoSize = true;
                crlabel.Text = "Enable Image Copyright:";
                _enabledCB.Text = "";
                _enabledCB.Left = 200;
                _enabledCB.Top = 100;
                _enabledCB.AutoSize = true;
    
                Label msglabel = new Label();
                msglabel.Left = 150;
                msglabel.Top = 130;
                msglabel.AutoSize = true;
                msglabel.Text = "Message:";
                _msgTB.Left = 200;
                _msgTB.Top = 130;
                _msgTB.Width = 200;
                _msgTB.Height = 50;
    
                Label collabel = new Label();
                collabel.Left = 160;
                collabel.Top = 160;
                collabel.AutoSize = true;
                collabel.Text = "Color:";
                _colCombo.Left = 200;
                _colCombo.Top = 160;
                _colCombo.Width = 50;
                _colCombo.Height = 90;
                _colCombo.Items.Add((object)"Yellow");
                _colCombo.Items.Add((object)"Blue");
                _colCombo.Items.Add((object)"Red");
                _colCombo.Items.Add((object)"White");
    
                Button apply = new Button();
                apply.Text = "Apply";
                apply.Click += new EventHandler(this.applyClick);
                apply.Left = 200;
                apply.AutoSize = true;
                apply.Top = 250;
    
                Controls.Add(crlabel);
                Controls.Add(_enabledCB);
                Controls.Add(collabel);
                Controls.Add(_colCombo);
                Controls.Add(msglabel);
                Controls.Add(_msgTB);
                Controls.Add(apply);
            }
    
            private void applyClick(Object sender, EventArgs e)
            {
                try
                {
                    UpdateVariables();
                    ServerManager mgr;
                    ConfigurationSection section;
                    mgr = new ServerManager();
                    Configuration config =
                    mgr.GetWebConfiguration
                    (
                           Connection.ConfigurationPath.SiteName, 
                           Connection.ConfigurationPath.ApplicationPath +
                           Connection.ConfigurationPath.FolderPath
                    );
    
                section = config.GetSection("system.webServer/imageCopyright");
                section.GetAttribute("color").Value = (object)color;
                section.GetAttribute("message").Value = (object)message;
                section.GetAttribute("enabled").Value = (object)featureenabled;
    
                mgr.CommitChanges();
    
                }
    
                catch
                {}
    
            }
    
            public void UpdateVariables()
            {
                featureenabled = _enabledCB.Checked;
                color = _colCombo.Text;
                message = _msgTB.Text;
            }
    
            public void ReadConfig()
            {
                try
                {
                    ServerManager mgr;
                    ConfigurationSection section;
                    mgr = new ServerManager();
                    Configuration config =
                    mgr.GetWebConfiguration(
                           Connection.ConfigurationPath.SiteName,
                           Connection.ConfigurationPath.ApplicationPath +
                           Connection.ConfigurationPath.FolderPath);
    
                    section = config.GetSection("system.webServer/imageCopyright");
                    color = (string)section.GetAttribute("color").Value;
                    message = (string)section.GetAttribute("message").Value;
                    featureenabled = (bool)section.GetAttribute("enabled").Value;
    
                }
    
                catch
                {}
    
            }
        }
    }
    

    虽然功能有很多,但此代码只不过是在 ModulePage 上放置几个控件,并对 IIS 配置存储进行读取和写入。

读取配置

ReadConfig 函数使用相同的 Microsoft.Web.Administration 接口来打开 IIS 配置存储。 UI 本身提供了配置设置的应用范围。

示例:

Connection.ConfigurationPath.SiteName,

Connection.ConfigurationPath.ApplicationPath+

Connection.ConfigurationPath.FolderPath

保存配置

单击“应用”按钮(applyClick 函数)时将保存配置。 UI 中所做的更改会传输到部分属性中,并将部分保存到磁盘。

section.GetAttribute("enabled").Value = (object)featureenabled;

mgr.CommitChanges();

此时,你已准备好使用“生成”菜单中的“生成解决方案”再次编译所有内容。 这会生成程序集 imageCopyrightUI 并将其放入全局程序集缓存中。

模块注册

UI 模块已生成,但我们仍然必须告知 IIS 管理控制台加载它。 为此,请执行以下操作:

  • 从全局程序集缓存中获取 UI 模块的强名称
  • 将强名称和类型添加到 IIS 管理控制台的配置文件中。 这会导致 IIS 管理控制台在启动时加载该类型
  • 启用 UI 模块列表中的模块

步骤

  1. 打开或使用现有的提升的命令 shell,并通过执行以下命令注册 Visual Studio 8.0 环境变量:

    "%vs80comntools%\vsvars32.bat
    
  2. 运行 GacUtil

    GACUTIL /l imageCopyrightUI
    
  3. 打开 %windir%\system32\inetsrv\config\administration.config 并在 <moduleProviders> 条目后面添加以下内容:

    <add name="imageCopyrightUI" type="IIS7Demos.imageCopyrightUIProvider, IIS7Demos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3fd9bd5e992ee757"/>
    

结果

任务已完成。 查看结果。

打开 IIS 管理控制台并导航到 /mypictures 应用程序。

双击“图像版权”项。

Screenshot of I I S Management Console with my pictures application selected and image Copyright message displayed.
图 8:图像版权用户界面

更改版权消息,单击“应用”并刷新浏览器。 版权消息已更改。 查看 %systemdrive%\inetpub\mypictures 目录中的 web.config 文件以查看更改后的配置。

总结

IIS 能够用以前不可能的方式进行扩展。 你可以使用自己的组件扩展 IIS 核心处理管道,将该组件的配置与 IIS 配置一起存储,甚至可以编写与标准 IIS 设置并存的用户界面插件。 回顾一下我们在前面的示例中执行的操作:

IIS 核心扩展性

我们向 IIS 核心添加了一个图像处理程序,该处理程序将版权消息插入到每个接受服务的 .JPG 文件中。 我们只编写了几行 C# 代码就做到了这一点。 处理程序的功能是由配置驱动的。 我们将配置存储到了常规 IIS 配置文件 applicationhost.config 和 web.config 中。我们还添加了对图像的缓存支持。

IIS 配置系统扩展性

我们将图像版权处理程序配置添加到了 IIS 配置系统中。 高度可读的 xml 存储、即时 API 和命令行支持、委托和分布式部署等优势都是免费的。 我们完全不用编写任何代码。

IIS 用户界面扩展性

为使我们的功能具有应有的可见性,我们添加了 IIS 用户界面模块。 尽管未显示,但完全可以通过 HTTPS 远程控制 IIS 用户界面。