
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á!
Publicado por José M. Aguilar a las 8:05 a. m.
Etiquetas: .net, c#, generadores, metaprogramación
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Componentes genéricos (templated components) en Blazor
José María Aguilar - Redirecciones HTTP 303, 307 y 308: ¿las conoces?
José María Aguilar
.NET Core / .NET
- Announcing .NET 6 Preview 2
Richard Lander - ICYMI C# 8 New Features: Upgrade Interfaces Without Breaking Existing Code
Jason Roberts - First look at InferSharp: A C# version of Facebook’s Infer
Neel Bhatt - Language detection and words-in-sentence classification in C#
Dan - Getting started with Dapr for .NET Developers
Laurent Kempé - How to map IPs to country for free with .NET and IP2Location
Thomas Ardal - Generating Date of Birth values for .NET5.0 Record types using AutoFixture
Adam Storr - AutoWrapper 4.5.0 Released!
Vincent Maverick Durano - Unexpected finding about “await using var”
Jiří Činčura - Download the right ChromeDriver version & keep it up to date on Windows/Linux/macOS using C# .NET
Niels Swimberghe - Blinking LEDs with Raspberry Pi
Richard Lander - My Favorite C# Features Part 2: LINQ
Jeffrey T. Fritz - Five C# Features You Might Not Know
Andrea Chiarelli - ConfigureAwaitChecker with support for “await using” and “await foreach”
Jiří Činčura - 6 free tools for .NET developers
Thomas Ardal - C# 9.0: Covariant Return Types – Specify More Specific Return Types in Overridden Methods and Properties
Thomas Claudius Huber - Investigating a Linux CVE with .NET Images
Richard Lander

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
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Extendiendo claims de usuarios en ASP.NET Core
José María Aguilar - Cómo invocar métodos de instancia C# desde Javascript con Blazor (interop 3/3)
José María Aguilar
.NET Core / .NET
- Ofuscación: cómo proteger el código de tus aplicaciones .NET
José Manuel Alarcón - How to Scan NuGet Packages for Security Vulnerabilities
Drew Gillies - TasKCompletionSource for I/O-Bound Operations
Mehdi Hadeli - Generate iCal calendar with .NET using iCAL.NET
Kristoffer Strube - State of the NuGet Ecosystem
Jiachen Jiang - Strongly-typed Ids using C# Source Generators
Gérald Barré - ICYMI C# 8 New Features: Prevent Bugs with Static Local Functions
Jason Roberts - Refactoring with reflection
Michał Białecki - The 8 most missing features in C#
Konrad Kokosa - C# Coding Standards – Updated
Jesse Liberty
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo solucionar el error "Unable to connect to web server 'IIS Express'" en Visual Studio
José María Aguilar - Renderizar una vista Razor a un string en ASP.NET Core MVC
José María Aguilar
.NET Core / .NET
- Free eBook: How to use Dapr for .NET Developers
Scott Hanselman - ICYMI C# 8 New Features: Simplify Array Access and Range Code
Jason Roberts - Experimenting with .NET 5 and 6 using Docker containers
Elton Stoneman - Multi-targeting a Roslyn analyzer
Gérald Barré - Generating HTTP API clients using Visual Studio Connected Services
Jon Galloway - How can I prevent a Windows Runtime WebView from loading any content beyond the initial request?
Raymond Chen - .NET 6 – Single file apps improved for Windows and Mac!
Bruno Capuano - How to create faster and smarter apps with .NET 5
Michael Crump - C#'s Functional Journey
Mads Torgersen - Using Streams with HttpClient to Improve Performance and Memory Usage
Marinko Spasojevic - Internals of the POH
Maoni Stephens - How to Debug Live .NET Application
Hasan Hasanov - C# 9.0: Pattern Matching in Switch Expressions
Thomas Claudius Huber

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?
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo invocar métodos estáticos C# desde Javascript con Blazor (interop 2/3)
José M. Aguilar - ¡Mi pantalla se ha puesto gris!
José María Aguilar
.NET Core / .NET
- Announcing .NET 6 Preview 1
Richard Lander - Cómo obtener el código fuente de cualquier programa o DLL escrita para .NET (C#)
José Manuel Alarcón - DotNet Boxed includes prescriptive templates for .NET Core
Scott Hanselman - ICYMI C# 8 New Features: Nested Switch Expressions
Jason Roberts - Correctly converting a character to lower/upper case
Gérald Barré - Packaging a Roslyn Analyzer with NuGet package references
Gérald Barré - .NET 5 Deterministic Builds & Source Linking
Mitchel Sellers - Pure functions and unused return values
Cezary Piątek - Cake Frosting: More Maintainable C# DevOps
Lee P Richardson - Introducing Spreadsheet Rich Cell Data Types for .NET Objects
Mackenzie Albitz - C# 9.0: Improved Pattern Matching
Thomas Claudius Huber - My Favorite C# Features - Part 1: Strong-types, Implicit-types, Anonymous-types, and Target-types
Jeffrey T. Fritz - Porting versus interop for .NET
Mark Heath

Es frecuente que alumnos de mi curso de Blazor en CampusMVP me pregunten sobre la existencia de bibliotecas de componentes que les ayuden a desarrollar aplicaciones profesionales más rápidamente, por lo que no podía pasar por alto la noticia que publicaban hace unos días los amigos de Radzen en su cuenta de Twitter:
En efecto, ¡los componentes para Blazor de Radzen han pasado a ser open source y distribuidos bajo licencia MIT!
Para los que no los conozcan, Radzen es uno de los referentes en el mundo de las herramientas y componentes visuales para el desarrollo rápido de aplicaciones web, pero lo que nos ocupa ahora son el conjunto de más de 60 componentes visuales para Blazor Server y WebAssembly que ahora podremos utilizar de forma totalmente gratuita (bueno, aunque existen opciones para pagar por servicios de soporte profesional).
Publicado por José M. Aguilar a las 8:05 a. m.
Etiquetas: blazor, blazorserver, blazorwasm, componentes
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cómo invocar métodos estáticos C# desde Javascript con Blazor (interop 2/3)
José María Aguilar - ¿Es mi biblioteca portable a .NET Core?
José María Aguilar
.NET Core / .NET
- An Introduction to Channels in C# & What's the Difference between Channel<T> and ConcurrentQueue<T> in C#?
Jeremy Clark - C#/WinRT Authoring Preview and Updates
Angela Zhang - Polymorphic deserialization with System.Text.Json
Josef Ottosson - ICYMI C# 8 New Features: Simplify If Statements with Property Pattern Matching
Jason Roberts - Tiny top-level programs with C# 9 and SmallSharp and Visual Studio
Scott Hanselman - Better refactoring for Unity projects using .NET analyzers
John Miller - Staying safe with .NET containers
Richard Lander - Building A Custom Event Hubs Event Processor with .NET
Matt Ellis - Creating a Windows Service with C#/.NET5
Alexandre Zollinger Chohfi - How to Unit Test Existing C# Apps? Easy—With a Mocking Tool
Viktoria Grozdancheva
Hoy voy a hablar de un cambio introducido en el framework hace ya algunos años, que, al menos en mi caso, pasó totalmente desapercibido en su momento y durante bastante tiempo después. Y he pensado que sería buena idea publicar sobre ello porque, como este mundo es así de grande, seguro que hay todavía algún despistado al que podría estar afectando a día de hoy y ni siquiera se ha dado cuenta :)
Como recordaréis, los atributos de validación [EmailAddress]
y [Url]
, presentes en el espacio de nombres System.ComponentModel.DataAnnotations
, los hemos utilizado durante años para asegurar que determinados valores de entrada eran direcciones de correo electrónico y URLs válidas, respectivamente:
public class Blog
{
[Required, EmailAddress]
public string ContactEmail { get; set; }
[Required, Url]
public string Url { get; set; }
}
Desde el principio de los tiempos, aún en ASP.NET "clásico", ambos atributos de validación utilizaban internamente complejas expresiones regulares para comprobar los valores, y la verdad es que funcionaban relativamente bien. Nuestras aplicaciones podían confiar en que valores que hubieran superado dichas validaciones serían, como mínimo, sintácticamente correctos y buenos candidatos a ser direcciones de correo o URLs válidas.
Pues bien, desde la llegada de NET 4.7.2, y luego en .NET Core, [EmailAddress]
y [Url]
ya no funcionan así. En palabras casi textuales del equipo de desarrollo, el objeto de estos dos atributos es simplemente prevenir algunos errores básicos al teclear, y no contemplar todas las posibilidades definidas en las respectivas RFC que describen la sintaxis de dichos valores.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Se pueden desarrollar aplicaciones ASP.NET Core con Visual Basic .NET?
José María Aguilar - Cómo invocar funciones Javascript desde Blazor (interop 1/3)
José María Aguilar - Más velocidad de carga y mejor SEO en tus apps Blazor WebAssembly mediante prerrenderización
José María Aguilar
.NET Core / .NET
- What I Learned About C# From Job Interviews
Michael Shpilt - ICYMI C# 8 New Features: Write Less Code with Using Declarations
Jason Roberts - Create Anonymous Data Object With AutoFixture From Type
Adam Storr - Tracing IO in .NET Core
Jonathan Channon - A C# Implementation of McCarthy’s Ambiguity Operator
Jorge L Orejel - Substring in C#
Mahesh Chand - Developer's Cheat Sheet for C# 9.0
Franco Tiveron - My mental model of Span, Memory and ReadOnlySequence in .NET
Szymon Kulec - Command Line Parser on .NET5
Alexandre Zollinger Chohfi - Common Files In A .NET Solution
Khalid Abuhakmeh

El parser de Blazor de versiones anteriores a la 5.0 era bastante permisivo con los espacios no significativos que los desarrolladores dejamos a la hora de escribir nuestro código de marcado. Es decir, todos los espacios incluidos en el código fuente, fueran importantes o no para el resultado final, formaban parte del proceso de renderización y, por tanto, trasladados tal cual al navegador.
Entendemos por espacio no significativo aquél carácter espacio, tabulador, saltos de línea o similares que el navegador no va a representar visualmente al componer la página. Por ejemplo, un marcado como "<h2>1 2</h2>
" suele representarse en el browser exactamente igual que si hubiéramos enviado "<h2>1 2</h2>
" (salvo que hayamos usado reglas CSS específicas en dirección contraria), porque todos los espacios intermedios son ignorados.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Autenticación JWT en APIs con ASP.NET Core
José María Aguilar - Cómo mostrar y ocultar elementos en Blazor
José María Aguilar
.NET Core / .NET
- ICYMI C# 8 New Features: Switch Expressions
Jason Roberts - PostSharp's Great Reset: Announcing Project "Caravela", a Roslyn-based aspect framework
Gael Fraiteur - .NET 5: How to enable .NET 5 runtime on console apps instead of .NET Core 3.1 ?
Anthony Giretti - Simplifying paths handling in .NET code with the FullPath type
Gérald Barré - Choosing a ServiceLifetime
Jimmy Bogard - Using C# Source Generators to create an external DSL
Luca Bolognese - Chromium WebView2 Control and .NET to JavaScript Interop
Rick Strahl

El desarrollo de EF6.TagWith lo comencé hace algo más de un año, cuando escribía para el blog lo interesante que me parecía el extensor TagWith()
de Entity Framework Core y me preguntaba por qué no existía algo similar para Entity Framework 6.x.
Como recordaréis, la idea era traer a EF "clásico" la posibilidad de añadir a consultas realizadas desde C# un comentario o etiqueta que después podría ser fácilmente visible en trazas, como las proporcionadas por SQL Server Profiler o herramientas de análisis de rendimiento.
No pensé que existieran muchos desarrolladores a los que pudiera interesar, pero con el tiempo esto me ha servido para confirmar que cualquier aportación a la comunidad, por pequeña que sea, puede ayudar a un buen número de personas.
A día de hoy, y por increíble que parezca, este pequeño y humilde paquetito ha sido instalado más de 6.000 veces, con una media de 10 descargas al día, y ha recibido issues y pull requests de desarrolladores que han decidido contribuir a su mejora a través del sitio del proyecto en GitHub. Impresionante.
Pues bien, por fin he podido dedicar un rato a actualizarlo y he publicado su versión 1.2.1. Esta revisión soluciona algunos errores menores y problemas de compatibilidad con proyectos .NET Framework 4.5, además de incluir un par de novedades fruto del feedback recibido de sus usuarios, que describimos a continuación.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Probar scripts en producción sin desplegar nada, y otros usos interesantes de Fiddler
José María Aguilar - Cómo personalizar el mensaje "Loading" de las aplicaciones Blazor WebAssembly
José María Aguilar
.NET Core / .NET
- Introducción a los registros (record) y los objetos inmutables de C# 9
Rubén Rubio - AutoFixture and .NET 5.0 Record Types
Adam Storr - Be Carefull With ZipArchive
Hasan Hasanov - Deep Dive into Open Telemetry for .NET
Muhammad Rehan Saeed - The Many Flavors of .NET
Sean Killeen - Best 20 C# & .NET Blogs
Seb Nilsson - How to use configuration with C# 9 top-level programs
Dave Brock - Flatten Strings with Regex.Replace
Khalid Abuhakmeh - .NET GC Internals mini-series
Konrad Kokosa - Find Prime Numbers With C# 9
Khalid Abuhakmeh

Leyendo las novedades de C# 9, hay una que pasa casi completamente desapercibida pero que me ha llamado la atención: la posibilidad de convertir prácticamente cualquier tipo en enumerable.
La magia consiste en que, a partir de esta versión, se podrá recorrer con un foreach
objetos que, o bien implementen IEnumerable
o directamente el conocido GetEnumerator()
, como lo hacen los arrays o strings, o bien existe un método extensor con el mismo nombre declarado sobre el tipo.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Cancelación de peticiones en ASP.NET Core y MVC
José María Aguilar - Componentes con cuerpo en Blazor
José María Aguilar
.NET Core / .NET
- Todo sobre los archivos .PDB: qué son y por qué se generan siempre al compilar una aplicación .NET
José Manuel Alarcón - .NET Worker Service: Working Hard So You Don’t Have To
Richard Reedy - Capitalize First Letter Of Words With C#
Khalid Abuhakmeh - Blank Zero Values in .NET Number Format Strings
Rick Strahl - .NET 5 Networking Improvements
Máňa Píchová - Migrating RealProxy Usage to DispatchProxy
Mike Rousos - Diagnostics improvements in .NET 5
Sourabh Shirhatti - Go (golang) Multiple Return Values
Jeremy Clark - Azure Active Directory's gateway is on .NET Core 3.1!
Avanindra Paruchuri - Happy 10th Birthday, NuGet!
Christopher Gill - Here's a One-Stop Shop for .NET 5 Improvements
David Ramel - How to configure your custom roslyn analyzer using an .editorconfig file
Carlos Pons - Taking the new Chromium WebView2 Control for a Spin in .NET
Rick Strahl - My preferred .NET console stack
Mattias Karlsson - Quick tip: listing global dev tools and extensions
Mark Heath

Pues parece que por fin hemos conseguido quitarnos de encima el nefasto 2020, y afrontamos un nuevo año con la esperanza de que sea, al menos, algo mejor que el anterior. Os deseo a todos que así sea; sobre todo que la salud os acompañe a vosotros y los que os rodean, y que esto permita que seáis felices tanto en lo personal como en lo profesional.
Y dicho esto, llega la hora de acudir a las tradiciones: el repaso de los posts más visitados durante el año que acabamos de dejar atrás, donde, como podemos ver, Blazor ha entrado con bastante fuerza :)
Top ten 2020 en Variable not found
Comenzando por el décimo puesto, encontramos el post cómo mostrar el número de usuarios conectados a una aplicación Blazor Server, en tiempo real, un interesante ejercicio que nos ayudaba a comprender cómo funcionan los circuitos de Blazor Server y cómo sacar partido a los componentes internos que nos permiten introducirnos en su ciclo de vida.
La novena posición la ocupa nuestro amigo Mario, protagonista del post incluir recursos estáticos en una Biblioteca de Clases Razor (RCL), donde lo usábamos para crear un componente Razor reutilizable que mostraba al simpático personaje correteando por la pantalla.
Continuamos con Blazor gracias a la serie sobre los mecanismos de interoperación con Javascript de este framework. En concreto, el post Cómo invocar métodos de instancia C# desde Javascript con Blazor es el que más vistas ha tenido, probablemente por su atractiva propuesta ;)
La posibilidad de publicar aplicaciones .NET Core en modo auto-contenido y en un único archivo no ha pasado desapercibida para los lectores del blog. Por ello, el post publicación self-contained y single-file en .NET Core, aparece ocupando la séptima posición del ranking anual.
Muy cerca del anterior en número de visitas, encontramos la respuesta a una pregunta relativamente frecuente a la hora de desarrollar aplicaciones .NET: ¿Usar try/catch
es malo para el rendimiento?. Una respuesta con demostración incluida, gracias al imprescindible BenchmarkDotnet.
La basura que va dejando en vuestro equipo las distintas versiones y revisiones de .NET Core conforme evoluciona el producto también parece haberos preocupado o, al menos, os ha llamado la atención. La aparición de una herramienta para limpiarlas fácilmente fue el detonante para escribir el post desinstala fácilmente versiones antiguas de .NET Core con "dotnet-core-uninstall".
AddMvc(), AddControllers(), AddControllersWithViews(), AddRazorPages()... ¿qué es todo eso?, ya en quinta posición de la lista, intentaba aclarar qué eran esos nuevos métodos que aparecían en el intellisense a la hora de registrar los servicios de MVC o Razor Pages a partir de la llegada de ASP.NET 3.0.
En tercera y cuarta posición respectivamente encontramos dos post muy relacionados. En el primero de ellos, describiendo APIs ASP.NET Core con Swagger, veíamos los conceptos básicos de OpenAPI y el uso de Swashbuckle para describir nuestras APIs creadas con ASP.NET Core. En el segundo, cómo documentar y generar código cliente de nuestras APIs utilizando Swagger/OpenAPI, revisábamos cómo sacar partido de dicha descripción, generando automáticamente la documentación de la API e incluso código cliente para acceder a ella.
A cierta distancia de los anteriores, ya en segundo puesto, tenemos la solución a un error que frecuentemente encontramos al desarrollar aplicaciones ASP.NET Core con Visual Studio e IIS Express. El post cómo solucionar el error "Unable to connect to web server 'IIS Express'" en Visual Studio describe paso a paso qué hacer cuando nos topamos con este incómodo inconveniente al ejecutar las aplicaciones.

Y por último, el indiscutible vencedor del año: ¿qué es Blazor, eso de lo que todo el mundo habla?. Este post intentaba despejar dudas en un momento en el que la palabra "Blazor" empezaba a sonar más de la cuenta y a despertar el interés de muchos desarrolladores, entre los que, por supuesto, me incluyo.
Para acabar, me gustaría también hacer una mención especial a ¡Toma las riendas! ¡Conviértete en Desarrollador 10x Certificado!, el post publicado el 28 de diciembre que, si bien no ha conseguido entrar en el ranking, se ha quedado bien cerca a pesar de haber tenido pocos días para acumular visitas. Me he divertido mucho escribiéndolo, leyendo las respuestas y comentarios que me han llegado por diversas vías, y comprobando que algunos incluso habéis traducido los textos en japonés para ver qué ponía :D
¡Vamos a por 2021!
Publicado en Variable not found.
Si nos dedicásemos a enroscar tapones de botellas probablemente podríamos medir nuestra productividad en términos del número de botellas cerradas por hora. Si cargásemos sacos en un muelle, quizás en kilos transportados por jornada... Hay muchos trabajos en los que es relativamente sencillo establecer una medida para conocer el grado de productividad con el que desempeñamos nuestras obligaciones.
Lamentablemente, esto no es así en la industria del software, que durante años ha ido dando tumbos, probando y descartando sucesivamente diversas métricas para intentar medir la productividad de los desarrolladores, como el cómputo de líneas de código por día, puntos función, puntos de historia o el grado de completitud de sprints, pero siempre sin éxito. En el desarrollo de software todo es demasiado etéreo: dado que no creamos ni manipulamos productos tangibles, no hay nada que poder pesar o contar, salvo las horas pegados a nuestra silla.
Sin embargo, todos tenemos una idea intuitiva de lo que es un desarrollador productivo, e incluso se ha hablado bastante de los desarrolladores 10x: programadores que son al menos diez veces más productivos que los que se encuentran en el lado opuesto del espectro. Esta idea parte de estudios científicos contrastados, y algunos destacados gurús incluso suben la apuesta llegando a estimar que determinados desarrolladores pueden producir entre diez y veintiocho veces más que sus compañeros. Casi nada.
Sin duda, un desarrollador 10x es todo un lujazo para las empresas, que lucharán para atraerlos, normalmente a base de ofrecer unas condiciones espectaculares, porque es mucho más rentable ofrecer a un desarrollador 10x el triple de sueldo que tener a diez desarrolladores para conseguir el mismo resultado.
Nuestro objetivo profesional, por tanto, debería ser dar el salto y convertirnos en uno de ellos.
Publicado por José M. Aguilar a las 12:01 a. m.
Etiquetas: 10x, bootcamp, inocentadas, productividad
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Dónde está Server.MapPath() en ASP.NET Core?
José María Aguilar - Cómo mostrar el número de usuarios conectados a una aplicación Blazor Server, en tiempo real
José María Aguilar
.NET Core / .NET
- Mejorar la legibilidad de números en tu código C# con separadores de dígitos
José Manuel Alarcón - What's next for System.Text.Json?
Layomi Akinrinade - Building a Code Analyzer for .NET
Tim Heuer - Batch.Parallel
Marc Clifton - C# in Simple Terms - Indexers
Matthew Jones - Implementing a Text Templating Language and Engine for .NET
Alexandre Mutel - Thinking With Properties: Examining Where
Cameron Presley - Implementing the page object pattern in UI tests
James Croft - Never forget a #if when multi-targeting .NET libraries or applications
Gérald Barré - Creating a game art asset pipeline in .NET
Sam Eddy - From .NET Standard to .NET 5
Immo Landwerth - How to add User-Agent header to HttpClient in .NET
Kristoffer Strube - .NET 5.0 on Google Cloud
Mete Atamel - Playing with C#9 Top-level Programs, Records and Elasticsearch.NET - Steve Gordon
Steve Gordon - The proper usages of Exceptions in C#
Patrick Smacchia - Overloading Vs. Overriding in C#
Sam Walpole - .NET 5 Source Generators - MediatR - CQRS
Tore Nestenius - C# vs. F#
Urs Enzler - C# 9 Covariant Return Types
Khalid Abuhakmeh

En Blazor, es habitual implementar la interfaz de nuestros componentes de forma declarativa, mezclando etiquetas que:
- Pueden ser HTML, y cuyo resultado irá textualmente al navegador
- Pueden ser instancias de otros componentes, por lo que al navegador irá el resultado de la renderización de éstos.
Por ejemplo, el siguiente código envía al navegador la etiqueta <h1>
y luego el resultado de renderizar el componente Blazor <MyComponent>
, en cuyo interior podrán existir a su vez otras etiquetas o componentes:
@page "/home"
<h1>Welcome!<h1>
<MyComponent />
Fijaos que, aunque es la fórmula que emplearemos en la mayoría de ocasiones, es una estructura totalmente rígida: podemos tener la total certeza de que el componente que será instanciado en la página anterior es MyComponent
, pero, ¿qué ocurre si queremos poder decidir en tiempo de ejecución qué componente instanciaremos en la página?
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Dónde están Application_Start y Application_End en ASP.NET Core?
José María Aguilar - Capturar todos los parámetros enviados a un componente Blazor
José María Aguilar
.NET Core / .NET
- Programación mínima, C# vs Python
Sergio León - Null Checking en C#
Jorge Serrano - What's new in Windows Forms runtime in .NET 5.0
Igor Velikorossov - .NET December 2020 Updates – 5.0.1
Rahul Bhandari - Rethrowing your exceptions wrong in .NET could erase your stacktrace
Niels Swimberghe - C# 9 records as strongly-typed ids
Thomas Levesque - Common Use Cases For .NET Reflection
Khalid Abuhakmeh - Cryptography Improvements in .NET 5
Tomasz Pęczek - Bring lights in Unity into the real-world using Philips Hue
Paul Marsh - New in .NET 5 - Top-level Statements
Bradley Wells - Automate a Markdown links page with Pinboard and C#
Dave Brock - Add Configuration to a .Net Core Console Application
Paul Michaels - C# in Simple Terms - Dates and Times
Matthew Jones - Using .NET and PowerPoint to generate cover images
Gérald Barré - No recompile, no redeploy, managing features flags in .NET Core, locally and with Azure
Chris Noring - Producing Packages with Source Link
Claire Novotny - Use local function attributes with C# 9
Dave Brock - The proper usages of the keyword 'static' in C#
Patrick Smacchia - Making C# More Welcoming
Matt Eland - Simplifying Multithreaded Scenarios With PostSharp Threading
Wade Gausden - C# 9 Records and Init Only Settings Without .NET 5
Brant Burnett - Dynamic Class Creation in C# - Preserving Type Safety in C# with Roslyn
José Manuel Redondo López
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Retorno de referencias y referencias locales en C#
José María Aguilar - Mostrar HTML "crudo" en componentes Blazor
José María Aguilar
.NET Core / .NET
- Introducing WaveEngine 3.1 based on .NET 5
Javier Cantón Ferrero - C# In Simple Terms - String Manipulation and Cultures
Matthew Jones - Noisy logs? Improve your signal-to-noise ratio with per-request logging and sampling
Gael Fraiteur - .NET 5 Breaking Changes to the Base Class Library
Jonathan Allen - Investigating a performance issue with a regex
Gérald Barré - Should You Always Create a Nuget Package? Asking for a Friend...
Shawn Wildermuth - When C# 9.0 patterns go wrong: mechanism over intent
Ian Griffiths - .NET Core 2.1, 3.1, and .NET 5.0 updates are coming to Microsoft Update
Jamshed Damkewala - .NET 5 Breaking Changes: Historic Technologies
Jonathan Allen - C# 9 - Top-Level Statements & C# 8 - Switch Expressions
Claudio Bernasconi - Understand The .NET 5 Runtime Environment
Khalid Abuhakmeh

Una pequeña pero interesante novedad introducida en Blazor 5, es la posibilidad de escribir nuestras propias factorías de componentes, o, como les llaman en el framework, Component Activators.
El Component Activator es un objeto singleton que implementa la interfaz IComponentActivator
, cuyo único requisito es el cumplimiento del siguiente contrato:
public interface IComponentActivator
{
IComponent CreateInstance(Type componentType);
}
Como se puede intuir, Blazor invocará al activator registrado en el sistema justo en el momento en que va a instanciar un componente: se le suministra el tipo como parámetro, y retornará ya un objeto IComponent
, la interfaz más básica que cumplen todos los componentes Blazor.
Por defecto, se utiliza como activador la clase interna DefaultComponentActivator
:
internal class DefaultComponentActivator : IComponentActivator
{
public static IComponentActivator Instance { get; } = new DefaultComponentActivator();
public IComponent CreateInstance(Type componentType)
{
var instance = Activator.CreateInstance(componentType);
if (!(instance is IComponent component))
{
throw new ArgumentException($"The type {componentType.FullName}"
+ $"does not implement {nameof(IComponent)}.", nameof(componentType));
}
return component;
}
}
Obviamente, si quisiéramos intervenir en el proceso de construcción de componentes, sólo tendremos que implementar nuestra clase personalizada y registrarla como singleton en el inyector de dependencias, asociada a la interfaz IComponentActivator
.
Para crear nuestra propia implementación, fijaos que la clase DefaultComponentActivator
es interna y no podemos heredar de ella, pero tiene un código tan simple que podemos usarlo para crear nuestras propias versiones.
Veamos un par de ejemplos.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Literales binarios y separador de dígitos numéricos en C#7
José María Aguilar - Blazor Server + Entity Framework Core = InvalidOperationException (si no tienes cuidado)
José María Aguilar
.NET Core / .NET
- Announcing Microsoft Q&A for .NET
James Montemagno - .NET Conf 2020 Demos & Sessions for .NET 5 + Virtual Events!
Jayme Singleton - Optimizing CSharp Null-Coalescing Operator
Stéphane Gay - How to make a WinForms app with .NET 5 entirely from the command line and publish as one self-contained file
Scott Hanselman - C# 9 - Improving performance using the SkipLocalsInit attribute
Gérald Barré - Conventional Options
Derek Greer - .Net 5 is PERFECT for DevOps
Davide Benvegnù - C# In Simple Terms - Expressions, Lambdas, and Delegates
Matthew Jones - Spectre.Console lets you make beautiful console apps with .NET Core
Scott Hanselman - C# 9 Records as DDD Value Objects
Vladimir Khorikov - Astonishing Performance of .NET 5: More Data
Alex Yakunin - Tests are hard, LightBDD can help
Jon Hilton - Monitoring .NET scheduled tasks
Thomas Ardal - Upgrading several of my Applications and Libraries to .NET 5.0
Rick Strahl - Using C#9 record and init property in your .NET Framework 4.x, .NET Standard and .NET Core projects
Patrick Smacchia - The difference between overloading and overriding in C#
Sam Walpole - The updated GetGCMemoryInfo API in .NET 5.0 and how it can help you
Maoni Stephens

Hace unos días fue lanzada la nueva versión de ASP.NET Core basada en el flamante .NET 5, que incluye un buen número de novedades para los desarrolladores Blazor, algunas de ellas bastante jugosas.
En este post vamos a ver por encima las que creo que son más destacables en esta nueva entrega:
- .NET 5 y mejoras de rendimiento
- CSS Isolation
- JavaScript Isolation
- Virtualización
- InputRadio & InputRadioGroup
- Soporte para IAsyncDisposable
- Soporte para upload de archivos
- Control del foco
- Parámetros de ruta catch-all
- Protected browser storage
- Prerenderización WebAssembly
- Lazy loading de áreas de aplicación en Web Assembly
- Otros cambios y mejoras
Publicado por José M. Aguilar a las 10:13 a. m.
Etiquetas: blazor, blazorserver, blazorwasm, novedades
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Diez años de enlaces interesantes: lo que siempre habéis querido saber sobre esta serie
José María Aguilar - Deconstrucción de tuplas y clases en C# 7
José María Aguilar
.NET Core / .NET
- dotnet-script 1.0.0 released – with support for .NET 5.0 and C# 9
Filip Woj - .NET Conf 2020 and .NET 5 links
João Antunes - .NET 5 and .NET Core SDK version pinning
Feodor Fitsner - Migrate .NET Core 3.1 to .NET Core 5.0
John Smith - C# in Simple Terms: Tuples and Anonymous Types & Attributes and Reflection
Matthew Jones - Creating a Network Speed Monitor in C#
Hannes Du Preez - Process.WaitForExitAsync is not the async equivalent of Process.WaitForExit in .NET 5
Gérald Barré - C# Index and Range Operators Explained
Patrick Smacchia - Coding Faster with the dotNetTips Utility: November 2020 Update
David McCarter - Your dotnet outdated is outdated! Update and help keep your .NET projects up to date
Scott Hanselman - Simplify your ASP.NET Core API models with C# 9 records
Dave Brock - Lazy Sunday with .NET 5
Shawn Wildermuth - C# Expression Trees: Property Getters
Zanid Haytam - Recursive Fibonacci and Memoization in C#
David Hayden - Vertical Slice Example Updated to .NET 5
Jimmy Bogard - What is .NET 5? (Overview, Features, Performance, Download)
Damir Arh - 6 less popular facts about C# 9 records
Konrad Kokosa - Understanding Disposables In .NET Dependency Injection Part 1 & Part 2 & Part 3
Steve Collins

Un alumno del curso de Blazor que tutorizo en CampusMVP me exponía problema bastante curioso con el que se había topado al implementar una página que, simplificando el escenario, venía a ser como la siguiente:
@page "/sum/{a:decimal}/{b:decimal}"
<h1>The sum is: @(A+B)</h1>
@code {
[Parameter] public decimal A { get; set; }
[Parameter] public decimal B { get; set; }
}
Esta página funcionaba correctamente con números enteros: podíamos acceder a "/sum/1/2" y veíamos el resultado correcto ("The sum is: 3"). Esto era así tanto accediendo a través del sistema de routing de Blazor (es decir, usando un link hacia esa ruta desde dentro de la aplicación) como accediendo directamente a la página introduciendo la ruta en la barra de direcciones del navegador.
Sin embargo, el problema surgía al usar valores decimales. Si desde dentro de la aplicación pulsábamos un enlace hacia "/sum/1.1/2.2", el resultado obtenido era correcto ("The sum is: 3.3"). Sin embargo, si en ese momento refrescábamos esa página, o bien accedíamos directamente a ella introduciendo la URL en el navegador, el servidor retornaba un error 404.
Extraño, ¿no?
Ahí van los enlaces recopilados durante la semana pasada, con jugosas novedades procedentes de la .NET Conf 2020. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Expresiones throw en C# 7
José María Aguilar - AddMvc(), AddControllers(), AddControllersWithViews(), AddRazorPages()... ¿qué es todo eso?
José María Aguilar
.NET Core / .NET
- Announcing .NET 5.0
Richard Lander - C# 9.0 on the record
Mads Torgersen - Announcing C#/WinRT Version 1.0 with the .NET 5 GA Release
Angela Zhang - Announcing F#5
Phillip Carter - Getting Started With NuGet 5.8
Jon Douglas - C# 9: Record Types Introduction & Deep-Dive
Claudio Bernasconi - .NET 5 - The breaking changes you need to know about
Miguel Bernard - Five Questions You May Have About ASP.NET Core For .NET 5
David Grace - Should I Migrate to .NET 5?
Rockford Lhotka - Astonishing Performance of .NET 5
Alex Yakunin - C# in Simple Terms: LINQ basics & Generics
Matthew Jones - C# ways of handling when being throttled by an API
Dominique St-Amand - Generating Code in C#
Rocket Mortgage Technology - Back to C# basics: Difference between "=>" and "{ get; } =" for properties
Jiří Činčura - Best 5 Tools for .NET Monitoring
Iryne Somera - Migrating to the new C# Azure KeyVault SDK Libraries
Dominique St-Amand
Por si te lo perdiste...
- Tuplas en C# 7
José María Aguilar - Cómo implementar view-models de componentes Blazor en clases code-behind
José María Aguilar
.NET Core / .NET
- Procesar SIGTSTP en netcore (Linux)
Eduard Tomás - Introducing C# 9: Extension GetEnumerator support for foreach loops
Anthony Giretti - C# in Simple Terms: Exceptions and Exception Handling & Arrays and Collections
Matthew Jones - Async code smells and how to track them down with analyzers
Cezary Piątek - .NET Core with NGINX on Linux
Irina Scurtu - Looking At System.IO.Path
Khalid Abuhakmeh - C#9 - init-only properties are not read-only at runtime
Gérald Barré - Additional HTTP, Sockets, DNS and TLS Telemetry in .NET 5 - Steve Gordon
Steve Gordon - New Environment.ProcessId in .NET 5
Jiří Činčura - Module Initializers In C# 9
Khalid Abuhakmeh
Durante las entregas anteriores hemos estado comentando los códigos de estado HTTP coincidentes con la entrega de enlaces interesantes de la semana, por aquello de tener culturilla general. En esta ocasión le llegó el turno al HTTP 419, que simplemente no existe, por lo que omitiremos esta sección hasta volvamos a coincidir de nuevo ;)
Y dicho esto, 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 - Ordenar por un campo enum con WebGrid
José María Aguilar
.NET Core / .NET
- The Future of Desktop: All You Need to Know about .NET 5!
Bianka Banova - Template-based code generation with Razor and Roslyn
Matteo Prosperi - Enumerating files using Globbing and System.IO.Enumeration
Gérald Barré - C# in Simple Terms: Interfaces and Abstract Classes & Namespaces
Matthew Jones - Mind Your Strings with .NET 5.0
Jimmy Bogard - FormattableStringFactory and Formats
Khalid Abuhakmeh - C# 9 The unknown goodies
Miguel Bernard - Consuming JSON Objects Stream (NDJSON) With HttpClient
Tomasz Pęczek - Generate QR Codes With C#
Khalid Abuhakmeh - Intercepting methods with PostSharp Community
Petr H. - Using C# 9 records as strongly-typed ids
Thomas Levesque

Hace unos días, un alumno de mi curso de Blazor en CampusMVP me preguntaba sobre la posibilidad de detectar cuándo un componente se estaba procesando en "modo prerenderización", con el fin de ejecutar cierta lógica únicamente en ese caso.
Me habría gustado responderle algo como "usa la propiedad IsPrerendering
del componente y ya lo tienes". Pero no, las cosas no son tan sencillas; Blazor no proporciona ninguna propiedad del estilo, y no existen fórmulas directas para conseguirlas, más allá de un par de hacks bastante poco elegantes:
- Intentar acceder al contexto HTTP, sólo disponible cuando estamos ejecutando código en el interior de una petición (es decir, cuando el componente se está prerenderizando).
- Ejecutar una función Javascript mediante interop, y capturar la excepción que se produce al hacerlo mientras se está prerenderizando el resultado, pues durante este proceso no es posible utilizar los mecanismos de interoperación.
En este post vamos a ver una alternativa más apropiada que las anteriores, sacando partido al inyector de dependencias y al hecho de que la prerenderización se ejecuta en el propio proceso de la petición que carga la página inicialmente. Y como veréis, la idea es muy sencilla.
Je, estaba deseando llegar a esta entrega de enlaces para poder contaros algo acerca del código de estado HTTP 418 😊
HTTP 418, cuya reason phrase es "I'm a teapot" (soy una tetera), es un código de estado definido por la IETF para dar soporte al HTCPCP (Hyper Text Coffe Pot Control Protocol), un protocolo especificado oficialmente en la RFC 2324 en el año 1998, con el objetivo de definir las normas de comunicación para posibilitar el control, la monitorización y el diagnóstico de cafeteras a través de Internet.
El protocolo, basado en HTTP, establece nuevos verbos (como BREW, para iniciar la elaboración de café), media types, encabezados personalizados e incluso un nuevo esquema de URIs llamado coffee URI scheme que puede utilizarse para identificar servidores y tipologías de café usando una sintaxis estándar.
Y también define nuevos códigos de retorno. Concretamente, el error 418 es usado por el servidor (el dispositivo, en este caso) para indicar al cliente que no puede procesar la petición al tratarse de una tetera y no una cafetera. Un error de cliente 4xx en toda regla ;)
Obviamente esto no era real, se trató de una trabajada broma del April's Fools Day (algo similar a nuestro Día de los Inocentes), pero que ha perdurado como una anécdota curiosa y simpática en el frío mundo de la definición de estándares.
Y ahora, van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- ¿Usar try/catch es malo para el rendimiento? Spoiler: no, siempre que nada falle
José María Aguilar - Inline out variables en C# 7
José María Aguilar
.NET Core / .NET
- Lecciones aprendidas tras migrar más de 25 proyectos a .NET Core
CampusMVP - Async code smells and how to track them down with analyzers
Cezary Piątek - Introducing C# 9: Attributes on local functions
Anthony Giretti - Abstract Classes vs. Interfaces in C#
Jeremy Clark - Choose a .NET Game Engine
Abdullah Hamed - Extract Available Settings Using C#
Zanid Haytam - C# in Simple Terms - Structs and Enums & Inheritance and Polymorphism
Matthew Jones - Dynamically invoking a generic method with Reflection in .NET C#
Brian Lagunas - Introducing C# 9: Static anonymous functions
Anthony Giretti - A Highly Biased Review of C# Changes from Version 1.0 to 9.0
Matthew MacDonald - C# designer Torgersen: Why the programming language is still so popular and where it's going next
Owen Hughes - C# 8.0 nullable references: defeating the point with empty strings
Ian Griffiths - C# 9 Record Factories
Steve Collins - DICOM Image Viewer
Amarnath S
Todos los usuarios que están utilizando una aplicación Blazor Server mantienen una conexión abierta con el servidor para enviar eventos y recibir las modificaciones de la interfaz de usuario. Y si habéis trabajado algo con Blazor, sabréis que cuando dicha conexión se corta aparece en el navegador un mensaje como el mostrado en la siguiente captura de pantalla:
Como se puede ver en la captura anterior, cuando se detecta la desconexión, se añade automáticamente a la página un <div>
con el identificador components-reconnect-modal
que bloquea la página (observad su posición fija a pantalla completa), mostrando al usuario un mensaje informándole de que se está intentando reconectar.
Si, transcurridos algo más de 30 segundos, la reconexión no ha sido posible, el contenido del <div>
cambiará para informar al usuario de que la conexión no pudo ser restablecida, y ofreciendo un botón para reintentarlo y un enlace para recargar la página completa:
Podemos comprobar muy fácilmente estos comportamientos si lanzamos la aplicación sin depuración (Ctrl+F5) desde Visual Studio y detenemos IIS Express desde su icono en la barra de herramientas de Windows.
Como comportamiento por defecto la verdad es que no está nada mal, pues nos proporciona una solución out of the box que será suficiente la mayoría de los casos. Sin embargo, la estética es obviamente mejorable... ¿y si quisiéramos modificar visualmente estos mensajes o incluso su comportamiento? Pues es lo que veremos en este post 🙂
expect
de la petición.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes y, por supuesto, que vuestras expectativas queden satisfechas :-)
Por si te lo perdiste...
- Tip: desinstalar rápidamente paquetes NuGet en proyectos .NET Core
José María Aguilar - Cambiar el idioma de mensajes del SDK de .NET Core
José María Aguilar
.NET Core / .NET
- Cómo garantizar el soporte a largo plazo de tu aplicación .NET
CampusMVP - Mediator Pattern en C#
Jorge Serrano - ¿Cómo puedo probar .NET 5 y C# 9?
Jorge Serrano - Announcing .NET 5.0 RC 2
Richard Lander - Introducing .NET Live TV - Daily Developer Live Streams
James Montemagno - How to Debug C# 9 Source Code Generators
Nick Randolph - Web Scraping with C#
Pierre de Wulf - Export Bitly Links using C#
Jason Gaylord - C# 9: Partial Methods get more flexibility
Miguel Bernard - Dynamic Queries with Expressions Trees in C#
Michael Shpilt - Async code smells and how to track them down with analyzers
Cezary Piątek - Some helpful extensions when dealing with types in .NET |
Marco Siccardi - C# 8.0 nullable references: prepare today by not misusing 'as'
Ian Griffiths - 4 Awesome Tools for .NET Debugging in Production
Michael Shpilt - C# in Simple Terms - Methods, Parameters, and Arguments & Classes and Members
Matthew Jones - Scaling Hangfire: Process More Jobs Concurrently
Derek Comartin - Ace Switch Expressions in C# 8
Khalid Abuhakmeh - .NET Internals: System.Threading.Channels - UnboundedChannel<T> Part 3 - Steve Gordon
Steve Gordon - Classic Path.DirectorySeparatorChar gotchas when moving from .NET Core on Windows to Linux
Scott Hanselman - How to Upgrade .NET CLI Templates
Kevin W. Griffin