Con la llegada de .NET 6 (preview 7 a día de redacción) y C# 10.0 podemos encontrar features muy interesantes, entre ellas la creación de minimal apis. No es ni más ni menos que una API con una cantidad de código muy reducida respecto a la versión habitual sacando los Controllers de la ecuación.

A diferencia de otros lenguajes, crear una API en C# tiene un “ritual” en el que en el Program.cs configuramos lo relativo al host ( si no lo tenemos en un proyecto aparte, que es lo recomendable )  y especificamos que vamos a usar nuestra clase Startup.

Dentro del Startup es donde configuramos los servicios, controladores, autenticación, etc. No es un proceso complejo cuando ya sabes como funciona, pero tampoco es simple.

En Python usando FastAPI creamos una API con unas pocas líneas de código como podemos ver en el ejemplo de Enrique Catalá Fastapi-Helloworld donde en poco más de 30 líneas de código levanta una api con tres métodos.

Con .NET 6 y C# 10.0 podemos hacer algo similar a como lo haríamos en Python, incluso con menos código.

Vamos a crear dos proyectos de API uno con .NET 5 y otro con .NET 6 para compararlos.

Estos son los ficheros que genera la plantilla para las diferentes versiones .NET6  y .NET 5.

NET6

Usando la plantilla webapi que trae dotnet vemos que la versión .NET 6 ya no trae el Startup.cs pero nos sigue generando controladores que podemos quitar para minimizar la API aún más.

En la versión de .NET 5 vemos el contenido al que ya estamos acostumbrados en el Startup.cs

.NET 6 – Minimal API: La nueva manera de hacer APIs

Al igual que en el Program.cs donde esta la configuración básica del proceso de hosting:

.NET 6 – Minimal API: La nueva manera de hacer APIs

Hasta aquí a lo que estamos acostumbrados, pero ¿Qué contiene la plantilla .NET 6 webapi?

.NET 6 webapi

Aquí ya estamos viendo varias features nuevas, la primera es la importación implícita de namespaces que nos ahorrará tener que incluir los usings más típicos.

Dependiendo del tipo de SDK que tenga nuestro proyecto se incluirán unos u otros.

SDK

Default namespaces

Microsoft.NET.Sdk

System

System.Collections.Generic

System.IO

System.Linq

System.Net.Http

System.Threading

System.Threading.Tasks

Microsoft.NET.Sdk.Web

System.Net.Http.Json

Microsoft.AspNetCore.Builder

Microsoft.AspNetCore.Hosting

Microsoft.AspNetCore.Http

Microsoft.AspNetCore.Routing

Microsoft.Extensions.Configuration

Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.Hosting

Microsoft.Extensions.Logging

Microsoft.NET.Sdk.Worker

Microsoft.Extensions.Configuration

Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.Hosting

Microsoft.Extensions.Logging

La segunda feature “nueva” que podemos ver (la han mejorado en C# 10 pero viene de C# 9) es el top-level statements que nos permite eliminar la necesidad de generar una clase con un método static que reciba el string[] args y acerca más el desarrollo de aplicaciones a la estrategia de las Azure Functions y transforma nuestra API o aplicación en un “script” con muchas comillas.

Como nota adicional, solo podemos tener un fichero “top-level” no como en las Azure Functions.

Ahora bien, la plantilla por defecto sigue implementando un controlador y la idea de crear un minimal API es poder quitar los controladores de toda la ecuación. Para eso tenemos la nueva sobrecarga de la API Map.

El contenido del controlador WeatherForecastController es el siguiente:

.NET 6 – Minimal API: La nueva manera de hacer APIs

Partiendo del Program.cs que nos proporciona la plantilla vamos a quitar las llamadas a builder.Services.AddController() y app.MapControllers() ya que no los vamos a utilizar y en su lugar llamaremos a builder.Services.AddEnpointsApiExplorer() para que Swagger siga funcionando.

De paso eliminamos la carpeta Controllers con su contenido, ¡hasta luego controladores!

Como en el ejemplo no vamos a usar autorización para el acceso a los métodos de la API quitamos también app.UseAuthorization().

Ahora añadimos el siguiente código a nuestro Program.cs:

string[] Summaries = new[]
{
“Freezing”, “Bracing”, “Chilly”, “Cool”, “Mild”, “Warm”, “Balmy”, “Hot”, “Sweltering”, “Scorching”
};
 
app.MapGet(“/”, ()=>{
 
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
});
 

Pero para que esto funcione, debemos añadir el using de nuestro namespace que es donde tenemos definida la clase WeatherForecast y se nos queda un Program.cs muy cuco.

.NET 6 – Minimal API: La nueva manera de hacer APIs

34 líneas de código, nada mal.

En este momento ya hemos pasado el template de webapi de controladores a minimal API, pero ¿esto es aplicable a proyectos reales?

Hasta la llegada de C# 10 nos podía valer para hacer alguna prueba, etc. pero con la nueva feature de mejora de funciones lambda la cosa cambia. Esta feature nos permite añadir atributos a las funciones lambda y podemos usar por ejemplo el [Authorize] en la definición de la función o el [FromBody] a los parámetros de la función.

Además la versión preview de app.MapGet, app.MapPost,… inyectarán los parámetros como hacía en los controladores con lo que podemos extraer la lógica del método de la API a servicios e inyectarlos a nuestro método.

Vamos a probarlo creando un HelloWorldService:

HelloWorldservice

Añadimos el servicio:

builder.Services.AddSingleton<IHelloWorldService,MyHelloWorldService>();

y añadimos el siguiente código

app.MapGet(“/hello-world”, async(IHelloWorldService service, ILoggerFactory loggerFactory)=>{
var logger = loggerFactory.CreateLogger(“hello-world”);
logger.LogInformation(“GET: hello-world”);
 
return new{
message=service.HelloWorld
};
});
app.MapPost(“/hello-world”, async(IHelloWorldService service,ILoggerFactory loggerFactory,[FromBody] string name )=>{
var logger = loggerFactory.CreateLogger(“hello-world”);
logger.LogInformation(“POST: hello-world”);
 
return new {
message=service.Hello(name)
};
});

 

Con esto creamos un método post que recibe el nombre a través del cuerpo del mensaje y un método Get que simplemente hace una llamada al servicio que se le inyecta. Además, para ejemplo pasamos el ILoggerFactory para ver por consola el hit de la request.

Hacemos un dotnet run –build del proyecto y vamos a la UI del Swagger para probarlo:

Net6 minimal
.NET 6 – Minimal API: La nueva manera de hacer APIs

Con estas herramientas podremos hacer nuestros proyectos de API de esta manera.

Pero, ¿Nos aporta algo más? Pues sí, rendimiento.

En el artículo publicado en el devblogs de Microsoft sobre la preview 4 de .NET 6 [ASP.NET Core updates in .NET 6 Preview 4 | ASP.NET Blog (microsoft.com)] donde comparan el rendimiento de las APIs con el nuevo routing vs APIs con MVC (Controladores) el nuevo routing es capaz de lograr 800k RPS (Request Per Second) mientras que los controladores 500k RPS usando el benchmark JSON de TechEmpower

Es una mejora bastante notable como para tenerlo en cuenta a la hora de elegir por donde afrontar un nuevo proyecto.

Tienes el código del ejemplo en nuestro GitHub

Conclusión

Por ir recapitulando, con la salida de .NET 6 en noviembre de 2021 (fecha prevista) recibiremos una mejora en rendimiento reduciendo la complejidad para crear APIs con una curva de aprendizaje menos agresiva.

Esto es lo que sabemos a día de hoy de lo que traerá .NET 6 y quedan un par de meses para la primera release, pero buena pinta tiene. ¡Habrá que estar atentos a ver qué novedades trae!

0 Shares:
Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

You May Also Like
SQL Server en Kubernetes (Parte 2)
Leer más

Matar al mensajero – SQL Server en Kubernetes (Parte 2)

En la primera parte de este artículo explicamos en qué consiste un SQL Server en contenedores y mostramos una forma sencilla de crear un entorno Kubernetes manejado. En esta segunda parte vamos a enfocarnos en los escenarios más críticos donde el uso de contenedores puede añadirnos latencias y esperas extras que acaben impactando en el rendimiento percibido por nuestros usuarios tras una migración de SQL Server a contenedores.