IIS & ASP.NET: Вгляд изнутри

1 комментарий

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

ISAPI-расширения

Разные типы запросов (имеются ввиду расширения, например, .html, .aspx) IIS (Internet Information Services) сервер обрабатывает по разному. Например, расширения .html IIS сервер может обработать сам. Для обработки таких расширений как .aspx, .asmx, .ashx используется специальный компонент ISAPI-расширение (Internet Server Application Programming Interface), в данном случае aspnet_isapi.dll, которое используется как в IIS5 так и IIS6. Связать новый тип расширения файла с модулем ISAPI можно в настройках IIS.
Websise configuration

От IIS до ASP.NET

Процесс обработки клиентского запроса на сервере начинается с драйвера Http.sys, который прослушывает входящие HTTP-запросы. Для наглядности схема обработки запроса показана на следующем рисунке.

IIS до ASP.NET

IIS5
В данной версии IIS сервера все расширения выполняются в рамках процесса inetinfo.exe. Для взаимодействия с расширениями используются именованые каналы (named pipes), что, сообственно, не повышает производительности. В связи с тем, что при обработке запроса приходится пересекать границы нескольких процессов, создаются дополнительные накладные расходы. Да и загрузка в контекст процесса inetinfo.exe всех расширений может привести к сбою сервера в случае выхода из строя одного из них.

IIS6
Начиная с Windows 2003 драйвер драйвера Http.sys был интегрирован на уровне ядра Windows. В Windows 2003 также был добавлен Web Administration Service (WAS), который проверяет расширения запросов. Если запрос предназначается ASP.NET-приложению (.aspx, .asmx, .ashx-расширения), WAS создает рабочий процес w3wp.exe и передает в него запрос, в ином случае запрос передаётся в IIS. Благодаря этому обработка запроса происходит быстрее, потому что нет лишних обращений через границы процессов.

После создания рабочего процесса в него загружается среда выполнения .NET, именно рабочий процесс является хостом CLR. После того, как CLR была запущена и сконфигурирована нужным образом, происходит вызов метода ISAPIRuntime.ProcessRequest, который можно сказать и является точкой входа в ASP.NET. Данный метод создает обьект класса HttpWorkerRequest, который потом передаётся в статический метод HttpRuntime.ProcessRequest.
На данный момент существуют три класса, реализующие HttpWorkerRequest.

Класс Описание
ISAPIWorkerRequestOutOfProc ASP.NET работает с IIS 5.0
ISAPIWorkerRequestInProcForIIS6 ASP.NET работает через IIS 6.0 (под Windows 2003)
ISAPIWorkerRequestInProc
ASP.NET работает без IIS 6.0 (под Windows 2003)


Ну а далее класс HttpRuntime создаёт обьект HttpContext. HttpContext в свою очередь, создаёт HttpRequest, HttpResponse. После этого через фабрику HttpApplicationFactory создается новый экземпляр HttpApplication. В него загружается его состояние, то есть объект класса HttpApplicationState. Далее выполняется инициализация HttpApplication.

Inside ASP.NET

Затем запросы пересылаюся на HTTP-модули, которые могут выполнить предварительную обработку перед запуском обработчика. После выполнения обработчика запрос снова пересылается на модули, которые могут выполнить заключительную обработку.
После того, как запрос был полностью обработан, экземпляр HttpApplication может быть помещён в пул, если на момент помещения размер пула не превысил 100 экземпляров (интересно почему данное число прописано хардкодом в классе HttpApplicationFactory?!), иначе все ресурсы, используемые этим обьектом, освобождаются, в том числе и Http-модули. У каждого из них вызывается метод Dispose.

Модули HTTP

Одним из средств расширения, которое предоставляет ASP.NET, являются HTTP-модули. С помощью HTTP-модулей можно подписаться на события, которые генерит класс HttpApplication и таким образом управлять обработкой HTTP-запросов. Для реализации сообственного HTTP-модуля нужно реализовать интерфейс

[code=c#]public interface IHttpModule

{
    void Dispose();
    void Init(HttpApplication context);
}[/code] В методе Init можно подписаться на события, которые генерирует класс HttpApplication.
 

Событие
Описание
BeginRequest Вызывается при поступлении нового запроса
AuthenticateRequest Запрос готов для выполнения аутентификации
PostAuthenticateRequest Вызывается после того, как модуль безопасности установил личность пользователя.
AuthorizeRequest Запрос готов для выполнения авторизации
PostAuthorizeRequest Вызывается после того, как был авторизирован пользователь для текущего запроса
ResolveRequestCache Вызывается после события авторизации, чтобы модули кэширования обрабатывали запрос из кэша
PostResolveRequestCache Происходит, когда ASP.NET обходит выполнение текущего обработчика событий и позволяет модулю кэширования обработать запрос из кэша
PostMapRequestHandler Вызывается после того, как ASP.NET связало текущий запрос подходящим HttpHandler'ом
AcquireRequestState Используется для восстановления текущего состояния (например, состояние сессии) для текущего запроса. (После этого события становится доступной сессия)
PostAcquireRequestState Происходит, когда состояние запроса (например, состояние сессии), было получено
PreRequestHandlerExecute Вызывается перед тем, как запрос начнёт обрабытывать HttpHandler.
PostRequestHandlerExecute Вызывается после того, как запрос обработал HttpHandler.
ReleaseRequestState Вызывается после того, как ASP.NET закочило обработку запроса. Оповещает модули состояния о необходимости сохранить данные состояния запроса.
PostReleaseRequestState Происходит, когда ASP.NET закончило выполнение всех обработчиков событий данные состояния запроса были сохранены
UpdateRequestCache Сообщает, что вся обработка запроса завершена и ответ сервера может быть закэширован.
PostUpdateRequestCache Вызывается, когда ответ сервера был закэширован.
EndRequest Последнее событие из цепочки, которое сигнализирует о завершении обработки запроса.

 Следующие события вызываются в неопределённом порядке:

Событие
Описание
PreSendRequestHeaders Вызывается перед отправкой Http-заголовков клиенту
PreSendRequestContent Вызывается перед отправкой содержимого ответа сервера коиента
Error Сигнализирует о необработанном исключении


Чтобы HttpApplication знал о существовании модуля, его необходимо зарегистрировать в web.config.

Пример регистрации HTTP-модуля:
[code=xml]<httpModules>
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions"/>
 </httpModules>[/code]

Обработчики HTTP

Другим средством расширения ASP.NET являются HTTP-обработчики (HttpHandler), которые обрабатывают определённый тип запросов. Чтобы создать свой обработчик нужно реализовать интерфейс
[code=c#]public interface IHttpHandler
{
     bool IsReusable { get; }
     void ProcessRequest(HttpContext context);
}[/code]Метод ProcessRequest выполняет непосредственную обработку запроса, а свойсто IsReusable указывает на то, может ли экземпляр даного класса использоваться повторно для других запросов. При IsReusable=false каждый раз будет создаваться новый экземпляр. Как и в случае с HTTP-модулями, HTTP-обработчики нужно зарегистрировать в конфигурационном файле. Пример:
[code=xml]<httpHandlers>
    <remove verb="*" path="*.asmx"/>
    <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions" validate="false"/>
</httpHandlers>[/code]Параметр path задает маску ресурсов, запросы к которым будут обрабатываться данным обработчиком. Verb задает типы HTTP-запросов, которые будут перенаправляться обработчику, например, "GET", "POST", "*" (включает любые типы запросов). Атрибут type указывает имя класса обработчика.
В корневом файле web.config (%SystemRoot%\Microsoft.NET\Framework\v%CLRVersion%\CONFIG) определены основные HTTP-обработчики:
[code=xml]<httpHandlers>
    <add verb="*" path="*.rules" type="System.Web.HttpForbiddenHandler" validate="true"/>
    <add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="True"/>
    <add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
    <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
    <add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>
    <add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    <add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    <add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    <add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    <add path="*.browser" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    <add path="*.sitemap" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    <add path="*.dll.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
    <add path="*.exe.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
    <add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    <add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
    ....
</httpHandlers>[/code]

Примечание

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

Ссылки по теме:

http://www.rsdn.ru/article/dotnet/insideaspnet.xml - когда этот пост был уже на половину готов, я обнаружил вот эту статью на RSDN. Поэтому, если интересно более детальное описания взаимодействия IIS и ASP.NET, рекомендую к прочтению.
http://www.15seconds.com/Issue/020417.htm
http://www.theserverside.net/tt/articles/showarticle.tss?id=IIS_ASP
http://www.programmersheaven.com/2/a-low-level-look-at-the-asp-page-2     

Что означает дружественные сборки?

2 коментари(и/ев)

Что означает дружественные сборки?Как известно, чтобы получить доступ к классу из другой сборки, этот класс должен быть обьявлен как public. Однако такие действия не всегда являются лучшим решением, так как в результате классом может воспользоваться кто угодно. Существует и другой модификатор доступа  - internal. Пометив класс как internal, область его видимости ограничивается сборкой в которой он обьявлен. Иногда же возникает необходимость объединить эти два подходы, то есть класс должен быть видим только внутри сборки, где он определён, и в некоторых случаях вести как public. Хорошим пример может послужить разбиение приложения на слои (layer), где каждому слою соответствует отдельная сборка. До появления .NET Framework 2.0 единственным выходом из этой ситуации было определения класса как public, но с выходом последнего появился специальный атрибут InternalsVisibleTo, который позволяет делать сборки "дружественными".

Например, у нас есть сборка А, классы которой помечены как internal. Для того чтобы сборка В могла обращаться к internal классам сборки А, в последнюю нужно добавить атрибут

[code=c#][assembly: InternalsVisibleTo("'имя сборки В', PublicKey='публичный ключ'")].[/code]

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

PS: использовать данный атрибут можно и в юнит-тестах, когда необходимо протестировать internal методы. Кстати, майкрософтовцы и сами широко используют данный атрибут, как пример сборка System.Data, посмотрите рефлектором.

Блог умер?!

7 коментари(и/ев)

Блог умер?!Как все могли заметить, последний месяц вышел совсем непродуктивным (3 поста за ноябрь - это слишком мало). Но этому есть ряд причин, хотя последние, как по мне, скорее отмазка. Главное чем я занимался - это готовился к экзамену 70-536 Microsoft .NET Framework - Application Development Foundation.

Так сложилось, что после сдачи в октябре экзамена 70-528, начальство порекомендовало сдать ещё один. Зачем?! Сложный вопрос... Возможно, чтобы просто оттянуть повышение зарплаты, надеясь на то, что следующий экзамен я соберусь сдавать не в скором времени. А возможно действительно во внимание принимается только получение статуса Microsoft Certified Technology Specialist (MCTS). Вообщем, ответы на все вопросы я получу в ближайшем будущем, так как уже через несколько дней мне предстоит сдать второй экзамен (70-536). Вот тогда-то всё и станет на свои места. Пока я надеюсь на лучшее и то, что было обещано, будет выполнено.

По экзамену. Подготовка к этому экзамену выдалась на много интересней. Я наконец-то прочитал книгу Рихтера "CRL via C#", которую купил года два назад. Это мне принесло наибольшее удовольствие. Изо всех книг по .NET Framework, которые есть у меня (2 издания Троелсена, Дейтел и т.д.) - эта на голову выше. Как по мне, она достойна внимания каждого .NET-разработчика.

Как показала подготовка, за более чем два года работы на .NET Framework, мне приходилось использовать далеко не все его возможности. 100%-новой темой для меня оказалась Code Access Security (CAS), до экзамена я даже и не догадывался об существовании таких возможностей. Наконец-то более детально разобрался с потоками, синхронизацией доступа к данным на основе блокировок, асинхронной моделью программирования, доменами, отражением, вообщем, со всем, для чего раньше нехватало времени.

Как и предидущая книга по 70-528 от Майкрософта, для 70-536 экзамена оказалась не лучше. К сожалению, её всё-таки пришлось читать, так как некоторый материал был изложен только в ней. 

На протяжении всего времени, для лучшего запоминания материала, составлял краткие заметки, которых в итоге собралось на 14 вордовских страниц. В ближайшем будущем постараюсь довести их до ума и выложить на блоге. Так же насобирал порядка 30 интересных вопросов по основам .NET Framework, на которых, сообственно, и собираюсь сконцентрировать свое внимание.

PS: блог снова оживает, я надеюсь.... :)

Использование одного файла AssemblyInfo.cs для всех проектов

Комментарии отсутствуют

Зачем это нужно?
В том случае, когда solution состоит из нескольких проектов и необходимо для всех сборок вручную поменять версию, задача превращается в рутинную работу. Если же выполнить ниже указанные действия, то изменять версию придётся только в одном файле.

Как это сделать?
1. Создаём AssemblyInfo.cs и ложим его в общую папку.
2. Добавляем существующий файл в каждый проект как ссылку (см. рисунок ниже).

  Использование одного файла AssemblyInfo.cs для всех проектов

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

Экзамен 70-528 Microsoft .NET Framework 2.0 - Web Based Client Development. Отчёт

2 коментари(и/ев)

MCP, Microsoft certified professionalНаконец-то это событие сбылось. Вчера сдал экзамен 70-528 Microsoft .NET Framework 2.0 – Web Based Client Development. Набрал немало-немного - 965 балов из 1000 возможных. Хочу поделится своими впечатлениями. Далее обо всём по порядку.

 

Предисловие.
Исторически сложилось, что наша контора (ISM Ukraine) сертифицирует своих сотрудников в БМС Консалтинг. К сожалению, в моем случае произошло исключение, так как БМС Консалтинг не работал по техническим причинам и сдать экзамен раньше ноября возможности не было. Я же в свою очередь не хотел откладывать это событие на потом и моё руководство пошло мне навстречу, решив поискать другой сертификационный центр. Другим сертификационным центром был избран Инком и в течении следующей недели рокуводство улаживало проблемы с документами. Этот процесс настолько растянулся, что я до последнего момента сомневался в позитивном решении этого вопроса. К счастью, всё закончилось хорошо и как я и просил экзамен был призначен на 23 октября.

Несколько слов об компании Инком
На данный момент компания Инком не сотрудничает с Прометрик (международная система тестирования, имеющая договор с Майкрософт), поэтому пройти тест 70-528 непосредственно у них пока возможности нет. Как я выяснил в процессе переписки с саппортом Инкома, центр тестирования Prometric у них откроется в течение месяца, а пока они отправляют своих клиентов для сдачи экзаменов Майкрософт к своим партнёрам. Таким партнёром в моём случае оказался Квазар-Микро.

Квазар-Микро

Зная не по наслышке о пробках в Киеве, на поиски Квазар-Микро я отправился заранее и в результате добрался до места назначения за час до установленого времени. Как оказалось компания Квазар-Микро занимает немалую площадь и мне пришлось немного походить в поисках нужного мне здания. Пройдя процедуру регистрации, я попал к нужному мне человеку. Хотя на часах ещё не было 11:00, сотрудница Квазар-Микро не заставила меня ждать и начала процедуру подготовки в экзамену. По ходу действия мне пришлось выложить запрещенные для использования устройства: телефон и флешку. Так подготовка занимает некоторое время, мне было предложено попить кофе (чаю) в специально отведённом месте. В добавок к чаю ещё предлагалось печенье. Такое гостепреимство не могло не поднять настроение.

Экзамен
Экзамен проводился в специально отведённом месте, оборудованном на 4-5 человек (точно не помню). Так как это был мой первый экзамен сначала пришлось потренироваться в целях обучения работы с программой. Лишь после этой процедуры я приступил к сдаче целевого экзамена. И тут-то наступило полное разочарование. Со всеми вопросами, как оказалось, я был знаком. Притом настолько знаком, что отвечал практически не в читываясь в вопросы. Последние полностью совпадали с вопросами в Braindump'ах, о месте расположения которых я упоминал в одном из предидущих постов. Самое смешное, что даже ответы были приведены в таком же порядке. Поэтому и не странно, что я потратил всего лишь 25-30 мин. вместо 180 отведённых. Как оказалось допустился нескольких ошибок, сколько именно сказать сложно, знаю только, что промахнулся в нелюбимой мной теме "Creating ASP.NET Mobile Web Applications".

Итоги
Сложность, вернее её полное отсутствие, в сдаче майкрософтовских экзаменов меня разочаровала. Теперь для меня это не показатель. И если раньше на ряду с разработанными проектами экзамены Майкрософта играли важную роль, то надалее в определении "крутости" разработчика я их не буду иметь ввиду, хотя вернее "буду иметь" ввиду :). Конечно, это только моё мнение и каждый пусть для себя делает свои выводы. Позитивным моментом в сдаче экзамена вижу только непосредственно саму подготовку. Ведь то время, что я потратил не прошло зря, и знания, которые я приобрёл, ни в коем случае не помешают.

Следующая страница