
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.

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í!

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!

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.

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.

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:

Seguimos descubriendo novedades aparecidas con .NET 6, y ahora le toca el turno a la nueva clase PeriodicTimer
, una fórmula para la ejecución de tareas periódicas en contextos asíncronos que evita el uso de los clásicos callbacks a los que nos tenía acostumbrados el framework.
Como recordaréis, .NET dispone de un buen número de formas de implementar temporizadores, o timers, para ejecutar tareas en intervalos periódicos. El más conocido probablemente sea el clásico System.Threading.Timer
, en el que especificábamos el callback o método que debía ejecutarse en cada intervalo de tiempo mediante un delegado (en el siguiente ejemplo, mediante una lambda):
var timer = new System.Threading.Timer(o =>
{
Console.WriteLine("Hey! " + DateTime.Now.ToLongTimeString());
}, null, 0, 1000);
Console.ReadKey();
Hey! 12:25:51
Hey! 12:25:52
Hey! 12:25:53
Hey! 12:25:54
Hey! 12:25:55
_
Pero también existía System.Timers.Timer
, que nos permitía lograr algo parecido, aunque esta el callback lo implementábamos mediante una suscripción al evento Elapsed
del objeto:
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (sender, eventArgs) =>
{
Console.WriteLine("Hey! " + DateTime.Now.ToLongTimeString());
};
timer.Start();
Console.ReadKey();
Existían algunas fórmulas más específicas para plataformas concretas, como las clases System.Windows.Forms.Timer
, System.Web.UI.Timer
u otras. Sin embargo, todas coincidían en varias cosas:
- Utilizaban callbacks de alguna u otra forma, lo que implica un cierto riesgo de leaks de memoria y problemas con los tiempos de vida de objetos cuando la cosa se complica.
- Los callbacks no permitían código asíncrono, lo que podía llevarnos a luchar contra los engorrosos escenarios de ejecución de código asíncrono en entornos síncronos (async-over-sync).
- Podían darse casos de superposición u overlapping entre las distintas ejecuciones, cuando éstas tardaban en completarse más que el intervalo de definido en el timer.

Versiones de .NET anteriores a la 6 no disponían de una fórmula específica para determinar si un tipo o interfaz está registrado como servicio en el sistema de inyección de dependencias.
La única forma de hacerlo era intentar resolverlo, usando métodos como GetService()
o GetService<T>()
, y comprobar si el resultado era null
:
var myService = serviceProvider.GetService<IMyService>();
if(myService is null)
{
// El servicio no está registrado, hacemos algo
}
¿Cuál es el inconveniente de esto? Si el servicio no está registrado, ninguno: la llamada retornará un nulo y listo.
El problema viene cuando sí está registrado, pues estaremos forzando la resolución de un servicio que, en realidad, no necesitamos para nada, pues sólo nos interesaba saber si existía o no. Porque recordemos que la resolución de un servicio podría tener un coste importante en términos de rendimiento, memoria, o incluso efectos colaterales en el estado de la aplicación, especialmente si nuestro servicio depende de otros, que a su vez dependen de otros, etc.

Estamos muy acostumbrados a comenzar nuestros métodos realizando comprobaciones para evitar que pasen a nuestro código valores nulos que pudieran romper la aplicación.
Desde el principio de los tiempos, estas guardas han presentado el siguiente aspecto:
public class MyService
{
public void MyMethod(object first, object second)
{
if(first == null)
{
throw new ArgumentNullException("first");
}
if(second == null)
{
throw new ArgumentNullException("second");
}
// ...
}
}
¿Todo bien, verdad? El código es aparentemente correcto y fácil de comprender, pero... ¡demasiado extenso! Hemos consumido casi diez líneas de código sólo realizando comprobaciones de "fontanería", y ni siquiera hemos empezado a plantear la funcionalidad real del método.
Afortunadamente, con el tiempo C# ha ido evolucionando y mejorando sucesivamente este escenario tan frecuente.

A raíz de los posts sobre generadores de código (como éste y éste), un amigo del blog me escribió para ver si de alguna forma era posible examinar el código fuente generado para poder depurarlo con mayor facilidad.
Y en efecto, es posible. Pero en vez de responderle directamente, he pensado que sería mejor compartirlo por aquí, de forma que pueda resultar de utilidad para alguien más :)

Como decíamos hace unos días, los generadores de código C# nos brindan la posibilidad de crear al vuelo código C# e incluirlo en nuestros proyectos en tiempo de compilación.
Por no alargar demasiado el post, vimos un sencillísimo ejemplo de implementación, pero ahora vamos a crear algo más complejo que podría ayudarnos a solucionar un problema que tendría difícil solución de no contar con esta característica del compilador.
1. Definición de objetivos
El reto al que vamos a enfrentarnos ya lo expusimos en el post anterior como un caso de uso simple de los generadores de código, así que vamos a reproducir la descripción del escenario.
Imaginemos que en nuestra aplicación tenemos clases que representan operadores matemáticos como SumOperator
, MultiplyOperator
, DivideOperator
, SubtractOperator
. Imaginad también que nos interesa tener un tipo enum Operators
donde aparezca un miembro por cada operador disponible, algo como:
public enum Operators
{
Sum,
Multiply,
Divide,
Subtract
}
El problema que tiene enfocar esto de forma manual es que resultaría sencillo implementar una nueva clase operador y olvidar crear su correspondiente entrada en la enumeración Operators
. Aquí es donde vienen al rescate los generadores de código :)
Lo que implementaremos hoy es un generador de código C# que creará la enumeración por nosotros en tiempo de compilación, manteniéndola sincronizada en todo momento con las clases que tengamos definidas en el proyecto. Para ello, crearemos un generador llamado OperatorsEnumGenerator
que:
- En la fase de análisis de código recopilará las clases del proyecto a compilar cuyo nombre finalice por
Operator
. - En la fase de generación de código creará el enum con los miembros registrados anteriormente.
¡Vamos allá!

Seguramente muchos coincidiremos en que una de las novedades más interesantes de la última versión del compilador de C# es lo que oficialmente han denominado C# Source Generators, o generadores de código fuente de C#.
Muy resumidamente, esta característica añade un nuevo paso en la compilación en el cual los desarrolladores podemos introducir componentes propios (generadores) que inspeccionen el código de la aplicación que está siendo compilada y generen nuevos archivos, que a su vez pueden ser compilados e incluidos en los ensamblados resultantes. Su objetivo, tal y como se declara en su documento de diseño, es posibilitar la metaprogramación en tiempo de compilación.
Veámoslo con un ejemplo donde, además de explicarlo mejor, se puede mostrar su utilidad. Imaginad que en nuestra aplicación tenemos clases que representan operadores matemáticos como SumOperator
, MultiplyOperator
, DivideOperator
, SubtractOperator
, y todos ellos heredan de una clase base Operator
. Imaginad también que nos interesa tener un tipo enumerado enum Operators
donde aparezca un miembro por cada operador disponible, algo como:
public enum Operators
{
Sum,
Multiply,
Divide,
Subtract
}
Muy probablemente os habéis encontrado alguna vez con un escenario similar y habéis sufrido la dificultad de mantener sincronizada la enumeración con las clases que heredan de Operator
: cada vez que aparezca un operador nuevo e implementemos la clase operador que lo representa, tendremos que acordarnos de ir a Operators
y añadir el miembro.
Pues bien, aunque simple, esto sería un caso de uso bastante claro para los generadores de código fuente de C#. Gracias a ellos, podríamos crear un componente generador que examine nuestro código en busca de herederos de Operator
y genere al vuelo, siempre en tiempo de compilación, un archivo de código con la enumeración Operators
.
A todos los efectos, es como si esa enumeración la hubiéramos escrito a mano, porque podremos usarla con normalidad, aparecerá en intellisense, etc., pero la diferencia es que será generada cada vez que compilemos el proyecto, asegurando así que siempre será correcta y completa.
Publicado por José M. Aguilar a las 8:05 a. m.
Etiquetas: .net, c#, generadores, metaprogramación, novedades

Ya hace tiempo que se lanzó .NET 5, pero seguro que algunos os habéis dado cuenta de que cuando desde Visual Studio creamos determinados tipos de proyecto, como bibliotecas de clases o proyectos de consola, por defecto éstos utilizan como target .NET Core 3.1 en lugar de .NET 5.
No se trata de un error; desde Microsoft justifican esta decisión porque .NET 5 no es una versión LTS, y prefieren que por defecto los proyectos sean creados usando una versión con mayor tiempo de soporte, como .NET Core 3.1.
Esto tiene fácil solución, porque tras crearlo simplemente deberíamos acceder a las propiedades del proyecto o editar el archivo .csproj
y modificar ajustar el target framework a nuestro antojo, pero, ¿cómo podríamos evitar tener que hacer esto cada vez?

try/catch
porque el mero hecho de usar este tipo de bloque de código afectaba al rendimiento.
La verdad es que de forma intuitiva se puede adivinar que esto no debería ser así. Si no se producen excepciones en un código que tengamos envuelto en un
try/catch
se debería ejecutar virtualmente a la misma velocidad que si no usáramos este tipo de bloque. Cosa distinta es si producen excepciones: ahí el rendimiento sí se verá seriamente penalizado, pero no es culpa del try/catch
sino del propio sistema de gestión de excepciones de .NET.Pero claro, lo dicho anteriormente es sólo cierto si somos capaces de demostrarlo, así que usaremos nuestro viejo conocido
BenchmarkDotnet
para desmontar este mito.
Podríamos decir que NDepend es un clásico en el mundo de las herramientas que nos ayudan a mejorar la calidad de nuestro software. Creado por Patrick Smacchia en 2004, pasó a ser comercial en 2007, y desde entonces ha ido mejorando con el objetivo de permitirnos analizar nuestros proyectos desde una perspectiva que difícilmente podríamos conseguir con otras herramientas.
Ya le echamos un vistazo por aquí hace muchos años, y tenía interés por ver cómo había evolucionado el producto y cómo se había adaptado a los cambios en plataformas y tecnologías que se han producido desde entonces, para lo que Patrick me ha brindado amablemente una licencia del producto.
Pero no contento con eso, y sabiendo que tenemos afición a regalar productos para desarrolladores de vez en cuando, también ha cedido una licencia de desarrollador, valorada en 399 Euros para sortear entre los lectores del blog :)
Nota: es importante aclarar que lo que vais a leer a continuación no ha sido filtrado ni condicionado en ningún momento por el equipo de NDepend.
Venga, lo confieso: yo también he generado desde mis aplicaciones contenidos HTML y los he enviado al cliente en un archivo con extensión XLS, incluso modificando el content-type, para que pareciera un documento de hoja de cálculo. Durante años. Y también le he dicho a mis clientes que el molesto mensaje que aparece al abrirlo desde Excel, el que indica que el contenido del archivo no coincide con la extensión del mismo, es algo normal.
Pero esto se acabó desde que descubrí ClosedXML, un magnífico componente para .NET basado en el estándar OpenXML que permite la generación de archivos Excel “de verdad”, con formato, estilos, fórmulas, rangos, filtros, y casi todo lo que se nos pueda ocurrir.
Publicado por José M. Aguilar a las 9:15 a. m.
Etiquetas: .net, asp.net, closedxml, componentes, desarrollo
System.ComponentModel.DataAnnotations
:CreditCardAttribute
, que puede ser utilizado para validar números de tarjeta de crédito.EmailAddressAttribute
, que validará direcciones de correo electrónico.FileExtensionsAttribute
, para validar extensiones en nombres de archivo.PhoneAttribute
, que indica cuándo una propiedad debe contener un número de teléfono válido.UrlAttribute
, que comprobará si el contenido de una propiedad es una URL válida.CompareAttribute
, que antes estaba disponible en System.Web.Mvc y ha “ascendido” a anotación de datos general, permite validar la igualdad de dos propiedades.
También se ha incluido soporte para el atributo
MembershipPasswordAttribute
, recientemente incluido en System.Web.Security
, que comprueba si una contraseña cumple los requisitos establecidos para las mismas en el membership provider.Publicado en Variable not found.
En este post vamos a ver cómo realizar validaciones basadas en anotaciones de forma manual, lo cual puede tener su utilidad en gran número de escenarios.
.Net
- Mono in 2011
Miguel de Icaza
Asp.net
- How to combine a Worker Role with a MVC4 Web Role into a single instance
Liam Cavanagh - ASP.NET MVC + Selenium + IISExpress
Stephen Walther - Model Binding with Dropdown List in ASP.NET 4.5
Abhijit Jana - Knockout 2.0.0 released
Steve Sanderson - Free eBook: OWASP Top 10 for .NET developers
Troy Hunt - Solving Duplicate Content with Distinct URLs Issue in ASP.NET MVC
Imran Baloch's - New Request validation features in ASP.Net 4.5
K. G. Sreeju Nair - Using CORS to access ASP.NET services across domains
Dave Ward - HttpRequestBase vs HttpRequest
Eduard Tomás - Debugging Application_Start and Module Initialization with IIS and Visual Studio
Rick Strahl - Rotate an ASP.NET Image Control using HTML 5 Canvas
Suprotim Agarwal - Retoques a MVC y Razor para proyectos grandes–Una recomendación
Lucas Ontivero - High-Performance ASP.NET Caching
Peter Vogel - Microsoft blogging platform gains 33% performance boost after adopting RequestReduce
Matt Wrocks
Azure / Cloud
- Azure Monitor for Windows Phone 7 is out!
Ibon Landa - Libro gratuito sobre Windows Azure (Parte IV): Diseño y herramientas
CampusMVP - SQL Azure Q4 2011 Service Release
Ibon Landa
Data access
- MongoDB Best Practices
Inés Sombra - Inserciones masivas en SQL Server CE vs SQL Server vs MongoDb (y II)
Josué Yeray - Raven DB VI, La hora de las consultas…
Unai Zorrilla
Html/Css/Javascript
- JavaScript as a First Language
John Resig - The output element in HTML5
Richard Clark - Excssive, herramienta online para comprimir archivos CSS
Zach Will (Vía desarrolloweb.com) - Meet the CSS4 selectors
Catalin Rosu - JavaScript for C# developers: calling functions and the ‘this’ variable
Julian M. Bucknall - Top 10 “Must Follow” JavaScript Best Practices
Salman Siddiqui - Online Javascript Compression Tool
BrightBit - The rise and rise of JavaScript
Dan North - Using the JavaScript Prototype Property to Structure and Extend Code
Dan Wahlin's - Multiple Attribute Values
Chris Coyier - The Seven Deadly Sins Of JavaScript Implementation
Christian Heilmann (vía @alegrebandolero)
Visual Studio/Complementos
- C# + ReSharper = Awesome: Tip #5 – Replace Constructor with Factory Method
Alvin Ashcraft - ReSharper 6.1, dotCover 1.2 and dotTrace 4.5.2 Performance Released
Hadi Hariri - C# + ReSharper = Awesome: Tip #4 – Convert Abstract Class to Interface
Alvin Ashcraft - C# + ReSharper = Awesome: Tip #3 – Convert Into LINQ Expression
Alvin Ashcraft
Publicado en Variable not found
Aprovecho además para pediros opinión sobre un nuevo formato de presentación de los enlaces, usando categorizaciones. De esta forma podréis acceder directamente a aquellos cuya temática os interese, en lugar de tener que leerlos todos para ver si hay alguno que al que valga la pena echar el vistazo. ¿Qué os parece? ¿Mejor así?
.Net
- Formatting Enumeration Constants
BlackWasp - Install-Package Roslyn
Kirill Osenkov - Return Multiple Values from Methods with Tuples
Peter Vogel - C# Fundamentals: Returning Zero or One Item As IEnumerable<T>
James Michael Hare - .Net Reflector y ILSpy, ¿podrían inferir mejor el código a partir del IL?
Lucas Ontivero
Asp.net
- [Video] ASP.NET vNext - Filtrado de datos - Value Provider Attributes
Luis Ruiz - How to use SignalR and Knockout in an ASP.NET MVC 3 web application to handle real-time UX updates
Justin Schwartzenberger - MVC and HTML5 Web Workers
Dean hume - Introducing SignalR.EventStream
Ben Dornis - Update jqGrid Html helper for ASP.NET MVC
Robin van der Knaap - Implement secure ASP.NET MVC applications
Jovan Popovic - Which is the Fastest Webserver? Apache, IIS, Nginx, LightHttpd or G-Wan?
WebPerformance (vía @campusmvp) - OWASP Top 10 for .NET developers part 10: Unvalidated Redirects and Forwards
Troy Hunt - Espresso Tip: IHttpHandler and IsReusable
David Neal - Introducción a less
Sergio León - Automatically trim html controls in a asp.net mvc project
Richard Wilde - On deploying ASP.NET MVC site as a desktop application
Andrei Marukovich - Todo sobre AutoEventWireUp en páginas ASP.NET Web Forms
José Manuel Alarcón - Using QUnit with Razor Layouts
Phil Haack - ASP.NET MVC ViewModel usage and pick your best pattern
Kazi Manzur Rashid - MVC Route/URL Generation Unit Tester
Codeplex - Easy URL rewriting in ASP.NET 4.0 web forms
Jalpesh Vadgama - Looking into Web performance in ASP.Net applications
Nikolaos Kantzelis - [Vídeo] ASP.NET vNext - Selección de datos (SelectMethod)
Luis Ruiz - Using SignalR to broadcast a slide deck
Marteen Balliauw
Azure / Cloud
- Utilizar Windows Azure AppFabric Caching como session provider
Gisela Torres - VMware Cloud Foundry cloud platform now supports .Net
Mary-Joe Foley - Now Available: SQL Azure Q4 2011 Service Release
Azure Team (vía @ibonilm) - The SQL Azure Team Unveils a New Server Management UI
Roger Jennings - Differences Between the Storage Emulator and Windows Azure Storage Services
MSDN
Conceptos
- Algorithms Course Materials
Jeff Erickson - Hash Functions
Bret Mulvey
Data access
- RavenDB (IV) La identidad de los documentos
Unai Zorrilla - Data Access Performance Comparison in .NET
Luis Rocha
Html/Css/Javascript
- 10 Best jQuery Form Plugins
jQuery4u - Your jQuery: Now With 67% Less Suck
Scott Kosman - JavaScript – Add Commas To Number
Shai Raiten - Frontend SPOF
Steve Souders - The 30 Most Effective jQuery Plugins
Awcore - Animations in HTML5
Florian Rappl - HTML 5 Input Types - How useful is this really going to be?
Rick Strahl - The CSS profilers are coming!
Lennart Schoors - A Key Code Checker for DOM Keyboard Events
Rick Strahl
Visual Studio/Complementos
- [HowTo] Agregar Ficheros a un Proyecto Existente
Javier Torrecilla - C# + ReSharper = Awesome: Tip #2 – Create Field
Alvin Ashcraft - NuGet 1.6 Release Notes
Nuget Team - [How To] Agregar un elemento de menú a Visual Studio.
Javier Torrecilla - Go To Definition for JavaScript Functions in Visual Studio 2011
Abhijit Jana - Introducing CSSCop - FxCop for stylesheets
Mads Kristensen
Otros
- La fruta más alta siempre sabe mejor
José Manuel Alarcón
Publicado en Variable not found