Разработка модулей и обработчиков IIS 7.0 с помощью .NET Framework

Майк Володарский

Обзор

В этой статье рассматривается начало разработки функций веб-сервера IIS 7.0 и более поздних версий на основе .NET Framework. В этой статье показано:

  1. Как решить, следует ли разрабатывать модуль IIS или обработчик IIS
  2. Настройка среды разработки с помощью Visual Studio, Visual C# Express или средств командной строки, предоставляемых платформой .NET Framework
  3. Создание первого проекта
  4. Разработка простого модуля и обработчика
  5. Развертывание простого модуля и обработчика на сервере IIS

Чтобы просмотреть некоторые управляемые модули и обработчики IIS в реальном мире и скачать их для приложения, посетите запросы перенаправления к приложению с помощью модуля HttpRedirection, Получите хорошие списки каталогов для веб-сайта IIS с помощью DirectoryListingModule и отображение красивых значков файлов в приложениях ASP.NET с помощью IconHandler.

Введение. Разработка функций IIS с помощью ASP.NET

Выпуски IIS до IIS 7.0 были представлены API C с именем ISAPI в качестве основного API расширяемости для создания функций веб-сервера. IIS 7.0 и более поздних версий были перепроектированы с нуля, чтобы предоставить новый API C++, на котором основаны все встроенные функции, чтобы обеспечить полную расширяемость веб-сервера во время выполнения.

В дополнение к этому IIS впервые предоставляет полнофункциональная API .NET для расширения веб-сервера, используя тесную интеграцию с ASP.NET 2.0. Это означает, что теперь вы можете расширить IIS с новыми функциями веб-сервера, созданными с помощью знакомых API ASP.NET 2.0. Аналогичным образом можно использовать существующие модули и обработчики ASP.NET 2.0 в IIS, используя интеграцию ASP.NET, чтобы повысить эффективность приложения без написания нового кода. Дополнительные сведения об интеграции ASP.NET в IIS см. в статье ASP.NET Интеграция с IIS 7.

Инструменты для работы: выбор вашей среды разработки

Чтобы создать модули и обработчики IIS, используйте любую среду, которая позволяет разрабатывать и компилировать сборки .NET. Ниже приведены некоторые распространенные варианты.

  1. Visual Studio 2005. Кроме того, можно скачать последнюю бета-версию Visual Studio 2008.
  2. Visual C# 2005 Express Edition, бесплатная загрузка (или другие средства Express, включая Visual Basic 2005 Express).
  3. Компилятор командной строки C# (csc.exe), включенный в среду выполнения .NET Framework (для других языков, вам потребуется скачать пакет SDK), а также любимый редактор исходного кода.

Примеры в этой статье используют C#, хотя вы можете разрабатывать компоненты IIS на любом другом поддерживаемом языке .NET (кроме управляемого C++). В статье показано, как разрабатывать компоненты расширяемости IIS со всеми тремя из перечисленных выше сред.

Замечание

Поскольку IIS использует существующие API ASP.NET для расширения .NET, вы можете разрабатывать модули и обработчики IIS с помощью .NET Framework 2.0 на Windows XP® и Windows Server® 2003. Однако если вы планируете использовать один из нескольких новых API-интерфейсов ASP.NET, которые были добавлены для поддержки новых функций IIS, необходимо разработать в Windows Vista или получить версию System.Web.dll из Windows Vista® или последнюю версию .NET Framework 3.5 для компиляции кода.

Два способа расширения IIS: модуль и обработчик

Все функции веб-сервера IIS соответствуют двум категориям: модулям и обработчикам.

Модуль, аналогичный фильтру ISAPI в предыдущих версиях IIS, участвует в обработке каждого запроса, чтобы изменить или добавить в него какой-то способ. Примеры некоторых встроенных модулей в IIS включают модули аутентификации, которые управляют процессом проверки подлинности запроса, модули сжатия, которые сжимают исходящий ответ, и модули ведения журналов, которые записывают информацию о запросе в журналы запросов.

Модуль — это класс .NET, который реализует интерфейс System.Web.IHttpModule и использует API в пространстве имен System.Web для участия в одном или нескольких этапах обработки запросов ASP.NET.

Обработчик, аналогичный расширению ISAPI в предыдущих версиях IIS, отвечает за обработку запроса и создание ответа для определенных типов контента. Основное различие между модулем и обработчиком заключается в том, что обработчик обычно сопоставляется с определенным путем запроса или расширением и поддерживает обработку определенного ресурса сервера, которому соответствует этот путь или расширение. Примеры обработчиков, предоставляемых службами IIS, включают ASP, который обрабатывает скрипты ASP, статический обработчик файлов, который обслуживает статические файлы и ASP. PageHandler NET, который обрабатывает страницы ASPX.

Обработчик — это класс .NET, реализующий интерфейс ASP.NET System.Web.IHttpHandler илиSystem.Web.IHttpAsyncHandler и использующий API в пространстве имен System.Web для создания http-ответа для определенного содержимого, который он поддерживает.

При планировании разработки функции IIS следует задать первый вопрос о том, отвечает ли эта функция за обслуживание запросов на определенный URL-адрес или расширение или применяется ко всем или некоторым запросам на основе произвольных правил. В предыдущем случае ваш должен быть обработчиком, а в последнем — модулем.

В этой статье показано создание простого модуля и простого обработчика, распространенных шагов при создании проекта и его компиляции, а также конкретных шагов по развертыванию на сервере.

Замечание

Вам не нужно разрабатывать обработчик, если вы разрабатываете модуль, и наоборот.

Начало работы: создание проекта Visual Studio

Чтобы создать модуль или обработчик, необходимо создать сборку .NET (DLL), содержащую классы модуля или обработчика. Если вы используете средства Visual Studio или Visual Studio Express, сначала создайте проект библиотеки классов:

  1. В меню "Файл" выберите "Создать", "Проект ...". В диалоговом окне "Новый проект" (ниже) выберите тип проекта "Visual C#" и выберите "Библиотека классов" в правом списке установленных шаблонов Visual Studio.

    Создание модуля и обработчика IIS7 в Visual Studio

  2. Необходимо добавить ссылку на сборку "System.Web.dll", которая содержит API, используемые для разработки ASP.NET модулей и обработчиков служб IIS. Щелкните правой кнопкой мыши узел "Ссылки" в узле Project в представлении дерева обозревателя решений справа, выберите "Добавить ссылку ..." и на вкладке .NET выберите сборку System.Web версии 2.0 (ниже).

    Добавление ссылки на System.Web.dllДобавление ссылки

Замечание

Вы можете использовать сборку System.Web версии 2.0 в Windows XP и Windows Server 2003, если вы не планируете воспользоваться преимуществами определенных ASP.NET API IIS. Модули и обработчики, скомпилированные со ссылкой на эту сборку, могут быть развернуты и работать в службах IIS в Windows Vista и Windows Server 2008 без проблем. Если вы хотите использовать несколько специфических API IIS ASP.NET в вашем модуле, необходимо разрабатывать на Windows Vista, Windows Server 2008 или получить библиотеку System.Web.dll из .NET Framework 3.5. К определенным API IIS относятся httpServerUtility.TransferRequest, коллекция HttpResponse.Headers, событие HttpApplication.LogRequest и несколько других.

Написание кода: создание простого модуля

Первая задача — создать простой модуль. Далее в статье мы также создадим пример обработчика.

Чтобы создать модуль, определите класс, реализующий интерфейс System.Web.IHttpModule .

  1. Удалите файл "class1.cs", созданный системой проекта, и добавьте новый класс C# с именем MyModule, щелкнув правой кнопкой мыши проект MyIIS7Project в представлении дерева справа, выбрав "Добавить", новый элемент", выбрав "Класс" и введя "MyModule.cs" в поле "Имя".

  2. Импортируйте пространство имен System.Web , чтобы можно было легко получить доступ к типам.

  3. Сделайте класс MyModule реализацией интерфейса IHttpModule и определите элементы интерфейса Dispose() и Init(). Это можно быстро сделать, щелкнув правой кнопкой мыши интерфейс IHttpModule и выбрав параметр "Реализовать интерфейс".

    Простой класс IHttpModule в Visual Studio

    Метод Dispose() предназначен для очистки всех неуправляемых ресурсов детерминированным образом при выгрузке модуля, чтобы ресурсы можно было освободить до завершения экземпляра модуля сборщиком мусора. Этот метод можно оставить пустым большую часть времени.

    Метод Init(Контекст HttpApplication) — это основной интересующий метод. Ее роль — выполнить инициализацию модуля и подключить модуль к одному или нескольким событиям обработки запросов, доступным в классе HttpApplication . Во время обработки запроса модуль будет задействован для каждого из событий, на которые он подписан, позволяя ему осуществлять свои функции. Для этого выполните указанные далее действия.

  4. Подпишитесь на одно или несколько событий обработки запросов, переключив метод в классе модуля на одно из событий в предоставленном экземпляре HttpApplication. Метод должен следовать подписи делегата System.EventHandler . Мы определяем новый метод с именем OnPreExecuteRequestHandler и подключаем его к событию PreRequestRequestHandlerExecute в HttpApplication, которое происходит непосредственно перед тем, как сервер собирается вызвать обработчик запроса.

    public void Init(HttpApplication context) 
    { 
        context.PreRequestHandlerExecute += 
            newEventHandler(OnPreRequestHandlerExecute) 
    }
    

    Реализация IHttpModule.Init() в Visual Studio

    На этом этапе наш модуль настроен для получения события PreRequestHandlerExecute по каждому запросу. Это можно повторить для всех других событий, которые вы хотите получать.

  5. Теперь мы делаем наши модули полезными, что-то, что иллюстрирует использование некоторых ASP.NET API, которые может использовать модуль. Проверьте, указывает ли запрос заголовок реферера, и если он указан, отклоните его, как глупый способ предотвратить ссылки на ваш веб-сайт с других веб-сайтов. Мы сделаем это в нашем методе OnPreRequestHandlerExecute, который вызывается прямо перед запуском обработчика по каждому запросу:

    public void OnPreRequestHandlerExecute (
       Object source, EventArgs e) 
    { 
       HttpApplication app = (HttpApplication)source; 
       HttpRequest    request = app.Context.Request; 
    
       if (!String.IsNullOrEmpty( request.Headers["Referer"] )) 
       { 
           throw new HttpException(403, 
                                                   "Uh-uh!"); 
       } 
    }
    

    <с0>Реализовать IHttpModuleРеализовать IHttpModule

    Замечание

    Экземпляр HttpApplication предоставляется модулю через исходный аргумент и требует приведения. Вы можете получить доступ к остальной части объектной модели запроса из экземпляра HttpApplication, например объекта HttpContext, и содержащегося объекта HttpRequest, представляющего запрос.

Приведенный выше код проверяет, указан ли заголовок ссылки, и если да, он отклоняет запрос с кодом 403 несанкционированной ошибки.

Написание кода: создание простого обработчика

Следующая задача — создать простой обработчик. Ранее в статье мы создали пример модуля— вернитесь назад, если вы хотите прочитать о создании модуля.

Чтобы создать обработчик, необходимо определить класс, реализующий интерфейс System.Web.IHttpHandler (мы также можем реализовать System.Web.IHttpAsyncHandler , если требуется, чтобы страница выполнялось асинхронно). Для этого выполните указанные далее действия.

  1. Если у вас еще нет, удалите файл "class1.cs", созданный системой проекта, и добавьте новый класс C# с именем MyHandler, щелкнув правой кнопкой мыши проект MyIIS7Project в представлении правой части дерева, выбрав "Добавить", новый элемент", выбрав "Класс" и введя "MyHandler.cs" в поле "Имя".

  2. Импортируйте пространство имен System.Web , чтобы можно было легко получить доступ к типам.

  3. Создайте класс MyHandler, реализующий интерфейс IHttpHandler , и определите элементы интерфейса IsReusable и ProcessRequest(). Это можно сделать быстро, щелкнув правой кнопкой мыши интерфейс IHttpHandler и выбрав параметр "Реализовать интерфейс":

    Реализация интерфейса IHttpHandler в Visual Studio

    IsReusable () указывает, можно ли повторно использовать экземпляр обработчика для последующих запросов. В некоторых случаях после обработки запроса обработчик может находиться в неправильном состоянии для обработки другого запроса, особенно если вы сохранили данные о предыдущем запросе в переменных-членах. Обратите внимание, что среда выполнения никогда не будет использовать один и тот же экземпляр обработчика для обработки двух запросов одновременно, даже если он помечен как повторно используемый. Если обработчик не сохраняет состояние каждого запроса в переменных-членах класса и функцию ProcessRequest можно вызывать многократно, установите этому свойству значение true, чтобы разрешить повторное использование.

    Метод ProcessRequest () является основной точкой входа обработчика. Ее роль заключается в обработке запроса, указанного экземпляром HttpRequest , доступным от предоставленного экземпляра HttpContext , и создать соответствующий ответ с помощью экземпляра HttpResponse , который также доступен вне httpContext. Метод ProcessRequest() будет вызываться средой выполнения во время этапа обработки запроса ExecuteRequestHandler, и ТОЛЬКО ЕСЛИ запрос сопоставлен с обработчиком на основе настроенных сопоставлений обработчиков. Это отличается от модуля, который получает уведомления для всех запросов к приложению.

  4. Сначала реализуйте свойство IsReusable . Так как наш обработчик не будет хранить состояние объекта для запроса и сможет поддерживать несколько вызовов ProcessRequest() с разными запросами, мы помечаем его как поддерживающий повторное использование, возвращая true.

    public bool IsReusable
    {
        get { return true; }
    
  5. Наконец, давайте реализуем метод ProcessRequest(), чтобы наш обработчик действительно выполнял полезные действия. Чтобы оставить вещи хорошими и простыми, наш обработчик вернет текущее время на сервере, при необходимости позволяя указать часовой пояс в строке запроса. Наша цель заключается в том, чтобы запросить URL-адрес, например http://myserver/time.tm, и получить текущее время на сервере. Кроме того, мы сможем получить Универсальное Координированное Время, запросив http://myserver/time.tm?utc=true. Вот наша реализация:

    public void ProcessRequest(HttpContext context) 
    { 
        DateTime dt; 
        String useUtc = context.Request.QueryString["utc"]; 
        if (!String.IsNullOrEmpty(useUtc) && 
                useUtc.Equals("true")) 
        { 
            dt = DateTime.UtcNow; 
        } 
        else 
        { 
            dt = DateTime.Now; 
        } 
        context.Response.Write( 
            String.Format( "<h1>{0}</h1>", 
                           dt.ToLongTimeString() 
                           ) ); 
    }
    

    Мы используем коллекцию HttpRequest.QueryString для получения переменной QueryString и записи текущего времени для ответа с помощью метода HttpResponse.Write . Это просто пример типов действий, которые вы можете сделать в обработчике- класс HttpRequest предоставляет гораздо больше сведений о запросе, а класс HttpResponse предоставляет ряд различных способов формирования ответа, возвращаемого клиенту.

    Реализация IHttpHandler.ProcessRequest в Visual Studio

Обработчик завершен.

Завершение кода: компиляция модуля или обработчика

Теперь, когда у нас реализован модуль и обработчик, мы можем скомпилировать их в сборку, которую ASP.NET может загрузить во время выполнения. Если вы используете Visual Studio или Visual Studio Express, скомпилируйте проект непосредственно из средства, нажав клавиши CTRL-SHIFT-B или щелкнув проект правой кнопкой мыши и выбрав "Сборка".

Сборка .DLL будет создана в <папке ProjectDirectory>\bin\debug, вместе с файлом символов .PDB, который можно использовать для отладки сборки на сервере, включая строки исходного кода в исключениях во время этапа отладки вашего проекта.

Если вы отправляете сборку на рабочий сервер, обязательно измените конфигурацию решения на "Выпуск", щелкнув правой кнопкой мыши узел решения, выбрав Configuration Manager и изменив тип на Debug. Отправьте релизную версию сборки (не включая файл PDB) — это удалит данные отладки из сборки и проведет оптимизацию, что приведет к ускорению работы кода.

Если вы не используете Visual Studio, скомпилируйте проект с помощью компилятора командной строки C#, включенного в среду выполнения Framework. Чтобы скомпилировать проект, откройте командную строку (обязательно запустите командную строку с параметром "Запуск от имени администратора", если вы находитесь в Windows Vista или Windows Server 2008):

> %windir%\Microsoft.NET\Framework\v2.0.50727\csc.exe /t:library /out:MyIIS7Project.dll /debug \*.cs /r:System.Web.dll

Это создает файлы MyIIS7Project.DLL и MyIIS7Project.PDB. Если вы хотите создать версию выпуска сборки, опустите переключатель /debug и включите параметр /o для оптимизации сборки.

Развертывание сборки на сервере

Теперь, когда мы реализовали пользовательский модуль и обработчик, мы развертываем их в нашем веб-приложении. Существует несколько способов развертывания модуля или обработчика в приложении, а также ряд вариантов конфигурации, которые можно использовать для настройки развертывания в соответствии с вашими потребностями. Мы проиллюстрируем самые простые шаги развертывания ниже. Дополнительные сведения о параметрах развертывания и конфигурации, включая развертывание модуля или обработчика для всего сервера, см. в следующей статье серии: развертывание модулей IIS и обработчиков (в ближайшее время).

В следующих шагах предполагается, что вы развертываете модуль и обработчик в существующем приложении на сервере IIS. Если у вас нет созданного приложения, используйте корневое приложение веб-сайта по умолчанию, которое обычно находится по адресу %systemdrive%\inetpub\wwwroot. В приведенном ниже примере мы развернем модуль и обработчик в приложении с именем myiis7project, расположенном на веб-сайте по умолчанию.

Чтобы развернуть модуль и обработчик, сначала сделайте сборку, содержащую их реализацию, доступной приложению ASP.NET:

  1. Скопируйте сборкуMyIIS7Project.dll, скомпилированную ранее, в каталог /BIN, расположенный в корне приложения. Если этот каталог не существует, создайте его.

  2. Настройте модуль и обработчик для загрузки в приложение. Откройте средство администрирования IIS7 с помощью меню "Пуск", введите inetmgr.exe в поле запуска или поиска и нажмите клавишу ВВОД. В инструменте дважды щелкните на узле сервера в столбце представления дерева слева, затем разверните узел "Сайты", и дважды щелкните на сайте или приложении, к которому вы хотите добавить ваш модуль и обработчик.

  3. Щелкните значок компонента "Модули", а затем щелкните действие "Добавить управляемый модуль ..." и в результирующем диалоговом окне введите имя модуля (произвольное) и полный тип модуля "MyIIS7Modules.MyModules.MyModule". Обратите внимание, что вы также можете выбрать тип в раскрывающемся списке, так как средство автоматически загружает сборку в корзину и обнаруживает типы, реализующие интерфейс IHttpModule. Нажмите кнопку ОК, чтобы добавить модуль.

    Добавление модуля IIS7

  4. Добавьте обработчик, дважды щелкнув узел сайта или приложения и выбрав значок функции "Сопоставления обработчиков". Затем щелкните действие "Добавить управляемый обработчик", а в результирующем диалоговом окне укажите "time.tm" для пути, "MyIIS7Modules.MyHandler" для типа и "MyHandler" для имени (произвольно). Опять же, обратите внимание, что тип присутствует в раскрывающемся списке, так как средство администрирования автоматически обнаружило этот тип в сборке. Нажмите кнопку ОК, чтобы добавить обработчик.

    Добавление обработчика IIS7

Конфигурация приложения, созданная приведенными выше действиями, настраивает модуль MyModule для загрузки в приложение (что позволяет запускать его для всех запросов) и сопоставляет обработчик MyHandler для обработки запросов к URL-адресу time.tm внутри приложения.

Обратите внимание, что эта конфигурация позволяет модулю и приложению запускаться только в приложениях интегрированного режима IIS. Если вы хотите, чтобы модуль и обработчик также выполнялись в классических приложениях в службах IIS, а также в более ранних версиях IIS, необходимо также добавить классическую ASP.NET конфигурацию для модуля и обработчика. Кроме того, при выполнении в классическом режиме IIS или более ранних версиях IIS, вашему обработчику требуется создать сопоставление скриптов, связывающее расширение .tm с ASP.NET в картах скриптов IIS, и ваш модуль выполняется только для запросов к расширениям, сопоставленным с ASP.NET. Дополнительные сведения об этом см. в разделе "Развертывание модулей IIS и обработчиков" (в ближайшее время).

Вы также можете добавить модуль и обработчик с помощью средства командной строки IIS, AppCmd.exeили управления конфигурацией IIS из скрипта или управляемого кода или путем размещения конфигурации непосредственно в файл web.config . Эти дополнительные параметры подробно рассматриваются в развертывании модулей и обработчиков IIS (в ближайшее время).

Тестирование модуля и обработчика

Мы развернули и настроили модуль или обработчик. Теперь, чтобы протестировать их:

  1. Проверьте наш обработчик, выполнив запрос на "time.tm" в нашем приложении. В случае успешного выполнения на сервере отображается текущее время. Отправьте запрос вашему приложению, например http://localhost/myiis7project/time.tm, так как мы развернули обработчик в приложении myiis7project на веб-сайте по умолчанию.

    Если обработчик правильно развернут в этом приложении, на сервере отображается текущее время:

    Тестирование обработчика IIS7

    Кроме того, попробуйте запросить http://localhost/myiis7project/time.tm?utc=true, чтобы отобразить время по UTC.

  2. Проверьте модуль. Создайте простую html-страницу с именемpage.html в приложении, которая ссылается на URL-адрес /time.tm :

    page.html

    <html>
      <body>
          <a href="time.tm">View current server time</a>
      </body>
    </html>
    

    Затем отправьте запрос на http://localhost/myiis7project/page.html для отображения ссылки. Щелкнув ссылку, вы увидите ошибку:

    Тестирование модуля IIS7

    Возникает вопрос, занимались ли мы уже запросом этого же URL-адреса и успешно получили время. Это связано с тем, что наш модуль настроен на отклонение запросов к приложению, указывающего заголовок ссылок, который добавляется браузером всякий раз, когда пользователь щелкает ссылку, чтобы перейти на веб-сайт, а не просто вводить URL-адрес в браузере напрямую. Таким образом, когда вы запросили URL-адрес напрямую, вы смогли получить к нему доступ, однако при переходе по ссылке с другой страницы ваш запрос был отклонен нашим модулем.

Сводка

В этой статье мы проиллюстрировали основные шаги по разработке модуля IIS и обработчика с помощью знакомых API-интерфейсов ASP.NET и их развертывания в приложении. Мы также обсудили варианты, которые у вас есть для среды разработки, и как решить, когда нужно создать модуль и обработчик. Сведения, приведенные в этой статье, позволяют создавать первые модули и обработчики для расширения возможностей приложений IIS.

Вы также можете просмотреть пример модуля, который обеспечивает базовую проверку подлинности через поставщиков членства ASP.NET в Разработке модуля с использованием .NET.

Не забудьте ознакомиться с дополнительными примерами того, как управляемые модули и обработчики IIS могут добавить значение в приложения, а также скачать их для приложения, перейдя к запросам перенаправления в приложение с модулем HttpRedirection, Получить хорошие списки каталогов для веб-сайта IIS с помощью DirectoryListingModule и отображать красивые значки файлов в приложениях ASP.NET с помощью IconHandler.