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.
Publicado por José M. Aguilar a las 12:05 a. m.
Etiquetas: concienciación, desarrolladores, errores
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...
- Cómo detectar navegadores que no soportan Blazor WebAssembly
José María Aguilar - Crear puntos de ruptura en tiempo de ejecución con .NET
José María Aguilar
.NET Core / .NET
- How to Secure Passwords with BCrypt.NET
Code Maze - Build Your Own Podcast App with .NET 7, Blazor, and .NET MAUI
James Montemagno - Ref-structs are technically obsolete
James Turner - Will ChatGPT replace .NET developers?
David Grace - Delete dotnet bin and obj folders recursively
Steve Smith - Extreme LINQ Performance Boost in .NET 7
Ivan Matec - Generating C# bindings for native libraries by using ChatGPT
Muhammad Azeez - Enhancing the Factory Pattern with C# Attributes
John Patrick Glattetre - Better assertions for your unit tests
Johan Smarius - Microsoft .NET History
Lazie Wouters - Introduction to MVVM Source Generators for C# .NET
Julian Ewers-Peters - Saving Christmas with Functional C#
Simon Painter - IEnumerable in C#
Code Maze - How the heap verification mode helps with debugging heap corruption
Maoni Stephens - C# 11.0: Raw String Literals
Thomas Claudius Huber
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).
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...
- Componentes genéricos (templated components) en Blazor
José María Aguilar - La depuración y las cinco fases del duelo
José María Aguilar
.NET Core / .NET
- Using Roslyn to Power C# SDK Generation from OpenAPI Specifications
Brant Burnett - Introducing Wolverine for Effective Server Side .NET Development
Jeremy D. Miller - Schedule Jobs with Quartz.NET
Code Maze - Moving to .NET 7 MSMQ Alternatives
Irwin Williams - PriorityQueues on .NET 7 and C# 11
Davide Bellone - .NET 7 Networking Improvements
Natalia Kondratyeva - 11 Ways of Making Your C# Harder to Use
Brendan Enrick - Fun with C# and Bingo
Eric King - C# 11: pattern matching and static abstract interfaces
Tom Deseyn - Add All Project to Solution with dotnet CLI
Steve Smith - Answer: What does this code print?
Oren Eini - Creating Multi-Tier Subscriptions using C#
Jonathan Danylko - Task<IDisposable> surprise
Jiří Činčura - Using Procdump to generate dumps on a specific .net core exception
Xiao Dong Zhu - Testing in DotNet
Mark Oliver
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.
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...
- Cómo invocar métodos de instancia C# desde Javascript con Blazor (interop 3/3)
José María Aguilar - Formas efectivas de ofuscar emails en páginas web
José María Aguilar
.NET Core / .NET
- A new wave of analyzers in .NET 8
Steven Giesel - C# 11 Strings in the Raw
Shawn Wildermuth - .NET and C# Versions
Niels Rasmussen - Floating-Point Types in C# - Double vs Float vs Decimal
Code Maze - An initial proof of concept of applicative assertions in C#
Mark Seemann - Hashing and Salting Passwords in C# - Best Practices
Diego García - C# Tip: Raise synchronous events using Timer (and not a While loop)
Davide Bellone - Having fun with C# 11 raw string literals
Jiří Činčura - Starting a process as normal user from a process running as Administrator
Gérald Barré - Benchmark Your Code Like dotNetDave!
David McCarter - Introducing C#11: List Pattern
Anthony Giretti - Trying out the built-in container support for the .NET SDK
Carlos Pons - Producer-Consumer Applications With .NET Channels Code Maze
Code Maze - New ArgumentException and ArgumentOutOfRangeException helpers in .NET 8
Steven Giesel
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.
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...
- Cómo solucionar el error "Unable to connect to web server 'IIS Express'" en Visual Studio
José María Aguilar - Cómo saber si tenemos el debug=true en el Web.config
José María Aguilar
.NET Core / .NET
- .NET 7 Adds Generic Math
Jonathan Allen - Creating Containers in .NET 7 with the .NET CLI
Anuraj Parameswaran - How to get allocations in .NET? And how big is an empty array?
Steven Giesel - Static Abstract Interface Members in C#11
Dirk Strauss - HashSet vs SortedSet in C#
Code Maze - Creating JSON Web Tokens using dotnet user-jwts tool
Anuraj Parameswaran - Tagged Strings in Visual Studio and .NET 7
Jonathan Allen - Killing all child processes when the parent exits (Job Object)
Gérald Barré - Wolverine | Next Generation .NET Command and Message Bus
Jeremy D. Miller - C# List Pattern Examples
Phil Haack - How to Check if a String Ends With a Number in C#
Code Maze - The dangers and gotchas of using scoped services in OptionsBuilder
Andrew Lock - .NET 7 Removes Its Insecure XmlSecureResolver
Jonathan Allen - "Use always a StringBuilder"
Steven Giesel - Towards a Beginner-Friendly DotNet
Matt Eland - How to Create and Publish a NuGet Package with dotnet CLI
Anuraj Parameswaran - Logging to Amazon Cloudwatch with Serilog in .NET
Mukesh Murugan - Frozen collections in .NET 8
Steven Giesel - The new .NET 7.0 IParsable<TSelf> interface
Patrick Smacchia - A Mostly Complete Guide to C# 11’s Final Features
Matthew MacDonald - Sending An Email In C#/.NET
Daniel Collingwood
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
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...
- Cómo invocar métodos estáticos C# desde Javascript con Blazor (interop 2/3)
José María Aguilar - Imágenes en cuadros de texto de formularios web
José María Aguilar
.NET Core / .NET
- Null-Coalescing ?? And Null-Coalescing Assignment ??= Operator
Code Maze - Enforcing .NET code style rules at compile time
Daniel Genezini - The Best C# 11 Feature You Don't Need
Matt Eland - My C# array, tuple, delegate declaration dilemma
Jiří Činčura - How to Return null From a Generic Method in C#
Code Maze - Introducing the C# 11 Required Keyword
Matt Eland - My favourite 'recent' LINQ improvements
Mark Heath - How to Use the “Using Static” Feature in C#
Code Maze - Book: C# for Babies
JetBrains - Using Dynamic LINQ With System.Linq.Dynamic.Core Library
Code Maze - C# 11 and .NET 7 Bring Generic Parsing
Jonathan Allen - C# 11 required members
Patrick Smacchia - Protect yourself when deserializing - System.Text.Json
Josef Ottosson - Anonymous test data with AutoFixture
Steven Giesel - Cysharp/MemoryPack: Zero encoding extreme performance binary serializer for C# and Unity.
Yoshifumi Kawai
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.
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...
- ¿A qué huele tu código?
José María Aguilar - Cómo invocar funciones Javascript desde Blazor (interop)
José María Aguilar
.NET Core / .NET
- .NET 7 is Available Today
Jon Douglas - Welcome to C# 11
Mads Torgersen - Announcing F# 7
Vlad Zarytovskii - Announcing NuGet 6.4 - Signed, Central, Delivered
Jon Douglas - What's new in Windows Forms in .NET 7.0
Igor Velikorossov - What's new for WPF in .NET 7
Pankaj Chaurasia - What's new in Orleans 7.0
Brady Gaster - Mutable value types are evil! Sort of...
Steven Giesel - Top 10 Dotnet Exception Anti-Patterns in C#
Matt Eland - How to Use HTML Agility Pack in C#
Diego García - Debugging tips and tools
Gérald Barré - Tasks vs Threads in C#
Code Maze - Concurrent Processing in .NET 6 with System.Threading.Channels (Bonus: Interval Trees)
Charles Chen - Source Generated RegEx in .NET 7
Steve Collins
En código que veo, incluso escrito por mí un tiempo atrás, es muy habitual encontrar comparaciones de cadenas de caracteres en las que, para asegurar que el casing no sea tenido en cuenta, se fuerza una conversión de alguno de los operandos, o incluso ambos, a mayúsculas o minúsculas.
En escenarios muy simples esto funcionará bien y no tendrá contraindicaciones especialmente graves para nuestro sistema. Veamos unos ejemplos:
// Ejemplo 1: conversión de un único operando
int Calculate(string op, int a, int b)
{
// Pasamos a minúsculas el operador para
// asegurar que encaja con la constante
if(op.ToLower()=="add")
{
return a+b;
}
else if(op.ToLower()=="sub")
{
return a-b;
}
...
}
// Ejemplo 2: conversión de ambos operandos
bool AreBrothers(User user1, User user2)
{
// Pasamos a mayúsculas ambos apellidos por
// si alguno se ha escrito usando otro casing
var areBrothers = user1.Surname.ToUpper() == user2.Surname.ToUpper();
return areBrothers;
}
Sin embargo, aunque pueda parecer despreciable, estas operaciones de transformación a mayúsculas o minúsculas tienen un coste importante, que se pone especialmente de manifiesto cuando estamos hablando de aplicaciones con mucha carga de usuarios, alojada en infraestructura muy ajustada o cuando se requiere un rendimiento extremo.
El error HTTP 503 (Service unavailable) lo retornan los servidores para indicar que no están disponibles para responder a la petición. Es habitual encontrarlo al intentar acceder a un sitio web que está en mantenimiento, temporalmente fuera de servicio, o ante un estado de sobrecarga (alta concurrencia, bajos recursos, etc.) El cliente debe interpretarlo como un error temporal, y puede volver a intentarlo de nuevo algo más adelante; para ello, a veces suele acompañarse de un encabezado Retry-After
con la fecha/hora o el número de segundos estimados en los que volverá a estar operativo.
Y ahora, ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo mostrar y ocultar elementos en Blazor
José María Aguilar - 8 curiosidades que quizás no conocías sobre los emoticonos ;-), Parte 1 y Parte 2
José María Aguilar
.NET Core / .NET
- Announcing .NET Community Toolkit v8.1.0 Preview 1
Sergio Pedri - Local functions vs lambda expressions
Steven Giesel - Handling times for an EV charger
Jon Skeet - Deserializing Json Streams using Newtonsoft.Json & System.Text.Json with C# & VB
Graeme_Grant - Advanced LINQ
Alvaro Montoya - Injectio - Source Generator for Dependency Injection
Paul Welter - Encrypt and Decrypt Text Values in .NET
Jamil Hallal - Getting Started With Worker Services
Assis Zang - Just store UTC? Not so fast! Handling Time zones is complicated.
Derek Comartin - Bring WCF apps to the latest .NET with CoreWCF and Upgrade Assistant
Sam Spencer - Marking API's as obsolete or as experimental
Steven Giesel
Primero de todo, va una pildorilla cultural coincidiendo con el número de entrega de la serie de enlaces.
Cuando un servidor HTTP está expuesto a sus clientes a través de un intermediario (proxy, gateway, balanceador o cualquier otro tipo de sistema), es dicho intermediario el que recibe en primera instancia las peticiones, reenviándolas a su destino final y retornando su respuesta. Esto se realiza de forma totalmente transparente para el cliente.
El error HTTP 502 (Bad gateway) es retornado por los servicios intermediarios (proxies, gateways, etc.) cuando no pueden obtener una respuesta válida desde el servidor de destino real de la petición. Por ejemplo, podría ocurrir si éste esté caído, parado por mantenimiento o desconectado de la red, entre otros motivos.
Por si te lo perdiste...
- Cómo personalizar el mensaje "Loading" de las aplicaciones Blazor WebAssembly
José María Aguilar - Cómo describir los elementos de una enumeración usando métodos de extensión y atributos (C# y VB.NET)
José María Aguilar
.NET Core / .NET
- Read CSV File in .NET using CsvHelper
Bradley Wells - Differences between .NET Collection Interfaces
Matt Eland - Automatically version and release .Net Application
Anto Subash - IComparable vs IComparer vs Comparison Delegate
Muhammed Saleem - Dictionary vs Hashtable in C#
Code Maze - The Forgotten Art of C# Inheritance
Szymon Kulec @Scooletz - C# 11 File Scoped Types
Patrick Smacchia - Using WASM and WASI to run .NET 7 on a Raspberry PI Zero 2 W
Laurent Kempé
Modificadores de visibilidad habituales como internal
, public
o private
nos acompañan desde los inicios de C#, permitiéndonos definir desde dónde queremos permitir el acceso a los tipos que definimos en nuestras aplicaciones. Así podemos indicar, por ejemplo, que una clase pueda ser visible sólo a miembros definidos en su mismo ensamblado, que pueda ser utilizada desde cualquier punto, o que un tipo anidado sólo pueda verse desde el interior de su clase contenedora.
Pues bien, C# 11 traerá novedades al respecto ;)
Disclaimer: lo que vamos a ver aquí es válido en la RC2 de .NET 7, pero aún podría sufrir algún cambio para la versión final, prevista para noviembre de 2022.
El error HTTP 501 "Not implemented" se utiliza para indicar al lado cliente que el servidor no soporta las funcionalidades necesarias para poder dar una respuesta a la petición. Puede retornarse acompañado del encabezado Retry-After
para indicar al cliente que puede volver a intentarlo más adelante, cuando estas funcionalidades hayan sido implementadas.
Por ejemplo, la MDN, indica que es la respuesta apropiada cuando el servidor no implementa el método HTTP utilizado en la petición ni para el recurso solicitado ni para cualquier otro. Fijaos que hay una diferencia respecto al error 405, que indica que el recurso está disponible con otro verbo HTTP.
Y ahora, ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Componentes con cuerpo en Blazor
José María Aguilar - Efectos laterales en métodos parciales
José María Aguilar
.NET Core / .NET
- Introducing Spectre.Console
Steve Smith - That Shouldn't Happen - UnreachableException in .NET 7
Abbot - Simplify NuGet Package Versions in your application with Central Package Management
Nick Randolph - Make The First Letter of a String Upper Case in C#
Code Maze - 8 reasons startups prefer Node.js over .NET, and are they justified?
Michael Shpilt - Accessing State in System.Text.Json Custom Converters
Steve Gordon - 3 (and more) ways to set configuration values in .NET
Davide Bellone - Task.ContinueWith implicit type conversion gotcha
Maciej Zwierzchlewski - Common C# Programming Mistakes
Code Maze - Generating Code Coverage Reports in .NET Core
Anuraj Parameswaran - Update on ImageSharp
.NET Foundation - Throwing exceptions - Why is my stack trace lost?
Steven Giesel - Builder Pattern with the implicit operator using
Josef Ottosson
Normalmente, nuestras aplicaciones web ASP.NET Core son hosteadas por aplicaciones de consola, que son las encargadas de crearlas, configurarlas y lanzarlas. Esto suele hacerse mediante una relación de uno a uno: una única aplicación de consola se encarga de gestionar todo el ciclo de vida de una única aplicación web.
Pero, ¿es así necesariamente? En este post veremos que no.
Pues no habría apostado a que llegaríamos tan lejos, pero sí, estamos ante la entrega número 500 de la serie de enlaces interesantes, un post semanal que recoge los mejores contenidos técnicos que voy encontrando por la red, y que me consta que a muchos también os resultan interesantes :)
Ya cuando la serie cumplió diez años publiqué un post respondiendo preguntas que me habéis hecho y seguís haciendo sobre ella, así que si tenéis curiosidad sobre como empezó, el tiempo que dedico a ello o criterios para seleccionar los enlaces, os recomiendo que echéis un vistazo al post, porque todo sigue vigente.
Y ahora, vamos al lío: ahí van los enlaces recopilados durante la semana pasada que, como de costumbre, espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Métodos parciales en C# 3 y VB.NET 9
José María Aguilar - Cómo mostrar el número de usuarios conectados a una aplicación Blazor Server, en tiempo real
José María Aguilar
.NET Core / .NET
- Announcing .NET 7 Release Candidate 2
Jon Douglas & Jeremy Likness & Angelos Petropoulos - Console.ReadKey improvements in .NET 7
Adam Sitnik - Boosting Performance With Sealed Classes in .NET
Marko Hrnčić - Low-level struct improvements in C# 11
Steven Giesel - Calculating MRR with Stripe and C#
Phil Haack - Cursed C# - Doing shenanigans in C#
Steven Giesel - What's new in System.Text.Json in .NET 7
Eirik Tsarpalis & Krzysztof Wicher & Layomi Akinrinade - Modern C# Techniques, Part 3: Generic Code Generation
Stephen Cleary - Functional Programming in C#—A Brief Consideration
Assis Zang - Infographics Compendium II - ThrowHelper, null Task and more
Steven Giesel
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Otras 101 citas célebres del mundo de la informática
José María Aguilar - Capturar todos los parámetros enviados a un componente Blazor
José María Aguilar
.NET Core / .NET
- Adiciones a LINQ en .NET 7.0
Octavio Hernandez - Understanding identity in .NET
Pierre Bouillon - Sorting in C#: OrderBy.OrderBy or OrderBy.ThenBy? What′s more effective and why?
Sergei Vasiliev - Ensuring best practices for NuGet packages
Gérald Barré - Write barrier optimizations in regions
Maoni Stephens - Bending .NET - Compiling 65,536 Programs with Roslyn to Find Valid Identifier Separator char's... then just use
SyntaxFacts.IsValidIdentifier
🤦
Niels Rasmussen - How to build a URL Shortener with C# .NET and Redis
Niels Swimberghe - Bing Ads Campaign Platform – Journey to .NET 6
Mike Treit - Modern C# Techniques, Part 2: Value Records
Stephen Cleary
Las inline route constraints, o restricciones de ruta en línea son un interesante mecanismo de ASP.NET Core para especificar condiciones sobre los parámetros definidos en el interior de los patrones de ruta.
Por ejemplo, una acción MVC o un endpoint mapeado usando el patrón /product/{id}
, será ejecutado cuando entren peticiones hacia las rutas /product/1
y product/xps-15
.
Sin embargo, si en el momento del mapeo utilizamos el patrón /product/{id:int}
estaremos indicando que el manejador sólo debe ser ejecutado cuando el valor del parámetro id
sea un entero.
Esto podemos verlo mejor en un ejemplo. Observad la definición de la siguiente acción MVC, que será ejecutada sólo si el valor para el parámetro id
es un entero, es decir, responderá a peticiones como /product/1
o /product/234
, pero será ignorada si la petición entrante se dirige a la ruta /product/xps-15
:
public class ProductController : Controller
{
...
[HttpGet("product/{id:int}")]
public async Task<ActionResult<Product>> ShowDetails(int id)
{
var product = ... // Obtener producto
return product != null ? product: NotFound();
}
}
O lo que sería su equivalente usando las minimal APIs introducidas en .NET 6:
app.MapGet("/product/{id:int}", async (int id) =>
{
var product = await new ProductCatalog().GetByIdAsync(1); // Obtener producto
return product != null ? Results.Ok(product) : Results.NotFound();
});
Como ya habréis adivinado, en
{id:int}
es donde estamos especificando que el parámetro de rutaid
debe ser entero.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Clases parciales en C# y VB.NET
José María Aguilar - Mostrar HTML "crudo" en componentes Blazor
José María Aguilar
.NET Core / .NET
- Use .NET from any JavaScript app in .NET 7
Pavel Šavara - How to Use Shouldly to Improve Unit Tests in .NET?
Code Maze - Microsoft Commerce's .NET 6 Migration Journey
Kurtis Story - How to generate a dump file of a .NET application
Gérald Barré - The ThreadPool in .NET 7 NativeAOT uses the Windows thread pool
Austin Wise - Introducing C#11: Auto Default structs
Anthony Giretti - Pattern matching is awesome
Steven Giesel - Generate Dynamic PDF Reports from an HTML Template Using C#
Praveen Kumar - Microsoft Teams’ Infrastructure and Azure Communication Services’ Journey to .NET 6
Siavash Fathi & Arman Raina & Bhaskar Bhattacharya - .NET: Learn LINQ as you never have before
Anthony Giretti - x86 vs x64 in .NET
Steven Giesel - By Reference in C#
Peter Ritchie - Modern C# Techniques, Part 1: Curiously Recurring Generic Pattern
Stephen Cleary - Generate Strongly-Typed Resources with .NET Core
Travis Illig - Infographics Compendium I - Generators, pure functions and more
Steven Giesel
En un vídeo del canal de Nick Chapsas, al que por cierto os recomiendo suscribiros, he descubierto que .NET 7 introducirá un mecanismo para "decorar" parámetros, propiedades y miembros de tipo string
de forma que podamos aportar información sobre el tipo de contenido que esperan almacenar.
Para que lo entendáis mejor, observad el siguiente ejemplo, una función que recibe un mensaje y un formato de fecha, y que escribe por consola la fecha actual en el formato indicado seguido del mensaje.
void Log(string message, string dateFormat)
{
Console.WriteLine(DateTime.UtcNow.ToString(dateFormat) + " - " + message);
}
Log("Hello!", "dd/MM/yyyy hh:mm");
Desde el punto de vista del consumidor de la función Log()
, gracias a las ayudas del IDE podremos deducir que el segundo parámetro de tipo string
, llamado dateFormat
, debería ser un formato de fecha válido en .NET. Sin embargo, el entorno de desarrollo no podrá ofrecer ningún tipo de ayuda a la hora de codificar la llamada ni detectar si se producen errores, pues no dispone de información suficiente sobre el tipo de contenido esperado en la cadena de texto que se le suministra.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo conseguir uniones en .Net
José María Aguilar - Blazor Server + Entity Framework Core = InvalidOperationException (si no tienes cuidado)
José María Aguilar
.NET Core / .NET
- C# 11 - Top 5 Features in the new C# Version
Nikola M. Zivkovic - Counting the leading zeroes in a binary number with C#
Andrew Lock - AutoMapper vs Mapster in .NET
Code Maze - Memory is complicated
Steven Giesel - Default interface members and missing “public” in implementation
Jiří Činčura - How to log Correlation IDs in .NET APIs with Serilog
Davide Bellone - Writing unsafe .NET code without the unsafe keyword
Gérald Barré - Enumeration class in C# using records
Josef Ottosson
En algunas ocasiones me he topado con escenarios en los que necesitaba contar, o incluso enumerar, las claves de los elementos presentes en una caché en memoria, inyectada en mis servicios en forma de objeto IMemoryCache
.
Aunque a priori pueda parecer sencillo, esta interfaz no proporciona métodos o propiedades que permitan acceder a la colección que actúa como almacén de los mismos, por lo que nos veremos obligados a usar una estructura de datos adicional (normalmente algún tipo de diccionario o hashset paralelo) para almacenar estos elementos.
¿O quizás tenemos otras fórmulas?
Tras varias semanas de parada, estamos de nuevo al pie del cañón y listos para iniciar la nueva temporada en el blog. Por detrás quedan algunas semanas de descanso, ya totalmente olvidadas, algunos objetivos incumplidos, como mover el blog a WordPress, y otros completados como la actualización de los cursos de ASP.NET Core y Blazor en CampusMVP a las últimas previews de .NET 7, que me ha tenido bastante ocupado.
Y qué mejor forma de volver que publicando la colección de enlaces que he ido recopilando durante la semana pasada, ¿verdad? Pues aquí los tenéis; como siempre, espero que os resulten interesantes.
Por si te lo perdiste...
- Diez años de enlaces interesantes: lo que siempre habéis querido saber sobre esta serie
José María Aguilar - Comentar porciones de código en un archivo .ASPX
José María Aguilar
.NET Core / .NET
- Announcing .NET 7 Release Candidate 1
Jeremy Likness - Working with System.Random and threads safely in .NET Core and .NET Framework
Andrew Lock - Referencing a Local Private NuGet Package in your Solution
Rick Strahl - Performance Improvements in .NET 7
Stephen Toub - .NET now on Windows Package Manager
Ashita Nagar - Serializing asynchronous operations in C#
Raymond Chen - C# Lambda Discards
Ian Griffiths - Improving Unit Tests with Fluent Assertions
Alvaro Montoya - Arm64 Performance Improvements in .NET 7
Kunal Pathak - AutoMapper Madness - Nuances in Self-Mapping
Scott DePouw - .NET One-line Scoped Initializers with Dependency Injection
Khalid Abuhakmeh - C# Tip: use Miniprofiler instead of Stopwatch to profile code performance
Davide Bellone - Microsoft Teams Assignments Service's Journey to .NET 6
Kevin Halverson - How to turn an ASP.NET Core appsettings.json file into a fast-read database
Jon P Smith
Como todos los mediados de Julio, poco más o menos, os informo de que el blog entrará en modo de bajo consumo de energía (de mi energía, básicamente 😉) hasta el próximo mes de septiembre, cuando volveremos a retomar el ritmo habitual de publicaciones.
Mientras tanto, espero descansar un poco, renovar fuerzas y disfrutar de la familia y la buena compañía, que durante el año no siempre es posible prestarles la atención que merecen.
Nos vemos a la vuelta, con las baterías bien cargadas y listos para comenzar la nueva temporada. ¡Que disfrutéis de las vacaciones!
Imagen: Puesta de sol en Cádiz (Costa Ballena)Autor: Guillermo Martínez
Publicado en Variable not found.
Como sabemos, la respuesta a todas las peticiones HTTP comienzan por un código de estado que indica el resultado de la operación. Ahí encontramos desde los códigos más célebres, como HTTP 200 (Ok) o HTTP 404 (Not found) hasta otras joyas menos conocidas como HTTP 429 (Too many requests) o HTTP 418 (I'm a teapot).
Sin embargo, pocas veces nos fijamos en el texto que acompaña al código de respuesta, denominado reason phrase (en los ejemplos anteriores va entre paréntesis, como "Ok" o "Not found"). Según se define en la RFC 7230 sección 3.1.2, la reason phrase...
"... existe con el único propósito de proporcionar una descripción textual asociada con el código de estado numérico, principalmente como una deferencia a los protocolos iniciales de Internet, que eran utilizados frecuentemente por clientes de texto interactivos. Un cliente DEBERÍA ignorar su contenido"
Por tanto, dado que se trata de un texto arbitrario y puramente informativo, deberíamos poder modificarlo a nuestro antojo, más allá de los textos estándar proporcionados por el framework.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- AddMvc(), AddControllers(), AddControllersWithViews(), AddRazorPages()... ¿qué es todo eso?
José María Aguilar - Inicialización rápida de objetos en C# 3.0 y VB.Net 9.0
José María Aguilar
.NET Core / .NET
- ¿Depende el ecosistema de .NET de Microsoft?
Iván Montilla - CoreWCF 1.1.0 and project templates
Sam Spencer - A Practical Guide to Higher Order Functions in C#
Sam Walpole - Async Enumerable in C# (Part 3)
Mark Heath - Finding the maximum value in an array using vectorization
Gérald Barré - Using the new INumber type to generify math functions in .NET 7
Pierre Bouillon - Lightweight Mathematical Permutations Using C#
James McCaffrey - Returning XML from minimal APIs in .NET 6
Andrew Lock - How to solve InvalidOperationException for constructors using HttpClientFactory in C#
Davide Bellone - HttpClient vs RestSharp - Which One to Use in .NET
Code Maze - Low Code Ceremony Sagas with Jasper & Marten
Jeremy D. Miller - Understanding the Stack and Heap in C#
Liam Mooney - Instrumenting .NET with OpenTelemetry
Sly Gryphon - Add an Infinispan cache to your ASP.NET application
Vittorio Rigamonti - Making production diagnostics easier with Source Link
Mark Downie
Un año más, es una alegría enorme compartir con vosotros que Microsoft me ha reconocido por duodécimo año consecutivo como MVP (Most Valuable Professional) en la categoría de tecnologías de desarrollo. Aunque ha pasado bastante tiempo desde que me sorprendiera el mail con el primer nombramiento, sigo recibiéndolo con gran ilusión, el orgullo de seguir formando parte de esta familia y también la responsabilidad de intentar estar a la altura de este honor.
Y como en este mundo hay que entender de dónde y por qué llegan las cosas, no puedo sino haceros llegar mi eterno agradecimiento a todos los que habéis hecho este sueño posible: a los que visitáis de vez en cuando este rinconcillo de la red para obtener o compartir información, porque sois la gasolina que hace que este motor funcione; al equipo del programa MVP, por su incansable trabajo para conseguir que tengamos una gran comunidad de desarrolladores; y, por supuesto, a mis tres niñas, que asumen mis ausencias con la naturalidad de lo que siempre ha sido así.
Aprovecho también para enviar mis felicitaciones a compañeros que continúan siendo MVP (ya sabéis que no es sólo llegar, también mantenerse) y a los que hoy han recibido ese email con una de las mayores alegrías de su vida :)
¡Nos vemos por aquí!
Publicado en Variable not found.
Una de las (muchas) cosas buenas que trajo ASP.NET Core (y .NET Core en general) sin duda ha sido la popularización de la inyección de dependencias y la filosofía de implementación de componentes desacoplados que expone en múltiples puntos.
Esto ha provocado que en nuestras aplicaciones sea ya habitual encontrar secciones de código dedicadas al registro de decenas o centenares de servicios usando los distintos ámbitos disponibles (scoped, singleton o transient). El problema es que esta abundancia de servicios y la asiduidad con la que registramos nuevos componentes o modificamos sus dependencias hace que se nos puedan pasar por alto detalles que pueden hacer que nuestra aplicación falle. Por ejemplo, es fácil que olvidemos registrar algún servicio, o que, por un despiste, inyectemos servicios en componentes registrados con ámbitos incompatibles.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Ojo a los antipatrones
José María Aguilar - Cómo implementar view-models de componentes Blazor en clases code-behind
José María Aguilar
.NET Core / .NET
- Rop.ProxyGenerator: Source Generator to create ProxyClasses
Ramón Ordiales - Async Enumerable in C# (Part 2)
Mark Heath - AlterNats — High Performance .NET
Yoshifumi Kawai - Ternary Operator ? : in C#
Code Maze - Merging concurrent IAsyncEnumerable<T> operations for increased performance
Stefan Schranz - ZString — Zero Allocation StringBuilder for .NET Core and Unity.
Yoshifumi Kawai - How to Use Span in C# to Improve Application Performance
Code Maze - High performance .NET: Building a Redis Clone – skipping strings
Oren Eini - Faster Guid comparisons using Vectors (SIMD) in .NET
Gérald Barré - Using Refit to Consume APIs in C#
Code Maze - Azure AD OAuth client credential flow with custom certificate walk-through
Nicola Delfino - Nondestructive Mutation and Records in C#
Zoran Horvat - Running .NET Core Applications as a Windows Service
Muhammed Saleem - C# vNext - What could come
Steven Giesel - Comparison of FFT Implementations for .NET
Christian Woltering - Challenge: Find the stack smash bug… – answer
Oren Eini - .NET Debugging Tips
Tim Deschryver - Leveraging trimming to make the Microsoft Store faster and reduce its binary size
Sergio Pedri
Como sabemos, ASP.NET Core viene configurado "de serie" para que el middleware que sirve los archivos estáticos (StaticFilesMiddleware
) los obtenga desde la carpeta wwwroot
. Y ya vimos hace bastante tiempo que si preferíamos utilizar otro nombre para guardar estos archivos, podíamos hacerlo con cierta facilidad.
Pero como a partir de ASP.NET Core 6 el nuevo modelo de configuración cambió varias piezas de sitio, es bueno volver a echar un vistazo y ver cómo podríamos hacerlo en las últimas versiones del framework.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Desinstala fácilmente versiones antiguas de .NET Core con "dotnet-core-uninstall"
José María Aguilar - Saber si una cadena está vacía usando métodos de extensión (C#/VB.Net)
José María Aguilar
.NET Core / .NET
- Benchmarking to the Bottom — Iterating Arrays in .NET
Stephen Walsh - Improving .NET host error messages and supportability
Richard Lander - Async Enumerable in C# (Part 1)
Mark Heath - How to Implement Retry Logic in C#
Code Maze - Implement IXmlSerializable in a readonly struct
Fons Sonnemans - C# 11 - Top 5 Features in the new C# Version
Nikola M. Zivkovic - Consuming anonymous types with DiagnosticListener in .NET 6
Andrew Lock - High performance .NET: Building a Redis Clone– the wrong optimization path
Oren Eini - How to Call Generic Method Using Reflection in C#
Ahsan Ullah - How to improve Serilog logging in .NET 6 by using Scopes
Davide Bellone - Wrap Event based functions into awaitable Tasks
Steven Giesel - Observing all HTTP requests in a .NET application
Gérald Barré - Write Test Progress To The Console With NUnit
Dawid Sibiński - Speed Up Logging in .NET 6
David McCarter - Using records when implementing the builder pattern in C#
Josef Ottosson
De casualidad me he topado con un interesante cambio que .NET 5 introdujo en los componentes de serialización y deserialización System.Text.Json
y que, al menos para mí, pasó totalmente desapercibido en su momento. Por eso, he pensado que quizás sea buena idea dejarlo por aquí, por si hay algún despistado más al que pueda resultar útil.
Como seguro sabéis, al usar los componentes de System.Text.Json
para serializar o deserializar una clase, utilizamos el atributo [JsonIgnore]
para marcar las propiedades que queremos que sean ignoradas al convertir desde y hacia JSON.
Por ejemplo, dada la siguiente clase:
class User
{
public int Id { get; set; }
public string Email { get; set; }
[JsonIgnore]
public string Token { get; set; }
}
En ella estamos indicando expresamente que la propiedad Token
debe ser ignorada, por lo que ésta no aparecerá si serializamos un objeto a JSON:
var user = new User { Id = 42, Email = "john@server.com", Token = "ABCDEF"};
Console.WriteLine(JsonSerializer.Serialize(user));
// Result:
{"Id":42,"Email":"john@server.com"}
Y lo mismo ocurre en sentido contrario:
var jsonStr = "{ \"Id\": 42, \"Email\": \"john@server.com\", \"Token\": \"ABCDEF\"}";
var user = JsonSerializer.Deserialize<User>(jsonStr);
// ¡user.Token es nulo aquí!
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- 101 citas célebres del mundo de la informática
José María Aguilar - ¿Usar try/catch es malo para el rendimiento? Spoiler: no, siempre que nada falle
José María Aguilar
.NET Core / .NET
- Announcing .NET 7 Preview 5
Angelos Petropoulos - OneService Journey to .NET 6
Dominic Nguyen - Introduction to Regular Expressions in C#
Code Maze - High performance .NET: Building a Redis Clone–separation of computation & I/O Oren Eini
- The Perils of Combining Multicast Delegates with Tasks in C#
Liam Mooney - (Re) Introducing Jasper as a Command Bus
Jeremy D. Miller - What is the difference between C#, .NET, IL and JIT?
Steven Giesel - Creating, Inspecting and Decompiling the World's (Nearly) Smallest C# Program
Steve Gordon - C# 11 static abstract members
Patrick Smacchia - goto in action - The exception from the rule
Steven Giesel - C#: IEnumerable, yield return, and lazy evaluation
Isaac Lyman - C# Warning Waves Hint at New Keywords in the Future
Jonathan Allen - Clean up some .NET Clutter
Joseph Guadagno - Should I avoid LINQ for performance reasons?
Mark Heath
Visual Studio sigue introduciendo novedades versión tras versión, y es fácil que algunas de ellas nos pasen desapercibidas y tardemos algún tiempo en conocerlas, o incluso en verles la utilidad. Un ejemplo lo tenemos en los breakpoints temporales y dependientes, dos nuevos tipos de puntos de interrupción añadidos en la versión 2022 que pueden venirnos bien a la hora de depurar aplicaciones.
En este post vamos a echarles un vistazo, por si hay algún despistado más que no se haya dado cuenta de estas novedades.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- El gran consejo para crear código mantenible
José María Aguilar - Cambiar el idioma de mensajes del SDK de .NET Core
José María Aguilar
.NET Core / .NET
- Reflection in C#
Code Maze - Runtime C# Code Compilation Revisited for Roslyn
Rick Strahl - Fun: Leaderboard Output Using C# Pattern Matching
Khalid Abuhakmeh - Exchange Online Journey to .NET Core
David Sterling - .NET 7 Preview 5 - Generic Math
Tanner Gooding - How to Mock the File System for Unit Testing in .NET
Code Maze - High performance .NET: Building a Redis Clone–naively & Analysis & Architecture
Oren Eini - Delegate, Action, Func, Lamdba expression
Steve Giesel - The curse of NULL
Stéphane Gay
Las top level statements o instrucciones de nivel superior de C# 9 introdujeron una alternativa muy concisa para implementar los entry points de nuestras aplicaciones. De hecho, en .NET 6 fueron introducidas como la opción por defecto en las plantillas, por lo que, de alguna forma, se nos estaba forzando a utilizarlas en todos los nuevos proyectos.
Y como casi siempre sucede, rápidamente aparecieron numerosos desarrolladores a los que este cambio no les había hecho nada de gracia, y se manifestaron claramente en contra de que esta fuera la opción por defecto. La decisión por parte de los equipos de Visual Studio y .NET, que ya podemos ver si tenemos las últimas actualizaciones instaladas, es dejar que cada desarrollador decida la opción que más le guste.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Programación esotérica
José María Aguilar - Rutado dinámico en ASP.NET Core 3 MVC
José María Aguilar
.NET Core / .NET
- Round-robin DNS support in .NET HttpClient
Gérald Barré - Photino: Open Source for Building Cross-Platform Desktop Apps via .NET Core
Raddevus - Consuming SOAP Services in .NET Core
Simon Timms - Change C# Record Comparison with Source Generators
Khalid Abuhakmeh - 8 things about Records in C# you probably didn't know
Davide Bellone - Using the Decorator Pattern to Auto-Instrument .Net Classes With Otel Tracing
Roni Dover - Securing .NET App Secrets with AWS Secrets Manager
Kurt Feeley - Getting Functional with C#
Charles Chen - Get the most out of Async/Await in C#
Yacoub Massad - Global Using Directives in C#
Code Maze
A veces, desde aplicaciones .NET de consola, escritorio, o incluso ASP.NET Core, puede resultar interesante conectarse con una hoja de Google Sheets para añadir filas de datos.
Hay varias formas de conseguirlo, pero aquí vamos a ver la que creo que es la más sencilla, pues permite evitar parte del engorroso workflow de OAuth y, lo que es mejor, podemos usarla sin necesitar credenciales de usuario desde, por ejemplo, un servidor o un proceso desasistido.
Ojo: las APIs de Google que vamos a ver son gratuitas, pero tienen limitaciones de uso que debéis conocer antes de utilizarlas.
A grandes rasgos, el proceso consta de los siguientes pasos, que seguiremos a lo largo del post:
- Configuración del proyecto y credenciales en Google Developer Console.
- Creación del documento Google Sheet en el que añadiremos las filas.
- Consumo de las APIs de Google para añadir datos.
¡A por ello!
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Métodos de extensión en C#
José María Aguilar - Publicación self-contained y single-file en .NET Core
José María Aguilar
.NET Core / .NET
- Performance: Lambda Expressions, Method Groups, and delegate caching
Gérald Barré - C# Lambdas Part 2, a Few More Complicated Examples
Bryan Hogan - Unusual optimizations; ref foreach and ref returns
Marc Gravell - How to Mock HttpClient with Unit Tests in C#
Code Maze - Get Tweet Engagements Using .NET and C#
Khalid Abuhakmeh - Everything You Need to Know About the .NET MAUI ListView
Jayaleshwari N. - Provide default configuration to your .NET applications
Niels Swimberghe - Mock Asynchronous Methods Using Moq in C#
Code Maze - Debugging NuGet Packages: Understanding Debugging Symbols and Using Source Link
Elisenda Gascon
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.