Desenvolver módulos e manipuladores do IIS 7.0 com o .NET Framework
por Mike Volodarsky
Visão geral
Este artigo e uma introdução ao desenvolvimento de recursos de servidor Web do IIS 7.0 e versões superiores com base no .NET Framework. Este artigo demonstra:
- Como decidir se deseja desenvolver um módulo ou manipulador do IIS
- Como configurar seu ambiente de desenvolvimento com o Visual Studio, Visual C# Express ou ferramentas de linha de comando fornecidas com o .NET Framework
- Como criar seu primeiro projeto
- Como desenvolver um módulo e manipulador simples
- Como implantar um módulo e manipulador simples em um servidor do IIS
Para ver alguns módulos e manipuladores gerenciados do IIS no mundo real e baixá-los para seu aplicativo, visite Redirecionar solicitações para seu aplicativo com o módulo HttpRedirection, Obter listagens de diretório de boa aparência para seu site do IIS com DirectoryListingModule e Exibir ícones de arquivo bonitos em seus aplicativos ASP.NET com IconHandler.
Introdução: desenvolver recursos do IIS com o ASP.NET
As versões do IIS anteriores ao IIS 7.0 apresentavam uma API C, chamada ISAPI, como uma API de extensibilidade primária para a criação de recursos de servidor Web. O IIS 7.0 e versões posteriores foram reprojetados desde o início para fornecer uma nova API C++, na qual todos os recursos prontos para uso são baseados, para permitir a extensibilidade completa do runtime do servidor Web.
Além disso, o IIS pela primeira vez também fornece uma API do .NET de fidelidade total para estender o servidor Web, aproveitando a integração total com o ASP.NET 2.0. Para você, isso significa que agora você pode estender o IIS com novos recursos de servidor Web criados com as conhecidas APIs do ASP.NET 2.0. Da mesma forma, você pode usar os módulos e manipuladores ASP.NET 2.0 existentes no IIS, aproveitando a integração ao ASP.NET para aumentar a eficiência do seu aplicativo sem precisar escrever nenhum novo código. Para saber mais sobre integração ao ASP.NET no IIS, confira ASP.NET Integração ao IIS 7.
Ferramentas do comércio: decidir sobre seu ambiente de desenvolvimento
Para criar módulos e manipuladores do IIS, use qualquer ambiente que permita desenvolver e compilar assemblies .NET. Algumas das opções comuns são:
- Visual Studio 2005. Como alternativa, você também pode baixar a versão beta mais recente do Visual Studio 2008.
- Visual C# 2005 Express Edition, que você pode baixar gratuitamente (ou outras ferramentas Express, incluindo o Visual Basic 2005 Express).
- O compilador de linha de comando C# (csc.exe) incluído no runtime do .NET Framework (para outras linguagens, você precisará baixar o SDK), além do seu editor de código-fonte favorito.
Os exemplos neste artigo usam C#, embora seja possível desenvolver componentes do IIS em qualquer outra linguagem .NET com suporte (exceto C++ gerenciado). O artigo ilustra como desenvolver componentes de extensibilidade do IIS com todos os três ambientes acima.
Observação
Como o IIS aproveita as APIs do ASP.NET existentes para sua extensibilidade do .NET, você pode desenvolver módulos e manipuladores .NET do IIS com o .NET Framework 2.0 no Windows XP® e no Windows Server® 2003. No entanto, se você planeja usar uma das várias novas APIs do ASP.NET adicionadas para dar suporte aos novos recursos do IIS, será preciso desenvolver no Windows Vista® ou obter a versão do System.Web.dll no Windows Vista ou a versão mais recente do .NET Framework 3.5 para compilar o código.
Duas maneiras de estender o IIS: Módulo vs. Manipulador
Os recursos do servidor Web do IIS são divididos em duas categorias: módulos e manipuladores.
Um módulo, semelhante ao filtro ISAPI em versões anteriores do IIS, participa do processamento de cada solicitação para alterá-la ou adicionar algo a ela de alguma forma. Exemplos de alguns módulos prontos para uso no IIS incluem módulos de autenticação, que manipulam o status de autenticação da solicitação, módulos de compactação, que compactam a resposta de saída e módulos de log, que registram informações sobre a solicitação nos logs de solicitação.
O módulo é uma classe .NET que implementa a interface System.Web.IHttpModule do ASP.NET e usa as APIs no namespace System.Web para participar de um ou mais fases de processamento de solicitações o ASP.NET.
Um manipulador, semelhante à extensão ISAPI em versões anteriores do IIS, é responsável por manipular a solicitação e produzir a resposta para tipos de conteúdo específicos. A principal diferença entre o módulo e o manipulador é que o manipulador normalmente é mapeado para um caminho ou extensão de solicitação específica e dá suporte ao processamento de um recurso de servidor específico ao qual esse caminho ou extensão corresponde. Exemplos de manipuladores fornecidos com o IIS incluem ASP, que processa scripts ASP, o manipulador de arquivos estáticos, que serve arquivos estáticos, e o PageHandler do ASP.NET, que processa páginas ASPX.
O manipulador é uma classe .NET que implementa a interface System.Web.IHttpHandler ou System.Web.IHttpAsyncHandler do ASP.NET e usa as APIs no namespace System.Web para produzir uma resposta HTTP para conteúdo específico ao que ele dá suporte.
Ao planejar o desenvolvimento de um recurso do IIS, a primeira pergunta a ser feita é se o recurso é responsável por atender a solicitações a uma URL/extensão específica ou se aplica a todas/algumas solicitações com base em regras arbitrárias. No primeiro caso, você deve ser um manipulador e, no segundo, um módulo.
Este artigo demonstra a criação de um módulo e de um manipulador simples, as etapas comuns na criação do projeto e na compilação, bem como as etapas específicas para implantá-los no servidor.
Observação
Você não precisa desenvolver um manipulador se estiver desenvolvendo um módulo e vice-versa.
Introdução: criar o projeto do Visual Studio
Para compilar um módulo ou um manipulador, você precisa produzir um assembly .NET (DLL) contendo as classes do módulo/manipulador. Se você estiver usando as ferramentas do Visual Studio ou do Visual Studio Express, a primeira etapa é criar um projeto de biblioteca de classes:
No menu "Arquivo", selecione "Novo", "Projeto…". Na caixa de diálogo Novo Projeto (abaixo), selecione o tipo de projeto "Visual C#" e selecione a "Biblioteca de Classes" na lista à direita de modelos instalados do Visual Studio.
Precisamos adicionar uma referência ao assembly "System.Web.dll" que contém as APIs usadas para desenvolver módulos e manipuladores do ASP.NET e IIS. Clique com o botão direito do mouse no nó "Referências" no nó Projeto no modo de exibição de árvore do gerenciador de soluções à direita, escolha "Adicionar referência…" e, na guia .NET, selecione o assembly System.Web, versão 2.0 (abaixo).
Observação
Você pode usar o assembly System.Web versão 2.0 no Windows XP e Windows Server 2003 caso não planeje aproveitar APIs do ASP.NET específicas do IIS. Os módulos e manipuladores compilados que fazem referência a esse assembly podem ser implantados e operados no IIS no Windows Vista e no Windows Server 2008 sem problemas. Se você quiser usar as poucas APIs do ASP.NET específicas do IIS em seu módulo, deverá desenvolver no Windows Vista, Windows Server 2008 ou obter o assembly System.Web.dll do .NET Framework 3.5. As APIs específicas do IIS incluem HttpServerUtility.TransferRequest, a coleção HttpResponse.Headers, o evento HttpApplication.LogRequest e vários outras.
Escrever código: criar um módulo simples
A primeira tarefa é compilar um módulo simples. Mais adiante no artigo, também compilaremos um manipulador de exemplo.
Para criar um módulo, defina uma classe que implementa a interface System.Web.IHttpModule.
Exclua o arquivo "class1.cs" gerado pelo sistema do projeto e adicione uma nova classe C# chamada MyModule clicando com o botão direito do mouse no projeto MyIIS7Project no modo de exibição de árvore à direita, selecionando "Adicionar", "Novo item", escolhendo "Classe" e digitando "MyModule.cs" no campo Nome.
Importe o namespace System.Web para que possamos acessar facilmente os tipos contidos nele.
Faça com que nossa classe MyModule implemente a interface IHttpModule e defina os membros da interface Dispose() e Init(). Faça isso rapidamente clicando com o botão direito do mouse na interface IHttpModule e escolhendo a opção "Implementar interface":
O método Dispose() tem como objetivos limpar de maneira determinística os recursos não gerenciados quando o módulo está sendo descarregado, para que os recursos possam ser liberados antes que a instância do módulo seja finalizada pelo coletor de lixo. Você pode deixar esse método em branco na maioria das vezes.
O método Init(contexto HttpApplication) é o principal método de interesse. Sua função é executar a inicialização do módulo e conectá-lo a um ou mais eventos de processamento de solicitação disponíveis na classe HttpApplication. Durante o processamento da solicitação, seu módulo será invocado para cada um dos eventos aos quais ele está assinado, permitindo a respectiva execução e realização do serviço. Para fazer isso:
Para assinar um ou mais dos eventos de processamento de solicitação, conecte um método da sua classe de módulo a um dos eventos na instância HttpApplication fornecida. O método deve seguir a assinatura delegada de System.EventHandler. Definimos um novo método, chamado OnPreExecuteRequestHandler, e o conectamos ao evento HttpApplication.PreRequestRequestHandlerExecute, que ocorre antes de o servidor estar prestes a invocar o manipulador da solicitação:
public void Init(HttpApplication context) { context.PreRequestHandlerExecute += newEventHandler(OnPreRequestHandlerExecute) }
Neste ponto, nosso módulo está configurado para receber o evento PreRequestHandlerExecute em cada solicitação. Você pode repetir isso para todos os outros eventos que deseja receber.
Agora fazemos com que nossos módulos realizem algo útil, ilustrando o uso de algumas das APIs do ASP.NET que um módulo poderia usar. Verifique se a solicitação especifica um cabeçalho de referenciador e, se afirmativo, rejeite-o, como uma forma de impedir que as pessoas vinculem seu site em outros sites. Faremos isso em nosso método OnPreRequestHandlerExecute, que é invocado antes que o manipulador seja executado em cada solicitação:
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!"); } }
Observação
A instância HttpApplication é fornecida ao módulo por meio do argumento source e requer conversão. Você pode acessar o restante do modelo de objeto de solicitação da instância HttpApplication, como o objeto HttpContext e o objeto HttpRequest contido que representa a solicitação.
O código acima verifica se o cabeçalho do referenciador foi especificado e, em caso afirmativo, rejeita a solicitação com um código de erro 403 Não autorizado.
Escrever código: criar um manipulador simples
A próxima tarefa é compilar um manipulador simples. Anteriormente no artigo, criamos um módulo de exemplo, volte se você quiser ler sobre como criar um módulo.
Para criar um manipulador, precisamos definir uma classe que implemente a interface System.Web.IHttpHandler (também podemos implementar o System.Web.IHttpAsyncHandler se quisermos que a página seja executada de maneira assíncrona). Para fazer isso:
Caso ainda não tenha o feito, exclua o arquivo "class1.cs" gerado pelo sistema do projeto e adicione uma nova classe C# chamada MyHandler clicando com o botão direito do mouse no projeto MyIIS7Project no modo de exibição de árvore à direita, selecionando "Adicionar", "Novo item", escolhendo "Classe" e digitando "MyModule.cs" no campo Nome.
Importe o namespace System.Web para que possamos acessar facilmente os tipos contidos nele.
Faça com que a classe MyHandler implemente a interface IHttpHandler e defina os membros da interface IsReusable e ProcessRequest(). Você pode fazer isso rapidamente clicando com o botão direito do mouse na interface IHttpHandler e escolhendo a opção "Implementar interface":
IsReusable () indica se a instância do manipulador pode ou não ser reutilizada para solicitações futuras. Em alguns casos, depois de processar a solicitação, seu manipulador pode ficar em um estado inadequado para processar outra solicitação, principalmente se você tiver armazenado dados sobre a solicitação anterior em variáveis de membro. Observe que o runtime nunca usará a mesma instância do manipulador para processar duas solicitações ao mesmo tempo, mesmo que esteja marcado como reutilizável. Se o manipulador não armazenar nenhum estado por solicitação em variáveis de membro e puder ter a função ProcessRequest chamada quantas vezes forem necessárias, torne esse retorno de propriedade true para permitir a reutilização.
O método ProcessRequest () é o ponto de entrada principal do manipulador. Sua função é processar a solicitação especificada pela instância HttpRequest disponível fora da instância HttpContext fornecida e gerar a resposta apropriada usando a instância HttpResponse também disponível fora do HttpContext. O método ProcessRequest() será invocado pelo runtime durante a fase de processamento da solicitação ExecuteRequestHandler e SOMENTE SE a solicitação mapeada para o manipulador for baseada nos mapeamentos de manipulador configurados. Isso é diferente de um módulo que recebe notificações para todas as solicitações ao aplicativo.
Implemente a propriedade IsReusable primeiro. Como nosso manipulador não armazenará nenhum estado de membro para a solicitação e poderá dar suporte a várias chamadas ao método ProcessRequest() com solicitações diferentes, vamos marcá-lo como reutilizável retornando true.
public bool IsReusable { get { return true; }
Por fim, implementaremos o método ProcessRequest() para fazer com que o manipulador realmente faça algo útil. Para manter a simplicidade, nosso manipulador retornará a hora atual no servidor, permitindo como opção que o fuso horário seja especificado na cadeia de caracteres de consulta. Nossa meta é solicitar uma URL, como
http://myserver/time.tm
, e obter a hora atual no servidor. Além disso, para obter o tempo universal coordenado, solicitaremoshttp://myserver/time.tm?utc=true
. Esta é nossa implementação: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() ) ); }
Usamos a coleção HttpRequest.QueryString para recuperar uma variável QueryString e gravamos a hora atual na resposta usando o método HttpResponse.Write. Esta é apenas uma amostra do que é possível fazer com o manipulador: a classe HttpRequest fornece muito mais informações sobre a solicitação e a classe HttpResponse fornece várias maneiras diferentes de moldar a resposta retornada ao cliente.
O manipulador está concluído.
Conclusão do código: compilar o módulo/manipulador
Agora que implementamos o módulo e o manipulador, podemos compilá-los em um assembly para que o ASP.NET carregue no runtime. Se você estiver usando o Visual Studio ou o Visual Studio Express, para compilar o projeto diretamente na ferramenta, pressione "Ctrl-Shift-B" ou clique com o botão direito do mouse no projeto e escolha "Build".
O assembly .DLL será gerado na pasta <ProjectDirectory>\bin\debug, juntamente com o arquivo de símbolos PDB que você pode usar para depurar o assembly no servidor / incluindo linhas de código-fonte em exceções durante a fase de depuração do projeto.
Se você estiver carregando o assembly em um servidor de produção, para alterar a configuração da Solução para "Liberar", clique com o botão direito do mouse no nó da solução, escolha Configuration Manager e altere o tipo para Depurar. Carregue a versão Liberar do assembly (deixe o arquivo PDB para trás). Isso vai remover as informações de depuração do assembly e otimizá-lo, resultando em um código mais rápido.
Se você não estiver usando o Visual Studio, compile o projeto com o compilador de linha de comando C# incluído no runtime da estrutura. Para compilar o projeto, abra um prompt de linha de comando (execute-o com a opção "Executar como Administrador" se você estiver no Windows Vista ou Windows Server 2008):
> %windir%\Microsoft.NET\Framework\v2.0.50727\csc.exe /t:library /out:MyIIS7Project.dll /debug \*.cs /r:System.Web.dll
Isso gera os arquivos MyIIS7Project.DLL e MyIIS7Project.PDB. Se você quiser compilar uma versão de lançamento do assembly, omita a opção /debug e inclua a opção /o para otimizar o assembly.
Implantar o assembly no servidor
Agora que implementamos o módulo e o manipulador personalizados, eles serão implantados em nosso aplicativo Web. Há várias maneiras de implantar um módulo ou manipulador no aplicativo, além de diversas opções de configuração para personalizar a implantação de acordo com suas necessidades. Ilustramos as etapas de implantação mais básicas abaixo. Para conferir uma discussão avançada sobre as opções de implantação e configuração, incluindo como implantar um módulo/manipulador para o servidor inteiro, confira o próximo artigo da série: Implantar módulos e manipuladores do IIS (disponível em breve).
As etapas abaixo pressupõem que você esteja implantando o módulo e o manipulador em um aplicativo existente no servidor do IIS. Se você não criou um aplicativo, use o aplicativo raiz do "Site Padrão" normalmente localizado em %systemdrive%\inetpub\wwwroot
. No exemplo abaixo, implantamos o módulo e o manipulador em um aplicativo chamado "myiis7project" localizado no Site Padrão.
Para implantar o módulo e o manipulador, primeiro disponibilize o assembly que contém a implementação para seu aplicativo ASP.NET:
Copie o assembly MyIIS7Project.dll compilado anteriormente para o diretório /BIN localizado na raiz do aplicativo. Se esse diretório não existir, crie-o.
Configure o módulo e o manipulador a serem carregados no aplicativo. Abra a ferramenta de Administração do IIS7 no menu Iniciar digitando inetmgr.exe na caixa de pesquisa/iniciar e pressionando Enter. Na ferramenta, clique duas vezes no nó de servidor no modo de exibição de árvore à esquerda, expanda o nó "Sites" e clique duas vezes no site ou aplicativo ao qual deseja adicionar o módulo e o manipulador.
Selecione o ícone do recurso "Módulos", clique na ação "Adicionar módulo gerenciado…" e, na caixa de diálogo resultante, digite o nome do módulo (arbitrário) e o tipo de módulo totalmente qualificado "MyIIS7Modules.MyModule". Observe que você também pode selecionar o tipo na caixa suspensa, pois a ferramenta carregará automaticamente o assembly no compartimento e descobrirá os tipos que implementam a interface IHttpModule. Pressione OK para adicionar o módulo.
Para adicionar o manipulador, clique duas vezes no nó do site/aplicativo novamente e selecione o ícone do recurso "Mapeamentos do Manipulador". Depois, clique na ação "Adicionar Manipulador Gerenciado" e, na caixa de diálogo resultante, especifique "time.tm" para o caminho, "MyIIS7Modules.MyHandler" para o tipo e "MyHandler" para o nome (arbitrário). Observe novamente que o tipo pode ser encontrado na caixa suspensa, já que a ferramenta de Administração detectou automaticamente esse tipo no assembly. Pressione OK para adicionar o manipulador.
A configuração do aplicativo gerada pelas ações acima configura o módulo MyModule a ser carregado no aplicativo (o que permite a execução para todas as solicitações) e mapeia o manipulador MyHandler para processar solicitações para a URL time.tm no aplicativo.
Observe que essa configuração permite que o módulo e o aplicativo sejam executados somente em aplicativos do modo Integrado no IIS. Se desejar que o módulo e o manipulador também sejam executados em aplicativos do modo Clássico no IIS e também em versões anteriores do IIS, é preciso também adicionar a configuração Clássica do ASP.NET ao módulo e ao manipulador. Além disso, ao executar no modo Clássico no IIS ou em versões anteriores do IIS, o manipulador exige que você crie um mapa de script mapeando a extensão .tm para o ASP.NET em mapas de script do IIS, e seu módulo é executado apenas para solicitações de extensões mapeadas para o ASP.NET. Para obter mais detalhes sobre isso, consulte Implantar módulos e manipuladores do IIS (disponível em breve).
Você também pode adicionar o módulo e o manipulador usando a ferramenta de linha de comando do IIS, AppCmd.exe, manipulando a configuração do IIS no script ou código gerenciado, inserindo a configuração diretamente no arquivo web.config. Essas opções adicionais são discutidas com mais detalhes em Implantar módulos e manipuladores do IIS (disponível em breve).
Testar o módulo e o manipulador
Implantamos e configuramos o módulo/manipulador. Agora vamos testá-los:
Para testar o manipulador, faça uma solicitação a "time.tm" no aplicativo. Se bem-sucedida, veremos a hora atual no servidor. Faça uma solicitação ao aplicativo, por exemplo
http://localhost/myiis7project/time.tm
, enquanto implantamos o manipulador no aplicativo myiis7project no Site Padrão:Se o manipulador tiver sido implantado corretamente no aplicativo, você verá a hora atual no servidor:
Tente também solicitar
http://localhost/myiis7project/time.tm?utc=true
para exibir a hora em UTC.Teste o módulo. Crie uma página HTML simples chamada page.html no aplicativo vinculada à URL /time.tm:
page.html
<html> <body> <a href="time.tm">View current server time</a> </body> </html>
Depois, faça uma solicitação para que
http://localhost/myiis7project/page.html
exiba o link. Ao clicar no link, o seguinte erro é exibido:Você pode se perguntar se não acabamos de solicitar a mesma URL acima e conseguimos ver a hora. Isso ocorre porque o módulo é configurado para rejeitar solicitações ao aplicativo que especificam um cabeçalho de referenciador, que é adicionado pelo navegador sempre que um usuário clica em um link para acessar seu site em vez de apenas digitar a URL no navegador diretamente. Portanto, quando solicitou a URL diretamente, você pôde acessá-la, mas quando clicou em um link em outra página, a solicitação foi rejeitada pelo nosso módulo.
Resumo
Neste artigo, ilustramos as etapas básicas para desenvolver um módulo e um manipulador do IIS com as APIs conhecidas do ASP.NET e implantá-las no seu aplicativo. Além disso, mostramos as opções disponíveis para o ambiente de desenvolvimento e como decidir quando compilar um módulo em vez de um manipulador. Com as informações deste artigo, você poderá compilar seus primeiros módulos e manipuladores tornando seus aplicativos IIS ainda mais avançados.
Você também pode conferir um módulo de exemplo que habilita a autenticação Básica usando provedores de associação do ASP.NET em Desenvolvendo um módulo usando o .NET.
Confira mais exemplos de como módulos e manipuladores gerenciados do IIS podem agregar valor aos seus aplicativos e baixe-os em Redirecionar solicitações para seu aplicativo com o módulo HttpRedirection, Obter listagens de diretório de boa aparência para seu site do IIS com DirectoryListingModule e Exibir ícones de arquivo bonitos em seus aplicativos ASP.NET com IconHandler.