lunes, 8 de febrero de 2016

asp net core y docker

Hace un tiempo estuve probando a ver si ya podía desarrollarla desde el mac con VsCode y no podía depurar asp.net desde el IDE así que lo dejé en stand-by. Este fin de semana he vuelto a la carga desde un equipo Windows para intentar hacer que mi api .net sea multiplataforma y los resultados son buenos.

En el post de hoy veremos como desarrollar una web api multiplataforma y también como publicarla en un contenedor docker en Azure (Linux). En primer lugar remarcar que estamos viendo cosas que todavía están por llegar oficialmente y puede ser que en poco tiempo cambien algunos de los pasos que describo a continuación. Para realizar el post, sobre todo para la publicación en docker me he apoyado en una serie de articulos que iré haciendo referencia.

Qué necesitas para hacer estas pruebas:
  • Visual Studio 2015
  • Cuenta en Azure (puedes obtener una subscripción temporal aquí).

Crear Api con Asp net core y Visual Studio 2015


En primer lugar en el asistente de nuevo proyecto en Visual Studio seleccionamos proyecto web de tipo asp.net y en la plantilla seleccionamos el vacío asp.net 5 (core). Por defecto si abres un proyecto asp.net con Visual Studio en Windows viene configurado para usar como host IIS Express (a Febrero 2016). Yo aquí me propongo hacer una api core “libre” de IIS, por tanto tenemos que despedirnos de IIS y el framework nativo. Para ello lo primero es eliminar todo resquicio de dnx 4.6 y IIS en el proyecto vacío de asp.net.

Propiedades del proyecto web:





Ves a project.json, elimina la configuración dnx46 de la sección frameworks y añade estas dependencias al proyecto:



El fichero project.json debería parecerse a este:
{
  "webroot": "wwwroot",
  "version": "1.0.0-*",

  "dependencies": {
    "System.Runtime": "4.0.20-beta-22816",
    "Microsoft.AspNet.Hosting": "1.0.0-beta5",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-beta5",
    "Microsoft.Framework.DependencyInjection": "1.0.0-beta5",
    "Microsoft.AspNet.Http.Extensions": "1.0.0-beta5",
    "Microsoft.AspNet.Http": "1.0.0-beta5",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta5",
    "Microsoft.AspNet.Mvc": "6.0.0-beta5"
  },

  "commands": {
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000",
    "kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5001"
  },

  "frameworks": {
    "dnxcore50": { }
  },

  "publishExclude": [
    "node_modules",
    "bower_components",
    "**.xproj",
    "**.user",
    "**.vspscc"
  ],
  "exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
  ]
}

Tenemos el command web para ejecutar en local (windows) y kestrel para cuando publiquemos en Linux.

Por último, asegúrate que Startup.cs tiene esta pinta
public class Startup
{
   public Startup(IHostingEnvironment env)
   {

   }

   // This method gets called by a runtime.
   // Use this method to add services to the container
   public void ConfigureServices(IServiceCollection services)
   {
   }

   // Configure is called after ConfigureServices is called.
   public void Configure(IApplicationBuilder app, IHostingEnvironment env)
   {
      app.Run(async (context) =>
      {
          await context.Response.WriteAsync("Hello World!");
      });
    }
}    

Si todo ha ido bien ya tienes una aplicación web, multiplataforma, totalmente desacoplada de IIS y windows corriendo en dnx.



Ahora estaría bien que la aplicación haga algo más que decir hola mundo. Verás que no es complicado. Simplemente tenemos que añadir la siguiente dependencia al archivo project.json (si no la has añadido ya en el paso anterior):

"Microsoft.AspNet.Mvc": "6.0.0-beta5"

Modificamos startup.cs:
public void ConfigureServices(IServiceCollection services)
{
     services.AddMvc();
}

// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
      app.UseMvc();
}
Por último creamos una carpeta controllers y dentro añadimos un archivo de tipo Web Api Controller. No lo edito, tal y como viene por defecto si compilas y vas a la url http://localhost:5000/api/values deberías ver el json de values.

Resumiendo hasta aquí, como ves el paquete mvc ya integra web api (antes eran paquetes separados) y ya no hay WebApiConfig ni necesidad de configurar rutas por defecto.

Publicar api en un contenedor Docker (Servicio en Azure)


En este post está bien explicado qué es Docker y el concepto DevOps en Español. Yo he seguido más o menos estos pasos para publicar. Os paso también un post de Hanselman al respecto.

Como se indica en los posts que hago referencia es necesario tener instalado el RC1 Update de Visual Studio y el cliente windows de docker.



Si ya tienes el RC1 ves a Extensions and Updates en Visual Studio y busca Docker:



Llegado este punto podemos crear la máquina virtual Ubuntu en Azure desde Visual Studio y gestionar las imagenes/contenedores donde correrán nuestras aplicaciones a través de docker.



Si todo va ok, si vas al portal de Azure o sino desde el panel de Azure en Visual Studio deberías ver la máquina.



Si te fijas verás que se han añadido una serie de archivos powerShell a tu proyecto que Visual Studio usará al publicar en la máquina que hemos configurado. Desde el asiente de publicación puedes validar la conexión al contenedor que acabas de crear en el paso anterior.



Al pulsar publish si todo va bien se publicará tu aplicación, puedes seguir los pasos de publicación en el panel de actividad de azure en Visual Studio.



Ya para acabar con el post, tras varios intentos fallidos esta fue mi expresión al conseguir publicar sin errores jajjajaja.



Bueno, espero que esto que comparto le sea útil a alguien. También podrías montar un docker en local y publicar contra este entorno, a mi me gustaría sacar tiempo para montarlo y así entrar con un poco más de detalle... Ahora ya puedo empezar a pasar mi api asp.net 4.5 y ver que soporta core y que no, por ejemplo tengo claro que de momento tendré que prescindir de funcionalidades SignalR. Otro punto que me tocará adaptar es como persistir la información porque mi api usar EF 6 code first y SQL Server que yo sepa todavía no corre en todas las plataformas ni está previsto que así sea. Como siempre espero ir sacando tiempo para publicar las pruebas de concepto, recordar que podéis seguir areaTIC en las redes sociales y colaborar en forma de comentarios, matices, aportaciones, insultos (sin pasarse) en definitiva feel free para participar!.