330 lines
10 KiB
Markdown
330 lines
10 KiB
Markdown
---
|
|
title: "Migración ASP 3.0 a .NET Core - Sistema de Rastreo de Cargas"
|
|
slug: "asp-to-dotnet-migration"
|
|
summary: "Tech Lead en la migración gradual de sistema crítico ASP 3.0 a .NET Core, con sincronización de datos entre versiones y reducción de costos de $20k/año en APIs de mapeo."
|
|
client: "Empresa de Logística y Rastreo"
|
|
industry: "Logística & Seguridad"
|
|
timeline: "12 meses (migración completa)"
|
|
role: "Tech Lead & Solution Architect"
|
|
image: ""
|
|
tags:
|
|
- ASP Classic
|
|
- .NET Core
|
|
- SQL Server
|
|
- Migration
|
|
- Tech Lead
|
|
- OSRM
|
|
- APIs
|
|
- Arquitectura
|
|
featured: true
|
|
order: 2
|
|
date: 2015-06-01
|
|
seo_title: "Migración ASP 3.0 a .NET Core - Case Carneiro Tech"
|
|
seo_description: "Caso de migración gradual de aplicación ASP 3.0 a .NET Core con sincronización de datos y reducción de $20k/año en costos de APIs."
|
|
seo_keywords: "ASP migration, .NET Core, legacy modernization, SQL Server, OSRM, tech lead, routing API"
|
|
---
|
|
|
|
## Descripción General
|
|
|
|
Sistema crítico de monitoreo de cargas de alto valor (TVs LED de $600 cada una, cargamentos de hasta 1000 unidades) utilizando rastreo GPS vía satélite. La aplicación cubría todo el ciclo: desde registro y evaluación de conductores (verificación de antecedentes policiales) hasta monitoreo en tiempo real y entrega final.
|
|
|
|
**Desafío principal:** Migrar aplicación legacy ASP 3.0 a .NET Core sin downtime, manteniendo operación crítica 24/7.
|
|
|
|
---
|
|
|
|
## Desafío
|
|
|
|
### Sistema Legacy Crítico
|
|
|
|
La empresa operaba un sistema mission-critical en **ASP 3.0** (Classic ASP) que no podía detenerse:
|
|
|
|
**Tecnología legacy:**
|
|
- ASP 3.0 (tecnología de 1998)
|
|
- SQL Server 2005
|
|
- Cluster failover on-premises (perfectamente capaz de soportar la carga)
|
|
- Integración con rastreadores GPS vía satélite
|
|
- Google Maps API (costo: **$20,000/año** solo para cálculo de rutas)
|
|
|
|
**Restricciones:**
|
|
- Sistema operando 24/7 con cargas de alto valor
|
|
- Imposibilidad de downtime durante migración
|
|
- Múltiples módulos interdependientes
|
|
- Equipo necesitaba continuar desarrollando features durante la migración
|
|
|
|
---
|
|
|
|
## Arquitectura de Solución
|
|
|
|
### Fase 1: Preparación de Infraestructura (Meses 1-3)
|
|
|
|
#### Upgrade de Base de Datos
|
|
```
|
|
SQL Server 2005 → SQL Server 2014
|
|
- Backup completo y validación
|
|
- Migración de stored procedures
|
|
- Optimización de índices
|
|
- Pruebas de performance
|
|
```
|
|
|
|
#### Estrategia de Sincronización Dual-Write
|
|
|
|
Implementé un **sistema de sincronización bidireccional** que permitía:
|
|
|
|
1. **Módulos nuevos (.NET Core)** escribían en la base de datos nueva
|
|
2. **Trigger automático** sincronizaba datos hacia la base de datos legacy
|
|
3. **Módulos antiguos (ASP 3.0)** continuaban funcionando normalmente
|
|
4. **Zero downtime** durante toda la migración
|
|
|
|
```csharp
|
|
// Ejemplo de sincronización implementada
|
|
public class DualWriteService
|
|
{
|
|
public async Task SaveDriver(Driver driver)
|
|
{
|
|
// Escribe en base de datos nueva (.NET Core)
|
|
await _newDbContext.Drivers.AddAsync(driver);
|
|
await _newDbContext.SaveChangesAsync();
|
|
|
|
// Trigger SQL sincroniza automáticamente hacia base de datos legacy
|
|
// Módulos ASP 3.0 continúan funcionando
|
|
}
|
|
}
|
|
```
|
|
|
|
**¿Por qué este enfoque?**
|
|
- Permitió migración **módulo por módulo**
|
|
- Equipo podía continuar desarrollando
|
|
- Rollback sencillo si fuera necesario
|
|
- Reducción de riesgo operacional
|
|
|
|
---
|
|
|
|
### Fase 2: Migración Gradual de Módulos (Meses 4-12)
|
|
|
|
Migré los módulos en orden de complejidad creciente:
|
|
|
|
**Orden de migración:**
|
|
1. ✅ Registros básicos (conductores, vehículos)
|
|
2. ✅ Evaluación de riesgo (integración con base policial)
|
|
3. ✅ Gestión de cargas y rutas
|
|
4. ✅ Monitoreo GPS en tiempo real
|
|
5. ✅ Alertas y notificaciones
|
|
6. ✅ Reportes y analytics
|
|
|
|
**Stack de la aplicación migrada:**
|
|
- `.NET Core 1.0` (2015-2016 era el inicio de .NET Core)
|
|
- `Entity Framework Core`
|
|
- `SignalR` para monitoreo real-time
|
|
- `SQL Server 2014`
|
|
- APIs RESTful
|
|
|
|
---
|
|
|
|
### Fase 3: Reducción de Costos con OSRM (Ahorro de $20k/año)
|
|
|
|
#### Problema: Costo Prohibitivo de Google Maps
|
|
|
|
La empresa gastaba **$20,000/año** solo en Google Maps Directions API para cálculo de rutas de camiones.
|
|
|
|
#### Solución: OSRM (Open Source Routing Machine)
|
|
|
|
Implementé una solución basada en **OSRM** (motor de ruteo open-source):
|
|
|
|
**Arquitectura de la solución:**
|
|
|
|
```
|
|
┌─────────────────┐
|
|
│ Frontend │
|
|
│ (Leaflet.js) │
|
|
└────────┬────────┘
|
|
│
|
|
▼
|
|
┌─────────────────┐ ┌──────────────┐
|
|
│ API Wrapper │─────▶│ OSRM Server │
|
|
│ (.NET Core) │ │ (self-hosted)│
|
|
└────────┬────────┘ └──────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────┐
|
|
│ Google Maps │
|
|
│ (display only) │
|
|
└─────────────────┘
|
|
```
|
|
|
|
**Implementación:**
|
|
|
|
1. **Servidor OSRM configurado** en servidor propio
|
|
2. **API wrapper amigable** en .NET Core que:
|
|
- Recibía origen/destino
|
|
- Consultaba OSRM (gratuito)
|
|
- Devolvía todos los puntos de la ruta
|
|
- Formateaba para el frontend
|
|
3. **Frontend** dibujaba la ruta en Google Maps (solo visualización, sin API de rutas)
|
|
|
|
```csharp
|
|
[HttpGet("route")]
|
|
public async Task<IActionResult> GetRoute(double originLat, double originLng,
|
|
double destLat, double destLng)
|
|
{
|
|
// Consulta OSRM (gratuito)
|
|
var osrmResponse = await _osrmClient.GetRouteAsync(
|
|
originLat, originLng, destLat, destLng);
|
|
|
|
// Retorna puntos formateados para el frontend
|
|
return Ok(new {
|
|
points = osrmResponse.Routes[0].Geometry.Coordinates,
|
|
distance = osrmResponse.Routes[0].Distance,
|
|
duration = osrmResponse.Routes[0].Duration
|
|
});
|
|
}
|
|
```
|
|
|
|
**Frontend con Leaflet:**
|
|
|
|
```javascript
|
|
// Dibuja ruta en el mapa (Google Maps solo para tiles)
|
|
L.polyline(routePoints, {color: 'red'}).addTo(map);
|
|
```
|
|
|
|
#### Intento con OpenStreetMap
|
|
|
|
Intenté sustituir también Google Maps (tiles) por **OpenStreetMap**, que funcionó técnicamente, pero:
|
|
|
|
❌ **A los usuarios no les gustó** la apariencia
|
|
❌ Preferían la interfaz familiar de Google Maps
|
|
|
|
✅ **Decisión:** Mantener Google Maps solo para visualización (sin costo de API de rutas)
|
|
|
|
**Resultado:** Ahorro de **~$20,000/año** manteniendo calidad de las rutas.
|
|
|
|
---
|
|
|
|
## Resultados e Impacto
|
|
|
|
### Migración Completa en 12 Meses
|
|
|
|
✅ **100% de los módulos** migrados de ASP 3.0 a .NET Core
|
|
✅ **Zero downtime** durante toda la migración
|
|
✅ **Equipo productivo** durante todo el proceso
|
|
✅ Sistema más rápido y escalable
|
|
|
|
### Reducción de Costos
|
|
|
|
💰 **$20,000/año ahorrados** con sustitución de Google Maps Directions API
|
|
📉 **Infraestructura optimizada** con SQL Server 2014
|
|
|
|
### Mejoras Técnicas
|
|
|
|
🚀 **Performance:** Aplicación .NET Core 3x más rápida que ASP 3.0
|
|
🔒 **Seguridad:** Stack moderno con parches de seguridad activos
|
|
🛠️ **Mantenibilidad:** Código C# moderno vs VBScript legacy
|
|
📊 **Monitoreo:** SignalR para tracking real-time más eficiente
|
|
|
|
---
|
|
|
|
## Fase No Ejecutada: Microservicios & Cloud
|
|
|
|
### Planificación Inicial
|
|
|
|
Participé en el **diseño y concepción** de la segunda fase (nunca ejecutada):
|
|
|
|
**Arquitectura planificada:**
|
|
- Migración a **Azure** (cloud estaba apenas comenzando en 2015)
|
|
- División en **microservicios**:
|
|
- Servicio de autenticación
|
|
- Servicio de GPS/tracking
|
|
- Servicio de rutas
|
|
- Servicio de notificaciones
|
|
- **Event-driven architecture** con message queues
|
|
|
|
**Por qué no fue ejecutada:**
|
|
|
|
Salí de la empresa inmediatamente después de concluir la migración a .NET Core. La segunda fase quedó planificada pero no fue implementada por mí.
|
|
|
|
---
|
|
|
|
## Tech Stack
|
|
|
|
`ASP 3.0` `VBScript` `.NET Core 1.0` `C#` `Entity Framework Core` `SQL Server 2005` `SQL Server 2014` `OSRM` `Leaflet.js` `Google Maps` `SignalR` `REST APIs` `GPS/Satellite` `Migration Strategy` `Dual-Write Pattern`
|
|
|
|
---
|
|
|
|
## Decisiones Clave & Trade-offs
|
|
|
|
### ¿Por qué sincronización dual-write?
|
|
|
|
**Alternativas consideradas:**
|
|
1. ❌ Big Bang migration (demasiado arriesgado)
|
|
2. ❌ Mantener todo en ASP 3.0 (insostenible)
|
|
3. ✅ **Migración gradual con sync** (elegido)
|
|
|
|
**Justificación:**
|
|
- Sistema crítico no podía detenerse
|
|
- Permitió rollback módulo por módulo
|
|
- Equipo continuó productivo
|
|
|
|
### ¿Por qué OSRM en vez de otros?
|
|
|
|
**Alternativas:**
|
|
- Google Maps: $20k/año ❌
|
|
- Mapbox: Licencia paga ❌
|
|
- GraphHopper: Configuración compleja ❌
|
|
- **OSRM: Open-source, rápido, configurable** ✅
|
|
|
|
### ¿Por qué no OpenStreetMap para tiles?
|
|
|
|
**Decisión basada en UX:**
|
|
- Técnicamente funcionó perfectamente
|
|
- Usuarios preferían interfaz familiar de Google
|
|
- **Compromiso:** Google Maps para visualización (gratis) + OSRM para rutas (gratis)
|
|
|
|
---
|
|
|
|
## Lecciones Aprendidas
|
|
|
|
### 1. Migración Gradual > Big Bang
|
|
|
|
Migrar módulo por módulo con sincronización permitió:
|
|
- Aprendizaje continuo
|
|
- Ajustes de ruta durante el proceso
|
|
- Confianza del equipo y stakeholders
|
|
|
|
### 2. Open Source Puede Ahorrar Mucho
|
|
|
|
OSRM ahorró **$20k/año** sin pérdida de calidad. Pero requiere:
|
|
- Expertise para configurar
|
|
- Infraestructura propia
|
|
- Mantenimiento continuo
|
|
|
|
### 3. UX > Tecnología A Veces
|
|
|
|
OpenStreetMap era técnicamente superior (gratuito), pero usuarios prefirieron Google Maps. **Lección:** Escuchar a los usuarios finales.
|
|
|
|
### 4. Planifique Cloud, pero Valide el ROI
|
|
|
|
En 2015, cloud estaba comenzando. La infraestructura on-premises (cluster SQL Server) era perfectamente capaz. **No fuerce cloud si no hay beneficio claro.**
|
|
|
|
---
|
|
|
|
## Contexto: Por qué 2015 fue un Momento Especial
|
|
|
|
**Estado de la tecnología en 2015:**
|
|
|
|
- ☁️ **Cloud en pañales:** AWS existía, Azure creciendo, pero adopción corporativa aún baja
|
|
- 🆕 **.NET Core 1.0 lanzado** en junio/2016 (usamos RC durante proyecto)
|
|
- 📱 **Microservicios:** Concepto nuevo, Docker en adopción inicial
|
|
- 🗺️ **Google Maps dominante:** APIs pagas, pocas alternativas open-source maduras
|
|
|
|
**Desafíos de la época:**
|
|
- Herramientas de migración ASP→.NET inexistentes
|
|
- Documentación .NET Core escasa (versión 1.0!)
|
|
- Patrones de arquitectura aún consolidándose
|
|
|
|
Este proyecto fue **pionero** al adoptar .NET Core al inicio, cuando la mayoría migraba a .NET Framework 4.x.
|
|
|
|
---
|
|
|
|
**Resultado:** Migración exitosa de sistema crítico 24/7, ahorro de $20k/año, y base sólida para evolución futura.
|
|
|
|
[¿Quiere discutir una migración similar? Póngase en contacto](#contact)
|