Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

19 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 2 de mayo de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 25 de abril de 2023
ASP.NET Core

Atributos como [FromRoute], [FromForm], [FromQuery] o [FromBody], entre otros, permiten ser muy precisos a la hora de indicar al framework cómo poblar los parámetros de los handlers de nuestros endpoints contruídos con Minimal APIs.

Por ejemplo, en la siguiente API sencilla se puede intuir que el parámetro id del manejador será obtenido de la ruta, mientras que number se obtendrá desde la query string:

app.MapPost("/friends/{id}/phones", ([FromRoute] int id, [FromQuery] string number) =>
{
    // Añadir un número de teléfono al amigo
});

Y otro ejemplo, en el que usamos  [FromBody] para especificar que el parámetro de tipo Friend queremos obtenerlo desde el cuerpo de la petición:

app.MapPut("/friends/{id}", ([FromRoute] int id, [FromBody] Friend friend) =>
{
    // Actualizar amigo
});

lunes, 24 de abril de 2023
martes, 18 de abril de 2023
Entity Framework

Versión tras versión, Entity Framework Core sigue introduciendo novedades que lo hacen cada vez más potente y atractivo para los desarrolladores. Sin ir más lejos, EF7, la última entrega disponible, incorporó bastantes mejoras en términos de rendimiento, soporte para columnas JSON, mapeo TPC, mapeo a procedimientos almacenados y muchas otras.

Pero una de las novedades que me resultó más interesante, quizás por ser muy esperada, fue la posibilidad de realizar borrados y actualizaciones de forma masiva sin tener que recurrir a lanzar directamente comandos SQL. O dicho de otra forma, con EF7 podremos ejecutar sentencias DELETE y UPDATE sobre la base de datos sin abandonar LINQ :)

lunes, 17 de abril de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 11 de abril de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

lunes, 3 de abril de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 28 de marzo de 2023
C#

A raíz del artículo publicado hace algunas semanas sobre las ventajas de usar diccionarios en lugar de listas, me llegaba vía comentarios un escenario en el que se utilizaba una clase List<T> para almacenar objetos a los que luego se accedía mediante clave. Lo diferencial del caso es que dichos objetos tenían varias claves únicas a través de las cuales podían ser localizados.

Por verlo por un ejemplo, el caso era más o menos como el que sigue:

public class FriendsCollection
{
    private List<Friend> _friends = new();
    ...
    public void Add(Friend friend)
    {
        _friends.Add(friend);
    }

    public Friend? GetById(int id) 
        => _friends.FirstOrDefault(f => f.Id == id);

    public Friend? GetByToken(string token) 
        => _friends.FirstOrDefault(f => f.Token == token);
}

Obviamente en este escenario no podemos sustituir alegremente la lista por un diccionario, porque necesitamos acceder a los elementos usando dos claves distintas. Pero, por supuesto, podemos conseguir también la ansiada búsqueda O(1) si le echamos muy poquito más de tiempo.

lunes, 27 de marzo de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 21 de marzo de 2023
C#

El pattern matching de C# proporciona la capacidad de analizar expresiones para ver si cumplen determinados "patrones" o presentan características determinadas. Podéis ver algunos ejemplos interesantes en el post Un vistazo a los patrones relacionales y combinadores.

Aunque ya los tengo bastante interiorizados y hago uso de ellos cuando toca, todavía no se me ha dado el caso de necesitar los patrones de listas, introducidos hace unos meses en C# 11. Así que no está de más echarles un vistazo para cuando se dé la ocasión 😉

lunes, 20 de marzo de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 14 de marzo de 2023
C#

A veces, los problemas de rendimiento de las aplicaciones, o determinadas funcionalidades de ellas, vienen derivados del uso de estructuras incorrectas para almacenar los datos, ya sea en memoria, base de datos o en cualquier tipo de almacén.

En este post vamos a centrarnos en un caso específico que me he encontrado demasiadas veces en código real: el uso indebido del tipo List<T> cuando sólo nos interesa buscar en esta colección por una propiedad que actúa como identificador único del objeto T.

lunes, 13 de marzo de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 7 de marzo de 2023
Visual Studio

Si desarrollas APIs, probablemente utilizarás Postman, Fiddler o herramientas similares para probarlas. Cualquier utilidad capaz de lanzar peticiones y analizar la respuesta, incluso basadas en línea de comandos como el desconocido Dotnet HTTP REPL, viene de perlas para ponernos en el lugar del cliente y comprobar cómo responde nuestra API ante determinados parámetros de entrada, o qué se siente al consumirla.

Tiempo atrás, el descubrimiento de la extensión REST client para Visual Studio Code supuso una bocanada de aire fresco en la forma de lanzar peticiones y examinar respuestas, para mi gusto mucho más cómoda que las que estaba acostumbrado a utilizar. Esta extensión permite definir peticiones HTTP en archivos de texto con extensión .http o .rest y ejecutarlas de forma realmente sencilla, sin abandonar el IDE.

Pues bien, la última revisión de Visual Studio 2022 (17.5) ha incluido el soporte nativo para este tipo de archivos, así que cada vez lo tenemos más sencillo. Y como es posible que alguno de vosotros aún no lo conozca, vamos a echarle un vistazo ;)

lunes, 6 de marzo de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

lunes, 27 de febrero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 21 de febrero de 2023
C#

Aunque muchos de nosotros trabajamos a diario con C#, siempre hay algo nuevo por aprender o formas de utilizar algunas características que nunca se nos habían ocurrido. Siempre.

En un nuevo capítulo de la serie de C# bizarro, hoy os planteo un reto sobre este código:

var sum = (int a, int b) => a + b;
var sub = (int a, int b) => a - b;
var mul = (int a, int b) => a * b;
var result = sum - sub + mul;

Console.WriteLine("Resultado: " + result(3, 2));
¿Compila? Y si es así, ¿qué aparece por consola? ¡No sigáis leyendo! Echad un vistazo al código e intentad averiguarlo antes de ver la solución pulsando aquí :)
Pues sí, este código es totalmente válido y compilará sin problema. Y al ejecutarlo, por consola veremos lo siguiente.
Resultado: 6

En primer lugar el código compila correctamente porque las variables sum, sub y mult, que hemos definido usando expresiones lambda de tipo Func<int, int, int>, a la postre son simplemente delegados.

Además, los tres delegados tienen la firma idéntica (reciben dos valores int y retornan un int), podemos utilizar los operadores de combinación suma "+" y resta "-", lo que da lugar a un delegado de multidifusión (multicast delegate).

En nuestro código, creamos el nuevo delegado de multidifusión result combinando sum y mult, que son los dos delegados que se suman. Por otra parte, la resta de sub es simplemente una maniobra de distracción, pues se intentará eliminar de la combinación un delegado que no existía previamente, por lo que la operación será ignorada.

var result = sum - sub + mul;

Tras ejecutar esta línea, result será un Func<int, int, int> cuya invocación provocará que se ejecuten secuencialmente, y por orden de llegada, los delegados que han sido combinados.

Por tanto, cuando se evalúa la expresión result(3, 2), se ejecutará primero la función sum(3, 2) y luego mul(3, 2), y será el resultado de esta última la que se retorne finalmente. De ahí obtenemos el 6 que va a la consola.

¿Qué, habías acertado?


Publicado en Variable not found.
lunes, 20 de febrero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 14 de febrero de 2023
Blazor

Hace poco, un alumno de mi curso de Blazor en CampusMVP me preguntaba si, para seguir con las viejas costumbres, desde Blazor Server era posible escribir en la consola del navegador.

Aunque no tiene demasiado sentido hacerlo dado que disponemos de buenas herramientas de depuración, me pareció un ejemplo interesante para aplicar los mecanismos de interoperación de Blazor con JavaScript. Además, quizás interese a alguien más, así que vamos a ver por aquí cómo hacerlo.

Pero antes de meternos en faena, vale la pena decir que lo que veremos no es específico de Blazor Server, sino que también podremos usarlo en Blazor WebAssembly. Los mecanismos básicos de interoperación con JavaScript son idénticos, por lo que en este post veremos cómo implementar un código válido para ambos tipos de hosting.

lunes, 13 de febrero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 7 de febrero de 2023
JavaScript

Me gusta estar atento a las novedades que van apareciendo el lenguajes y frameworks que nos ayudan a mejorar la forma de hacer las cosas. Lamentablemente, en este mundo tan cambiante no es fácil estar al día en todo, y hay muchas veces que sigo haciendo cosas como siempre aunque existan fórmulas más modernas y mejores para conseguirlo.

Un ejemplo lo he encontrado hace poco, cuando, trabajando con JavaScript, una vez más he tenido necesidad de parsear la URL de la página actual en busca de los valores de los parámetros suministrados en la query string al cargar una página. Lo habitual en estos casos era tirar de Google o StackOverflow y acabar implementado una función parecida a la siguiente:

function getParameterValue(name, url = window.location.href) {
    name = name.replace(/[\[\]]/g, '\\$&');
    var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, ' '));
}

Casualmente, en este caso recordé haber leído de pasada sobre la existencia de un "nuevo" objeto de JavaScript que actualmente nos permite hacerlo de forma más sencilla, así que aproveché para ponerme un poco al día al respecto ;)

lunes, 6 de febrero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 31 de enero de 2023
.NET

Seguimos hablando de problemas que es habitual solucionarlos de una determinada manera, quizás por costumbre, quizás por pereza, o tal vez por desconocimiento de que haya otras formas de hacerlo. En este caso, hablaremos de una necesidad que probablemente habréis tenido alguna vez: transformar un GUID a una cadena de caracteres eliminando los habituales guiones.

Es decir, dado un GUID con el valor 1f5772a6-91ca-4035-8b6d-9676ec6d0eaa, queremos obtener su representación como cadena de caracteres, pero eliminando los guiones, resultando "1f5772a691ca40358b6d9676ec6d0eaa".

lunes, 30 de enero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

lunes, 23 de enero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante una griposa y febril semana pasada. Así que espero que os resulten especialmente interesantes. ;-)

Por si te lo perdiste...

.NET Core / .NET

martes, 17 de enero de 2023
ASP.NET Core

Desde la llegada de ASP.NET Core, hace ya algunos años, muchos hemos echado de menos el filtro [OutputCache] de ASP.NET MVC "clásico". Aunque el nuevo framework ofrece alternativas interesantes para gestionar la caché tanto en el lado cliente como en el servidor, ninguna aportaba las funcionalidades que este filtro nos ofrecía.

Como recordaréis, a diferencia de las opciones ofrecidas actualmente por ASP.NET Core, como el filtro [ResponseCache] o el middleware ResponseCaching, que básicamente se regían por los encabezados presentes en peticiones y respuestas HTTP, el filtro [OutputCache] es una solución de caché residente exclusivamente en el servidor. En este caso, la decisión de si el resultado a una petición se almacena o no se realiza completamente desde la aplicación, de forma totalmente independiente a encabezados o requisitos procedentes del lado cliente.

En ASP.NET Core 7 este filtro ha vuelto a la vida en forma de middleware, que ofrece sus funcionalidades con dos sabores distintos:

  • Con anotaciones aplicables a endpoints implementados con Minimal API.
  • Como filtro, aplicable a controladores y acciones MVC.

Echémosles un vistazo.

lunes, 16 de enero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 10 de enero de 2023
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

lunes, 9 de enero de 2023
2023 Top ten

Ante todo, aprovecharé esta inigualable ocasión para desearos lo mejor para este nuevo año 2023 que se está empezando a dibujar. Espero que tengáis oportunidad de cumplir vuestros proyectos y de disfrutar del camino que os lleve a ellos.

Y para empezar con buen pie, como es habitual, vamos a repasar los 10 artículos más leídos en Variable Not Found durante este 2022 que acaba de terminar.

miércoles, 28 de diciembre de 2022

Computer bug

En septiembre de 1947, Grace Murray Hopper y sus compañeros de la Universidad de Harvard descubrieron, sobre un relé electromagnético de su Mark II, una polilla (en inglés, moth) chamuscada que provocaba que su programa no funcionara correctamente. "No funciona porque aquí hay un bicho", debieron pensar.

martes, 27 de diciembre de 2022
Enlaces interesantes

Lo primero, aunque llegue algo tarde, aprovecho para desearos unas felices fiestas :)

Y siguiendo con nuestro tema, aunque no está recogido en ninguna RFC ni documento oficial (o al menos no he sido capaz de encontrarlo) el código de error HTTP 509 (Bandwidth Limit Exceeded) suele utilizarse para informar al lado cliente de que la solicitud no puede ser procesada porque el servidor ha sobrepasado el límite de ancho de banda que tenía disponible. Normalmente ocurre cuando el plan del hosting utilizado es insuficiente para manejar el tráfico del sitio web, por lo que debe ser upgradeado para que todo siga funcionando.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 20 de diciembre de 2022
Blazor

Si habéis trabajado algo con Blazor, seguramente sabréis que los componentes escritos en archivos .razor son traducidos en tiempo de compilación a lenguaje C# y posteriormente compilados como cualquier otra clase de nuestro proyecto.

Por tanto, ¿que impediría que nos saltásemos ese paso y escribiéramos nuestros componentes directamente en C#? Efectivamente, nada ;)

En este post veremos cómo hacerlo.

Pero antes, un disclaimer: apenas existen razones prácticas para implementar componentes visuales usando C#. Usando Razor todo será más sencillo, rápido y tendremos menos riesgo a equivocarnos, así que esa debe ser la opción por defecto. Por tanto, lo que vamos a ver aquí no debéis usarlo salvo en casos justificados (por ejemplo, cuando queráis crear componentes sin UI).

lunes, 19 de diciembre de 2022
Enlaces interesantes

El código de estado HTTP 508 (Loop Detected) indican que el servidor ha finalizado la operación debido a la detección de un bucle infinito mientras procesaba una petición realizada con el valor "infinite" en el encabezado "depth". Este encabezado forma parte de las extensiones HTTP de WebDAV y se usa para realizar operaciones que pueden afectar a un recurso y a todos sus miembros, hasta el nivel de profundidad especificado.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 13 de diciembre de 2022
C#

Otra de las novedades del flamante C# 11 viene a romper una limitación histórica: la ausencia de tipos genéricos en la definición de atributos.

Hasta esta versión del lenguaje, cuando necesitábamos introducir referencias a tipos de datos en un atributo, debíamos pasar obligatoriamente por el uso de un System.Type y el verboso operador typeof(). Además de incómodo, no había forma de limitar los tipos suministrados, dando lugar a errores en tiempo de ejecución que bien podrían haber sido resueltos el compilación con las herramientas apropiadas.

Dicho así quizás sea difícil de entender, pero veámoslo con un ejemplo.

lunes, 5 de diciembre de 2022
Enlaces interesantes

Pasando del 503 ninguno de los códigos de estado HTTP son demasiado conocidos, así que esto se está convirtiendo en una oportunidad para echarles un vistazo y al menos, saber que están ahí.

Esta semana seguimos con el HTTP 507 (Insufficient storage), que indica que el espacio de almacenamiento en el servidor no es suficiente para completar la operación. Según la especificación, la petición no debe ser reintentada hasta que sea solicitada por una acción independiente del usuario; o sea, que cuando recibamos este error, deberíamos informar al usuario y, si procede, permitirle reintentar.

Y ahora, ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 29 de noviembre de 2022
ASP.NET Core

Hace algunas semanas vimos cómo crear inline route constraints, o restricciones de ruta en línea en ASP.NET Core, y creamos un ejemplo simple que permitía al sistema de routing detectar si el valor suministrado a través de un parámetro de ruta era una palabra palíndroma.

Para ello, creamos la restricción "palindrome" que, implementada en la clase PalindromeConstraint podíamos usar de la siguiente forma:

// Uso en minimal API:
app.MapGet("/test/{str:palindrome}", (string str) => $"{str} is palindrome");

// Uso en MVC:
public class TestController : Controller
{
    [HttpGet("/test/{str}")]
    public string Text(string str) => $"{str} is palindrome";
}

Sin embargo, si atendemos a la lista de restricciones disponibles de serie en ASP.NET Core, vemos que hay algunas de ellas que son parametrizadas, como maxlength o range:

Plantilla de ruta Significado
/order/{orderId:minlength(5) orderId debe tener como mínimo 5 caracteres
/setAge/{age:int:range(0,120) age debe ser un entero entre 0 y 120

En este post vamos a ver precisamente eso, cómo crear una restricción personalizada con parámetros.

lunes, 28 de noviembre de 2022
Enlaces interesantes

El desconocido (al menos para mí) código de estado HTTP 506 (Variant also negotiates) indica que el servidor tiene un error de configuración en el contexto de la Negociación Transparente de Resultados (RFC 2295). Permite informar al cliente de que la variante que ha elegido está configurada para participar en la negociación de contenidos, pero no es válida como endpoint para el proceso de negociación-

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 22 de noviembre de 2022
Blazor

Hoy va un post cortito, pero que puede venir bien a alguien que esté intentando "trocear" su aplicación en distintos proyectos y se haya encontrado con este problema.

Echemos un vistazo al contenido típico del archivo App.razor de una aplicación Blazor (Server o WebAssembly, da lo mismo):

<Router AppAssembly="@typeof(Program).Assembly">
    ...
</Router>

Resulta que el componente Router escanea durante su inicialización el ensamblado que hayamos indicado en su atributo AppAssembly, por defecto el ensamblado actual, en busca de componentes que:

  • Hayan definido sus rutas mediante directivas @page de Razor,
  • o bien, que tengan su ruta especificada con atributos [Route]

En cualquiera de los casos, los componentes localizados son añadidos a la tabla de rutas y, por tanto, será posible navegar hacia ellos modificando la ruta del navegador, ya sea programáticamente (usando el servicio NavigationManager) o bien mediante la pulsación de enlaces o modificación directa en la barra de direcciones.

Hasta aquí, todo correcto. El problema viene cuando las páginas que queremos añadir a la tabla de rutas no están en el ensamblado actual, o se encuentran repartidas en varios ensamblados distintos, por ejemplo en:

  • Otros proyectos de la solución
  • Ensamblados externos, referenciados directamente
  • Paquetes NuGet instalados en el proyecto
lunes, 21 de noviembre de 2022
Enlaces interesantes

Creo que nunca me he topado en persona con este código de error, así que es una buena ocasión para conocer un poco sobre él.

El código HTTP 505 (HTTP Version Not Supported) es retornado por un servidor cuando rechaza o no soporta la versión major de HTTP utilizada en la petición. En este caso, se recomienda que el servidor incluya en la respuesta la descripción del motivo por el que no soporta la versión utilizada, y qué protocolos debería usar en su lugar.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 15 de noviembre de 2022
C#

La llegada de C#11 viene acompañada de un buen número de novedades, algunas de ellas bastante jugosas, como los raw string literals o el nuevo modificador "file" que ya hemos ido viendo por aquí.

En esta ocasión, vamos a echar el vistazo a otra de las novedades que pueden resultar de bastante utilidad en nuestro día a día: los miembros requeridos.

lunes, 14 de noviembre de 2022
Enlaces interesantes

Como vimos hace unas semanas, el código HTTP 502 es usado por gateways, proxies o intermediarios similares para informar al cliente de que la petición al servidor real estaba retornando un error, pero, ¿qué ocurre cuando dicho servidor ni siquiera responde en un tiempo determinado? Pues para eso existe el HTTP 504 (Gateway timeout).

Y ahora, ahí van los enlaces recopilados durante la semana pasada, con muchas novedades y lanzamientos que, como de costumbre, espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET