Compartir a través de


ASP.NET

Introducción al proyecto Katana

Howard Dierking

Cuando ASP.NET se lanzó por primera vez en el año 2002, las cosas eran distintas. Internet seguía siendo relativamente inmadura, con aproximadamente 569 millones de usuarios que dedicaban en promedio 46 minutos al día visitando unos 3 millones de sitios web. Solo diez años después, estos mismos indicadores revelan una Internet con aproximadamente 2.270 millones de usuarios que navegan en promedio durante 4 horas al día en 555 millones de sitios web (ver bit.ly/MY7GzO).

Claramente este crecimiento propició también los cambios correspondientes en las necesidades de los desarrolladores de aplicaciones con respecto a los marcos subyacentes, herramientas y tiempos de ejecución que usan para desarrollar y ejecutar sus aplicaciones web. Las aplicaciones web modernas tienen que ser capaces de evolucionar rápidamente y de valerse de muchos componentes y marcos diferentes; y necesitan ser lo suficientemente ligeras para que se puedan ejecutar de manera eficiente en el tiempo de ejecución masivo de la nube.

Garantizar que ASP.NET cumpla con estos requisitos de hoy y del futuro es la principal motivación detrás del proyecto Katana.

¿Qué es Katana?

De hecho, las semillas del proyecto Katana se sembraron fuera de Microsoft en un proyecto de código abierto llamado Open Web Interface for .NET (OWIN), una especificación que define las interacciones entre los servidores web y los componentes de las aplicaciones (ver owin.org). Como la finalidad de la especificación es estimular un ecosistema amplio y dinámico de servidores web y componentes de aplicación basados en Microsoft .NET, esta reduce todas las interacciones entre los servidores y las aplicaciones a un conjunto pequeño de tipos, además de una firma de función única conocida como el delegado de la aplicación o AppFunc:

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

Cada componente en una aplicación basada en OWIN proporciona un delegado de aplicación a un servidor. Los componentes luego se enlazan en forma de cadena para formar una canalización y un servidor basado en OWIN inserta solicitudes dentro de esta. Para aprovechar los recursos en forma eficiente, todos los componentes de la canalización deben ser asincrónicos, lo cual se refleja en el delegado de la aplicación que devuelve un objeto Task.

Todos los estados, como el estado de la aplicación, estado de la solicitud, estado del servidor, etcétera, se conservan en el objeto IDictionary<string, object> que se especifica en el delegado de la aplicación. Esta estructura de datos, conocida como el diccionario del entorno, se pasa de un componente a otro a medida que la solicitud avanza por la canalización. Aunque se puede insertar cualquier tipo de datos clave-valor en el diccionario del entorno, la especificación de OWIN define claves para algunos elementos centrales de HTTP, tal como se aprecia en la figura 1.

Figura 1 Claves del diccionario del entorno requeridas en una solicitud HTTP

 

Nombre de la clave Descripción del valor
"owin.RequestBody" Un objeto Stream con el cuerpo de la solicitud, si es que lo hay. Se puede usar Stream.Null como marcador de posición si la solicitud no tiene cuerpo.
"owin.RequestHeaders" Un IDictionary<string, string[]> con encabezados de solicitud.
"owin.RequestMethod" Una cadena con el método de solicitud HTTP de la solicitud (como GET y POST).
"owin.RequestPath" Una cadena con la ruta de acceso de la solicitud. La ruta debe ser relativa a la “raíz” del delegado de la aplicación.
"owin.RequestPathBase" Una cadena que contiene la porción de la ruta de acceso de la solicitud que corresponde a la “raíz” del delegado de la aplicación.
"owin.RequestProtocol" Una cadena que contiene el nombre del protocolo y la versión (por ejemplo HTTP/1.0 o HTTP/1.1).
"owin.RequestQueryString" Una cadena que contiene el componente de la cadena de consulta del identificador URI de la solicitud HTTP sin el símbolo inicial “?” (por ejemplo foo=bar&baz=quux). Este valor puede ser una cadena vacía.
"owin.RequestScheme" Una cadena que contiene el esquema URI que se emplea para la solicitud (como HTTP o HTTPS).

La definición de un conjunto de pares clave-valor para el diccionario del entorno permite que los diferentes autores de marcos y componentes interactúen en una misma canalización de OWIN, sin que tengan que ponerse de acuerdo sobre un modelo de objetos .NET específico, como el caso de HttpContextBase en ASP.NET MVC o HttpRequestMessage/HttpResponseMessage en ASP.NET Web API.

Estos dos elementos, el delegado de la aplicación y el diccionario del entorno, forman la especificación de OWIN. El proyecto Katana es el conjunto de componentes y marcos basados en OWIN que creó y publicó Microsoft.

Los componentes de Katana se pueden representar con la pila arquitectónica de la figura 2.

Katana Project ArchitectureFigura 2 Arquitectura del proyecto Katana

La pila se compone de las siguientes capas:

  • Host: el proceso que ejecuta la aplicación y que puede ser cualquier cosa, desde IIS o un ejecutable independiente hasta nuestro propio programa personalizado. El host es el responsable del proceso de inicio, de cargar otros componentes de OWIN y de detener los procesos en forma predecible.
  • Servidor: el responsable de establecer el enlace a un puerto TCP, de construir el diccionario del entorno y de procesar las solicitudes mediante una canalización de OWIN.
  • Middleware: el nombre que se da a todos los componentes que procesan solicitudes en una canalización de OWIN. Puede ser cualquier cosa, desde un simple componente de compresión hasta un marco completo como ASP.NET Web API, aunque, desde el punto de vista del servidor, no es más que un simple componente que expone el delegado de la aplicación.
  • Aplicación: este es nuestro código. Como Katana no reemplaza a ASP.NET, sino que es una forma nueva de componer y hospedar los diferentes componentes, las aplicaciones ASP.NET Web API y SignalR no requieren de cambios, ya que esos marcos pueden participar en su propia canalización de OWIN. De hecho, para estos tipos de aplicaciones, los componentes de Katana solo serán visibles dentro de una pequeña clase de configuración.

Desde el punto de vista arquitectónico, Katana está compuesto de manera tal, que cada una de estas capas se pueda sustituir fácilmente, frecuentemente y sin necesidad de cambios en el código. Al procesar una solicitud HTTP, las capas funcionan en conjunto, similar al flujo de datos que se aprecia en la figura 3.

Example of the Data Flow in KatanaFigura 3 Ejemplo del flujo de datos en Katana

Creación de una aplicación web moderna con Katana

Las aplicaciones web modernas generalmente tienen cuatro características:

  1. Generación de marcado del lado servidor
  2. Servicio de entrega de archivos estáticos
  3. Web API para procesar solicitudes AJAX
  4. Mensajería en tiempo real

La creación de una aplicación con todas estas funciones requiere de una variedad de marcos diferentes, debidamente especializados para cada función. Pero la composición de una aplicación a partir de estos marcos puede resultar difícil y, en la práctica, exige hospedar las diferentes partes en IIS, además de aislarlas posiblemente entre sí mediante aplicaciones y directorios virtuales.

Katana, en cambio, permite componer una aplicación web moderna a partir de un amplio abanico de tecnologías web diferentes y luego hospedar esa aplicación donde queramos, expuesta bajo un solo extremo HTTP. Esto ofrece varias ventajas:

  • La implementación se simplifica, ya que implica una sola aplicación en vez de una aplicación para cada función.
  • Permite agregar funciones adicionales, como por ejemplo la autenticación, que se pueden aplicar a todos los componentes inferiores de la canalización.
  • Los diferentes componentes, ya sea de Microsoft o de otros proveedores, pueden operar con el mismo estado de solicitud mediante el diccionario del entorno.

Ahora exploraremos una aplicación de ejemplo que tiene un dominio que debería resultarle conocido: el seguimiento de errores. La aplicación presentará un conjunto de errores en diferentes estados (pendiente, en curso y listo) y permitirá cambiar el estado del error. Y, como diferentes personas podrían estar administrando los errores en forma simultánea, el explorador se actualizará en tiempo real cada vez que cambia el estado de un error. Esto es lo que usaré para escribir la aplicación: Nancy (nancyfx.org) para la generación de marcado del lado servidor y entrega de archivos estáticos, ASP.NET Web API (asp.net/web-api) para procesar las solicitudes AJAX y SignalR (signalr.net) para los servicios de mensajería en tiempo real.

Además, aunque no dedicaré mucho tiempo al marcado y los scripts en el cliente del explorador, usaré Knockout.js para separar el marcado en HTML de los datos de Web API y SignalR.

El principio básico que hay que tener en mente es que compondré todos estos marcos diferentes en una sola canalización de OWIN, así que, a medida que disponga de funcionalidades nuevas, podré agregarlas a la aplicación al insertarlas simplemente en la canalización.

Para comenzar

Una de las finalidades de Katana es entregarnos un control preciso sobre las funciones de nuestras aplicaciones (y, por lo tanto, sobre el costo, en términos de rendimiento, para procesar cada solicitud). Teniendo esto presente, comienzo por crear un nuevo proyecto de aplicación web ASP.NET vacío en Visual Studio 2013 Preview, tal como se ilustra en la figura 4.

A New ASP.NET Web Application Project in Visual Studio 2013 PreviewFigura 4 Nuevo proyecto de aplicación web ASP.NET en Visual Studio 2013 Preview

Las plantillas para proyectos web, incluso las vacías, ofrecen una función útil ya que, de manera predeterminada, colocan los ensamblados compilados directamente en la carpeta /bin en vez de /bin/debug (como se acostumbra en los otros tipos de proyectos). El host predeterminado de Katana busca los ensamblados en esta carpeta /bin. Podríamos crear una aplicación basada en Katana como biblioteca de clases, pero tendríamos que modificar las propiedades del proyecto para cumplir con esta estructura o proporcionar nuestro propio cargador personalizado que busque los ensamblados y tipos en otra estructura de carpetas.

Luego, completaré el código de generación de marcado del lado servidor mediante el marco web Nancy.

Nancy cuenta con una sintaxis concisa que permite crear rápidamente sitios y servicios basados en HTTP. E incluso más importante para este ejercicio es que, al igual que ASP.NET Web API, no tiene ningún tipo de dependencias de System.Web.dll y se escribió para que se ejecutara en su propia canalización de OWIN. Los ostros marcos como ASP.NET MVC tienen dependencias de System.Web.dll (en el momento de redactar este artículo), por lo que resultan menos aptos para el hospedaje fuera de IIS.

Por lo general, cuando agregamos funciones nuevas a la aplicación, comenzamos por agregar un paquete NuGet. (Puede obtener más información sobre NuGet en docs.nuget.org.) A la hora de escribir esto, muchos de los paquetes que se usan aquí son versiones preliminares, así que debe permitir que los paquetes preliminares aparezcan en el cuadro de diálogo de NuGet.

Para agregar Nancy a la aplicación, podría instalar simplemente el paquete NuGet de Nancy. Sin embargo, como también deseo ejecutar Nancy en su propia canalización de OWIN, instalaré el paquete Nancy.Owin (nuget.org/packages/nancy.owin). Esto instalará el paquete Nancy como una dependencia y proporcionará métodos auxiliares adicionales para configurar Nancy en mi canalización de OWIN.

A continuación, tengo que crear un módulo de Nancy (similar a un controlador Model-­View-Controller o MVC) para procesar las solicitudes, además de una vista para mostrar algo en el explorador. Este es el código del módulo (HomeModule.cs): 

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

Como podrá apreciar, el módulo declara que las solicitudes dirigidas a la raíz de la aplicación (“/”) las debe procesar el delegado anónimo que se define en la función lambda asociada. Esa función crea un modelo que contiene el título de la página e indica a Nancy que presente la vista “home” al pasar el modelo a la vista. La vista, que se muestra en la figura 5, inserta la propiedad title del modelo en los elementos title y h1 de la 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 obtener más información sobre estos listados, consulte la documentación de Nancy.

Ahora que implementé la funcionalidad básica de Nancy, tengo que establecer una canalización de OWIN y configurar el módulo de Nancy para que participe en esa canalización. Para esto, primero debo instalar los componentes host y servidor de Katana, luego escribir una pequeña cantidad de código estructural para preparar la canalización de OWIN e insertar Nancy en esa canalización.

Para los componentes host y servidor de Katana, comenzaré por usar IIS Express y System.Web, ya que Visual Studio los reconoce en forma nativa, lo que permitirá una experiencia fluida con F5 durante la compilación de la aplicación. Para incorporar el host System.Web en el proyecto, instalo el paquete NuGet Microsoft.Owin.Host.SystemWeb (bit.ly/19EZ2Rw).

Los componentes predeterminados de Katana emplean varias convenciones diferentes para cargar y ejecutar aplicaciones OWIN, inclusive la clase de inicio. Cuando un host de Katana carga una aplicación OWIN, detecta y ejecuta una clase de inicio a partir de las siguientes reglas (en orden de precedencia):

  • Si el archivo web.config contiene una propiedad appSetting con key=“owin:AppStartup”, el cargador usa el ese valor. El valor debe ser un nombre válido de un tipo .NET.
  • Si el ensamblado contiene el atributo [assembly: OwinStartup(typeof(MyStartup))], entonces el cargador empleará el tipo que se especifica en el valor del atributo.
  • Si no se cumple ninguna de estas condiciones, entonces el cargador examinará los ensamblados cargados hasta encontrar un tipo llamado Startup con un método que coincida con la firma void Configure(IAppBuilder app).

En este ejemplo, permitiré que el cargador examine los ensamblados para encontrar la clase. Sin embargo, cuando el proyecto contiene muchos tipos y ensamblados diferentes, conviene usar el atributo appSetting o assembly para evitar búsquedas innecesarias.

Creo la clase de inicio que inicializará mi canalización de OWIN y agrego Nancy como componente de la canalización. Creo una clase nueva llamada Startup y agrego un método de configuración, del siguiente modo:

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

UseNancy es un método de extensión disponible a través del paquete NuGet de Nancy.Owin . Aunque podemos agregar el middleware mediante los métodos Use más genéricos de IAppBuilder, muchas bibliotecas de middleware proporcionan estos métodos de extensión, lo que simplifica el proceso de configuración.

Llegados a este punto, puede ejecutar el proyecto en Visual Studio con F5 y verá que, aunque todavía no es nada emocionante, contamos con una aplicación web completamente funcional. A estas alturas, la canalización de OWIN consta de un solo componente, Nancy, tal como se aprecia en la figura 6.

A Functional Web Application with a Single Component
Figura 6 Una aplicación web funcional con un solo componente

Incorporación de datos con ASP.NET Web API

Actualmente, la vista de HTML solo consiste en el marcado estático primario. Ahora le entregaré al usuario algunos errores verdaderos con los que trabajar. En muchas aplicaciones web modernas, la tarea de la entrega de datos al explorador cliente se trasladó del marco de generación de marcado del lado servidor (como el módulo Nancy) a un servicio Web API independiente. Luego, el explorador carga la página HTML e inmediatamente ejecuta código JavaScript que recupera los datos de Web API y construye el marcado HTML en forma dinámica en la página misma.

Comenzaré por construir la Web API mediante el marco ASP.NET Web API. Como de costumbre, el primer paso es instalar el paquete NuGet de Web API. Para asegurarme de que podré insertar ASP.NET Web API fácilmente en mi canalización de OWIN, instalaré el paquete Microsoft.Asp­Net.WebApi.Owin (bit.ly/1dnocmK). Este paquete instalará el resto del marco ASP.NET Web API como dependencias. Después de instalar el marco, creo una API sencilla, tal como se ilustra en la 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;
  }
}

La API contiene un método para devolver un conjunto de objetos de error desde un repositorio, además de algunos métodos para pasar los errores de un estado a otro. Encontrará información abundante sobre ASP.NET Web API en asp.net/web-api.

Ahora que definí el controlador de ASP.NET Web API, tengo que agregarlo a la canalización de OWIN existente. Para esto, simplemente agrego las siguientes líneas al método Configuration de la clase de inicio:

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

Igual que en el caso de Nancy, el paquete OWIN de ASP.NET Web API proporciona el método de extensión UseWebApi, lo que permite incorporar fácilmente ASP.NET Web API en la canalización existente de OWIN. La canalización de OWIN ahora consta de dos componentes, ASP.NET Web API y Nancy, tal como se aprecia en la figura 8.

The OWIN Pipeline with Two Components
Figura 8 Canalización de OWIN con dos componentes

Cuando las solicitudes entran en la canalización, si coinciden con una de las reglas de enrutamiento de ASP.NET Web API, ASP.NET Web API procesa la solicitud y genera una respuesta. De lo contrario, la solicitud sigue recorriendo la canalización, donde Nancy trata de procesarla. Si ningún componente de la canalización es capaz de procesar una solicitud determinada, entonces los componentes predeterminados de Katana devuelven una respuesta HTTP 404.

Aunque tengo una ASP.NET Web API que funciona, todavía la vista home no accede a ella. Por lo tanto, agregaré el código necesario para consumir los datos de Web API y generar un listado de errores en cada uno de los diferentes estados: pendiente, en curso y listo. Para esta tarea, emplearé Knockout.js, una biblioteca Model-View-ViewModel (MVVM) para JavaScript. Puede encontrar más información sobre Knockout en knockoutjs.com.

Para habilitar la generación dinámica de marcado HTML del lado cliente mediante Knockout, lo primero que debo hacer es recuperar todos los errores de ASP.NET Web API y crear un viewModel que Knockout pueda enlazar a los elementos HTML. Esto se ilustra en la figura 9.

Figura 9 Configuración del viewModel con los errores

<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>

Una vez que se creó el viewModel, Knockout puede generar el contenido HTML en forma dinámica y actualizarlo al enlazar el viewModel a los elementos HTML decorados con atributos de Knockout. Por ejemplo, el listado de errores pendientes se puede generar a partir del viewModel mediante los atributos que se aprecian en la figura 10.

Figura 10 Atributos para generar el listado de errores pendientes

<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>

Adición de notificaciones de cambios en tiempo real con SignalR

A estas alturas, tenemos una aplicación web completamente funcional de una página. Los usuarios pueden buscar la vista home y trasladar los errores entre los diferentes estados. Además, las tecnologías subyacentes para el nivel de funcionalidad actual, Nancy y ASP.NET Web API, se ejecutan juntos en la misma canalización de OWIN.

Avanzaré otro paso más, sin embargo, y permitiré que diferentes usuarios vean, en tiempo real, las actualizaciones que los otros usuarios realizan en los errores. Para esto, me valgo de la biblioteca SignalR que proporciona una API del lado cliente y del lado servidor para procesar el intercambio de mensajes en tiempo real entre el explorador y un servidor web. SignalR también se escribió para que funcione en su propia canalización de OWIN, así que resultará trivial agregarlo a la aplicación existente.

Emplearé una característica llamada Hubs de SignalR y, aunque los pormenores de SignalR están fuera del alcance de este artículo, un Hub permite que los clientes y servidores llamen los métodos de la contraparte. (Encontrará una excelente introducción a SignalR en bit.ly/14WIx1t.) En mi aplicación, cuando ASP.NET Web API recibe una solicitud para cambiar el estado de un error, primero lo actualiza y luego difunde el error actualizado a través de la clase Hub de SignalR a todos los exploradores cliente que actualmente estén conectados a la aplicación.

Iniciaré este proceso al crear una clase Hub en el servidor. Como no estoy empleando ninguna función adicional de SignalR, mi Hub consistirá simplemente en la siguiente definición de clase vacía:

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

Para enviar difusiones al Hub desde ASP.NET Web API, primero debo obtener una instancia del contexto del tiempo de ejecución. Para esto, puedo agregar el siguiente constructor a BugsController:

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

Luego puedo difundir el error actualizado desde el interior de una de las acciones MoveToXX a todos los exploradores cliente conectados:

_hub.Clients.All.moved(bug);

En la vista home, después de agregar unas cuantas referencias de script a las bibliotecas JavaScript de SignalR, puedo conectarme a bugsHub y comenzar a escuchar los mensajes “trasladados” mediante el siguiente código:

$.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 cuando recibo una llamada del servidor a través de la función moved, llamo el método moveBug de viewModel, igual como lo hacía previamente con el controlador de clics del elemento. La diferencia es que como este método es el resultado de una difusión de SignalR, todos los exploradores cliente pueden actualizar los viewModel al mismo tiempo. Esto queda totalmente claro al abrir dos ventanas en el explorador, realizar cambios en una y luego ver cómo cambia el estado en la otra.

Tal como señalé, agregar SignalR a la canalización de OWIN es trivial. Simplemente agrego la siguiente línea al método Configuration de la clase de inicio:

app.MapSignalR();

Esto crea una canalización como la que se muestra en la figura 11.

The OWIN Pipeline with Three Components
Figura 11 Canalización de OWIN con tres componentes

Autohospedaje

Ahora tengo una aplicación de administración de errores funcional que, aunque todavía carece de algunas características claves, es capaz de hacer varias cosas interesantes. Paso a paso, agregué funciones a la aplicación al usar componentes middleware de Microsoft y otros proveedores a Katana. Sin embargo, gran parte de esto ya era posible con HttpModules y HttpHandlers en ASP.NET. ¿Qué logré entonces, aparte de proporcionar una solución más sencilla y controlada por el código para componer las piezas de la canalización?

La clave está en recordar el diagrama de la arquitectura general de Katana de la figura 2. Hasta ahora, solamente he trabajado en las dos capas superiores de la pila de Katana. Sin embargo, todas estas capas se pueden reemplazar fácilmente, incluso el servidor y el host.

Para demostrarlo, tomaré toda la canalización, la sacaré de IIS y System.Web.dll y la ubicaré en un servidor HTTP sencillo y ligero, hospedado por un archivo ejecutable de Katana llamado OwinHost.exe. El autohospedaje puede resultar útil en diferentes situaciones, desde las instalaciones donde la máquina de desarrollo no cuenta con ningún servidor web hasta situaciones de producción donde la aplicación se implementa en un entorno de hospedaje compartido que aísla los procesos y no expone ningún acceso a un servidor web.

Comenzaré por instalar los siguientes paquetes NuGet adicionales:

Luego, vuelvo a compilar la aplicación. Observe que la nueva compilación no es necesaria para ejecutar la aplicación en el servidor y host nuevos. El único requisito es que en tiempo de ejecución estos archivos existan en la carpeta /bin y la nueva compilación es simplemente una forma conveniente de copiar los archivos a /bin.

Una vez que se instalaron los paquetes y se copiaron los archivos, abro un símbolo del sistema, navego a la carpeta raíz del proyecto web y, tal como se aprecia en la figura 12, llamo OwinHost.exe desde la carpeta packages:

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

Calling OwinHost.exe from Within the Packages Folder
Figura 12 Ejecución de OwinHost.exe desde la carpeta packages

De manera predeterminada, OwinHost.exe se iniciará, cargará el servidor Microsoft.Owin.Host.HttpListener y comenzará a escuchar en el puerto 5000. Luego puedo navegar a http://localhost:5000 para confirmar que se esté ejecutando toda la aplicación.

Además, se pueden reemplazar casi todos los valores predeterminados mediante modificadores para la línea de comando. Por ejemplo, para escuchar en un puerto diferente, usamos -p 12345. Si queremos usar un servidor completamente diferente, usamos -s ensamblaje.de.servidor.personalizado. El poder del diseño de Katana radica en la modularidad. A medida que se generan innovaciones en cualquiera de las capas de la pila, estas se pueden integrar inmediatamente en las aplicaciones en ejecución. Y como el contrato entre todos los componentes de la pila es simplemente el delegado de la aplicación, la velocidad de innovación puede ser mucho más rápida de lo que está disponible ahora.

Recién estamos comenzando

Katana 2.0 se lanzará con Visual Studio 2013. La versión nueva se concentra en dos aspectos:

  • Proporcionar los componentes de infraestructura centrales para el autohospedaje.
  • Proporcionar un conjunto sofisticado de middleware para la autenticación, para los proveedores sociales como Facebook, Google, Twitter y cuenta Microsoft, además de proveedores para Windows Azure Active Directory, cookies y federación.

Después del lanzamiento de Katana 2.0, inmediatamente comenzará el trabajo en el siguiente conjunto de componentes de Katana. Los detalles y las prioridades recién se están determinando, pero usted puede influir en esta decisión al informar cualquier problema en katanaproject.codeplex.com. Por último, todo el código de este artículo está disponible en bit.ly/1alOF4m.

Howard Dierking *es jefe de programas en el equipo de marcos y herramientas para Windows Azure, donde se concentra en ASP.NET, NuGet y Web API. Previamente, Dierking actuó como redactor jefe de MSDN Magazine y también estaba a cargo del programa de certificación de desarrolladores de Microsoft Learning. Antes de entrar a Microsoft trabajó durante diez años como desarrollador y arquitecto de aplicaciones con un enfoque en sistemas distribuidos. *

Gracias a los siguientes expertos técnicos de Microsoft por su ayuda en la revisión de este artículo: Brady Gaster y Scott Hanselman.