
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo saber si un tipo está registrado en el proveedor de servicios de .NET 6, pero sin necesidad de resolverlo
José María Aguilar - Introducción a SignalR (I): Conceptos básicos
José María Aguilar
.NET Core / .NET
- C# 12: todo lo nuevo del lenguaje aparecido con .NET 8
José Manuel Alarcón - Creating Microsoft Teams Applications with Visual Studio and .NET
Anuraj Parameswaran - How to Check if a File Is in Use With C#
Code Maze - Sep 0.3.0 - Unescape Support (still the Most Efficient .NET CSV Parser)
Niels Rasmussen - 5 Awesome C# Refactoring Tips
Milan Jovanović - Behind [LogProperties] and the new telemetry logging source generator
Andrew Lock - Scriban for Text and Liquid Templating in .NET
Khalid Abuhakmeh - Primary constructors has caused concerns for C# developers
David Grace - Embedding a minimal ASP.NET Web Server into a Desktop Application
Rick Strahl - Building resilient cloud services with .NET 8
Martin Tomka - A journey about the new interceptors of .NET 8
Steven Giesel - TDD and refactoring to patterns in C#: how to write a cron parser
Nicolas Descartes - How to Determine the Operating System in .NET Core
Code Maze - How to make libraries compatible with native AOT
Eric Erhardt - Intercepting HTTP requests with a DelegatingHandler
Tim Deschryver - In Defence of Doubles
Anthony Lloyd
Publicado por José M. Aguilar a las 8:05 a. m.
Etiquetas: enlaces

Como sabéis, hasta ahora, los componentes Blazor podían ejecutarse en dos tipos de hosting distintos, Blazor Server y Blazor WebAssembly. Aunque cada uno tiene sus escenarios ideales de uso, ambos enfoques conseguían lo mismo, implementar Single Page Applications en C#, sin necesidad de utilizar JavaScript (bueno, o al menos, minimizando radicalmente su uso):
- Con Blazor Server, se mantiene en el servidor una copia del DOM de cada usuario conectado, de forma que C# puede manipularlo directamente. Luego, mediante una conexión websockets, se sincronizan los cambios con el cliente.
- Blazor WebAssembly lleva al navegador el runtime de .NET, las bibliotecas base y los ensamblados de la aplicación, por lo que todo se ejecuta directamente en el lado cliente gracias a WebAssembly.
Estas dos formas de ejecutar componentes son muy apropiadas cuando se trata de elementos interactivos, capaces de responder a eventos de usuarios y con capacidad de actualizar el contenido de la página. Sin embargo, son muy poco eficientes cuando se trata de páginas estáticas que no requieren interacción con el usuario:
-
Para poder mostrar en el navegador un contenido, en Blazor Server hay que esperar a que el lado cliente descargue la página contenedora, un archivo JavaScript y se establezca la conexión websockets con el servidor, tras lo cual se enviará el contenido de la página.
-
En Blazor WebAssembly, el cliente debe descargar la página contenedora, los ensamblados y todo el entorno de ejecución de .NET y lanzarlo todo sobre WebAssembly. En este momento se puede mostrar el contenido de la página.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Declaración de espacios de nombre en una línea con file-scoped namespaces de C#10
José María Aguilar - Establecer el foco automáticamente en MVC, versión declarativa
José María Aguilar
.NET Core / .NET
- .NET 8: Todas las novedades en 2 minutos
José Manuel Alarcón - Announcing .NET Chiseled Containers
Richard Lander - ConcurrentStack in C#
Code Maze - Find a subset from a set of values whose sum is closest to a specific value–C#
Bart Wullems - Intro to .NET and C# - Differences, Structure, SDK, Runtime...
Code Maze - Embedding additional files in an MSBuild binary log file
Gérald Barré - A failed experiment with interceptors in C# 12 and .NET 8
Andrew Lock - Lo-Fi Service Discovery in .NET8
David Whitney - Fake It Til You Make It...To Production
Martin Taillefer - Validating JSON Against a Schema
Paul Michaels - The Differences Between Quartz.NET and Hangfire
Code Maze - Async Lambda Statements
Bryan Hogan - Primary Constructors – Using C# 12 in Rider and ReSharper
Matthias Koch - How To Harness System.Reactive For The Observer Pattern
Nick Cosentino

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Curiosidad: ¿Por qué el encabezado 'referer' se llama así, y cómo nos afecta a los desarrolladores .NET?
José María Aguilar - ASP.NET MVC: establecer el foco en un control al cargar la página
José María Aguilar
.NET Core / .NET
- Announcing .NET 8
Gaurav Seth - Announcing C# 12
Kathleen Dollard - Announcing F#
Tomáš Grošup - Removing allocations by reducing closure scopes using local variables
Gérald Barré - The Evolution of C#
Aram Tchekrekjian - Optimizing C# code analysis for quicker .NET compilation
Anthony Simmon - Exploring What's New in C# 12
Darren Horrocks - VestPocket: File-based Data Storage for AOT .NET Applications
Khalid Abuhakmeh - How to Use Interceptors in C# 12
Code Maze - A more flexible and enhanced way of logging in .NET 8
Steven Giesel - How to extract, create, and navigate Zip Files in C#
Davide Bellone - C# Interceptors
Paul Michaels - Enums in CSharp – A Simple Guide To Expressive Code
Nick Cosentino - Alias any Type with C# 12
Michael Jolley - Top 10 Must-Have Features in Syncfusion’s C# PDF Library
Sowmiya Loganathan - Standard and Custom Numeric Format Strings in .NET
Code Maze - The CSharp Switch Statement – How To Go From Zero To Hero
Nick Cosentino

Desde su llegada con la versión 7 del lenguaje C#, allá por 2017, nuestro lenguaje favorito dispone de soporte para tuplas. Sin embargo, no he visto muchos proyectos donde estén siendo utilizadas de forma habitual; quizás sea porque pueden hacer el código menos legible, o quizás por desconocimiento, o simplemente porque lo que aportan podemos conseguirlo normalmente de otras formas y preferimos hacerlo como siempre para no sorprender al que venga detrás a tocar nuestro código.
Pero bueno, en cualquier caso, es innegable que las tuplas han venido para quedarse, así que en este post vamos a ver algunos usos posibles, y a veces curiosos, de esta característica del lenguaje C#.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- El atributo CallerArgumentExpression, o cómo conocer las expresiones usadas como argumentos en llamadas a un método en C#
José María Aguilar - Funciones constructoras en Javascript
Oscar Sotorrío
.NET Core / .NET
- Reading a stream of JsonDocuments separated by new lines (ndjson)
Gérald Barré - Merging Multiple PDFs Using the iText Library
Matjaz Prtenjak - The convenience of System.IO
Richard Lander - Pangram validator in one line
Christian Heilmann - Implementing Distributed Locks in .NET Core with Redis or ZooKeeper
Hamed Salameh - MoonSharp - Running Lua Scripts in .NET
Khalid Abuhakmeh - Updates On Microsoft’s BinaryFormatter Obsoletion Strategy
DevExpress Blogs - Provide opt-in to experimental APIs using C#12 ExperimentalAttribute
Maarten Balliauw - Comparing ForEach Method and Foreach Statement in C#
Code Maze - Let’s build a custom Microsoft Graph connector
Waldek Mastykarz - Read and Write Windows Registry in C#
Code Maze - ConfigureAwait in .NET 8
Stephen Cleary - Discovering The Features Of DotNetFiddle – How To Compile C# Online
Nick Cosentino - .NET Task Parallel Library vs System.Threading.Channels
Charles Chen - TimeProvider makes it easier to mock time in .NET 8
David Grace - Automating Memory Profiling with the JetBrains dotMemory Profiler API
Steve Gordon - Interactive LINQ tutorial, especially for beginners
Steven Giesel

El otro día me descubrí escribiendo un código parecido al siguiente:
return $"Order: {Items.Length} items, {Total.ToString("#,##0.#0")}";
Mal, lo que se dice mal, no estaba; funcionaba perfectamente y cumplía los requisitos, pero me di cuenta de que no estaba aprovechando todo el potencial de las cadenas interpoladas de C# que ya habíamos comentado por aquí mucho tiempo atrás.
Y como siempre que tengo algún despiste de este tipo, pienso que quizás pueda haber alguien más al que le ocurra o no esté al tanto de esta posibilidad el lenguaje, así que vamos a ver cómo podíamos haberlo implementado de forma algo más simple.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo evitar que entren argumentos nulos en métodos de C#: un recorrido histórico (y lo que nos trae el futuro)
José María Aguilar - Limpiar un input type=file
José María Aguilar
.NET Core / .NET
- Avoiding flaky tests with TimeProvider and ITimer: Exploring the .NET 8 preview
Andrew Lock - Managing Directories With Directory and DirectoryInfo in C#
Code Maze - Exploring Object Layouts - To kill a mocking bug
Jeroen Vannevel - Functional Error Handling in .NET With the Result Pattern
Milan Jovanović - A C# port of validation with partial round trip
Mark Seemann - Yes you can create classes on the stack!
Steven Giesel - How to Build a Query String for a URL in C#?
Code Maze - Caching your WebView Environment to manage multiple WebView2 Controls
Rick Strahl - Handling Dates With Noda Time in .NET
Code Maze - Collection expressions brings the spread operator to C# 12
David Grace - How to Force Run .NET Application as Administrator
Code Maze - Await Tuples Directly
Mehran Davoudi - Save Files With Elevated Permissions on UnauthorizedAccessException
Rick Strahl

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- El Tao de la Programación
José María Aguilar - Generación de rutas con parámetros de query string en Blazor 6
José María Aguilar
.NET Core / .NET
- .NET 8 Top 10 New Features
Patrick Smacchia - What′s new in C# 12: overview
Konstantin Volohovsky - Customizing the behavior of record copy constructors
Gérald Barré - Ignore Null Values With AutoMapper
Code Maze - Open-Sourcing Metalama Compiler, a Roslyn Branch with Source Transformers
Gael Fraiteur - How To Handle Exceptions in CSharp – Tips and Tricks for Streamlined Debugging
Nick Cosentino - C# Tip: How to create Unit Tests for Model Validation
Davide Bellone - A Generic Timeout Helper
Ricardo Peres - Interfaces can have private methods
Steven Giesel - Source Code Generators, DIY
Bnaya Eshet - C# Record Explained
Patrick Smacchia
Pues hoy vamos con un truquillo rápido ;)
Como sabemos, cuando usamos Razor Pages para construir aplicaciones sobre ASP.NET Core, la convención por defecto obliga a que nuestras páginas se encuentren en la carpeta /Pages del proyecto.
¿Pero qué ocurre si somos algo tiquismiquis y no nos gusta esa ubicación o no podemos usarla por cualquier motivo? En este post vamos a ver cómo cambiar esta convención para que nuestras páginas Razor se encuentren en otra carpeta.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Por qué no compila este código C#?
José María Aguilar - ASP.NET MVC: obtener id y nombre de un control de formulario
José María Aguilar
.NET Core / .NET
- Customizing the name of embedded resources in .NET
Gérald Barré - Updates to Docker images in .NET 8: Exploring the .NET 8 preview
Andrew Lock - Source Generator playground
Bart Wullems - C# Overtaking Java in Popularity Index
David Ramel - Using Keyed Services to Resolve Dependencies in .NET
Code Maze - Pre-commit hooks with Husky.NET - build, format, and test your .NET application before a Git commit
Davide Bellone - .NET 6 - Parallel.ForEachAsync
Bart Wullems - Microsoft .NET Code Analysis: Remove Unnecessary Lambda Expressions
David McCarter - 3 Reasons to Delay Adopting .NET 8 and 10 to do it ASAP
Uno Platform Team

Sabemos que está feo y no sea especialmente recomendable en muchos casos, pero hay veces en las que es totalmente necesario acceder a miembros privados de una clase. Por ejemplo, sería un requisito imprescindible si fuéramos a implementar un serializador o deserializador personalizado, o necesitásemos clonar objetos, o simplemente realizar pruebas unitarias a una clase que no ha sido diseñada para ello.
Para conseguirlo, siempre hemos utilizado los mecanismos de introspección de .NET, conocidos por todos como reflexión o por su término en inglés reflection. Por ejemplo, imaginemos una clase como la siguiente, virtualmente inexpugnable:
public class BlackBox
{
private string _message = "This is a private message";
private void ShowMessage(string msg) => Console.WriteLine(msg);
public override string ToString() => _message;
}
Aunque a priori no podemos hacer nada con ella desde fuera, usando reflexión podríamos acceder sin problema a sus miembros privados, ya sean propiedades, campos, métodos o cualquier tipo de elemento, como podemos ver en el siguiente ejemplo:
var instance = new BlackBox();
// Obtenemos el valor del campo privado _message:
var field = typeof(BlackBox)
.GetField("_message", BindingFlags.NonPublic | BindingFlags.Instance);
var value = field!.GetValue(instance);
// Ahora llamamos al método privado ShowMessage():
var method = typeof(BlackBox)
.GetMethod("ShowMessage", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(instance, [value]);
// Al ejecutar, se nuestra en consola: "This is a private message"
Sin embargo, de todos es sabido que la reflexión es un mecanismo muy lento, a veces farragoso en su implementación y, sobre todo, incompatible con tree-shaking, que es como se suele llamar la técnica que usan los compiladores de eliminar del código final todas las clases, métodos y propiedades que no se utilizan en el código final. Esta técnica va tomando cada vez más relevancia conforme los compiladores son capaces de crear directamente ejecutables nativos puros, porque permiten reducir de forma considerable el peso de los artefactos creados.
Por esta razón, en .NET 8 se ha incluido una nueva fórmula para acceder a miembros privados, mucho más eficiente y amistosa con AOT, porque se lleva a tiempo de compilación algo que antes obligatoriamente se resolvía en tiempo de ejecución.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- El veloz murciélago hindú…
José María Aguilar - Implicit usings en C#10
José María Aguilar
.NET Core / .NET
- Announcing .NET 8 RC2
Jon Douglas - OpenSilver 2.0 released
Userware - Full precision floating-point summation in C#
Anthony Lloyd - Get the default value of a type at runtime
Gérald Barré - Replace Line Breaks in a String in C#
Code Maze - Getting Started With NServiceBus in .NET
Milan Jovanović - Padding for Overlaid Structs
Stephen Cleary - How To Use Embedded Resources in .NET
Khalid Abuhakmeh - Revisiting Various Change Feeds Consumption in .NET
Tomasz Pęczek - xUnit And Moq – How To Master Unit Testing In C#
Nick Cosentino - Lessons learned from building a static code analyzer for C#
Daniel Genezini - Primary constructors changes initialisation behaviour in C# 12
David Grace - Structured Concurrency in C#
Steven Giesel - .NET 8 New and Efficient Way to Check IP is in Given IP Range
Sibeesh Venu - ConcurrentQueue in C#
Michal Kaminski - Simplify Source Generator creation the RoslynGenerator template
Bart Wullems

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Lo que ocurre cuando desarrolladores diseñan interfaces de usuario (II)
José María Aguilar - Directivas using globales en C# 10
José María Aguilar
.NET Core / .NET
- Logs en .Net
Fernando Escolar - How to test the logs from ILogger in .NET
Gérald Barré - Testing Time-Dependent Code With TimeProvider in .NET
Code Maze - Performance Improvements in .NET 8
Rico Mariani - Rolling Forward to Major Versions in .NET
Rick Strahl - How To Display .NET Collections with the Oxford Comma
Khalid Abuhakmeh - Selecting Xml Nodes With XPath in C#
Code Maze - Effortlessly Resolving Circular Dependencies in .NET with SmartInject
Daan Acohen - Arm64 Performance Improvements in .NET 8
Kunal Pathak - Don't Use "Task.WhenAll" for Interdependent Tasks
Jeremy Clark - Tales from the .NET Migration Trenches - Our First Views
Jimmy Bogard - The convenience of System.Text.Json
Richard Lander - Looking at Producer/Consumer Dependencies: Bounded vs. Unbounded Channels & Producer/Consumer Exception Handling
- Jeremy Clark

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Por qué llamamos "uppercase" y "lowercase" a mayúsculas y minúsculas?
José María Aguilar - 32 Síntomas que indican que estás afectado por el desarrollo
José María Aguilar
.NET Core / .NET
- Polly v8 officially released
Joel Hulen - Wolverine Expands its Multi-Tenancy Story to HTTP
Jeremy D. Miller - Create Cryptographic Numbers With RandomNumberGenerator
Code Maze - How to write logs from ILogger to xUnit.net ITestOutputHelper
Gérald Barré - Less boilerplate code with the new primary constructor in C# 12
Steven Giesel - Don’t persist GetHashCode() in .NET!
Isaac Abraham - The convenience of .NET
Richard Lander - The case of the mysterious comparison
Mark Seemann - C# Tip: Improve memory allocation by initializing collection size
Davide Bellone - Using a Discard Variable in C#
Code Maze - Green Thread Experiment Results
David Wrighton - Debugging Enhancements in .NET 8
James Newton-King - Wolverine Interoperability with Others
Jeremy D. Miller - Memory Optimization With ArrayPool in C#
Code Maze - How To Use BenchmarkDotNet For Beginners
Nick Cosentino - Tales from the .NET Migration Trenches
Jimmy Bogard - Questions I asked as .NET interviewer
Steven Giesel - Memory-Mapped Files and Overlaid Structs
Stephen Cleary - 22 C# Best Practices
Code Maze - How to Add Comments to Excel Documents Using C#
Mohan Chandran

Seguro que más de una vez habéis tenido que construir una abstracción sobre DateTime
para poder controlar apropiadamente la obtención de la fecha/hora actual y otras operaciones relacionadas con el tiempo.
Suelen ser bastante útiles cuando creamos pruebas unitarias de métodos que dependan del momento actual. Por ejemplo, ¿cómo testearíamos de forma automática que las dos líneas de ejecución del siguiente método DoSomething()
funcionan correctamente? Sería imposible salvo que ejecutásemos las pruebas a una hora determinada, algo que se antoja complicado 😉
public class MyClass
{
public string DoSomething()
{
var now = DateTime.Now;
return now.Second == 0
? "A new minute is starting"
: "Current second " + now.Second;
}
}
Sin duda, una forma mejor y más test friendly sería contar con una abstracción sobre el proveedor de tiempos capaz de retornar la fecha y hora actual, por ejemplo:
public interface IDateTimeProvider
{
DateTime GetCurrentDateTime();
}
De esta forma, podríamos reescribir la clase MyClass
de forma que recibiera por inyección de dependencias nuestro proveedor IDateTimeProvider
. Así sería realmente sencillo crear un par de pruebas unitarias que, suministrando los valores correctos a través de esta dependencia, podrían recrear los escenarios a cubrir:
public class MyClass
{
private readonly IDateTimeServices _dateTimeServices;
public TimeHelpers(IDateTimeServices dateTimeServices)
{
_dateTimeServices = dateTimeServices;
}
public string DoSomething()
{
var now = _dateTimeServices.GetCurrentDateTime();
return now.Second == 0
? "A new minute is starting"
: "Current second " + now.Second;
}
}
Aunque hacerlo de esta manera en nuestras aplicaciones es lo ideal, hay partes que se quedarían fuera de esta posibilidad, como las bibliotecas de terceros que de alguna forma dependan de las funcionalidades proporcionadas por DateTime
.
Por esta razón, .NET 8 va a introducir una abstracción que nos permitirá gestionar estos escenarios de forma más homogénea y generalizada en aplicaciones y componentes .NET.
Os presento la clase abstracta TimeProvider
😁

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- 5 motivos por los que tus acciones MVC reciben objetos vacíos o nulos en ASP.NET Core
José María Aguilar - Validación de peticiones en ASP.NET, o cómo evitar el error “Request.Form peligroso”
José María Aguilar
.NET Core / .NET
- Métricas en .Net
Fernando Escolar - What's new in System.Text.Json in .NET 8
Eirik Tsarpalis - Extending HTTPClient with Custom Http Message Handlers in dotnet
Abdul Rahman - How to Validate JWTs in .NET
Andrea Chiarelli - Sharing WireMock in sequential and parallel tests
Cezary Piątek - Accessing private members without reflection in C#
Gérald Barré - Discriminated Unions in C#
Maarten Balliauw - Back to .NET basics: How to easily build a Strategy pattern using dependency injection
Carlos Pons - Synchronization Mechanisms - Volatile vs Interlocked vs lock in C#
Code Maze - Feature Flags in .NET and How I Use Them for A/B Testing
Milan Jovanović - When to Use ReaderWriterLockSlim Over lock in C#
Code Maze - System.Text.Json JsonConverter Test Helpers
Khalid Abuhakmeh - Feature Flags 101: A Guide for .NET Developers
Davide Bellone - .NET 8–Keyed/Named Services
Bart Wullems - ASCII vs UTF8 - How To Navigate Character Encoding
Nick Cosentino - Different Log Levels in Serilog
Code Maze - Less boilerplate code with the new primary constructor in C# 12
Steven Giesel

La verdad es que este año me ha dado algo de pereza volver a abrir el blog después de este periodo veraniego de descanso. Aunque disfrute escribiendo y compartiendo información, mantener esto medio vivo requiere esfuerzo y tiempo, que obviamente dejo de dedicar a otras cosas que también me gustan 🙂
Pero bueno, la cuestión es que por aquí andamos de nuevo, listos para inaugurar oficialmente la temporada 2023-2024. ¿Y qué mejor forma de hacerlo que con una nueva recopilación de enlaces interesantes? ¡Pues vamos allá!
Por si te lo perdiste...
- CRUD en Blazor usando el componente DataGrid de Syncfusion
José María Aguilar - Parámetros opcionales: úsense con precaución
José María Aguilar
.NET Core / .NET
- Trazas en .Net
Fernando Escolar - Announcing .NET 8 RC1
Leslie Richardson - Performance Improvements in .NET 8
Stephen Toub - Tales from the .NET Migration Trenches, Empty proxy & Shared library
Jimmy Bogard - Working with API that supports remote streaming using HTTPClient in dotnet
Abdul Rahman Shabeek Mohamed - Building a Resilient Email Sending Method in .NET with SmtpClient, Retry Support, and the Outbox Pattern
Steve Smith - Your Quick Guide to Pattern Matching in C#
Aram Tchekrekjian - Listing Windows virtual desktops using .NET
Gérald Barré - File-Scoped Types in C# 11
Code Maze - Dictionaries in C#: How To Use The Different Variations
Nick Cosentino - Dumb Developer Tricks - Fizz Buzz with C# 12 and Polly
Khalid Abuhakmeh - Creating custom debug visualizers for Visual Studio 2022
Thomas Ardal - Techniques for Checking Floating-Point Equality in C#
Code Maze - The best C# REPL is in your terminal
Anthony Simmon - How to Use Moq to Return a Value That Was Passed Into a Method
Code Maze - Reverse engineering natively-compiled .NET apps
Michal Strehovský - Resilient Http Calls using Polly.
Dhananjeyan Balaretnaraja

Si sois habituales del blog, probablemente ya sabréis lo que os voy a decir ;)
Como todos los años por estas fechas, empieza el periodo vacacional y aprovecharé para bajar un poco el ritmo, descansar unos días y disfrutar de familia y amigos.
Por tanto, dejaré el blog en modo de bajo consumo hasta bien entrado septiembre, cuando, ya con las pilas recargadas, volveré al ataque con nuevos artículos y enlaces interesantes. Eso sí, durante este periodo seguiré echando el ojo periódicamente a comentarios o mensajes que me dejéis, aunque no los responderé con la misma celeridad que en otras épocas del año.
Aprovecho para desearos a todos un feliz verano y que disfrutéis de las vacaciones. ¡Nos vemos a la vuelta!
Publicado en Variable not found.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Se pueden crear componentes Blazor que no hereden de ComponentBase o alguno de sus descendientes?
José María Aguilar - Consejos imprescindibles por si algo falla
José María Aguilar
.NET Core / .NET
- The minimal API AOT compilation template: Exploring the .NET 8 preview Part 1 & Part 2
Andrew Lock - TimeProvider and ITimer: Writing Unit Tests with Time in .NET 8 Preview 4
Artur Ampilogov - Roslyn Compiler and Analyzers in .NET
Code Maze - Why I like and prefer xUnit
Steven Giesel - Adding a Readme to NuGet Package Landing Pages
Khalid Abuhakmeh - Finding Symbols in Your C# Projects Using Roslyn
Calvin A. Allen - Converting a Byte Array to Hexadecimal String in C#
Code Maze - Customizing Return Value Behavior in Wolverine for Profit and Fun
Jeremy D. Miller - 7 Things about C#: If Statements
Joe Mayo - Discriminated Unions in C# With OneOf
Ryan Miranda - Improved Source Generators and Code Fixers Arrive in .NET Community Toolkit 8.2.1!
Sergio Pedri - Microsoft .NET Code Analysis: UTF-7 Encoding Is Insecure
David McCarter
Por decimotercer año consecutivo, me complace enormemente informaros de que Microsoft ha tenido a bien reconocerme de nuevo como MVP (Most Valuable Professional) en tecnologías de desarrollo. ¡13 años ya, uau! ¡Pero si el primero parece que fue ayer!
Muchas gracias al increíble equipo de Microsoft que hay detrás de este programa por haberme honrado con este reconocimiento, y especialmente a nuestra gran Cristina González por su dedicación, cercanía y ponérnoslo todo tan fácil cuando la necesitamos.
También agradeceros a vosotros, mis queridos amigos, que sois los que con vuestras visitas, lecturas, comentarios y apoyo incondicional hacéis que este sueño siga siendo posible año tras año.
¡Nos vemos por aquí!
Publicado en Variable not found.

Seguro que habéis visto más de una vez un código parecido al siguiente, en el que llamamos a una API REST externa y su resultado es deserializado a un objeto .NET para introducirlo en el flujo de la aplicación:
async Task<User[]> GetUsersAsync()
{
var httpClient = _httpClientFactory.CreateClient();
// Hacemos la llamada
var response = await httpClient.GetAsync("https://jsonplaceholder.typicode.com/users");
// Si la cosa no fue bien, retornamos
if (!response.IsSuccessStatusCode)
return Array.Empty<User>();
// Descargamos la respuesta y la deserializamos
var usersAsJson = await response.Content.ReadAsStringAsync();
var users = JsonSerializer.Deserialize<User[]>(usersAsJson);
return users;
}
Fijaos que el JSON de la respuesta de la API lo guardamos en una cadena de caracteres para, justo después, deserializarlo y convertirlo en un array de objetos User
. Que levante la mano el que no lo haya hecho nunca 😉
¿Y veis dónde está el problema? A la salida de este método, tendremos en memoria dos copias de los datos de los usuarios, una en forma de string
JSON y otra en el objeto que hemos deserializado.
Si estamos hablando de respuestas pequeñas o con poca concurrencia, probablemente el impacto es inapreciable. Pero si las estructuras retornadas por la API tuvieran un tamaño considerable o estamos en un escenario de múltiples llamadas simultáneas, esta duplicidad sería un auténtico derroche de recursos.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Expresiones new con el tipo de destino en C# 9
José María Aguilar - ¿Esa enumeración está vacía?
José María Aguilar
.NET Core / .NET
- El inyector de dependencias de .Net
Fernando Escolar - Consideraciones al publicar un paquete NuGet
Iván Montilla - Missing Stack trace when eliding the await keyword
Steven Giesel - Using the new configuration binder source generator: Exploring the .NET 8 preview
Andrew Lock - Log4net Appenders Introduction With C# Examples
Muhammed Saleem - How to Use Factory Pattern With Dependency Injection in .NET
Ahsan Ullah - 7 Things about C#: Console I/O
Joe Mayo - Microsoft .NET Code Analysis: Always Add Braces in C#
David McCarter - Test Data Generation With AutoFixture in .NET
Code Maze - Rx.NET v6.0: Enhancing Compatibility, Trimming Support, and Many More
Almir Vuk - LINQ: Select.Where or Where.Select?
Steven Giesel - Using Explicit Operators in Microsoft .NET to Perform Type Conversions
David McCarter - How to Hash Passwords with BCrypt in C#
Claudio Bernasconi - Introduction to .NET Releases And Updates
Aram Tchekrekjian - How to Generate C# Business Object Class from a CSV File
Greg Lutz

Cuando en ASP.NET Core MVC usamos rutado por convención, lo habitual es que accedamos a las acciones mediante rutas definidas en el patrón, como [controller]/[action]
. Así, podemos encontrarnos con rutas como /PendingInvoices/ViewAll
para acceder a la siguiente acción:
public class PendingInvoicesController : Controller
{
public IActionResult ViewAll() => Content("Show all pending invoices");
}
Lo mismo ocurre con páginas Razor. Si usamos las rutas por defecto, al archivo /Pages/ShowAllPendingInvoices.cshtml
podríamos acceder mediante la ruta /ShowAllPendingInvoices
. No es que sean rutas terribles, pero tampoco podemos decir que sean lo mejor del mundo en términos de legibilidad y conveniencia.
El kebab-casing consiste en separar con un guion "-" las distintas palabras que componen los fragmentos de la ruta, por lo que en los casos anteriores tendríamos /pending-invoices/view-all
y show-all-pending-invoices
, algo bastante más legible, elegante, y apropiado desde el punto de vista del SEO.
El nombre kebab-casing viene de que visualmente el resultado es similar a un pincho atravesando trozos de comida. Imaginación que no falte 😉
En este post vamos a ver cómo aprovechar los puntos de extensibilidad del sistema de routing de ASP.NET Core para modificar la forma en que genera rutas y así adaptarlo a nuestras necesidades.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Creando gráficas estadísticas en Blazor con los componentes visuales de Syncfusion
José María Aguilar - 30 Leyes epónimas relacionadas con el desarrollo de software (I)
José María Aguilar
.NET Core / .NET
- Introducing the New T4 Command-Line Tool for .NET
Mike Corsaro - Seamless Integration Testing With WireMock.NET
Code Maze - C# 12: Collection literals
Steven Giesel - Wolverine 1.0 is Out! & Wolverine’s Middleware Strategy is a Different Animal
Jeremy D. Miller - Differences Between ExpandoObject, DynamicObject and dynamic
Code Maze - How to use RuntimeHelpers.IsReferenceOrContainsReferences to micro-optimize collections
Gérald Barré - C# Source Code Generators
Bruno Sonnino - C# Struct vs Class: Decoding Key Differences and Use Cases
Wade Gausden - Learn how to mock your HttpClient in C# now with 2 simple methods
Henrique Dalcin Dalmas - Microsoft Forms Service’s Journey to .NET 6
Ray Yao - Validating nested DataAnnotation IOptions recursively with MiniValidation
Andrew Lock - Using StringBuilder To Replace Values
Khalid Abuhakmeh - Parsing websites in C# with Html Agility Pack or AngleSharp
Thomas Ardal - Create your own Mediator (like Mediatr)
Steven Giesel - Getting the .NET Desktop Runtime Installed with a Custom Runtime Checker and Installer
Rick Strahl - Improved .NET Debugging Experience with Source Link
Patrick Smacchia - 7 Things about C#: Running Apps
Joe Mayo - Permutations of a String in C#
Matjaz Prtenjak - Five Reasons Why I Love HangFire
Kevin W. Griffin - Value Objects in C#
Code Maze

Desde la aparición de los nullable reference types, o tipos referencia anulables, en C# 8, nos encontramos frecuentemente con el warning de compilación CS8618, que nos recuerda que las propiedades de tipo referencia definidas como no anulables (es decir, que no pueden contener nulos) deben ser inicializadas obligatoriamente porque de lo contrario contendrán el valor null
, algo que iría en contra de su propia definición.
Para verlo con un ejemplo, consideremos una aplicación de consola con el siguiente código:
var friend = new Friend() {Name = "John", Age = 32};
Console.WriteLine($"Hello, {friend.Name}");
public class Friend
{
public string Name { get; set; }
public int Age { get; set; }
}
La aplicación se ejecutará sin problema, aunque al compilarla obtendremos el warning CS8618:
D:\Projects\ConsoleApp78>dotnet build
MSBuild version 17.4.1+9a89d02ff for .NET
Determining projects to restore...
Restored D:\Projects\ConsoleApp78\ConsoleApp78.csproj (in 80 ms).
D:\Projects\ConsoleApp78\Program.cs(8,19): warning CS8618: Non-nullable property 'Name'
must contain a non-null value when exiting constructor. Consider declaring the
property as nullable.
[...]
[D:\Projects\ConsoleApp78\ConsoleApp78.csproj]
1 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.63
D:\Projects\ConsoleApp78\ConsoleApp78>_
También en Visual Studio podremos ver el subrayado marcando la propiedad como incorrecta:
Aunque muchas veces este warning viene bien porque nos ayudará a evitar errores, hay otras ocasiones en las que puede llegar a ser molesta tanta insistencia. Y en estos casos, ¿cómo podemos librarnos de este aviso?
Disclaimer: algunas de las soluciones mostradas no son especialmente recomendables, o incluso no tienen sentido en la práctica, pero seguro que son útiles para ver características de uso poco habitual en C#.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Crear manualmente instancias de clases usando el proveedor de servicios de .NET
José María Aguilar - PremoniSense, la gran novedad de Visual Studio 2010
José María Aguilar
(¿No era este post una premonición en sí mismo? :D)
.NET Core / .NET
- Announcing .NET 8 Preview 5
Jiachen Jiang - 12: Primary constructor on classes and struct
Anthony Giretti - Optional DependencyInjection in .NET
Federico Alterio - Introduction to Firebase in .NET
Phil Broderick - Collatz sequences by function composition
Mark Seemann - C# Tip: Use custom Equality comparers in Nunit tests
Davide Bellone - How does List work under the hood in .NET?
Steven Giesel - How to detect heap allocations
Bart Wullems

Ya he comentado alguna vez que el hecho de trabajar a diario con C# no implica que conozcamos todas sus funcionalidades, detalles, trampas y recovecos. Después de muchos años, yo sigo encontrándome sorpresas bastante a menudo.
Hace poco, andaba haciendo algunas pruebas y llegué a un código como el siguiente:
var a = 1;
var (b, c) = 4;
var (d, e, f) = 9;
Console.WriteLine(a + b + c + d + e + f ); // Muestra por consola "14"
Así al vistazo, diréis que el código no compila tal cual, pero la pregunta es: ¿sería posible que compilara y, además, mostrara la salida que pretendemos sin tocar una sola línea de las que vemos ahí?
Si lo pensáis un poco seguro que podéis responder a las preguntas. Y si no, pulsad aquí para ver la solución 👇👇
Pues en efecto, el código tal y como está no compila, así que debemos pasar a la siguiente parte de la pregunta: qué podemos hacer para que compile y, además, muestre por consola el valor que buscamos, sin tocar ni una coma de esas cuatro líneas de código propuesto como punto de partida.
Si nos fijamos bien, la primera línea es una asignación normal, pero en la segunda y tercera línea estamos asignando valores a variables usando sintaxis propia de tuplas. En el fondo, ambas líneas son iguales, y fallan en compilación porque no podemos asignar un entero a un tupla. ¿O quizás sí?
Si recordáis, hace mucho tiempo hablamos por aquí de la deconstrucción de clases, un interesante mecanismo que, al más puro estilo de cheff sofisticado, permitía deconstruir o descomponer objetos en tuplas, simplemente implementando el método Deconstruct()
.
Pues bien, resulta que este método Deconstruct()
puede implementarse de forma externa al tipo que va a ser deconstruido mediante extension methods. Seguro que ya empezáis a ver por dónde van los tiros... 😉 En efecto, podríamos implementar el método extensor Deconstruct()
sobre el tipo int
e introducir en él la lógica que nos interese.
Una posible implementación sería la siguiente, en la que tenemos sobrecargas de Deconstruct()
para dos y tres parámetros de salida, entre los que repartimos equitativamente el valor del entero a deconstruir:
public static class IntegerExtensions
{
public static void Deconstruct(this int i, out int i1, out int i2)
{
(i1, i2) = (i / 2, i / 2);
}
public static void Deconstruct(this int i, out int i1, out int i2, out int i3)
{
(i1, i2, i3) = (i / 3, i / 3, i / 3);
}
}
Si ejecutamos ahora mentalmente el código propuesto, veremos que se cumplen los requisitos iniciales:
var a = 1; // a=1
var (b, c) = 4; // "4" se deconstruye en (2,2). Por tanto: b=c=2
var (d, e, f) = 9; // "9" se deconstruye en (3,3,3). Por tanto, d=e=f=3
Console.WriteLine(a + b + c + d + e + f ); //
1+2+2+3+3+3 -> Muestra "14":
Bonito y maquiavélico uso de tuplas y deconstrucción, ¿verdad? 😉

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Indicios de que tu interfaz de usuario fue creado por un programador
José María Aguilar - 3 formas de saber si un componente se está ejecutando en Blazor Server o WebAssembly
José María Aguilar
.NET Core / .NET
- Compartir un fichero C# entre varios proyectos (sin referencias)
Iván Montilla - Time abstraction in .NET 8
Steven Giesel - Where are Objects Allocated in C#? Understanding Heap and Stack
Gevorg Chobanyan - Use secrets in unit tests
Mark Heath - Expression Trees in C#
Code Maze - Enhancing .NET Hot Reload with CreateNewOnMetadataUpdate, MetadataUpdateHandler and MetadataUpdateOriginalType Attributes
Nick Randolph - Refactoring Change Preventers in C#
Code Maze - How to add Dependency Injection, Configurations, and Logging in a .NET 7 Console Application
Davide Bellone - Introducing Sep - Possibly the World's Fastest .NET CSV Parser
Niels Rasmussen - Reduce heap allocations by using static anonymous functions
Bart Wullems - Span / Memory / ReadOnlySequence in C#
Steven Giesel - Managed vs Unmanaged Code (Garbage Collection) in C#
Code Maze - .NET 8: Why .NET 8 preview doesn’t show up in Visual Studio 2022 ?
Anthony Giretti

Hace unos días hablábamos de la serialización polimórfica en .NET 6, y vimos qué posibilidades teníamos para conseguirlo sin tener que escribir un custom converter o conversor personalizado. Y aunque realmente .NET 6 permite hacerlo, no es lo más elegante del mundo porque teníamos que operar sobre tipos object
.
Pero por suerte, en .NET 7 la cosa ha mejorado y ya tenemos opciones razonables para conseguirlo basadas en los dos nuevos atributos [JsonDerivedType]
y [JsonPolymorphic]
. Veamos cómo utilizarlos.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Un vistazo a los patrones relacionales y combinadores, lo nuevo de C# 9 para exprimir el pattern matching
José María Aguilar - El patrón Post-Redirect-Get
José María Aguilar
.NET Core / .NET
- Timers en .Net
Fernando Escolar - nameof get's a bit better in C# 12
Steven Giesel - How to Use SFTP For Secure File Upload in .NET
Code Maze - Getting .NET Library Projects to Output Dependent Assemblies
Rick Strahl - What's the latest .NET roadmap?
Steve Smith - Memory Allocation Optimization With BenchmarkDotNet
Code Maze - How to Convert a String to a Span in C#
Code Maze - Step-by-Step Guide to Adding and Removing Watermarks in PDF using C#
Sameerkhan - New Terminal logger for .NET 8
Steven Giesel - Raiders of the lost root: looking for memory leaks in .NET
Christophe Nasarre - VerificationException in .NET Framework when using structs
Kevin Gosse - .NET 7–Serialize private fields and properties
Bart Wullems - Implicit Operators in C# and How To Create a Multi Type
Nick Cosentino - .NET Micro-Optimization and Refactoring Trick
Patrick Smacchia

Imaginad una clase como la siguiente, que representa las características básicas de los archivos almacenados en una aplicación:
public class File
{
public string FileName { get; set; }
public ulong SizeBytes { get; set; }
}
Y ahora, imaginemos también una clase que hereda de la anterior para modelar específicamente, aunque también de forma resumida, los archivos de vídeo:
public class VideoFile: File
{
public string Codec { get; set; }
public TimeSpan Duration { get; set; }
}
Y puestos a imaginar, acabemos con el siguiente método, que retorna la representación JSON del objeto File
que recibe como parámetro:
string SerializeFile(File file) => JsonSerializer.Serialize(file);
Gracias al polimorfismo, ese pilar imprescindible de la Programación Orientada a Objetos, podríamos invocar este método con objetos de tipo File
, VideoFile
o cualquier descendiente de alguno de ambos, puesto que en todos los casos se trata de objetos de tipo File
:
var file = new File
{
FileName = "file.txt", SizeBytes = 1024
};
Console.WriteLine(SerializeFile(file));
var videoFile = new VideoFile
{
FileName = "video.mp4",
SizeBytes = 1024 * 1024,
Codec = "H264",
Duration = TimeSpan.FromMinutes(3)
};
Console.WriteLine(SerializeFile(videoFile));

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Inicializar a null propiedades sin tipo
José María Aguilar - Cómo saber si un objeto no es nulo (edición C# 9)
José María Aguilar
.NET Core / .NET
- Building a Dynamic Logical Expression Builder in C#
Yohan Malshika - Building Functional .NET Applications: a Guide for Choosing between Nahla Davies
- Detect Globalization-Invariant mode in .NET
Gérald Barré - Understanding the C# Init Operator
Bradley Wells - C# logging: Best practices in 2023 with examples and tools
Shane Duggan - How to Convert Stream to Byte Array in C#
Januarius Njoku - The Ultimate .NET Version Guide
Claudio Bernasconi - How to automatically update a Windows Forms Application?
Renato Ivanescu - .NET 7: Simplify Patch requests with PatchAsJsonAsync extension
Anthony Giretti - 6 useful extensions for IEnumerable
Steven Giesel - Understanding IOptions, IOptionsMonitor, and IOptionsSnapshot in .NET 7
Davide Bellone - Is WPF Dead? - The Current State of WPF [2023]
Claudio Bernasconi - Common C# exceptions and how to fix them
Carlos Schults - How does TryGetNonEnumeratedCount work?
Steven Giesel - How to Generate Permutations in C#
Matjaz Prtenjak - Refactor your .NET HTTP Clients to Typed HTTP Clients
Tim Deschryver - Feature toggle management in .NET Core
Krzysztof Begiedza - .NET Core–Monitor cache misses
Bart Wullems
Hace pocos meses hablábamos de la vuelta del clásico [OutputCache]
en ASP.NET Core 7 y veíamos cómo podía simplificarnos la vida a la hora de cachear en el servidor respuestas de peticiones.
Haciendo un rápido recordatorio, la novedad era la posibilidad de introducir en el pipeline el middleware OutputCacheMiddleware
, que se encargaría de almacenar las respuestas de endpoints y reutilizarlas en posteriores peticiones que cumplieran los requisitos apropiados.

Tras una semana de parón por una semanilla de relax en Roma (ciudad que, por cierto, os recomiendo que visitéis si no lo habéis hecho ya), ahí van los enlaces recopilados durante los últimos días. Como de costumbre, espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Comprometidos o involucrados?
José María Aguilar - Crear bloques de código Razor reutilizables en Blazor con Render Fragments
José María Aguilar
.NET Core / .NET
- Top 5: Errores de performance en C#
Fernando Escolar - Announcing .NET 8 Preview 4
Jon Douglas - Serilog project update, May 2023
Nicholas Blumhardt - Control Visual Studio from an external application
Gérald Barré - Seamlessly Import and Export CSV Data in Excel Using C#
Mohan Chandran - Prevent .NET Application Insights telemetry loss
Anthony Simmon - Exploring Code Performance Testing in C# with BenchmarkDotNet
Kostis Grontis - Why do we need Wait() and Pulse() Methods in C# Threading?
Kulasangar Gowrisangar - Introduction - Rust for C#/.NET Developers
Atif Aziz et al - Upcoming availability of .NET Framework 4.8.1 on Windows Update and Catalog
Brett Lopez - Multidimensional Array vs Jagged Array in C#
Dusko Mirkovic - URI Encode and Decode in .NET
Code Maze - Concurrent Hosted Service Start and Stop in .NET 8
Steve Gordon - Hot Reload Supports Modifying Generics!
Mikelle Rogers - Client Support for Calling WCF/CoreWCF with System.ServiceModel 6.0 Is Here!
Sam Spencer - C# Tip: Advanced Switch Expressions and Switch Statements using filters
Davide Bellone - TaskCompletionSource Pitfalls
Stephan Gay - Struct vs. Record vs. Class in C#
A. Yohan Malshika - An alternative approach to structuring your tests in XUnit
Bart Wullems - Exploring the C# Source Link Feature: Enhancing Debugging Experiences
Neel Bhatt - XML Serialization in C# .NET Core: A Comprehensive Guide
Sanjay M.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo mostrar por consola las líneas que se van añadiendo a logs o archivos de texto, en tiempo real
José María Aguilar - Métodos condicionales en .NET
José María Aguilar
.NET Core / .NET
- C# Record Type: Nondestructive Mutation, Equality, DTOs, and More
Bradley Wells - Verifying your DI Container
Steven Giesel - Reading Windows Application Manifest of an exe in .NET
Gérald Barré - Calling internal ctors in your unit tests”
Phil Haack - Using sizeof() Operator in C#
Code Maze - How to Create a Custom Slack Bot with .NET 7
Daniel Donbavand - How to convert audio to different formats using C# and FFmpeg
Niels Swimberghe - Dot Net Office : Top Microsoft NuGet Packages in 2023
Dot Net Office - Prevent a Hangfire job from running when it is already active
Tim Deschryver - Controlling the log level of your application
Steven Giesel

El 8 de mayo de 2006 decidí subir a un tren, teniendo más o menos clara la dirección, pero sin saber en qué parada me bajaría.
Cuando en aquél post inicial decía literalmente "espero que el viaje sea largo", probablemente no me refería a tan largo. Aún con la tenacidad de la que hacía gala, era imposible imaginar que diecisiete años después seguiría por aquí, contemplando el paisaje y escribiendo sobre lo que veo, intentando contribuir a una comunidad a la que tanto debo.
Más de 1.430 posts, más de 3.000 comentarios de lectores, más de cinco millones de consultas... pero sobre todo, muchísimo aprendido por el camino y, con suerte, espero que no solo por mi parte 😉