Scriptcs y Katana: aplicaciones web ligeras en C#

Después de haber trabajado un tiempo con Javascript y las herramientas que ofrece Node.js, cada vez me llaman menos la atención las novedades que está habiendo en el mundo de .NET.

Seguramente por la influencia de esas tecnologías y la forma de trabajar con ellas, los dos proyectos que más interesantes me resultan dentro del panorama actual en .NET son scriptcs y OWIN.

Ya escribí hace tiempo una introducción a scriptcs, un sistema que nos permite trabajar con C# de forma similar a como lo haríamos con un lenguaje de scripting, sin necesidad de crear proyectos de Visual Studio y de una manera más «libre».

Por su parte, OWIN es un estándar que define un interface para comunicar aplicaciones web con el servidor en que se ejecutan. Apoyándose en ese estándar, Katana ofrece un conjunto de componentes que ayudan a desarrollar aplicaciones web basadas en OWIN de una forma cómoda. Si quieres aprender algo más sobre Katana, te recomiendo los posts de Jose María Aguilar en Variable Not Found.

Juntando ambas ideas, podemos desarrollar servidores web usando C# de una forma mucho más ligera que con el típico proyecto web de Visual Studio.

Instalando scriptcs

Desde mi primer post sobre scriptcs, las cosas han avanzado bastante y ahora su instalación es muy sencilla a través de Chocolatey, un gestor de paquetes para Windows (piensa en algo así como un NuGet pero para aplicaciones).

Para instalar scriptcs, necesitamos instalar primero Chocolatey (si no lo tenemos instalado):

c:\>@powershell -NoProfile -ExecutionPolicy Unrestricted -Command "iex ((New-Object Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin

A continuación, usamos Chocolatey para instalar scriptcs:

c:\>cinst scriptcs

Si todo ha ido bien, tendremos instalado scriptcs y añadido al path (puede ser necesario reiniciar la consola que has usado para instalar todo esto para que se actualice el path). Podemos comprobar que todo funciona creando un fichero y ejecutándolo con scriptcs:

c:\>echo Console.WriteLine("Hola Mundo") > sample.csx
c:\>scriptcs sample.csx
Hola Mundo

Usando Katana con scriptcs

Scriptcs usa internamente NuGet como gestor de paquetes, por lo que podemos usar cualquier paquete NuGet desde nuestros scripts. Para usar Katana, instalaremos los siguientes paquetes:

c:\dev\katana-sample>scriptcs -install Microsoft.Owin.Hosting
c:\dev\katana-sample>scriptcs -install Microsoft.Owin.Host.HttpListener

OJO: en teoría, todas las dependencias instaladas deberían aparecer en el fichero packages.config de la carpeta donde estamos generando la aplicación, pero parece que la versión actual de scriptcs tiene algunos problemas con ello. Si tienes algun problema al ejecutar la aplicación porque no encuentra un espacio de nombres, puedes probar a eliminar el fichero packages.config y volver a crearlo con el comando scriptcs -save. Sí, es una lata, pero es lo que tiene usar cosas que todavía están en desarrollo.

Una vez que tenemos instalados los paquetes, podemos crear nuestro script para levantar una aplicación web alojada sobre un HttpListener:

using Owin;
using Microsoft.Owin.Hosting;

public void Configure(IAppBuilder app)
{
  app.Run(ctx => 
  {
    ctx.Response.ContentType = "text/plain";
    return ctx.Response.WriteAsync("Parece que funciona");
  });
}

using (WebApp.Start("http://localhost:8888", Configure))
{
  Console.WriteLine("Pulsar cualquier tecla para salir...");
  Console.ReadKey();
}

El código que tenéis arriba no sería código C# válido, tenemos un método Configure que no está en ninguna clase y tenemos código (el using) que no está en ningún método, pero con scriptcs podemos hacer cosas así, usando C# con un estilo más de scripting.

La aplicación no hace gran cosa (más bien no hace nada), pero si navegáis a la URL http://localhost:8888 veréis un mensaje indicando que está activa.

Lo que estamos haciendo arrancar una aplicación web (WebApp) de Katana, indicando que queremos configurarla a través del método Configure, que debe ser un Action<IAppBuilder>. Ésta es una de las muchas formas de configurar Katana, y aunque normalmente la configuración suele residir en su propia clase, en este contexto de scripting no tiene sentido crear una clase que sólo tenga un método dentro cuando puedo tener el método «suelto» directamente.

Por comparar, el mismo ejemplo anterior creado con node.js sería algo así:

var http = require('http');

var handler = function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Parece que funciona');	
}

http.createServer(handler)
  .listen(1337, '127.0.0.1');

console.log('Server running at http://127.0.0.1:1337/');

El código es muy similar en ambos casos, e incluso se parecerías más si usásemos en C# un Script Pack como Scriptcs.Owin que nos ahorrase los usings.

Conclusiones

C# es uno de mis lenguajes favoritos, lo conozco bien, me gusta su sintaxis y es muy potente, pero a veces requiere demasiada ceremonia y código boilerplate para poder hacer cosas que deberían ser mucho más sencillas. Si le unimos que Visual Studio es una herramienta tan completa como pesada, está bien poder contar con soluciones como ésta para esos casos en que necesitamos una forma de desarrollar más ligera y ágil.

No creo que scriptcs reemplace a Visual Studio (tampoco es su objetivo), pero es una alternativa a tener en cuenta en determinados escenarios.

La combinación de scriptcs con Katana me parece muy potente para casos en que queremos levantar una aplicación web sin depender de un IIS, por ejemplo, al ejecutar tests de extremo a extremo con angularjs, en un entorno de desarrollo o en un servidor de integración continua.