Aprende en casa Ir a KODOTI
Aprende en casa KODOTI

KODOTI de .NET Core 2.2 a 3.0 - Todo una odisea

Les contamos nuestra experiencia migrando todo el proyecto a la versión 3 de .NET Core.

Rodríguez Patiño, Eduardo
Rodríguez Patiño, Eduardo
2020-07-03 | 1,580 lecturas

Se dicen que los cambios pueden ser dolorosos y KODOTI no ha sido ajeno a este. En esta publicación vamos a contar nuestra experiencia migrando toda la plataforma a la versión 3 de .NET Core.

.NET Core 2.2

Esta fue la versión que estuvimos operando hasta hace poco y la cual teníamos que migrar a la nueva versión de .NET Core. Cabe resaltar que iniciamos con .NET Core 2.0 y los cambios hasta la versión 2.2 fue un simple update del Nuget Package Manager e instalar las versiones recientes del framework.

¿Era necesario hacer la migración?, si y tal vez. Si porque de esta manera tenemos acceso a las actualizaciones y mejoras de esta y además, todo los cambios a tiempo son más sencillo que en vez de hacerlo en el futuro. Por el otro lado, dijimos un tal vez, porque podíamos haber esperado pero antes que siga creciendo la plataforma decidimos hacer los cambios para que de esta manera los nuevos proyectos se puedan plantear sobre la versión más reciente.

¿CÓMO FUE EL PROCESO DE MIGRACIÓN?

Horrible, el cambio fue doloroso y vamos a detallar todo lo que nos pasó ..

SE CORROMPIERON LAS MIGRACIONES

Nosotros usamos Entity Framework Core para gestionar las consultas a la base de datos pero ya que estabamos trabajando en la migración quisimos agregar algunas mejoras al proyecto y las nuevas migraciones se creaban remal, recontra mal.

La solución fue la siguiente:

  • Eliminar todas las migraciones generadas en el proyecto y el snapshot.
  • Ejecutar una nueva migración para generar una nueva base de datos.
  • Insertar la data mediante un script para resincronizar nuestra base de datos omitiendo la tabla __EFMigrationsHistory, porque la nueva migración es la que predomina.

CAMBIOS EN LOS STARTUPS

ASP.NET Core 3 cambia la inicialización del StartUp el resto es lo mismo que hemos visto en ASP.NET Core 2.2. Lo único trabajoso fue actualizar la versión para los 4 proyectos web que maneja KODOTI.

public void ConfigureServices(
    IServiceCollection services
)
{
    services.AddControllersWithViews();
}

public void Configure(
    IApplicationBuilder app,
)
{
    app.UseRouting();
    app.UseStaticFiles();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

ACTUALIZAR LA VERSIÓN DEL FRAMEWORK EN TODOS LOS PROYECTOS

Esto si dolió, porque KODOTI maneja nada menos que 31 proyectos en una misma solución.

Aunque parezca que es demasiado, lo que hace cantidad es nuestra capa common que son varios proyectos pequeños que en futuro van a pasar a ser paquetes de NuGet y por eso hemos creado varios proyectos pequeños para que se puedan empaquetar facilmente y el proyecto pueda consumir solo lo que necesita.

Adicionalmente, KODOTI en el futuro pasará a hacer un proyecto orientado a microservicios por eso es muy importante poder crear los NuGet Packages.

SE PERDIERON DEPENDENCIAS

Como poniendo un ejemplo, nuestro proyecto de autenticación usa Social Login para ingresar al sistema ya sea usando tu cuenta de Google, Facebook o Microsoft. Por ende, con la nueva versión estos paquetes deben ser descargado independientemente. Asumo que antes estaba todo incorporado en ASP.NET Identity Core.

services.AddAuthentication()
    .AddGoogle("Google", options => {})
    .AddFacebook("Facebook", options => {})
    .AddMicrosoftAccount("Microsoft", options => {});

BYE, BYE NEWTONSOFT ..

.NET Core 3 llega con JsonSerializer, entonces para evitar dependencias de terceros hemos decidido hacer este cambio. Para nuestra suerte habíamos creado un método de extensión para agilizar la serialización y deserialización. Por lo tanto, el cambio no ha sido tan dramático, solo tuvimos que retirar la dependencia de los proyectos.

public static string Serialize(this object data, bool lowerCase = false)
{
    if(!lowerCase)
        return JsonSerializer.Serialize(data);

    return JsonSerializer.Serialize(
        data,
        new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            WriteIndented = true
        }
    );
}

public static T Deserialize<T>(this string data)
{
    if (string.IsNullOrEmpty(data)) 
        return default(T);

    return JsonSerializer.Deserialize<T>(data, new JsonSerializerOptions { 
        PropertyNameCaseInsensitive = true
    });
}

BINDING

  • El mapeo de objetos no perdona nada, por ejemplo si pasamos la información de una petición ajax al servidor y una de las propiedades que en nuestro modelo es un entero y llega como string, simplemente al llegar hará que el modelo pasado sea NULL.
  • El reemplazo de Newtonsoft hizo que los TimeSpan no se puedan deserializar. Más información en este enlace https://github.com/dotnet/corefx/issues/38641.

LINQ SE FUE A LA MIERDA ..

Esto fue lo más doloroso, porque algunas expresiones lambda no podía ser interpretadas e hizo que se caiga casi todo el sistema por lo cual tuvimos que hacer un esfuerzo en QA para cambiar los queries afectados.

Veamos algunas consultas que fallaron:

Antes funcionaba esto ..

await orderQuery.GroupBy(g => g.OrderId).CountAsync()

Ahora requiere un select ..

await orderQuery.GroupBy(g => g.OrderId).Select(x => x.Key).CountAsync()

Otro ejemplo usando DefaultIfEmpty ..

await _context.Orders.Select(x => x.Income).DefaultIfEmpty(0).AverageAsync();

Así lo solucinamos y nos gusta más ..

await _context.Orders.Select(x => (decimal?) x.Income).AverageAsync() ?? 0;

Y así varios queries más se fueron cayendo porque ya no son soportados. Uno de los cambios de Entity Framework 3, esta en que las versiones previas ejecutaban el query y lo que no podían interpretar a SQL lo hacían en memoria, ahora no es así.

https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/

MORALEJA

Esto nos ha llevado a la conclusión que las pruebas unitarias son muy importantes y debemos dedicar un SPRINT a implementar dichas pruebas. El problema es que en un proyecto avanzado es más costoso pero igual se puede ir de a pocos, no necesariamente tienes que implementar a todo el proyecto, se puede ir comenzando con los módulos principales.


Estudia con nosotros

🚀 Mejora tus oportunidades laborales