Cuando en ASP.NET Core MVC usamos rutado por convención, lo habitual es que accedamos a las acciones mediante rutas definidas en el patrón, como [controller]/[action]
. Así, podemos encontrarnos con rutas como /PendingInvoices/ViewAll
para acceder a la siguiente acción:
public class PendingInvoicesController : Controller
{
public IActionResult ViewAll() => Content("Show all pending invoices");
}
Lo mismo ocurre con páginas Razor. Si usamos las rutas por defecto, al archivo /Pages/ShowAllPendingInvoices.cshtml
podríamos acceder mediante la ruta /ShowAllPendingInvoices
. No es que sean rutas terribles, pero tampoco podemos decir que sean lo mejor del mundo en términos de legibilidad y conveniencia.
El kebab-casing consiste en separar con un guion "-" las distintas palabras que componen los fragmentos de la ruta, por lo que en los casos anteriores tendríamos /pending-invoices/view-all
y show-all-pending-invoices
, algo bastante más legible, elegante, y apropiado desde el punto de vista del SEO.
El nombre kebab-casing viene de que visualmente el resultado es similar a un pincho atravesando trozos de comida. Imaginación que no falte 😉
En este post vamos a ver cómo aprovechar los puntos de extensibilidad del sistema de routing de ASP.NET Core para modificar la forma en que genera rutas y así adaptarlo a nuestras necesidades.
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...
- Creando gráficas estadísticas en Blazor con los componentes visuales de Syncfusion
José María Aguilar - 30 Leyes epónimas relacionadas con el desarrollo de software (I)
José María Aguilar
.NET Core / .NET
- Introducing the New T4 Command-Line Tool for .NET
Mike Corsaro - Seamless Integration Testing With WireMock.NET
Code Maze - C# 12: Collection literals
Steven Giesel - Wolverine 1.0 is Out! & Wolverine’s Middleware Strategy is a Different Animal
Jeremy D. Miller - Differences Between ExpandoObject, DynamicObject and dynamic
Code Maze - How to use RuntimeHelpers.IsReferenceOrContainsReferences to micro-optimize collections
Gérald Barré - C# Source Code Generators
Bruno Sonnino - C# Struct vs Class: Decoding Key Differences and Use Cases
Wade Gausden - Learn how to mock your HttpClient in C# now with 2 simple methods
Henrique Dalcin Dalmas - Microsoft Forms Service’s Journey to .NET 6
Ray Yao - Validating nested DataAnnotation IOptions recursively with MiniValidation
Andrew Lock - Using StringBuilder To Replace Values
Khalid Abuhakmeh - Parsing websites in C# with Html Agility Pack or AngleSharp
Thomas Ardal - Create your own Mediator (like Mediatr)
Steven Giesel - Getting the .NET Desktop Runtime Installed with a Custom Runtime Checker and Installer
Rick Strahl - Improved .NET Debugging Experience with Source Link
Patrick Smacchia - 7 Things about C#: Running Apps
Joe Mayo - Permutations of a String in C#
Matjaz Prtenjak - Five Reasons Why I Love HangFire
Kevin W. Griffin - Value Objects in C#
Code Maze
Desde la aparición de los nullable reference types, o tipos referencia anulables, en C# 8, nos encontramos frecuentemente con el warning de compilación CS8618, que nos recuerda que las propiedades de tipo referencia definidas como no anulables (es decir, que no pueden contener nulos) deben ser inicializadas obligatoriamente porque de lo contrario contendrán el valor null
, algo que iría en contra de su propia definición.
Para verlo con un ejemplo, consideremos una aplicación de consola con el siguiente código:
var friend = new Friend() {Name = "John", Age = 32};
Console.WriteLine($"Hello, {friend.Name}");
public class Friend
{
public string Name { get; set; }
public int Age { get; set; }
}
La aplicación se ejecutará sin problema, aunque al compilarla obtendremos el warning CS8618:
D:\Projects\ConsoleApp78>dotnet build
MSBuild version 17.4.1+9a89d02ff for .NET
Determining projects to restore...
Restored D:\Projects\ConsoleApp78\ConsoleApp78.csproj (in 80 ms).
D:\Projects\ConsoleApp78\Program.cs(8,19): warning CS8618: Non-nullable property 'Name'
must contain a non-null value when exiting constructor. Consider declaring the
property as nullable.
[...]
[D:\Projects\ConsoleApp78\ConsoleApp78.csproj]
1 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.63
D:\Projects\ConsoleApp78\ConsoleApp78>_
También en Visual Studio podremos ver el subrayado marcando la propiedad como incorrecta:
Aunque muchas veces este warning viene bien porque nos ayudará a evitar errores, hay otras ocasiones en las que puede llegar a ser molesta tanta insistencia. Y en estos casos, ¿cómo podemos librarnos de este aviso?
Disclaimer: algunas de las soluciones mostradas no son especialmente recomendables, o incluso no tienen sentido en la práctica, pero seguro que son útiles para ver características de uso poco habitual en C#.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Crear manualmente instancias de clases usando el proveedor de servicios de .NET
José María Aguilar - PremoniSense, la gran novedad de Visual Studio 2010
José María Aguilar
(¿No era este post una premonición en sí mismo? :D)
.NET Core / .NET
- Announcing .NET 8 Preview 5
Jiachen Jiang - 12: Primary constructor on classes and struct
Anthony Giretti - Optional DependencyInjection in .NET
Federico Alterio - Introduction to Firebase in .NET
Phil Broderick - Collatz sequences by function composition
Mark Seemann - C# Tip: Use custom Equality comparers in Nunit tests
Davide Bellone - How does List work under the hood in .NET?
Steven Giesel - How to detect heap allocations
Bart Wullems
Ya he comentado alguna vez que el hecho de trabajar a diario con C# no implica que conozcamos todas sus funcionalidades, detalles, trampas y recovecos. Después de muchos años, yo sigo encontrándome sorpresas bastante a menudo.
Hace poco, andaba haciendo algunas pruebas y llegué a un código como el siguiente:
var a = 1;
var (b, c) = 4;
var (d, e, f) = 9;
Console.WriteLine(a + b + c + d + e + f ); // Muestra por consola "14"
Así al vistazo, diréis que el código no compila tal cual, pero la pregunta es: ¿sería posible que compilara y, además, mostrara la salida que pretendemos sin tocar una sola línea de las que vemos ahí?
Si lo pensáis un poco seguro que podéis responder a las preguntas. Y si no, pulsad aquí para ver la solución 👇👇
Pues en efecto, el código tal y como está no compila, así que debemos pasar a la siguiente parte de la pregunta: qué podemos hacer para que compile y, además, muestre por consola el valor que buscamos, sin tocar ni una coma de esas cuatro líneas de código propuesto como punto de partida.
Si nos fijamos bien, la primera línea es una asignación normal, pero en la segunda y tercera línea estamos asignando valores a variables usando sintaxis propia de tuplas. En el fondo, ambas líneas son iguales, y fallan en compilación porque no podemos asignar un entero a un tupla. ¿O quizás sí?
Si recordáis, hace mucho tiempo hablamos por aquí de la deconstrucción de clases, un interesante mecanismo que, al más puro estilo de cheff sofisticado, permitía deconstruir o descomponer objetos en tuplas, simplemente implementando el método Deconstruct()
.
Pues bien, resulta que este método Deconstruct()
puede implementarse de forma externa al tipo que va a ser deconstruido mediante extension methods. Seguro que ya empezáis a ver por dónde van los tiros... 😉 En efecto, podríamos implementar el método extensor Deconstruct()
sobre el tipo int
e introducir en él la lógica que nos interese.
Una posible implementación sería la siguiente, en la que tenemos sobrecargas de Deconstruct()
para dos y tres parámetros de salida, entre los que repartimos equitativamente el valor del entero a deconstruir:
public static class IntegerExtensions
{
public static void Deconstruct(this int i, out int i1, out int i2)
{
(i1, i2) = (i / 2, i / 2);
}
public static void Deconstruct(this int i, out int i1, out int i2, out int i3)
{
(i1, i2, i3) = (i / 3, i / 3, i / 3);
}
}
Si ejecutamos ahora mentalmente el código propuesto, veremos que se cumplen los requisitos iniciales:
var a = 1; // a=1
var (b, c) = 4; // "4" se deconstruye en (2,2). Por tanto: b=c=2
var (d, e, f) = 9; // "9" se deconstruye en (3,3,3). Por tanto, d=e=f=3
Console.WriteLine(a + b + c + d + e + f ); //
1+2+2+3+3+3 -> Muestra "14":
Bonito y maquiavélico uso de tuplas y deconstrucción, ¿verdad? 😉
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Indicios de que tu interfaz de usuario fue creado por un programador
José María Aguilar - 3 formas de saber si un componente se está ejecutando en Blazor Server o WebAssembly
José María Aguilar
.NET Core / .NET
- Compartir un fichero C# entre varios proyectos (sin referencias)
Iván Montilla - Time abstraction in .NET 8
Steven Giesel - Where are Objects Allocated in C#? Understanding Heap and Stack
Gevorg Chobanyan - Use secrets in unit tests
Mark Heath - Expression Trees in C#
Code Maze - Enhancing .NET Hot Reload with CreateNewOnMetadataUpdate, MetadataUpdateHandler and MetadataUpdateOriginalType Attributes
Nick Randolph - Refactoring Change Preventers in C#
Code Maze - How to add Dependency Injection, Configurations, and Logging in a .NET 7 Console Application
Davide Bellone - Introducing Sep - Possibly the World's Fastest .NET CSV Parser
Niels Rasmussen - Reduce heap allocations by using static anonymous functions
Bart Wullems - Span / Memory / ReadOnlySequence in C#
Steven Giesel - Managed vs Unmanaged Code (Garbage Collection) in C#
Code Maze - .NET 8: Why .NET 8 preview doesn’t show up in Visual Studio 2022 ?
Anthony Giretti
Hace unos días hablábamos de la serialización polimórfica en .NET 6, y vimos qué posibilidades teníamos para conseguirlo sin tener que escribir un custom converter o conversor personalizado. Y aunque realmente .NET 6 permite hacerlo, no es lo más elegante del mundo porque teníamos que operar sobre tipos object
.
Pero por suerte, en .NET 7 la cosa ha mejorado y ya tenemos opciones razonables para conseguirlo basadas en los dos nuevos atributos [JsonDerivedType]
y [JsonPolymorphic]
. Veamos cómo utilizarlos.
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)
Por si te lo perdiste...
- Un vistazo a los patrones relacionales y combinadores, lo nuevo de C# 9 para exprimir el pattern matching
José María Aguilar - El patrón Post-Redirect-Get
José María Aguilar
.NET Core / .NET
- Timers en .Net
Fernando Escolar - nameof get's a bit better in C# 12
Steven Giesel - How to Use SFTP For Secure File Upload in .NET
Code Maze - Getting .NET Library Projects to Output Dependent Assemblies
Rick Strahl - What's the latest .NET roadmap?
Steve Smith - Memory Allocation Optimization With BenchmarkDotNet
Code Maze - How to Convert a String to a Span in C#
Code Maze - Step-by-Step Guide to Adding and Removing Watermarks in PDF using C#
Sameerkhan - New Terminal logger for .NET 8
Steven Giesel - Raiders of the lost root: looking for memory leaks in .NET
Christophe Nasarre - VerificationException in .NET Framework when using structs
Kevin Gosse - .NET 7–Serialize private fields and properties
Bart Wullems - Implicit Operators in C# and How To Create a Multi Type
Nick Cosentino - .NET Micro-Optimization and Refactoring Trick
Patrick Smacchia