Laboratorio 21

Crear una Web API minima .NET y Docker con Copilot

Antes de ejecutar este laboratorio, instalemos primero los paquetes de software necesarios y configuremos el entorno

Fuente validada

Lab_21_WebAPI_NET_Docker.docx

Esta pagina fue reconstruida desde el documento del ZIP entregado como fuente principal.

Conformidad visual

Sin imagenes publicadas

El archivo fuente contiene 0 imagenes embebidas. Para garantizar conformidad, no se publican imagenes heredadas de otros materiales.

Criterio GH-300

Practica verificable

Ejecuta los comandos, captura evidencia propia y valida cada sugerencia de Copilot antes de aceptarla.

Alcance de publicacion: Solo se publica el contenido del laboratorio indicado por el archivo Lab_21_WebAPI_NET_Docker.docx. Las imagenes no se muestran porque el ZIP no incluye imagenes embebidas en este documento.

Certificación GH-300

Laboratorio 21

WebAPI .NET Minimal + Docker con GitHub Copilot

Autor: Carlos Crudo

linkedin.com/in/carloscrudo

Creación de una Web API mínima con .NET y generación de la imagen Docker correspondiente usando GitHub Copilot para acelerar el desarrollo full-stack.

Temas que cubre este laboratorio:

.NET Minimal API con Copilot

Swagger / OpenAPI auto-generado

Dockerfile para .NET con Copilot

Docker Compose para desarrollo local

Publicar en GitHub Container Registry

Copilot Chat para debugging .NET

Laboratorio 21: WebAPI .NET Minimal + Docker con GitHub Copilot

Lab 21 - Crear una WebAPI mínima usando .NET y una imagen Docker correspondiente con GitHub Copilot

Objetivo:

El objetivo es crear una Web API Mínima usando .NET 7.0 y una imagen Docker correspondiente con la ayuda de GitHub Copilot. Aquí usamos GitHub Copilot tanto como podemos.

Prueba diferentes cosas y mira qué puede hacer GitHub Copilot por ti, como generar un archivo Docker o una clase, añadir comentarios, etc.

Antes de ejecutar este laboratorio, instalemos primero los paquetes de software necesarios y configuremos el entorno

Ejercicio 0: Instalar y configurar el entorno

Necesitas descargar e instalar los siguientes paquetes de software para configurar el entorno que permita ejecutar este laboratorio.

• dotnet-sdk-8.0

Abre el navegador de Edge.

En el campo URL del navegador, copia y pega el enlace para descargar el paquete de software en la máquina virtual de tu laboratorio.

dotnet-sdk-8.0 https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-8.0.401-windows-x64-installer

Nota: Por defecto, los paquetes se guardarán en la carpeta de descargas.

Instalar .NET SDK Ve a la carpeta Descargas (C:\Users\Admin\Descargas) y haz doble clic en dotnet-sdk-8.0.401 y sigue el proceso de instalación.

Ejercicio 1: Configurar el proyecto en VS Code

Abre el código de Visual Studio desde el menú Inicio.

Seleccionar archivo -> abrir carpeta...

Selecciona la carpeta CopilotHackathon desde C:\Labfiles y haz clic en Seleccionar carpeta.

Haz clic en Sí, confío en los autores.

Ejercicio 2: Introducción

Nota: El código generado por el Copilot puede variar en distintas ejecuciones. En los pasos en los que se involucra la generación de código a continuación, hemos dado el código de referencia. Por favor, utilízalo para comprobar la corrección del código generado por Copilot o para resolver errores, si los hay.

Abre Program.cs desde dotnet -> MinimalAPI.

Dentro de MinimalAPI\Program.cs después de la línea AÑADIR NUEVOS PUNTOS FINALES HERE (LÍNEA NÚMERO 19), ESCRIBE Y PULSA Enter. El Copilot sugerirá el código en gris.*// Hello World Get endpoint*

Una vez que tengas el código generado por el Copilot, puedes aceptarlo o descartarlo. Para aceptar, haz clic en el botón Ctrl y aparecerá la barra de opciones sobre el texto gris. Otra opción es simplemente pulsar la tecla Tab.

Código de referencia: app.MapGet("/", () => "Hello World!");

El código ahora se verá así. Guarda el archivo.

Haz clic derecho en la carpeta dotnet y selecciona Abrir en Terminal Integrado.

Desde el terminal, ejecuta el siguiente comando.

dotnet test

Ejercicio 3: Crear nuevas funcionalidades

Junto al endpoint de Hello World, añade DíasEntreFechas.

Pulsa Ctrl+I en orden, abre el Copilot en línea.

Introduce el siguiente texto y pulsa el botón Enviar.

/DaysBetweenDates:

calculate days between two dates

receive by query string two parameters date1 and date2, and calculate the days between those two dates.

El Copilot ahora genera código y lo introduce en el archivo Program.cs. Una vez hecho, verás dos opciones: Aceptar o Desechar. Acepta el código.

Una vez aceptado, selecciona el código generado y pulsa Ctrl+I. Entra y pulsa Enter. Haz clic en Aceptar una vez que el código se convierta en una sola línea.Convert this code into a single line

Código de referencia - app.MapGet("/DaysBetweenDates", (DateTime date1, DateTime date2) => (date2 - date1).Days.ToString());

Introduce las siguientes declaraciones (comentado) y haz clic en Enter.

Haz clic en Aceptar para aceptar el código generado por el Copiloto.

*/

*/validatephonenumber:*

*receive by querystring a parameter called phoneNumber*

*validate phoneNumber with Spanish format, for example +34666777888*

*if phoneNumber is valid return true*

/*

Código de referencia:

app.MapGet("/validatephonenumber", (string phonenumber) => Regex.IsMatch(phonenumber, @"^(\+[0-9]{9})$").ToString());

Añade el texto de abajo como en la función de Copilot en línea, en el archivo Program.cs y pulsa Enter.

/validatespanishdni:

receive by querystring a parameter called dni

calculate DNI letter

if DNI is valid return "valid"

if DNI is not valid return "invalid"

En este caso, puede que quieras consultar varias soluciones de Copilot para elegir la que mejor se adapte a la forma de calcular la carta. Para ver las primeras 10 sugerencias de Copilot, pulsa ctrl + enter.

Acepta el código generado por GitHub.

Código de referencia:

app.MapGet("/validatespanishdni", (string dni) => {

var valid = false;

if (dni.Length == 9 && int.TryParse(dni.Substring(0, 8), out int number))

{

var letters = "TRWAGMYFPDXBNJZSQVHLCKE";

var letter = letters[number % 23];

valid = dni.EndsWith(letter.ToString());

}

return valid ? "valid" : "invalid";

});

Selecciona Chat en el panel izquierdo.

Introduce el texto siguiente y haz clic en Enter.

/returncolorcode:

receive by querystring a parameter called color read colors.json file and return the rgba field get color var from querystring iterate for each color in colors.json to find the color return the code.hex field

Asegúrate de que el Copilot dé los pasos detallados y luego el código generado. Coloca el cursor en el archivo Program.cs, después del código validatspanishdni. Haz clic en el icono Insertar en el cursor para pegar el código en el archivo.

Código de referencia:

app.MapGet("/color", (string color) =>

{

var colors = JsonSerializer.Deserialize<Color[]>(File.ReadAllText("colors.json"));

return colors.First(c => c.Name == color).Code.HEX;

});

Asegúrate de que no haya errores en el código generado. Si existe un error, mantén el código de referencia como referencia y corre el código.

En este caso, hay un error: Color no contiene definición de código.

El código generado se actualiza como se indica a continuación para resolver los errores.

Introduce el texto de abajo y pulsa Enter y revisa y acepta el código generado por Copilot.

*/

*/tellmeajoke:*

*Make a call to the joke api and return a random joke*

/*

Código de referencia:

app.MapGet("/tellmeajoke", async () => {

var client = new HttpClient();

var response = await client.GetAsync("https://official-joke-api.appspot.com/jokes/random");

var joke = await response.Content.ReadAsStringAsync();

return joke;

});

NOTA: Este es un ejemplo en el que quizá necesites usar tu propio conocimiento y juicio para validar que Copilot sigue las mejores prácticas. Que Copilot imite lo que muchos desarrolladores hacen no siempre significa que sea la forma correcta. Puede que tengas que ser muy específico en tu prompt para informar a Copilot de cuáles son las mejores prácticas. Consejo: Presta atención a HttpClient.

Copilot puede ayudarte a aprender nuevos frameworks.

Introduce el texto de abajo en Copilot inline y pulsa Enter.

/parseurl:

Retrieves a parameter from querystring called someurl

Parse the url and return the protocol, host, port, path, querystring and hash

Return the parsed host

Código de referencia:

app.MapGet("/parseurl", (string someurl) => {

var uri = new Uri(someurl);

var host = uri.Host;

var protocol = uri.Scheme;

var port = uri.Port;

var path = uri.AbsolutePath;

var query = uri.Query;

var hash = uri.Fragment;

return host;

});

Copilot también puede ayudar con este tipo de comandos localmente. La función se llama Copilot en la línea de crédito. Puedes obtener más información sobre esta función aquí.

Abre Copilot Inline, introduce el texto de abajo y pulsa Enter.

/listfiles:

Get the current directory

Get the list of files in the current directory

Return the list of files

Código de referencia:

app.MapGet("/listfiles", () => {

var currentDirectory = Directory.GetCurrentDirectory();

var files = Directory.GetFiles(currentDirectory);

return files;

});

Introduce el texto de abajo en el copilot en línea y pulsa Enter.

/calculatememoryconsumption:

Return the memory consumption of the process in GB, rounded to 2 decimals

Código de referencia:

*// Calculate memory consumption endpoint*

app.MapGet("/calculatememoryconsumption", () =>

{

var process = System.Diagnostics.Process.GetCurrentProcess();

var memoryUsage = process.WorkingSet64 / (1024.0 * 1024 * 1024); *// Convert to GB*

return Math.Round(memoryUsage, 2);

});

Introduce el texto de abajo en Copilot inline y pulsa Enter.

/randomeuropeancountry:

Make an array of european countries and its iso codes

Return a random country from the array

Return the country and its iso code

Código de referencia:

*// Random European Country endpoint*

app.MapGet("/randomeuropeancountry", () =>

{

var europeanCountries = new Dictionary<string, string>

{

{ "Albania", "AL" },

{ "Andorra", "AD" },

{ "Austria", "AT" },

{ "Belarus", "BY" },

{ "Belgium", "BE" },

{ "Bosnia and Herzegovina", "BA" },

{ "Bulgaria", "BG" },

{ "Croatia", "HR" },

{ "Cyprus", "CY" },

{ "Czech Republic", "CZ" },

{ "Denmark", "DK" },

{ "Estonia", "EE" },

{ "Finland", "FI" },

{ "France", "FR" },

{ "Germany", "DE" },

{ "Greece", "GR" },

{ "Hungary", "HU" },

{ "Iceland", "IS" },

{ "Ireland", "IE" },

{ "Italy", "IT" },

{ "Kosovo", "XK" },

{ "Latvia", "LV" },

{ "Liechtenstein", "LI" },

{ "Lithuania", "LT" },

{ "Luxembourg", "LU" },

{ "Malta", "MT" },

{ "Moldova", "MD" },

{ "Monaco", "MC" },

{ "Montenegro", "ME" },

{ "Netherlands", "NL" },

{ "North Macedonia", "MK" },

{ "Norway", "NO" },

{ "Poland", "PL" },

{ "Portugal", "PT" },

{ "Romania", "RO" },

{ "Russia", "RU" },

{ "San Marino", "SM" },

{ "Serbia", "RS" },

{ "Slovakia", "SK" },

{ "Slovenia", "SI" },

{ "Spain", "ES" },

{ "Sweden", "SE" },

{ "Switzerland", "CH" },

{ "Ukraine", "UA" },

{ "United Kingdom", "GB" },

{ "Vatican City", "VA" }

};

var random = new Random();

var index = random.Next(europeanCountries.Count);

var country = europeanCountries.ElementAt(index);

return $"{country.Key} ({country.Value})";

});

Ejercicio 4: Documentar el código

Abre la ventana del chat.

Escribe, documenta el archivo Program.cs y selecciona Enviar.

GitHubCopiot genera una breve documentación del archivo Program.cs.

Ejercicio 5: Pruebas de construcción

Abre Program.cs archivo.

Selecciona el endpoint DaysBetweenDates, pulsa Ctrl+I para abrir el Copilot en línea.

En la línea de Copilot, escribe /tests y haz clic en el botón Enviar.

Copia la prueba generada.

Abre la IntegrationTests.cs desde MinimalAPI.Tests.

Pégalo en el archivo de CS después del bloque de prueba de Hello World. Resuelve cualquier problema que pueda surgir.

Abre el chat del Copilot desde el panel izquierdo.

Escribe , el comando para crear unidades de prueba y pulsa Enter. El Copilot genera un archivo de prueba. Copia su contenido./tests

Abre IntegrationTests.cs desde MinimalAPI.Tests.

Sustituye el contenido del archivo por el código generado por Copilot y guarda.

Importante: Revisa si hay errores y arréglalo usando el comando /fix o manualmente. Usa el código de referencia de abajo para solucionar el problema.

Si las pruebas no se generan para todos los endpoints, desde el chat, especifica el nombre del endpoint y pide al Copilot que genere la prueba como se indica a continuación. Actualiza los nombres de los endpoints según cuáles se hayan actualizado y cuáles falten en tu prueba.

generate test units for moviesbydirector, parseurl, listfiles, calculatememoryconsumption and randomeuropeancountry

Código de referencia:

using System;

using System.Net.Http;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc.Testing;

using Xunit;

public class EndpointTests : IClassFixture<WebApplicationFactory<Program>>

{

private readonly WebApplicationFactory<Program> _factory;

private readonly HttpClient _client;

public EndpointTests(WebApplicationFactory<Program> factory)

{

_factory = factory;

_client = _factory.CreateClient();

}

[Fact]

public async Task Get_HelloWorld_ReturnsHelloWorld()

{

var response = await _client.GetAsync("/");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.Equal("Hello World!", stringResponse);

}

[Fact]

public async Task Get_ValidatePhoneNumber_ReturnsInvalid()

{

var response = await _client.GetAsync("/validatephonenumber?phonenumber=123456789");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.Equal("False", stringResponse);

}

[Fact]

public async Task Get_ValidateSpanishDni_ReturnsValid()

{

var response = await _client.GetAsync("/validatespanishdni?dni=12345678Z");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.Equal("valid", stringResponse);

}

[Fact]

public async Task Get_Color_ReturnsHexCode()

{

var response = await _client.GetAsync("/color?color=red");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.Equal("#FF0000", stringResponse); *// assuming red color returns #FF0000*

}

[Fact]

public async Task Get_TellMeAJoke_ReturnsJoke()

{

var response = await _client.GetAsync("/tellmeajoke");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.NotNull(stringResponse); *// assuming the joke API always returns a joke*

}

[Fact]

public async Task Get_ParseUrl_ReturnsHost()

{

var response = await _client.GetAsync("/parseurl?someurl=https://www.example.com");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.Equal("www.example.com", stringResponse);

}

[Fact]

public async Task Get_ListFiles_ReturnsFiles()

{

var response = await _client.GetAsync("/listfiles");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.NotNull(stringResponse); *// assuming the API always returns a list of files*

}

[Fact]

public async Task Get_CalculateMemoryConsumption_ReturnsMemoryUsage()

{

var response = await _client.GetAsync("/calculatememoryconsumption");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.NotNull(stringResponse); *// assuming the API always returns a memory usage*

}

[Fact]

public async Task Get_RandomEuropeanCountry_ReturnsCountry()

{

var response = await _client.GetAsync("/randomeuropeancountry");

response.EnsureSuccessStatusCode();

var stringResponse = await response.Content.ReadAsStringAsync();

Assert.NotNull(stringResponse); *// assuming the API always returns a country*

}

*// Add similar tests for the other endpoints*

}

Desde el terminal, ejecuta el comando, prueba dotnet

Si la prueba pasa, deberías ver un resultado similar al que aparece en la captura de pantalla de abajo.

Puedes añadir más pruebas si es necesario.

Ejercicio 6: Crear un archivo Dockerfile

Haz clic derecho en la carpeta dotnet y selecciona Nuevo archivo y nombra el archivo como Dockerfile.

Nombra el archivo como Dockerfile.

En el archivo recién creado, pulsa Ctrl+I, escribe el texto de abajo y pulsa Enter.

Generar contenido para Dockerfile para .NET 8 Nombre del proyecto - MinimalAPI

Acepta el código generado.

Guarda el archivo. Desde el Terminal, ejecuta el siguiente comando.

docker build -t dotnetapp .

Usa el código de referencia para resolver errores si los hay.

Código de referencia:

*# Use the official .NET SDK image as the base image*

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build

*# Set the working directory in the container*

WORKDIR /app

*# Copy the project file(s) to the container*

COPY *.csproj ./

*# Copy the remaining source code to the container*

COPY . ./

*# Build the application*

RUN dotnet build -c Release

*# Publish the application*

RUN dotnet publish -c Release --no-build -o out

*# Use the official .NET runtime image as the base image for the final stage*

FROM mcr.microsoft.com/dotnet/runtime:8.0 AS runtime

*# Set the working directory in the container*

WORKDIR /app

*# Copy the published output from the build stage to the final stage*

COPY --from=build /app/out ./

*# Set the entry point for the container*

ENTRYPOINT ["dotnet", "MinimalAPI.dll"]

Ejecuta el siguiente comando para ejecutar la app en el puerto 8080

docker run -d -p 8080:80 --name dotnetapp dotnetapp

Ahora tenemos la app dotnet ejecutándose en el docker.