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.
Publicado por José M. Aguilar a las 8:05 a. m.
Etiquetas: aspnetcore, trucos
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.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Sabes 1337?
José María Aguilar - Cómo documentar y generar código cliente de nuestras APIs utilizando Swagger/OpenAPI
José María Aguilar
.NET Core / .NET
- What's new in C# 11
Bill Wagner - Copying a collection: ToList vs ToArray
Gérald Barré - C# Method to Check if a Number is Composite
Jamil Hallal - Coding Faster with dotNetTips Spargine 6: Validating Arguments Made Easy
David McCarter - Central Package Management for .NET Projects
Bartosz Jarmuż - How to open and read XML files in C# .NET 6
Sanjay M. - 3 ways to check the object passed to mocks with Moq in C#
Davide Bellone - PDF Creation Made Easy with Syncfusion Document Processing Libraries
Praveen Kumar - Unity and .NET, what’s next?
Alexandre Mutel & Kristyna Hougaard

Hace unos días, Variable Not Found cumplió dieciséis añitos de vida, una eternidad para este mundo en el que vivimos, donde todo ocurre tan rápido y las cosas cambian a una velocidad de vértigo 😊.
Dieciséis años viviendo algo único. Cada uno de los 1.350 artículos publicados ha sido para mí una increíble oportunidad de mejora y aprendizaje y, con suerte, espero (y confío) haber podido ayudar a alguno de los muchísimos visitantes que durante este periodo han pasado por aquí y me han animado a seguir en la brecha.
Dieciséis años creciendo juntos. Comencé esta aventura con más pelo, mejor vista y bastante menos canas, pero la ilusión de poder escribir sobre lo que me gusta, con el plus de que esto pudiera ser útil para alguien, sigue intacta.
Pero bah, dejémonos de historias sentimentales... como es tradición, veamos cómo ha funcionado el blog durante este año.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Describiendo APIs ASP.NET Core con Swagger
José María Aguilar - 32 técnicas de producción de ideas
José María Aguilar
.NET Core / .NET
- Announcing .NET 7 Preview 4
Jeremy Likness - Regular Expression Improvements in .NET 7
Stephen Toub - Using the when Keyword in C# While Handling Exceptions
Code Maze - C# Tip: Convert ExpandoObjects to IDictionary
Davide Bellone - Configuring the Diagnostics Port for dotnet monitor
Mark Downie - Finding “routes” of all-pairs shortest paths with Floyd-Warshall algorithm in C#
Oleg Karasik - The Azure Cosmos DB Journey to .NET 6
Vinod Sridharan - Raw String Literals In C# 11
Wade Gausden - Serializing a Cookie container in C#
Infinite Loop - Override vs New Polymorphism In C# .NET
Wade Gausden - How to Find All Distinct Elements of a Given Integer Array
Jamil Hallal

Solemos pensar que el punto de entrada de una aplicación .NET, ya sea el método estático Main()
del clásico Program.cs
o el nuevo Program.cs
de .NET 6 que utiliza top level statements, es lo primero que se ejecuta en nuestras aplicaciones, en realidad no es así. Hay vida antes de que nuestra aplicación empiece a correr ;)
Aunque obviamente su utilidad es limitada y no es algo que necesitaremos hacer a menudo (o probablemente nunca), es conveniente saber que existen varias formas de insertar código que se ejecute antes que lo que siempre hemos considerado el entry point de nuestra aplicación, y es lo que veremos en este post.

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Qué es Blazor, eso de lo que todo el mundo habla?
José María Aguilar - Cómo reconocer a los buenos desarrolladores
José María Aguilar
.NET Core / .NET
- Set C# Language Version for All the Projects in a Solution
Bartosz Jarmuż - Getting telemetry data from inside or outside a .NET application
Gérald Barré - How to install and test nuget packages locally
Gary Woodfine - Case Study: Double performance in under 30 minutes
Nik Karpinsky - Techniques and tools to update your C# project - Migrating to nullable reference types
Maarten Balliauw - Using HTTPListener to build a HTTP Server in C#
Nick Charlton - Upgrading a WCF service to .NET 6 with CoreWCF
Mike Rousos - Microsoft Graph's Journey to .NET 6
Joao Paiva - Challenge: Spot the optimization & Challenge: Spot the optimization–solution
Oren Eini - Quickly Map Your NuGet Packages to Sources
Erdembayar Yondon - Generating sortable Guids using NewId
Andrew Lock - One step beyond by using .NET Collections to its fullest
Ioannis Kyriakidis - On awaiting a task with a timeout in C#
Raymond Chen - Forcing HttpClient to use IPv4 or IPv6 addresses
Gérald Barré - Hacking C# - Adjustable arrays
Simon Painter
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Recomendarías a tu hijo que se dedicase al mundo del desarrollo de software?
José María Aguilar - Incluir recursos estáticos en una Biblioteca de Clases Razor (RCL)
José María Aguilar
.NET Core / .NET
- Dockerfile para .Net 6
Fernando Escolar - CoreWCF 1.0 has been Released, WCF for .NET Core and .NET 5+
Sam Spencer - C++ For C# Developers: Part 1 – Introduction
Jackson Dunstan - How to generate Fake data in C#?
Karthik Chintala - Annotating your C# code - Migrating to nullable reference types
Maarten Balliauw - Create .NET Objects without Calling The Constructor
Khalid Abuhakmeh - Sharing coding style and Roslyn analyzers across projects
Gérald Barré - Different Ways to Implement IHttpClientFactory in .NET Core Apps
Mahesh More - Using User Secrets Configuration In .NET
Wade Gausden - C#: Add event handlers dynamically using reflection
Mike Hadlow
Imaginad que tenemos un controlador MVC como el siguiente:
public class TestController : Controller
{
public IActionResult Add(int a, int b)
{
return Content($"Result: {a + b}");
}
}
Claramente, la acción Add()
retornará la suma de los enteros a
y b
que le llegarán como parámetros de la query string:
GET https://localhost:7182/test/add?a=1&b=2 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Result: 3
Pero, como sabemos, podríamos llamar a la acción sin indicar alguno de esos parámetros, o incluso ninguno de ellos:
Petición | Respuesta |
---|---|
GET /test/add?a=1&b=2 | Result: 3 |
GET /test/add?a=0&b=0 | Result: 0 |
GET /test/add?a=1 | Result: 1 |
GET /test/add | Result: 0 |
Esto es así porque el binder será capaz de poblar correctamente los parámetros a
y b
cuando estén presentes en la cadena de la petición y sean correctos, o les asignará su valor por defecto (0
) cuando no hayan sido suministrados.
Pero dado que el cero es un valor de entrada válido, a priori desde nuestro código no tendríamos forma de distinguir cuándo el parámetro ha sido omitido y cuándo se ha establecido expresamente.
¿Cómo podríamos hacerlo?
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- 7 Hábitos de personas altamente innovadoras
José María Aguilar - Streaming en gRPC, parte II: Streaming bidireccional
José María Aguilar
.NET Core / .NET
- ¿Se ha vuelto demasiado complejo C#?
Eduard Tomás - Cómo manejar JSON en .NET con System.Text.Json
José Manuel Alarcón - Ejemplo de un método deshonesto en C# .NET y cómo refactorizarlo
Albert Capdevila - C# 11 Preview Updates - Raw string literals, UTF-8 and more!
Kathleen Dollard - A Time-Scoped Registration Mechanism for Microsoft.Extensions.DependencyInjection
David Kröll - Running JavaScript inside a .NET app with JavaScriptEngineSwitcher
Andrew Lock - Internals of C# nullable reference types - Migrating to nullable reference types
Maarten Balliauw - Using dotnet format Command to Format the C#/.NET Code
Ryan Miranda - C# async await explained
Patrick Smacchia - Building a NuGet Packages Architecture Part 6 - Enhancing your packages
Imar Spaanjaars - C# Tip: How to temporarily change the CurrentCulture
Davide Bellone - Async and Async Void Event Handling in WPF
Rick Strahl - C# Code Rules
Christian Findlay - Running and Debugging Multiplatform .NET Core (.NET5 or .NET6) GUI and Console Applications on Windows Subsystem for Linux (WSL)
Nick Polyak

La semana pasada veíamos algunas alternativas para comprobar de forma eficiente si una cadena de texto contiene un JSON válido y, al hilo de dicho post, el amigo Javier Campos aportó vía Twitter una fórmula adicional mejor que las que vimos aquí.
El código en cuestión es el siguiente:
public bool IsJsonWithReader(string maybeJson)
{
try
{
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(maybeJson));
reader.Read();
reader.Skip();
return true;
}
catch
{
return false;
}
}
La estructura Utf8JsonReader ofrece una API de alto rendimiento para acceder en modo forward-only y read-only al JSON presente en una secuencia de bytes UTF8. Los métodos Read()
y Skip()
se encargan respectivamente de leer el primer token del JSON y saltarse todos sus hijos, con lo que en la práctica se recorrerá el documento completo, lanzándose una excepción en caso de ser inválido.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Streaming en gRPC, parte I: Streaming unidireccional
José María Aguilar - Variables locales implicítamente tipadas en C#
José María Aguilar
.NET Core / .NET
- Announcing .NET 7 Preview 3
Jon Douglas - Nullable reference types in C# - Migrating to nullable reference types
Maarten Balliauw - Getting Disk information in Windows with C#
Bruno Sonnino - Reflected Image in C# with GDI and Unchecked Code
AdventureDriver - .NET Automatic Updates for Server Operating Systems
Jamshed Damkewala - Keeping up with .NET: learning about new features and APIs
Andrew Lock - Adding Alt Text To Twitter Images Using C#
Khalid Abuhakmeh - Warning on lower case type names in C# 11
Jared Parsons - Faster .NET development on Kubernetes with Skaffold
Salvatore Merone - Introducing Central Package Management
Jeff Kluge - Using the Roslyn APIs to Analyse a .NET Solution
Steve Gordon - Deep C# - Interface
Mike James - Discussing alternative memory management strategy for .NET
Mark Pelf - Dissecting AutoMapper Programming Horror
Jimmy Bogard - Ignoring JSON Key Casing and Numbers as Strings when Deserializing with System.Text.Json
Bryan Hogan
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Ojo con la inicialización de propiedades usando expression bodied members
José María Aguilar - 13 Consejos para comentar tu código
José María Aguilar
.NET Core / .NET
- .NET Framework 4.5.2, 4.6, and 4.6.1 will reach End of Support on Apr 26, 2022
Jamshed Damkewala - How to prevent Email HTML injection in C# and .NET
Niels Swimberghe - Implementing OAuth2 Client credentials flow APP to APP security using Azure AD non interactive
Damien Bowden - GDI/User Object Leak Tracking – The Easy Way
Alois Kraus - Creating and Using HTTP Client SDKs in .NET 6
Oleksii Nikiforov - Must-Know Concepts Related to LINQ and IEnumerable
Ioannis Kyriakidis - How segments and regions differ in decommitting memory in the .NET 7 GC
Maoni Stephens - C# Pattern Matching Explained
Patrick Smacchia - C# Tip: Use Debug-Assert to break the debugging flow if a condition fails
Davide Bellone - Value types and exceptions in .NET profiling
Christophe Nasarre - Forcing HttpClient to use IPv4 or IPv6 addresses
Gérald Barré - Challenge: Why is this code broken?
Oren Eini - Speed Up Logging in .NET
David McCarter

Al hilo del post Cómo recibir un JSON como string en una acción ASP.NET Core MVC, el amigo Alberto dejaba una interesante pregunta en los comentarios: ¿y si una vez hemos recibido el string
, queremos validar que sea un JSON válido?
Obviamente, una forma sencilla sería intentar deserializarlo por completo a la clase de destino, siempre que ésta sea conocida. Para ello podríamos utilizar el método Deserialize<T>()
del objeto JsonSerializer
de System.Text.Json
, disponible en todas las versiones modernas de .NET, de la siguiente manera: