Autor en Google+
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 ;)

16 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, 24 de mayo de 2022
Compartir:
Esoterismo

A veces no es necesario usar lenguajes esotéricos para crear un código que nadie sea capaz de entender a simple vista... de hecho, lo hacemos muy frecuentemente en nuestro día a día 😉. Basta nombrar inapropiadamente unas cuantas variables, acoplar y desacoplar sin criterio o usar una mala indentación para que nuestro código ya venga "ofuscado" de serie, sin usar ninguna herramienta externa.

Sin embargo hay otro nivel de maldad, que consiste en el abuso de la flexibilidad de sintaxis en algunos lenguajes para construir expresiones diabólicamente enrevesadas. Hace poco me topé por casualidad con un buen ejemplo de ello en JavaScript, un código que, a simple vista, es imposible de entender:

// ¿Qué retorna esta expresión?
(_$=($,_=[]+[])=>$?_$($>>+!![],($&+!![])+_):_)(255)

Obviamente, podemos copiarla y pegarla en la consola de nuestro navegador, y rápidamente veremos de qué se trata. Sin embargo, me pareció interesante dedicar unos minutos a intentar comprender el código, así que vamos a ir troceando y refactorizando esta expresión ilegible hasta convertirla en algo que, al menos, podamos digerir.

Compartir:
lunes, 23 de mayo de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 17 de mayo de 2022
Compartir:
16 años de Variable Not Found

Hace unos días, Variable Not Found cumplió dieciséis añitos de vida, una eternidad para este mundo en el que vivimos, donde todo ocurre tan rápido y las cosas cambian a una velocidad de vértigo 😊.

Dieciséis años viviendo algo único. Cada uno de los 1.350 artículos publicados ha sido para mí una increíble oportunidad de mejora y aprendizaje y, con suerte, espero (y confío) haber podido ayudar a alguno de los muchísimos visitantes que durante este periodo han pasado por aquí y me han animado a seguir en la brecha.

Dieciséis años creciendo juntos. Comencé esta aventura con más pelo, mejor vista y bastante menos canas, pero la ilusión de poder escribir sobre lo que me gusta, con el plus de que esto pudiera ser útil para alguien, sigue intacta.

Pero bah, dejémonos de historias sentimentales... como es tradición, veamos cómo ha funcionado el blog durante este año.

Compartir:
lunes, 16 de mayo de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 10 de mayo de 2022
Compartir:
.NET

Solemos pensar que el punto de entrada de una aplicación .NET, ya sea el método estático Main() del clásico Program.cs o el nuevo Program.cs de .NET 6 que utiliza top level statements, es lo primero que se ejecuta en nuestras aplicaciones, en realidad no es así. Hay vida antes de que nuestra aplicación empiece a correr ;)

Aunque obviamente su utilidad es limitada y no es algo que necesitaremos hacer a menudo (o probablemente nunca), es conveniente saber que existen varias formas de insertar código que se ejecute antes que lo que siempre hemos considerado el entry point de nuestra aplicación, y es lo que veremos en este post.

Compartir:
lunes, 9 de mayo de 2022
Compartir:
Intel 486

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 3 de mayo de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 26 de abril de 2022
Compartir:
ASP.NET Core

Imaginad que tenemos un controlador MVC como el siguiente:

public class TestController : Controller
{
    public IActionResult Add(int a, int b)
    {
        return Content($"Result: {a + b}");
    }
}

Claramente, la acción Add() retornará la suma de los enteros a y b que le llegarán como parámetros de la query string:

GET https://localhost:7182/test/add?a=1&b=2 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

Result: 3

Pero, como sabemos, podríamos llamar a la acción sin indicar alguno de esos parámetros, o incluso ninguno de ellos:

Petición Respuesta
GET /test/add?a=1&b=2 Result: 3
GET /test/add?a=0&b=0 Result: 0
GET /test/add?a=1 Result: 1
GET /test/add Result: 0

Esto es así porque el binder será capaz de poblar correctamente los parámetros a y b cuando estén presentes en la cadena de la petición y sean correctos, o les asignará su valor por defecto (0) cuando no hayan sido suministrados.

Pero dado que el cero es un valor de entrada válido, a priori desde nuestro código no tendríamos forma de distinguir cuándo el parámetro ha sido omitido y cuándo se ha establecido expresamente.

¿Cómo podríamos hacerlo?

Compartir:
lunes, 25 de abril de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 19 de abril de 2022
Compartir:
.NET

La semana pasada veíamos algunas alternativas para comprobar de forma eficiente si una cadena de texto contiene un JSON válido y, al hilo de dicho post, el amigo Javier Campos aportó vía Twitter una fórmula adicional mejor que las que vimos aquí.

El código en cuestión es el siguiente:

public bool IsJsonWithReader(string maybeJson)
{
    try
    {
        var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(maybeJson));
        reader.Read();
        reader.Skip();
        return true;
    }
    catch
    {
        return false;
    }
}

La estructura Utf8JsonReader ofrece una API de alto rendimiento para acceder en modo forward-only y read-only al JSON presente en una secuencia de bytes UTF8. Los métodos Read() y Skip() se encargan respectivamente de leer el primer token del JSON y saltarse todos sus hijos, con lo que en la práctica se recorrerá el documento completo, lanzándose una excepción en caso de ser inválido.

Compartir:
lunes, 18 de abril de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
lunes, 11 de abril de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 5 de abril de 2022
Compartir:
.NET

Al hilo del post Cómo recibir un JSON como string en una acción ASP.NET Core MVC, el amigo Alberto dejaba una interesante pregunta en los comentarios: ¿y si una vez hemos recibido el string, queremos validar que sea un JSON válido?

Obviamente, una forma sencilla sería intentar deserializarlo por completo a la clase de destino, siempre que ésta sea conocida. Para ello podríamos utilizar el método Deserialize<T>() del objeto JsonSerializer de System.Text.Json, disponible en todas las versiones modernas de .NET, de la siguiente manera:

Compartir:
lunes, 4 de abril de 2022
Compartir:
Compartir:
martes, 29 de marzo de 2022
Compartir:
ASP.NET Core

A veces, sobre todo en aplicaciones muy grandes, con las definiciones de rutas muy complejas o cuando nos toca analizar aplicaciones ajenas, puede ser interesante saber qué punto del código está procesando una petición determinada, ya sea un endpoint definido usando Endpoint Routing o Minimal APIs o bien sea una acción de un controlador MVC.

En este post vamos a ver cómo conseguirlo de forma muy sencilla, mediante la implementación un pequeño middleware que, insertado en el pipeline, añadirá en el encabezado información sobre el handler que generó la respuesta de la petición actual.

Compartir:
lunes, 28 de marzo de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 22 de marzo de 2022
Compartir:
.NET

Aunque no es algo frecuente ni especialmente recomendable, hay veces que tenemos que introducir en el código algún tipo de lógica, trazas o comprobaciones que solo queremos aplicar mientras depuramos o desarrollamos y, en ningún caso, queremos que vaya a producción.

En estos casos, aparte de anudarnos un lazo en el dedo mientras mantengamos estos cambios para asegurar la eliminación del código de pruebas antes de subir la aplicación a producción, otra idea puede ser utilizar directivas para que este código solo actúe mientras depuramos, o incluso para evitar la compilación exitosa en modo "Release" (el usado normalmente al publicar).

Compartir:
lunes, 21 de marzo de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 15 de marzo de 2022
Compartir:
ASP.NET Core

En los tiempos de ASP.NET "clásico", cuando los settings de la aplicación los almacenábamos en el viejo Web.config, cualquier intento de cambio de valores mientras ejecutábamos la aplicación era inevitablemente sinónimo de reinicio. Esto, aunque bastante molesto, tenía sentido porque el mismo archivo XML se utilizaba para almacenar tanto los valores de configuración "de negocio" como aspectos puramente técnicos o del comportamiento de la infraestructura de ASP.NET, y la aplicación debía reiniciarse para poder aplicarlos.

Con la llegada del sistema de settings de .NET Core esto mejoró bastante, introduciendo la posibilidad de almacenar valores en bastantes orígenes distintos (archivos .json, .ini, .xml, variables de entorno, parámetros de línea de comandos, user secrets, diccionarios en memoria y muchos otros, incluso totalmente personalizados), y nuevas fórmulas para la obtención de éstos, como la inyección de dependencias, settings tipados y, por fin, la posibilidad de realizar cambios en caliente.

Compartir:
lunes, 14 de marzo de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 8 de marzo de 2022
Compartir:
Programación No podemos negar que el tipo de datos boolean está fuertemente arraigado en los desarrolladores. Desde nuestros inicios en este mundillo, nos acostumbramos a pensar que las máquinas sólo entienden de unos y ceros o sus variantes humanas: "sí" y "no", "verdadero" y "falso" o similares. Y por alguna misteriosa razón, tendemos a ver la realidad y modelar nuestras soluciones utilizando estas primitivas tan básicas.

Pero aunque indudablemente los tipos booleanos o flags son una fórmula muy compacta para almacenar información, el mundo suele ser mucho más complejo y estas simplificaciones son a menudo origen de problemas y trampas para nuestro yo del futuro.

En este post vamos a ver algunos escenarios en los que este tipo de dato puede llegar a complicarnos la vida.

Compartir:
lunes, 7 de marzo de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
lunes, 28 de febrero de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 22 de febrero de 2022
Compartir:
.NET

Aún no hemos terminado de asimilar las novedades de C# 10, cuando ya empiezan a llegar noticias de lo que encontraremos en la próxima versión, C# 11, que si todo va bien se lanzará en noviembre de este año.

Una de las que más me ha llamado la atención de momento es la llegada de raw string literals, una característica que mejorará bastante la posibilidad de escribir constantes de cadena multilínea en nuestro código.

Veamos en qué consiste.

Disclaimer: la nueva versión de C# está aún en desarrollo, y detalles de los que veamos aquí podrían cambiar antes de lanzarse definitivamente.
Compartir:
lunes, 21 de febrero de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 15 de febrero de 2022
Compartir:
.NET

Seguimos descubriendo novedades aparecidas con .NET 6, y ahora le toca el turno a la nueva clase PeriodicTimer, una fórmula para la ejecución de tareas periódicas en contextos asíncronos que evita el uso de los clásicos callbacks a los que nos tenía acostumbrados el framework.

Como recordaréis, .NET dispone de un buen número de formas de implementar temporizadores, o timers, para ejecutar tareas en intervalos periódicos. El más conocido probablemente sea el clásico System.Threading.Timer, en el que especificábamos el callback o método que debía ejecutarse en cada intervalo de tiempo mediante un delegado (en el siguiente ejemplo, mediante una lambda):

var timer = new System.Threading.Timer(o =>
{
    Console.WriteLine("Hey! " + DateTime.Now.ToLongTimeString());
}, null, 0, 1000);

Console.ReadKey();
Hey! 12:25:51
Hey! 12:25:52
Hey! 12:25:53
Hey! 12:25:54
Hey! 12:25:55
_

Pero también existía System.Timers.Timer, que nos permitía lograr algo parecido, aunque esta el callback lo implementábamos mediante una suscripción al evento Elapsed del objeto:

var timer = new System.Timers.Timer(1000);
timer.Elapsed += (sender, eventArgs) =>
{
    Console.WriteLine("Hey! " + DateTime.Now.ToLongTimeString());
};
timer.Start();
Console.ReadKey();

Existían algunas fórmulas más específicas para plataformas concretas, como las clases System.Windows.Forms.Timer, System.Web.UI.Timer u otras. Sin embargo, todas coincidían en varias cosas:

  • Utilizaban callbacks de alguna u otra forma, lo que implica un cierto riesgo de leaks de memoria y problemas con los tiempos de vida de objetos cuando la cosa se complica.
  • Los callbacks no permitían código asíncrono, lo que podía llevarnos a luchar contra los engorrosos escenarios de ejecución de código asíncrono en entornos síncronos (async-over-sync).
  • Podían darse casos de superposición u overlapping entre las distintas ejecuciones, cuando éstas tardaban en completarse más que el intervalo de definido en el timer.
Compartir:
lunes, 14 de febrero de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 8 de febrero de 2022
Compartir:
ASP.NET Core MVC

Dada una petición como la siguiente:

POST https://localhost:5001/friends HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{ "name": "Jon", "age": 24 }

Lo habitual es que queramos recibir los datos ya materializados en forma de objeto de .NET. Esto podemos conseguirlo fácilmente desde una acción como la siguiente:

[Route("friends")]
public class FriendsController : Controller
{
    [HttpPost]
    public ActionResult Test([FromBody]Friend friend)
    {
        return Content($"Hello, {friend.Name}, you are {friend.Age} years old");
    }
}

Pero aunque no es algo que ocurra con frecuencia, a veces podríamos necesitar recibir el cuerpo JSON de una petición como string, es decir, en crudo, sin deserializarlo ni procesarlo de ninguna manera para, ya más adelante, hacerlo nosotros manualmente. Y aunque a primera vista pudiera resultar trivial, tiene un poco más de truco de lo que parece...

Compartir:
lunes, 7 de febrero de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 1 de febrero de 2022
Compartir:
Blazor

Si habéis utilizado isolation con módulos JavaScript en Blazor 5, probablemente lo que vamos a ver en este post os resulte muy interesante para organizar los archivos JavaScript de la aplicación, especialmente aquellos que sean utilizados desde un único componente.

Como recordaréis, el aislamiento de JavaScript de Blazor permitía cargar de forma dinámica un archivo .js y ejecutar código definido en él. Por ejemplo, imaginad un módulo como el siguiente, definido en wwwroot/modules/MyPrompt.js:

export function showPrompt(message, defaultValue) {
    return prompt(message, defaultValue);
}

Compartir:
lunes, 31 de enero de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 25 de enero de 2022
Compartir:
ASP.NET Core

El middleware de gestión de errores DeveloperExceptionPageMiddleware ha estado con nosotros desde la llegada de .NET Core, allá por 2016, ayudándonos a mostrar información detallada de las excepciones producidas en tiempo de ejecución mientras estábamos desarrollando. De hecho, era frecuente encontrar un código como el siguiente en las clases Startup de las aplicaciones ASP.NET Core, pues se incluía por defecto en todas las plantillas de proyecto de este tipo:

...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    ... // Otros middlewares
}

El extensor UseDeveloperExceptionPage() era el encargado de añadir el middleware DeveloperExceptionPageMiddleware al pipeline, de forma que éste podía capturar las excepciones y mostrar una página amigable y con información útil para los desarrolladores.

Sin embargo, si echamos un vistazo al código de configuración del pipeline en los proyectos ASP.NET Core 6 (que, por cierto, sabréis que ya no se encuentra en Startup.cs sino en Program.cs), vemos que ya no aparece ninguna referencia a este middleware. ¿Qué ha pasado? ¿Qué has hecho con nuestro DeveloperExceptionPage, ASP.NET Core 6?

Compartir:
lunes, 24 de enero de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 18 de enero de 2022
Compartir:
.NET

Versiones de .NET anteriores a la 6 no disponían de una fórmula específica para determinar si un tipo o interfaz está registrado como servicio en el sistema de inyección de dependencias.

La única forma de hacerlo era intentar resolverlo, usando métodos como GetService() o GetService<T>(), y comprobar si el resultado era null:

var myService = serviceProvider.GetService<IMyService>();
if(myService is null)
{
    // El servicio no está registrado, hacemos algo
}

¿Cuál es el inconveniente de esto? Si el servicio no está registrado, ninguno: la llamada retornará un nulo y listo. 

El problema viene cuando sí está registrado, pues estaremos forzando la resolución de un servicio que, en realidad, no necesitamos para nada, pues sólo nos interesaba saber si existía o no. Porque recordemos que la resolución de un servicio podría tener un coste importante en términos de rendimiento, memoria, o incluso efectos colaterales en el estado de la aplicación, especialmente si nuestro servicio depende de otros, que a su vez dependen de otros, etc.

Compartir:
lunes, 17 de enero de 2022
Compartir:
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

Compartir:
martes, 11 de enero de 2022
Compartir:
Enlaces interesantes

Vamos con la primera colección del año :) Aquí van los enlaces recopilados durante estas fiestas que, como de costumbre, espero que os resulten interesantes.

Por si te lo perdiste...

.NET Core / .NET

Compartir:
lunes, 10 de enero de 2022
Compartir:
Top ten 2020 en Variable not found

Pues parece que comenzamos 2022 con deseos bastante parecidos a los que ya teníamos un año atrás: que la situación actual mejore y que la salud os permita ser felices y disfrutar de todo lo que os rodea. Algo hemos avanzado respecto al año pasado, pero aún nos queda mucho camino por recorrer para volver a la ansiada normalidad.

Pero bueno, independientemente de esto, seguro que lo que más estáis esperando en este momento es el tradicional post donde comentaremos las entradas más visitadas durante el pasado año, así que ahí va 😁

Compartir: