ASP.NET

Introdução ao projeto Katana

Howard Dierking

Quando o ASP.NET foi lançado em 2002, os tempos eram outros. A Internet ainda estava em um estado de relativa infância, com aproximadamente 569 milhões de usuários gastando uma média de 46 minutos por dia em cerca de 3 milhões de sites. Essas mesmas medidas tiradas apenas 10 anos depois revelam uma Internet com aproximadamente 2,27 bilhões de usuários gastando uma média de 4 horas por dia em 555 milhões de sites (consulte bit.ly/MY7GzO).

Claramente, esse crescimento impulsionou mudanças correspondentes nas necessidades dos desenvolvedores de aplicativos em relação a estruturas subjacentes, ferramentas e tempos de execução que eles utilizam para criar e executar aplicativos Web. Os aplicativos Web modernos devem conseguir evoluir rapidamente, aproveitando muitos componentes e muitas estruturas diferentes, e eles precisam de um pequeno volume de memória para serem executados com eficiência no tempo de execução em larga escala da nuvem.

Garantir que o ASP.NET consiga atender a essas necessidades atuais e futuras é a principal motivação por trás do projeto Katana.

O que é Katana?

As sementes do projeto Katana foram, na verdade, semeadas fora da Microsoft com um projeto de software livre chamado OWIN (Open Web Interface for .NET), uma especificação que define a interação entre servidores Web e componentes de aplicativos (consulte owin.org). Como o objetivo da especificação é estimular um amplo e vibrante ecossistema de componentes de aplicativos e servidores Web com base no Microsoft .NET Framework, ela reduz todas as interações entre servidores e aplicativos a um pequeno conjunto de tipos e uma única assinatura de função conhecida como representante do aplicativo, ou AppFunc:

using AppFunc = Func<IDictionary<string, object>, Task>;

Todo componente em um aplicativo com base em OWIN fornece um representante de aplicativo a um servidor. Os componentes são, então, encadeados em um pipeline, no qual um servidor com base em OWIN envia solicitações por push. A fim de usar recursos de maneira eficiente, todos os componentes no pipeline devem ser assíncronos, e isso é refletido no representante do aplicativo que retorna um objeto Task.

Todos os estados, incluindo o estado do aplicativo, da solicitação, do servidor e assim por diante, são mantidos no objeto IDictionary<string, object> especificado no representante do aplicativo. Essa estrutura de dados, conhecida como dicionário do ambiente, é transmitida de componente para componente à medida que uma solicitação avança pelo pipeline. Ao passo que nenhum dado de chave/valor pode ser inserido no dicionário do ambiente, a especificação do OWIN define chaves para alguns elementos principais de HTTP, conforme exibido na Figura 1.

Figura 1 Chaves de dicionário de ambiente necessárias para uma solicitação HTTP

 

Nome da chave Descrição do valor
"owin.RequestBody" Um Stream com o corpo da solicitação, se houver. Stream.Null pode ser usado como um espaço reservado se não houver nenhum corpo de solicitação.
"owin.RequestHeaders" Um IDictionary<string, string[]> de cabeçalhos de solicitação.
"owin.RequestMethod" Uma cadeia de caracteres contendo o método de solicitação HTTP da solicitação (como GET e POST).
"owin.RequestPath" Uma cadeia de caracteres contendo o caminho da solicitação. O caminho deve ser relativo à “raiz” do representante do aplicativo.
"owin.RequestPathBase" Uma cadeia de caracteres contendo a parte do caminho de solicitação correspondente à “raiz” do representante do aplicativo.
"owin.RequestProtocol" Uma cadeia de caracteres contendo o nome e a versão do protocolo (como HTTP/1.0 ou HTTP/1.1).
"owin.RequestQueryString" Uma cadeia de caracteres contendo o componente de cadeia de caracteres de consulta do URI da solicitação HTTP, sem o “?” à esquerda (com foo=bar&baz=quux). O valor pode ser uma cadeia de caracteres vazia.
"owin.RequestScheme" Uma cadeia de caracteres contendo o esquema de URI usando para a solicitação (como HTTP ou HTTPS).

Definir um conjunto de base de pares chave-valor de dicionário de ambiente permite que muitos autores de estrutura e componente diferentes interoperem em um pipeline do OWIN, sem forçar um acordo sobre um modelo de objeto do .NET específico, como HttpContextBase no ASP.NET MVC ou HttpRequestMessage/HttpResponseMessage na API Web ASP.NET.

Esses dois elementos, o representante do aplicativo e o dicionário do ambiente, formam a especificação do OWIN. O projeto Katana é o conjunto estruturas e componentes com base em OWIN criado e fornecido pela Microsoft.

Os componentes do Katana podem ser visualizados por meio da pilha arquitetônica representada na Figura 2.

Katana Project ArchitectureFigura 2 Arquitetura do projeto Katana

A pilha consiste nas camadas a seguir:

  • Host - O processo que executa o aplicativo e pode ser qualquer coisa, desde IIS ou um executável autônomo até seu próprio programa personalizado. O host é responsável pela inicialização, pelo carregamento de outros componentes do OWIN e pelo desligamento normal.
  • Servidor - Responsável pela associação a uma porta TCP, construindo o dicionário do ambiente e processando as solicitações por meio de um pipeline do OWIN.
  • Middleware - Nome dado a todos os componentes que tratam de solicitações em um pipeline do OWIN. Ele pode abranger desde um simples componente de compactação até uma estrutura completa, como a API Web ASP.NET. E, a partir da perspectiva do servidor, ele é apenas um componente que expõe o representante do aplicativo.
  • Aplicativo - Esse é o seu código. Como o Katana não é uma substituição para o ASP.NET, mas, em vez disso, é uma nova maneira de compor e hospedar componentes, a API Web ASP.NET e os aplicativos do SignalR permanecem inalterados, pois essas estruturas podem participar em um pipeline do OWIN. Na verdade, para esses tipos de aplicativos, os componentes do Katana poderão ser vistos apenas em uma pequena classe de configuração.

Em termos de arquitetura, o Katana é decomposto de forma que cada uma dessas camadas possa ser facilmente substituída, geralmente sem exigir uma recompilação do código. Ao processarem uma solicitação HTTP, as camadas trabalham juntas, de maneira semelhante ao fluxo de dados exibido na Figura 3.

Example of the Data Flow in KatanaFigura 3 Exemplo de fluxo de dados no Katana

Criando um aplicativo Web moderno com o Katana

Os aplicativos Web modernos geralmente têm quatro recursos:

  1. Geração de marcação no lado do servidor
  2. Serviço de arquivo estático
  3. API Web para manipular solicitações AJAX
  4. Mensagens em tempo real

Criar um aplicativo com todos esses quatro recursos exige uma variedade de estruturas diferentes convenientemente especializadas para o recurso relevante. Entretanto, compor um aplicativo a partir dessas estruturas pode ser desafiador e, no momento, exige a hospedagem das diferentes partes do aplicativo em IIS, possivelmente, isolando umas das outras por meio do uso de aplicativos e diretórios virtuais.

Em contrapartida, o Katana permite que você redija um aplicativo Web moderno a partir de uma grande variedade de tecnologias da Web diferentes e, em seguida, hospede esse aplicativo em qualquer local que desejar, em exposição sob um único ponto de extremidade HTTP. Isso fornece vários benefícios:

  • A implantação é fácil porque envolve apenas um único aplicativo, em vez de um aplicativo por recurso.
  • Você pode adicionar outros recursos, como a autenticação, que podem ser aplicados a todos os componentes de downstream no pipeline.
  • Os componentes diferentes, independentemente de serem da Microsoft ou de terceiros, podem funcionar no mesmo estado de solicitação por meio do dicionário do ambiente.

Agora, vamos explorar um aplicativo de exemplo que tem um domínio com o qual você deve estar familiarizado: acompanhamento de bugs. O aplicativo apresentará um conjunto de bugs em diversos estados diferentes — lista de pendências, em funcionamento e concluído — e permitirá que eu mova os bugs entre os estados. E, como muitas pessoas diferentes podem estar gerenciando os bugs simultaneamente, ele atualizará todos os navegadores em tempo real quando o estado de um bug for alterado. Aqui está o que usarei para criar o aplicativo: Nancy (nancyfx.org) para a geração de marcações no lado do servidor e serviço de arquivo estático; API Web ASP.NET (asp.net/web-api) para lidar com as solicitações AJAX; e SignalR (signalr.net) para os serviços de mensagens em tempo real.

Além disso, como não vou gastar muito tempo com marcações e scripts para o cliente do navegador, usarei Knockout.js para separar a marcação HTML dos dados da API Web e do SignalR.

O princípio essencial para ter em mente é que vou compor todas essas estruturas diferentes em um único pipeline do OWIN. Dessa maneira, à medida que novos recursos forem disponibilizados, eu poderei adicioná-los ao aplicativo simplesmente inserindo-os no pipeline.

Introdução

Um dos objetivos do Katana é fornecer a você um controlo preciso sobre os recursos adicionados ao seu aplicativo (e, portanto, sobre o que você gasta em termos de desempenho para processar cada solicitação). Com isso em mente, começarei a criar um novo projeto de aplicativo Web ASP.NET vazio no Visual Studio 2013 Preview, conforme exibido na Figura 4.

A New ASP.NET Web Application Project in Visual Studio 2013 PreviewFigura 4 Um novo projeto de aplicativo Web ASP.NET no Visual Studio 2013 Preview

Os modelos de projeto Web, mesmo os vazios, fornecem um recurso útil no qual, por padrão, são colocados os assemblies compilados diretamente na pasta /bin, em vez de na pasta /bin/debug, como é comum em outros tipos de projetos. O host padrão do Katana procura por assemblies na pasta /bin. Você poderia criar um aplicativo com base no Katana, como uma biblioteca de classes, mas precisaria modificar as propriedades de seu projeto para ficar de acordo com essa estrutura ou fornecer seu próprio carregador de aplicativos personalizado capaz de pesquisar assemblies e tipos em uma estrutura de pastas diferente.

Em seguida, vou escrever o código de geração de marcação no lado do servidor usando a estrutura Web do Nancy.

O Nancy possui uma sintaxe concisa, o que facilita a compilação de sites e serviços com base em HTTP. O mais importante neste exercício é que, da mesma maneira que a API Web ASP.NET, ele não tem nenhuma dependência no System.Web.dll e foi projetado para ser executado em um pipeline do OWIN. As estruturas, como o ASP.NET MVC, têm dependências na System.Web.dll (no momento em que escrevo este artigo), o que as torna menos apropriadas para cenários de hospedagem que não sejam do IIS.

Para a maioria, ao adicionar uma nova funcionalidade ao aplicativo, você começa pela adição de uma pacote NuGet. Saiba mais sobre NuGet em docs.nuget.org. No momento em que escrevi este artigo, muitos dos pacotes em uso aqui eram versões de pré-lançamento e, por isso, você deve se certificar de permitir que pacotes de pré-lançamento sejam exibidos na caixa de diálogo do NuGet.

Para adicionar o Nancy ao aplicativo, eu poderia apenas instalar o pacote NuGet do Nancy. Entretanto, como também desejo executar o Nancy em um pipeline do OWIN, instalarei o pacote Nancy.Owin (nuget.org/packages/nancy.owin). Isso instalará o pacote do Nancy como uma dependência e fornecerá métodos auxiliares adicionais para a configuração do Nancy em meu pipeline do OWIN.

Em seguida, devo criar um módulo do Nancy (semelhante a um controlador MVC, ou Modelo-­Exibição-Controlador) para manipular as solicitações, bem como uma exibição para mostrar algo para o navegador. Este é o código para o módulo (HomeModule.cs): 

public class HomeModule : NancyModule
{
  public HomeModule() {
    Get["/"] = _ => {
      var model = new { title = "We've Got Issues..." };
      return View["home", model];
    };
  }
}

Como é possível observar, o módulo declara que as solicitações direcionadas para a raiz do aplicativo (“/”) devem ser tratadas pelo representante anônimo definido na lambda associada. Essa função cria um modelo que contém o título da página e instrui o Nancy para renderizar a exibição “inicial”, passando o modelo para a exibição. A exibição, mostrada na Figura 5, insere a propriedade de título do modelo nos elementos title e h1 da página.

Figura 5 Home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>@Model.title</title>
</head>
  <body>
    <header>
      <h1>@Model.title</h1>   
    </header>
    <section>
      <h2>Backlog</h2>
      <ul class="bugs" id="backlog">
        <li>a bug</li>
      </ul>
    </section>
    <section>
      <h2>Working</h2>
      <ul class="bugs" id="working">
        <li>a bug</li>
      </ul>
    </section>
    <section>
      <h2>Done</h2>
      <ul class="bugs" id="done">
        <li>a bug</li>
      </ul>
    </section>
  </body>
</html>

Para obter mais informações sobre essas listas, consulte a documentação do Nancy.

Agora que já implementei a funcionalidade Nancy básica, preciso estabelecer um pipeline do OWIN e configurar o módulo do Nancy para participar nesse pipeline. Para isso, preciso primeiro instalar os componentes de host e servidor do Katana; em seguida, devo escrever uma pequena quantidade de código de direcionamento para configurar o pipeline do OWIN e inserir o Nancy nesse pipeline.

Para os componentes de host e servidor do Katana, começarei usando IIS Express e System.Web, pois eles são compreendidos pelo Visual Studio de maneira inerente, além de permitirem uma experiência de F5 suave durante a compilação do aplicativo. Para incorporar o host de System.Web ao projeto, eu devo instalar o Microsoft.Owin.Host.SystemWeb do pacote NuGet (bit.ly/19EZ2Rw).

Os componentes padrão do Katana usam várias convenções diferentes para o carregamento e a execução de aplicativos do OWIN, incluindo a classe de inicialização. Quando um host do Katana carrega um aplicativo do OWIN, ele descobre e executa uma classe de inicialização com base nas seguintes regras (em ordem de precedência):

  • Se o arquivo web.config contiver um appSetting com key=“owin:AppStartup”, o carregador usará o valor da configuração. O valor deve ser um nome do tipo .NET válido.
  • Se o assembly contiver o atributo [assembly: OwinStartup(typeof(MyStartup))], o carregador usará o tipo especificado no valor do atributo.
  • Se nenhuma dessas condições for verdadeira, o carregador verificará os assemblies carregados em busca de um tipo chamado Startup com um método que corresponda à assinatura void Configure(IAppBuilder app).

Para este exemplo, permitirei que o carregador verifique os assemblies em busca da classe. Entretanto, se houver muitos tipos e assemblies diferentes em seu projeto, seria aconselhável usar o atributo appSetting ou de assembly para evitar verificações desnecessárias.

Criarei a classe de inicialização que irá inicializar meu pipeline do OWIN e adicionar o Nancy como um componente do pipeline. Criarei uma nova classe chamada Startup e adicionarei um método de configuração, conforme mostrado a seguir:

public class Startup
{
  public void Configuration(IAppBuilder app)
  {
    app.UseNancy();
  }
}

UseNancy é um método de extensão disponibilizado pelo pacote NuGet Nancy.Owin. Embora seja possível adicionar middleware usando métodos Use mais genéricos do IAppBuilder, muitas bibliotecas de middleware fornecerão esses métodos de extensão úteis que facilitam o processo de configuração.

Neste ponto, você pode executar o projeto no Visual Studio usando F5 e ver que, apesar de ainda não ser absurdamente incrível, você já possui um aplicativo Web totalmente funcional. Neste ponto, o pipeline do OWIN consiste em um único componente, o Nancy, conforme exibido na Figura 6.

A Functional Web Application with a Single Component
Figura 6 Um aplicativo Web funcional com um único componente

Incorporando dados com a API Web ASP.NET

Atualmente, a exibição HTML consiste em marcação estática primária. Agora, vou fornecer aos usuários alguns bugs reais com os quais trabalhar. Para muitos aplicativos Web modernos, a tarefa de entregar dados a um cliente de navegador mudou da estrutura de geração de marcação no lado do servidor (como o módulo do Nancy) para um serviço de API Web separado. Dessa maneira, o navegador carrega a página HTML e imediatamente executa o JavaScript, que busca os dados na API Web e compila dinamicamente a marcação HTML na própria página.

Começarei construindo a API Web usando a estrutura da API Web ASP.NET. Como de costume, a primeira etapa é instalar o pacote NuGet da API Web. Para garantir que seja possível inserir a API Web ASP.NET em meu pipeline do OWIN, vou instalar o pacote Microsoft.Asp­Net.WebApi.Owin (bit.ly/1dnocmK). Esse pacote instalará o restante da estrutura da API Web ASP.NET como dependências. Após a instalação da estrutura, criarei uma API simples, conforme exibido na Figura 7.

Figura 7 BugsController.cs

public class BugsController : ApiController
{
  IBugsRepository _bugsRepository = new BugsRepository();
  public IEnumerable<Bug> Get()
  {
    return _bugsRepository.GetBugs();
  }
  [HttpPost("api/bugs/backlog")]
  public Bug MoveToBacklog([FromBody] int id)
  {
    var bug = _bugsRepository.GetBugs().First(b=>b.id==id);
    bug.state = "backlog";
    return bug;
  }
  [HttpPost("api/bugs/working")]
  public Bug MoveToWorking([FromBody] int id)
  {
    var bug = _bugsRepository.GetBugs().First(b => b.id == id);
    bug.state = "working";
    return bug;
  }
  [HttpPost("api/bugs/done")]
  public Bug MoveToDone([FromBody] int id)
  {
    var bug = _bugsRepository.GetBugs().First(b => b.id == id);
    bug.state = "done";
    return bug;
  }
}

A API contém um método para retornar um conjunto de objetos de bug de um repositório, bem como alguns métodos para mover os bugs entre diferentes estados. Mais informações sobre a API Web ASP.NET podem ser encontradas em asp.net/web-api.

Agora que um controlador da API Web ASP.NET já foi definido, preciso adicioná-lo ao meu pipeline do OWIN existente. Para fazer isso, vou apenas adicionar as linhas a seguir ao método Configuration em minha classe de inicialização:

var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute("bugs", "api/{Controller}");
app.UseWebApi(config);

Da mesma maneira que Nancy, o pacote do OWIN da API Web ASP.NET fornece o método de extensão UseWebApi, facilitando a incorporação da API Web ASP.NET ao meu pipeline do OWIN existente. Agora, o pipeline do OWIN consiste em dois componentes, a API Web ASP.NET e o Nancy, conforme exibido na Figura 8.

The OWIN Pipeline with Two Components
Figura 8 Pipeline do OWIN com dois componentes

À medida que as solicitações chegarem no pipeline, se elas corresponderem a uma das regras de roteamento da API Web ASP.NET, a API Web ASP.NET irá tratar da solicitação e gerar uma resposta. Caso contrário, a solicitação continuará pelo pipeline, onde o Nancy tentará tratar dela. Se nenhum componente do pipeline conseguir lidar com uma solicitação específica, os componentes padrão do Katana retornarão uma resposta HTTP 404.

Embora eu tenha uma API Web ASP.NET em funcionamento, ela não está sendo acessada atualmente pela exibição inicial. Por isso, adicionarei um código para consumir os dados da API Web e gerar uma lista de bugs em cada um dos diferentes estados: lista de pendências, em funcionamento e concluído. Para essa tarefa, vou aproveitar o Knockout.js, uma biblioteca MVVM (Model-View-ViewModel) JavaScript. Mais informações sobre Knockout podem ser encontradas em knockoutjs.com.

Para habilitar a geração de marcação HTML dinâmica no lado do cliente usando Knockout, a primeira coisa que preciso fazer é buscar todos os bugs da API Web ASP.NET e criar um viewModel que o Knockout possa associar a elementos HTML. Isso é mostrado na Figura 9.

Figura 9 Configurando viewModel de bugs

<script>
  $(function () {
    var viewModel;
    $.getJSON('/api/bugs', function(data) {
      var model = data;
      viewModel = {
        backlog: ko.observableArray(
          model.filter(function(element) { return element.state === 'backlog'; })),
        working: ko.observableArray(
          model.filter(function(element) { return element.state === 'working'; })),
        done: ko.observableArray(
          model.filter(function(element) { return element.state === 'done'; })),
        changeState: function (bug, newState) {
          var self = this;
          $.post('/api/bugs/' + newState, { '': bug.id }, function(data){
            self.moveBug(data);
          });
        },
        moveBug: function (bug) {
          // Remove the item from one of the existing lists
          ...
          // Add bug to correct list
          this[bug.state].push(bug);
        }
      };
      ko.applyBindings(viewModel);
    })
  })
</script>

Após o viewModel ser criado, o Knockout poderá gerar e atualizar o conteúdo HTML dinamicamente associando o viewModel a elementos HTML decorados com atributos específicos do Knockout. Por exemplo, a lista de pendências pode ser gerada a partir do viewModel usando os atributos mostrados na Figura 10.

Figura 10 Atributos para a geração da lista de pendências

<section>
  <h2>Backlog</h2>
  <ul class="bugs" id="backlog" data-bind="foreach:backlog">
    <li>
      [<span data-bind="text: id"></span>] <span data-bind="text: title"></span>:
        <span data-bind="text: description"></span>
      <ul>
        <li><a href="#" data-bind="click: $root.changeState.bind($root, $data,
          'working')">Move to working</a></li>   
        <li><a href="#" data-bind="click: $root.changeState.bind($root, $data,
          'done')">Move to done</a></li>   
      </ul>
    </li>
  </ul>
</section>

Adicionando notificações de alteração em tempo real com o SignalR

Neste ponto, tenho um aplicativo Web de página única totalmente em funcionamento. Os usuários podem navegar para a exibição inicial e mover os bugs entre os diferentes estados. Além disso, as tecnologias subjacentes para o nível de funcionalidade atual, o Nancy e a API Web ASP.NET, estão em execução juntas no mesmo pipeline do OWIN.

Vou um pouco mais além, entretanto, e vou permitir que diferentes usuários vejam, em tempo real, as atualizações feitas nos bugs por outros usuários. Para isso, aproveitarei a biblioteca do SignalR, que fornece uma API de cliente e de servidor para o gerenciamento de trocas de mensagens em tempo real entre o navegador e o servidor Web. O SignalR também foi escrito para ser executado em um pipeline do OWIN e, por isso, adicioná-lo ao meu aplicativo existente será trivial.

Usarei um recurso do SignalR chamado Hubs e, embora os detalhes do SignalR estejam além do escopo deste artigo, um Hub permite que clientes e servidores chamem métodos entre si. Para obter uma excelente introdução ao SignalR, consulte bit.ly/14WIx1t. Em meu aplicativo, quando a API Web ASP.NET recebe uma solicitação para alterar o estado de um bug, ela atualiza o bug e, em seguida, difunde o bug atualizado por meio do SignalR Hub para todos os clientes de navegador conectados ao aplicativo no momento.

Começarei esse processo criando um Hub no servidor. Como não estou aproveitando nenhum recurso adicional do SignalR, meu Hub consistirá apenas na seguinte definição de classe vazia:

[HubName("bugs")]
public class BugHub : Hub
{
}

A fim de enviar difusões para o Hub a partir da API Web ASP.NET, eu preciso primeiro obter uma instância para o seu contexto de tempo de execução. Posso fazer isso adicionando o seguinte construtor BugsController:

public BugsController()
{
  _hub = GlobalHost.ConnectionManager.GetHubContext<BugHub>();
}

A partir de uma das ações de MoveToXX, posso difundir o bug atualizado para todos os clientes de navegador conectados:

_hub.Clients.All.moved(bug);

Na exibição inicial, após adicionar algumas referências de script às bibliotecas JavaScript do SignalR, posso estabelecer a conexão com bugsHub e começar a ouvir as mensagens “movidas” com o seguinte:

$.connection.hub.logging = true;
var bugsHub = $.connection.bugs;
bugsHub.client.moved = function (item) {
  viewModel.moveBug(item);
};
$.connection.hub.start().done(function() {
  console.log('hub connection open');
});

Observe que, quando eu recebo uma chamada do servidor por meio da função moved, eu chamo o método viewModel moveBug da mesma maneira que no manipulador de cliques do item. A diferença é que, como esse método é o resultado de uma difusão do SignalR, todos os clientes de navegador podem atualizar seus viewModels ao mesmo tempo. É possível ver isso claramente ao abrir duas janelas de navegador, fazer alterações em uma delas e, em seguida, visualizar a mudança de estado na outra janela.

Como observei anteriormente, a adição do SignalR ao pipeline do OWIN é trivial. Eu apenas adiciono o seguinte ao método Configuration da classe de inicialização:

app.MapSignalR();

Isso cria um pipeline como o da Figura 11.

The OWIN Pipeline with Three Components
Figura 11 Pipeline do OWIN com três componentes

Mudando para a hospedagem interna

Agora, possuo um aplicativo de gerenciamento de bugs em funcionamento que, embora ainda não tenha alguns recursos importantes, pode fazer algumas coisas interessantes. Eu adicionei recursos de maneira incremental ao aplicativo usando componentes de middleware do Katana da Microsoft e de terceiros. Entretanto, muito disso já foi possível hoje usando HttpModules e HttpHandlers do ASP.NET. Então, o que eu realmente realizei além de fornecer uma abordagem mais simples orientada por código para redigir os componentes do pipeline?

O importante é se lembrar do diagrama da arquitetura do Katana de alto nível na Figura 2. Até aqui, eu trabalhei apenas nas duas camadas superiores da pilha do Katana. No entanto, todas as essas camadas podem ser facilmente substituídas, incluindo o servidor e o host.

Para demonstrar, vou pegar todo o meu pipeline, retirá-lo do IIS e da System.Web.dll e colocá-lo no topo de um servidor HTTP leve e simples, que está sendo hospedado por um executável do Katana chamado OwinHost.exe. A hospedagem interna pode ser útil em vários cenários, abrangendo desde instalações em que não existe um servidor Web instalado na máquina de desenvolvimento até situações de produção em que o aplicativo está sendo implantado em um ambiente de hospedagem compartilhada que usa o isolamento de processos e não expõe o acesso a um servidor Web.

Começarei instalando os seguintes pacotes NuGet adicionais:

Em seguida, recompilarei o aplicativo. Observe que a recompilação não é obrigatória para a execução do aplicativo sobre um novo servidor e host. O único requisito é que esses arquivos existam na pasta /bin em tempo de execução, e a recompilação é uma maneira conveniente de fazer com que os arquivos sejam copiados na pasta /bin.

Após os pacotes serem instalados e os arquivos copiados, eu abro um prompt de comando, navego até a pasta raiz do projeto Web e, conforme exibido na Figura 12, chamo o OwinHost.exe a partir da pasta dos pacotes:

> ..\packages\OwinHost.2.0.0\tools\OwinHost.exe

Calling OwinHost.exe from Within the Packages Folder
Figura 12 Chamando OwinHost.exe a partir da pasta dos pacotes

Por padrão, OwinHost.exe irá iniciar, carregar o servidor de Microsoft.Ow­in.Host.HttpListener e começar a ouvir na porta 5000. Em seguida, é possível navegar para http://localhost:5000 a fim de confirmar que todo o aplicativo está em execução.

Além disso, praticamente todos os padrões podem ser substituídos usando opções de linha de comando. Por exemplo, se você desejar ouvir em uma porta diferente, use -p 12345. Se desejar usar um servidor completamente diferente, use -s your.custom.server.assembly. A potência do design do Katana está em sua modularidade. Como as inovações podem ocorrer em qualquer camada da pilha, elas podem ser imediatamente integradas a aplicativos em execução. E, como o contrato entre todos os componentes da pilha é apenas o representante do aplicativo, o ritmo de inovação pode ser muito maior do que o que está disponível agora.

Apenas uma introdução

O Katana 2.0 será lançado com o Visual Studio 2013. A nova versão tem duas áreas de foco principais:

  • Fornecer componentes da infraestrutura principal para a hospedagem interna
  • Fornecer um amplo conjunto de middleware para autenticação, incluindo fornecedores de redes sociais, como o Facebook, o Google, o Twitter e uma Conta da Microsoft, bem como provedores para o Active Directory do Windows Azure, cookies e federação

Após o lançamento do Katana 2.0, o trabalho começará imediatamente no próximo conjunto de componentes do Katana. Os detalhes e as prioridades ainda estão sendo determinados, mas você pode influenciar essa discussão apresentando questões em katanaproject.codeplex.com. Por fim, todo o código usado neste artigo pode ser encontrado em bit.ly/1alOF4m.

Howard Dierking *é gerente de programas da equipe de estruturas e ferramentas do Windows Azure, na qual o seu foco está em ASP.NET, NuGet e APIs Web. Anteriormente, Dierking trabalhou como editor-chefe da MSDN Magazine e também comandou o programa de certificação de desenvolvedores para o Microsoft Learning. Antes de fazer parte da Microsoft, ele foi desenvolvedor e arquiteto de aplicativos por dez anos, com foco em sistemas distribuídos. *

Agradecemos aos seguintes especialistas técnicos da Microsoft pela revisão deste artigo: Brady Gaster e Scott Hanselman