[Curso] ASP.NET WebAPI profesional en Madrid

Después de un tiempo pensado en tocar también el tema de la formación (Ya que soy MCT y de momento no he impartido ningún curso presencial) he decidido crear mi primer curso presencial en Madrid: ASP.NET WebAPI profesional. El curso cuesta 150 € y durante esta semana para los 15 madrugadores que compren un ticket habrá un descuento de 30 €. A continuación os detallo un poco de que irá:

  • Introducción a HTTP / REST / Hypermedia
  • Routing
  • Controllers
  • Message Handlers & Filters
  • Media Type Formatters
  • Model Binding
  • Validación
  • Inyección de dependencias
  • Tests unitarios
  • Seguridad

Descripción:

Si estas pensando en implementar una API REST o simplemente quieres ampliar tus conocimientos, entonces acércate a este curso intensivo de 8 horas en el que construiremos desde cero un proyecto con ASP.NET WebAPI. Una vez finalizado el taller, podrás terminar la solución en casa y tener el conocimiento necesario para comenzar tu propio proyecto y desarrollar una API REST que enamore a los programadores que la consuman.

 

Horario:

Viernes 5 de Julio de 2013 de 16:00 a 20:00

Sábado 6 de Julio de 2013 de 10:00 a 14:00

Para este taller se recomienda traer un portátil con Visual Studio 2012 Update 2 instalado.

Localización:

C/ Alberto Aguilera Nº 70 4º derecha, 28015 Madrid

Si tienes alguna duda sobre el curso puedes escribirme a luis_ruiz_pavon [at] hotmail.com 

Un saludo

[WebAPI] Consumiendo servicios WebAPI con HttpClient

ASP.NET WebAPI nos proporciona también un cliente HTTP (System.Net.Http.HttpClient) para consumir servicios de WebAPI desde clientes .NET. System.Net.Http.HttpClient nos proporciona la funcionalidad básica para enviar peticiones y recibir respuestas.

Para empezar a trabajar con System.Net.Http.HttpClient podemos hacer uso de Nuget e instalar el paquete Microsoft.AspNet.WebApi.Client:

image

Una vez instalado, escribimos el siguiente fragmento de código:

using (var httpClient = new HttpClient())

{

    httpClient.BaseAddress = new Uri("http://localhost:12534/api/");

 

    var response = await httpClient.GetAsync("products");

    var products = await response.Content.ReadAsAsync<List<Product>>();

 

    foreach (var product in products)

    {

        Console.WriteLine("Product: {0}", product.Name);

    }

}

 

Console.Read();

Lo que estamos haciendo es crear una instanacia de HttpClient. A continuación a la propiedad BaseAdress le asignamos el valor de la url de nuestra api (Sin recurso, la dirección base). Posteriormente, haciendo uso de las nuevas características de C# 5 async await, hacemos una petición con el método GetAsync pasándole el nombre del recurso (products en este caso) para recuperar todos los productos. Esto nos devolverá un objecto del tipo HttpResponseMessage (Si has trabajado con WebAPI te sonará y sino te suena, básicamente junto con la clase HttpRequestMessage sirven para manejar los mensajes de petición y respuesta HTTP). Por último, con la respuesta accedemos al contenido por medio de la propeidad Content y con el método ReadAsync<>, deserializamos el contenido y lo convertimos en una lista de productos que posteriormente iteramos y mostramos por pantalla.

También podéis usar HttpClient en Windows Phone, Windows 8…

http://www.hanselman.com/blog/NuGetPackageOfTheWeek13PortableHttpClientMakesPortableLibrariesMoreUseful.aspx

Un saludo.

[Editado] Apuntes de Entity Framework (I) – Introducción

[Añado al post las correcciones de Unai]

Aprovechando que estoy estudiando un poco sobre Entity Framework para incorporarlo a mi actual proyecto, he decidido ir compartiendo los apuntes que voy tomando de diferentes fuentes. Cualquier corrección, mejora o aportación será muy bien recibida.

Introducción

Desde la llegada de .NET  Framework allá por el 2002, muchos de nosotros hemos usado ADO.NET en nuestras aplicaciones para acceder a la base de datos. El problema de usar ADO.NET, es que estas quedan fuertemente acopladas a la base de datos.

Los ORMs simplifican la interacción de nuestras aplicaciones con los datos, introduciendo una capa de abstracción entre el código de nuestra aplicación y el esquema de la base de datos, haciendo nuestro código menos acoplado y flexible, evitando el tener que preocuparnos por las sentencias SQL y trabajar con objetos fuertemente tipados evitando así errores de sintaxis.

Un ejemplo de ORM es Entity Framework que veremos en esta serie de posts.

En EntityFramework disponemos de 3 enfoques de desarrollo:

  • Database first
  • Model first
  • Code first

De estos 3, los más usados son Model First y Code First.

Model First:

Haciendo uso del Entity Designer tool diseñas el modelo de dominio y el designer genera un script que crea la base de datos por tí, además de las entidades, los mapeos con las tablas de la base de datos y las relaciones. Se genera un fichero de extensión .edmx

Code First:

En esta caso no usaremos un archivo .edmx para diseñar nuestro modelo, sino que escribiremos nuestro dominio directamente con C# y Entity Framework escaneará nuestras clases y basandose en una serie de convenciones intentará mapear nuestro dominio con las tablas de una base de datos existente o creandola por nosotros. Por ejemplo, si tenemos en una entidad de dominio una propiedad que se llama Id, Entity Framework asumirá que es la clave primaria de la tabla.

Contexto y entidades

En Entity Framework el contexto (ObjectContext) es la puerta de enlace entre el modelo y el framework subyacente encargado de conectar con la base de datos y mapear las operaciones de los objectos con los comandos de base de datos.

EntityFramework provee 2 tipos de contextos:

  • ObjectContext
  • DbContext

DbContext es un warpper de ObjectContext que agiliza muchas de las acciones comunes que realizamos con ObjectContext.

El constructor de DbContext acepta como parámetro el nombre de la base de datos y conecta por defecto con SQLExpress o LocalDb. Si ambos están instalados, usa por defecto SQLExpress. Podemos usar otra base de datos pasando como parámetro el nombre del connection string que queremos usar en vez de el motor de base de datos por defecto. El connection string podemos almacenarlo en el archivo de configuración de nuestra aplicación (Web.Config o app.config):

Xml

<configuration>

    <connectionStrings>

        <add name=”CommerceDBproviderName=”System.Data.SqlServerCe.4.0

                              connectionString=”Data Source=Commerce.sdf/>

    </connectionStrings>

</configuration>

 
C#
 
DbContext context = new DbContext(“CommerceDB”);

 

CRUD operations

using (var context = new DbContext(“CommerceDB”)) 

{ 

    DbSet<Orders> orders = context.Set<Orders>(); 

    var order = orders.Find(“XXX-XX-XXXX”); 

    order.Dispatched = DateTime.Now; 

    context.SaveChanges(); 

}

En el código anterior lo que estamos haciendo es crear un contexto, acceder al conjunto de órdenes a través del método genérico Set<T> mediante el método Find buscamos por clave primaria la orden. Una vez que tenemos la entidad, modificamos su propiedad Dispatched y salvamos los cambios en base de datos.

Tip: Es muy importante mantener en nuestra aplicación un número concurrente de DbContext bajo. Cada DbContext abre una conexión con la base de datos y la mantiene abierta durante cierto tiempo. Un número concurrente elevado de conexiones abiertas puede provocar problemas de rendimeinto en nuestra aplicación. Cuando declaramos un DbConext es recomendable hacer uso de la sentencia using que se encargará de cerrar la conexión y cualquier cache en memoria de objetos que se hayan consultado recientemente serán también eliminados.

Unai -> No es cierto, EF nunca deja abierta una conexión.Siempre la abre y la cierra de forma automática después de cada operación. De hecho el trabajo con las conexiones ha sido una de las demandas que se han satisfecho en EF 6, ahora tu le puedes indicar que eres el Owner de una conexión para que no se encargue el de la gestión de abrir/cerrar. Hay una feature specification respecto a esto en entityframework.codeplex.com.

Normalmente lo que se suele hacer por norma general, es crear una clase que deriva de DbContext y expone propiedades de tipo DbSet<T> de cada entidad de nuestro dominio.

public class CommerceContext : DbContext 

{ 

    public CommerceContext() : base(“CommerceDB”) { } 

    public DbSet<Order> Orders { get; set; } 

    public DbSet<Customer> Customers { get; set; } 

}

Cuando DbContext es incializado, detecta si la base de datos existe, sino existe, Entity Framework puede crearla en base a la información de nuestra clase derivada. Para crear la base de datos podemos usar la clase generica CreateDatabaseIfNotExists<T>

var initializer = new CreateDatabaseIfNotExists<CommerceContext>(); 

initializer.InitializeDatabase(new CommerceContext());

Change Tracking

Entity Framework change tracking soporta 2 modos:

  • Active change tracking: Cada propiedad informa al contexto de que ha cambiado
  • Pasive change tracking: Es el contexto el encargado de detectar cambios antes de salvar los cambios, comprandolo con un snapshot que tomó cuando se recuperó la entidad.

Cuando llamamos al método SaveChanges del contexto, este comprueba si el modo Active change tracking está habilitado. Si solo está habilitado el modo pasivo, el DbContext llama al método DetectChanges. Este enumera todas las entidades recuperadas por el contexto y compara cada propiedad con el valor original de cuando fue recuperada. Todos los cambios serán actualizados en la base de datos.

Para soportar el modo Active change tracking deberemos marcar todas las propiedades de nuestras entidades dominio como virtuales (virtual) y Entity Framework creará un proxy en tiempo de ejecución para informar de todos los cambios.

Unai -> Hay ciertas cosas que no son correctas tal y como las comentas, te recomiendo la lectura de la siguiente serie, te pongo la 3 entrega pero están los enlaces para las otras, de Arthurs Vickers uno de los devs de EF, blog.oneunicorn.com/…/secrets-of-detectchanges-part-3-switching-off-automatic-detectchanges. Por cierto, aquí el menda hizo un par de pull request para el AddRange y RemoveRange que eliminan la necesidad de desactivar el change tracking para estas operaciones sobre N elementos.

DataAnnotations

Por defecto Entity Framework mapea el nombre de nuestras entidades de dominio y propiedades con el nombre de las tablas y columnas. Si queremos cambiar este comportamiento por defecto podemos hacer uso de atributos como [Table] y [Column]:

Unai -> Ummm, en realidad utiliza un pluralizador para estos nombres, en EF 6 este pluralizador es publico y se puede enchufar ( otro pull request del menda, y no es por echarme flores 🙂 ) con tu DbConfiguration y el método SetPluralizationService. Yo tengo un pluralizador en castellano que espero publicar en poco tiempo en codeplex dentro del proyecto contrib por si te interesa…

using System.ComponentModel.DataAnnotations; 

using System.ComponentModel.DataAnnotations.Schema; 

 

[Table("Products")] 

public class Product 

{ 

    public int Id { get; set; } 

    [Column("ProductName")] 

    public string Name { get; set; } 

}

Podemos representar claves foráneas de 2 maneras diferentes:

  • Desde la propiedad de clave foránea a la propiedad de entidad.
  • Desde la propiedad de la entidad a la propiedad de clave foránea.

A continuación se muestra un ejemplo con ambos casos:

[ForeignKey("Customer")] 

public Guid CustomerId { get; set; } 

public Customer Customer { get; set; } 

 

public Guid CustomerId { get; set; } 

[ForeignKey("CustomerId")] 

public Customer Customer { get; set; }

En este caso es una relación a uno, para una relación a muchos bastaría con modificar el tipo de la propiedad Customer a IColelction<Customer> o IEnumerable<Customer>.

Teniendo ambas propiedades ganamos en flexibilidad y performance, porque si necesitas recuperar la entidad entera puedes acceder a ella a tarvés de la propiedad Customer y también por motivos de rendimeinto, si solo necesitas la clave a través de la propiedad CustomerId.

FluentAPI

Si queremos que nuestras clases este en otra librería que nada tenga que ver con Entity Framework y no esten llenas de atributos, podemos hacer uso de Entity Framework Fluent API.

Hay 2 maneras de usar EntityFramework Fluent API:

  • Sobreescribiendo el método OnModelCreating de nuestro DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder) 

{ 

    modelBuilder.Entity<Customer>().ToTable("Customers"); 

    modelBuilder.Entity<Customer>().HasKey(c => c.Id); 

    modelBuilder.Entity<Customer>().Property(c => 

        c.Name).HasColumnName("CustomerName"); 

}

  • Heredando de la clase EntityTypeConfiguration.
protected override void OnModelCreating(DbModelBuilder modelBuilder)

{

    modelBuilder.Configurations.Add(new CustomerMapping());

}

 

public class CustomerMapping : EntityTypeConfiguration<Customer>

{

    public CustomerMapping()

    {

        ToTable("Customers");

        HasKey(t => t.ID);

        Property(t => t.ID).HasColumnName("CustomerId");

        Property(t => t.Name).HasColumnName("CustomerName");

    }

}

Yo prefiero usar la segunda opción, así tenemos más clara todo la configuración de mapeos y evitamos tener un método con cientos de lineas configuracion de mapeos.

Unai -> Correcto, en EF 6 tenéis un AddFromAssembly ( pull request mio tb ) que es capaz de pillar de forma automática todos los EntityTypeConfiguration ( incluso con constructores no públicos para evitar tentaciones de usarlos directamente )  y así te evitas tener las n-mil líneas de Configuration.Add(…)

Y hasta aquí la introducción a Entity Framework. En el siguiente post veremos las consultas.

[EVENTO] #TunodeYoxaml #YonodeTuxaml

Este fin de semana tuvo lugar en Santa Pola el supereventazo #TunodeYoxaml #YonodeTuxaml en el que tuve el placer de poder participar y el que me acompañaron desde Madrid 3 amiguetes @gulnor @panicoenlaxbox y @Chkduke (@achamorroman se nos cayó en el último momento) y que tengo que darles las gracias porque me lo he pasado genial y por el regalito geek!!!

En la foto de inferior los 4 magníficos con @XaviPaper después del evento en el bar (No todo es programar)

BI9zQmrCUAAEv3e

Me gustaría dar las gracias publicamente a los organizadores y patrocinadores por hacer realidad el evento, por lo que hemos aprendido (16 ponencias de todo tipo), por habernos tratado tan bien, por el buen ambiente que hubo durante todo el fin de semana, por la buena organización, por las cervezas… de verdad muchas gracias, habéis dejado el listón muy pero que muy alto!!!

Comenté que para mi presentación me había basado en un libro gratuito y muy interesante, que tan solo tiene 38 páginas:

Web API Design – Crafting Interfaces that Developers Love

Un saludo.

PD: ¿Cuando tendrémos disponibles el vídeo del cierre del evento a cargo de @_pedrohurtado? XD

[ASP.NET WebAPI] Como recibir tipos complejos en nuestros controladores por URL

Actualmente, me encuentro desarrollando una API, me he encontrado con que en  algunos controladores, mejor dicho, en los métodos o acciones de estos controladores necesito recibir un tipo complejos, algo como esto:

public JObject GetProductsByTag(string tag, QueryStringRequestCommand requestCommand)

Este tipo complejo tiene básicamente las siguientes propiedades:

public class QueryStringRequestCommand
{
    [Minimum(1)]
    public int PageIndex { get; set; }
    [Minimum(1)]
    [Maximun(50)]
    public int PageSize { get; set; }
    public string Sort { get; set; }
} 

¿Para que uso este tipo complejo?

Pues para agrupar los valores que me vienen del QueryString y no tener un controlador con muchos parámetros y poder validarlos con atributos (DataAnnotations), así pues cuando se llame al controlador de productos:

/api/products/tagged/harinas?sort=newest&pageIndex=1&pageSize=20

se deserialize en un objeto del tipo QueryStringRequestCommand, pero!!! si pruebas este código tal cual lo he puesto, te darás cuenta que dicho parámetro vendrá a null:

image

Esto es debido a que al tratarse de un tipo complejo, WebAPI intentará deserializar la información con un media type formatter, que por defecto miran en el cuerpo de la petición y en nuestro caso está vacío porque esta información viene en la Url.

¿Pero como le digo a mi controlador como deserializar esta información?

Pues de una manera muy sencilla, basta con decorar el parámetro con este atributo FromUri para que utilize el model binder

public JObject GetProductsByTag(string tag, [FromUri] QueryStringRequestCommand requestCommand)

Probamos de nuevo y funciona!!!

image

¿A partir de ahora en todos métodos de mi controlador tengo que añadir el atributo FromUri?

Esa es una muy buena pregunta y la respuesta es NO.

Para ello vamos a hacer buen uso de la extensibilidad de WebAPI y para ello lo primero es crear una interfaz vacía que nos sirva de contrato:

public interface IRequestCommand
{
}

En nuestro tipo complejo la implementamos

public class QueryStringRequestCommand : IRequestCommand
{
    [Minimum(1)]
    public int PageIndex { get; set; }
    [Minimum(1)]
    [Maximun(50)]
    public int PageSize { get; set; }
    public string Sort { get; set; }
}

Y por último, vamos a añadir una regla a la colección de reglas ParameterBindingRules de la configuración (HttpConfiguration) para que sepa como hacer bind de nuestro tipo complejo:

config.ParameterBindingRules.Insert(
    0,
    descriptor => typeof(IRequestCommand).IsAssignableFrom(descriptor.ParameterType) ?
        new FromUriAttribute().GetBinding(descriptor) : null);

Cuando el tipo complejo que recibimos en la petición, sea asignable a nuestra interfaz IRequestCommand, que en el caso de QueryStringRequestCommand lo es porque implementa esta interfaz usará una instancia del atributo FromUri y así nos evitamos tener que estar decorando todos muestro métodos con este atributo (DRY).

image

Un saludo y espero que os haya gustado.

[Fiddler] Scratchpad es tu aliado

Si eres un enamorado de Fiddler (Sino lo conoces ya estas tardando en descargarlo e instarlo) como yo y te pasas el día lanzando llamadas a tu API REST y esas llamadas son muy repetitivas, te recomiendo que uses Scratchpad.

¿Que es Scratchpad?

Es una opción que viene por defecto en Fiddler que nos permite mantener una lista de nuestras llamadas HTTP.

¿Como funciona?

En la tab de Composer (Básicamente nos permite crear nuestras Request HTTP) creamos nuestra Request, en este ejemplo estoy llamando a WebAPI para que me devuelva un listado ordenado y paginado de preguntas:

image

Ejecutamos la Request, pinchamos en la pestaña de Scratchpad y arrastramos la respuesta:

image

A partir de ahora y aunque cerremos Fiddler, tendremos nuestra petición lista para lanzarla las veces que queramos con tan solo seleccionarla y ejecutarla:

image

Buen fin de semana a todos!!!

[Review] Patrones de diseño para C#

Hoy os voy a hablar de un libro que he estado leyendo estas últimas semanas Patrones de diseño para C# y la verdad es que me ha sorprendido bastante.

_2d1068cf0750487d35d1c52cbc071da8

A traves de un caso de estudio de venta online de vehículos nos va introduciendo en el mundo de los patrones de diseño, mostrando como aplicarlos en cada caso y que nos aporta cada uno, y encima en nuestra lengua materna Smile

Los patrones que aparecen en el libro son:

  1. Patrones de construcción:
    1. Abstract Factory
    2. Builder
    3. Factory Method
    4. Prototype
    5. Singleton
  2. Patrones de estructuración:
    1. Adapter
    2. Bridge
    3. Composite
    4. Decorator
    5. Façade
    6. Flyweight
    7. Proxy
  3. Patrones de comportamiento:
    1. Chain of Responsibility
    2. Command
    3. Interpreter
    4. Iterator
    5. Mediator
    6. Memento
    7. Observer
    8. State
    9. Strategy
    10. Template Method
    11. Visitor

Un saludo.

[ASP.NET WebAPI] Cuando usar un Message Handler y cuando un Filter

Podríamos pensar a simple vista que un message handler y un filter tienen la misma función en WebAPI pero tienen diferentes características y digo esto porque veo algunos ejemplos en que creo que no se hace un uso correcto de ellos.

A continuación os pongo un enlace a un poster de WebAPI para que todo el mundo tenga claro el pipeline de WebAPI:

ASP.NET Web API HTTP Message Lifecycle

Si nos fijamos en el poster podemos observar que los message handlers son invocados al principio y en cada petición del pipeline de WebAPI antes incluso de que se cree una instancia del controlador que corresponda en la petición, por lo cual son ideales en escenarios en los que tengamos que ejecutar algo de lógica que requiera ser ejecutada en cada petición, un ejemplo de ello sería la autenticación. Tenemos la oportunidad de crear una respuesta directamente y evitar que se siga ejecutando el pipeline.

Para poneros un ejemplo real imaginad que queremos controlar que nuestra aplicación solo pueda ser llamada de manera segura sobre SSL, para ellos podríamos crear un message handler:

public class SslMessageHandler : DelegatingHandler

{

    protected override Task<HttpResponseMessage> SendAsync(

        HttpRequestMessage request, 

        System.Threading.CancellationToken cancellationToken)

    {

        if (request.RequestUri.Scheme != Uri.UriSchemeHttps)

        {

            var forbiddenResponse =

                request.CreateResponse(HttpStatusCode.Forbidden);

 

            forbiddenResponse.ReasonPhrase = "SSL is required";

 

            return Task.FromResult(

                forbiddenResponse);

        }

 

        return base.SendAsync(request, cancellationToken);

    }

}

Y lo registramos:

config.MessageHandlers.Add(

        new SslMessageHandler());

Con esto comprobamos al principio del pipeline sí la petición se ejecuta de manera segura sobre https y sino creamos una respuesta de error al cliente. Si esto mismo lo hacemos con un filter estaríamos ejecutando todo el pipeline de Http Message handlers, creando el controlador, aplicando el filtro… esto al final acaba afectando al performance de nuestra api ya que todo ese tiempo de pipeline lo podríamos haber ahorrado usando un message handler.

Los filtros por el contrario tienen otra finalidad, por ejemplo los filtros para excepciones se ejecutan solo sí dentro del pipeline del controlador se produce una excepción, además como sabéis los filtros tienen un orden de ejecución dependiendo de su tipo, los primeros en ejecutarse son los AuthorizationFilters, luego los ActionFilters y por último los ExceptionFilters y ademas estos filtros los podemos aplicar globalmente, por controlador o por acción.

Un saludo.

Bibliografía: PRO ASP.NET WebAPI

[ASP.NET WebAPI] Validaciones: Evitar errores duplicados

Si estas trabajando con WebAPI y usando DataAnnotations te habrás dado cuenta que cuando el modelo que recibes no es válido y lanzas un error al cliente salen mensajes de error duplicados:

image

Los mensajes de la key “car” no son de DataAnnotations, son de los formatters, que por defecto chequean los campos requeridos y si encuentran algún error durante la fase de formateo añaden el mensaje de error a la colección de errores del ModelState.

Para eliminar estos errores y dejar más limpias las respuestas de error de nuestra API, podemos implementar nuestro propio IRequiredMemberSelector y remplazar el de los formatters:

public class MyRequiredMemberSelector 

    : IRequiredMemberSelector {

 

    public bool IsRequiredMember(MemberInfo member) {

 

        return false;

    }

}

Ahora solo falta decirle a los formatters que usen nuestro IRequiredMemberSelector:

var config = GlobalConfiguration.Configuration;

 

foreach (var formatter in config.Formatters)

{

    formatter.RequiredMemberSelector = new MyRequiredMemberSelector();

}

Y el resultado:

image

Un saludo

[MVP] MVPSummit2013.Dispose();

La semana pasada tuve el placer de asistir a mi primer MVP Summit y la verdad es que ha sido una experiencia increíble. Salimos de Madrid mi compañero y amigo Jorge Serrano rumbo a Amsterdam para luego coger un vuelo directo a Seattle. En el aeropuerto nos juntamos con Alberto Díaz y cogimos el Link dirección DownTown para juntarnos con más MVP españoles y amigos de Plain Concepts.

El fin de semana estuvimos de compras, visitando la fábrica de la Boeing y disfrutando de la gastronomía americana:

El sábado tuvimos una cena de MVPs y españoles que trabajan en Microsoft y el domingo por la mañana partimos hacia Bellevue para alojarnos en el Hyatt y prepararnos para las sesiones técnicas. He podido conocer en persona a David Fowler, Damian Edwards, Scott Hanselman, gente del equipo de producto de ASP.NET, Entity Framework gracias a mi amigo Unai Zorrila… pero sin duda con lo que me quedo de verdad es con los buenos momentos que he pasado con el grupo de MVP españoles, los amigos de Plain Concepts y los españoles que trabajan en Microsoft.

Hemos visitado el campus de Microsoft y de paso hemos aprovechado para hacer unas compras en la Store de Microsoft

WP_20130227 2

Hemos tenido un par cenas organizadas por Microsoft, una en el Hyatt de bienvenida y otra de despedida en el estadio de los Seattle Sounders

En esta última tuve el placer de interpretar un “Spanish Hit” como es el archiconocido “Paquito el Chocolatero”

El jueves regresamos al DownTown y estuvimos haciendo turismo por Seattle:

WP_20130227 22WP_20130227 55

Y el sábado regresamos de vuelta a España.

Por último, no quiero terminar este post sin antes dar las gracias a Cristina Gónzalez nuestra MVP Lead que nos cuida un montón.

Un saludo.