Extensión de Visual Studio (VSIX) que agrega una Tool Window para trabajar con JSON sin salir del IDE: formatear, validar, minificar, convertir JSON ↔ C#, y más — todo con theming nativo del Shell de Visual Studio (Claro, Oscuro, Azul, Alto Contraste).
Requisitos
- Visual Studio 2022 (17.x) o superior.
- Workload "Visual Studio extension development" instalado (VS Installer → Modificar → marcar el workload).
Instalación
- Cloná el repo:
git clone https://github.com/ajflores/arjuyJson.git
- Abrí
arjuyJsonApp\ArjuyJsonApp.sln en Visual Studio.
- Compilá (
Build > Build Solution). El .vsix queda en ArjuyJsonApp\bin\Debug\net472\ArjuyJsonApp.vsix (o bin\Release si compilaste en Release).
- Doble click al
.vsix para instalarlo en tu Visual Studio, o F5 desde el proyecto para probarlo en una instancia experimental sin instalarlo de forma permanente.
- Una vez instalada, abrila desde Tools → ArjuyJson Tools (o buscá "ArjuyJson" con
Ctrl+Q, el Quick Launch de VS).
Funcionalidades
Pretty-print de un JSON: agrega indentación legible.
Input:
{"producto":"Teclado Mecánico","precio":45.99,"stock":25,"activo":true}
Output:
{
"producto": "Teclado Mecánico",
"precio": 45.99,
"stock": 25,
"activo": true
}
Validar
Detecta si el JSON es válido y, si no lo es, resalta en rojo directamente sobre el editor de entrada la línea exacta del error (no solo un mensaje de texto) — el editor de input usa AvalonEdit justo para poder hacer esto.
Input (con un error real: falta una coma):
{
"producto": "Teclado Mecánico",
"precio": 45.99
"stock": 25,
"activo": true,
"categoria": {
"nombre": "Periféricos",
}
}
Resultado: el editor resalta la línea 4 ("stock": 25,) en rojo, y el mensaje de estado indica: Línea 4, posición 2: '"' is invalid after a value.... Además, la coma final después de "Periféricos" (línea 7) también se detecta como error — inválida en JSON estricto, sin importar qué motor de serialización tengas seleccionado (ver más abajo).
Minificar
Lo inverso de Formatear: compacta el JSON quitando espacios y saltos de línea. Útil para pegar en archivos de configuración o variables de entorno.
Input:
{
"a": 1,
"b": [1, 2]
}
Output:
{"a":1,"b":[1,2]}
JSON a C#
Genera clases C# (POCO, con { get; set; }) a partir de un JSON de ejemplo. Infiere tipos automáticamente (string, int, long, double, bool, objetos anidados, List<T>), y detecta el tipo numérico correcto según el valor (45.99 → double, 25 → int).
Input:
{
"nombre_cliente": "Ana",
"edad": 34,
"saldo": 1250.75,
"activo": true,
"direccion": { "calle": "Av. Siempre Viva", "numero": 742 },
"compras": [
{ "producto": "Notebook", "precio": 899.99 }
]
}
Output (con el checkbox "Agregar [JsonPropertyName]" tildado — agrega el atributo a TODAS las propiedades, para que el mapeo funcione sin importar cómo esté casing-eado el JSON original):
public class Root
{
[JsonPropertyName("nombre_cliente")]
public string NombreCliente { get; set; }
[JsonPropertyName("edad")]
public int Edad { get; set; }
[JsonPropertyName("saldo")]
public double Saldo { get; set; }
[JsonPropertyName("activo")]
public bool Activo { get; set; }
[JsonPropertyName("direccion")]
public Direccion Direccion { get; set; }
[JsonPropertyName("compras")]
public List<Compra> Compras { get; set; }
}
public class Direccion
{
[JsonPropertyName("calle")]
public string Calle { get; set; }
[JsonPropertyName("numero")]
public int Numero { get; set; }
}
public class Compra
{
[JsonPropertyName("producto")]
public string Producto { get; set; }
[JsonPropertyName("precio")]
public double Precio { get; set; }
}
C# a JSON
El camino inverso: pegás clases C# (el mismo patrón simple public class X { public Tipo Prop { get; set; } }, con soporte de List<T> y clases anidadas) y genera un JSON de ejemplo. Como una clase C# solo define tipos, no valores reales, el JSON se completa con datos de ejemplo generados por heurística según el nombre y tipo de cada propiedad — nunca datos inventados con forma "falsa" tipo null/0 para todo.
Input:
public class PedidoDto
{
public int IdPedido { get; set; }
public string Cliente { get; set; }
public decimal Total { get; set; }
public bool Pagado { get; set; }
public List<ItemPedido> Items { get; set; }
}
public class ItemPedido
{
public string Sku { get; set; }
public int Cantidad { get; set; }
public double PrecioUnitario { get; set; }
}
Output (valores de ejemplo — cambian en cada ejecución):
{
"IdPedido": 7,
"Cliente": "texto_ejemplo_1",
"Total": 9416.32,
"Pagado": true,
"Items": [
{ "Sku": "texto_ejemplo_2", "Cantidad": 90, "PrecioUnitario": 6482.47 },
{ "Sku": "texto_ejemplo_3", "Cantidad": 5, "PrecioUnitario": 6282.27 }
]
}
Notá que Total (tipo decimal) recibió un valor con forma de moneda — la heurística reconoce nombres como Precio/Monto/Saldo/Total/Costo y genera valores en un rango realista, en vez de un número al azar sin sentido.
Límites, a propósito y documentados (no es Roslyn, es un parser de texto liviano — decisión consciente para no sumar ~10-20MB al VSIX): soporta clases POCO simples, List<T>, tipos string/int/long/double/decimal/bool y clases anidadas definidas en el mismo texto. NO soporta herencia, records, structs, ni generics distintos de List<T>. Si el texto no matchea el patrón esperado, la herramienta lo dice explícitamente en vez de devolver un JSON inventado.
Limpiar Escapes
Resuelve un problema muy específico y muy común: cuando copiás el valor de una variable string desde el debugger de Visual Studio (Locals/Watch/Quick Watch), VS te lo muestra con los caracteres escapados tal cual — \r\n en vez de saltos de línea reales, \" en vez de comillas. Este botón lo desescapa para que puedas Formatear/Validar el JSON real que hay debajo.
Input (copiado tal cual del Watch window de VS):
{\r\n \"Nombre\": \"Ana Martinez\",\r\n \"Edad\": 58,\r\n \"Direccion\": {\r\n \"Calle\": \"Av. Corrientes 1234\",\r\n \"Ciudad\": \"Rosario\"\r\n }\r\n}
Output:
{
"Nombre": "Ana Martinez",
"Edad": 58,
"Direccion": {
"Calle": "Av. Corrientes 1234",
"Ciudad": "Rosario"
}
}
Funciona tanto si copiaste el valor CON las comillas envolventes que muestra VS, como si copiaste solo el contenido interno — la herramienta detecta ambos casos automáticamente.
Selector de motor: System.Text.Json / Newtonsoft.Json
Formatear, Validar y Minificar pueden correr sobre System.Text.Json (motor por defecto, nativo de .NET) o Newtonsoft.Json — útil si tu proyecto ya depende de Newtonsoft y querés confirmar que el comportamiento de parseo es el mismo que vas a tener en producción. Ambos motores dan resultados consistentes ante el mismo input (por ejemplo, los dos detectan comas finales inválidas de la misma forma).
Normalización de Casing
Convierte las keys de un JSON (no los valores) a camelCase o PascalCase, recursivamente en objetos anidados.
Input (keys mezcladas, a propósito feas):
{"Nombre_Cliente":"Ana","direccion_envio":{"Calle_Principal":"9 de Julio","numero-piso":3}}
Output con camelCase:
{"nombreCliente":"Ana","direccionEnvio":{"callePrincipal":"9 de Julio","numeroPiso":3}}
Copiar al portapapeles
Un botón junto al panel de salida copia el resultado actual con un clic (Clipboard.SetText), sin tener que seleccionar y copiar manualmente.
Arquitectura (para quien quiera contribuir)
- MVVM estricto:
Views/ (XAML + code-behind mínimo) → ViewModels/ (comandos + estado observable) → Services/ (lógica pura, sin dependencia de WPF).
- Servicios separados por responsabilidad:
IJsonSerializationService (Formatear/Validar/Minificar/Casing, con soporte de dos motores) e ICSharpConversionService (JSON↔C#, Limpiar Escapes).
- Contrato de resultado unificado: todas las operaciones devuelven un objeto que implementa
IOperationResult (Success + ErrorMessage), nunca dejan propagar una excepción cruda hasta la UI.
- Input implementado con AvalonEdit (no un
TextBox plano) para poder resaltar la línea exacta de un error de validación.
- Theming 100% vía
VsBrushes/VsColors del Shell de VS — sin colores hardcodeados, respeta el tema activo del IDE automáticamente.
Stack técnico
- .NET Framework 4.7.2 (requisito del modelo clásico de extensibilidad VSIX, que corre in-process con
devenv.exe)
- WPF + MVVM
System.Text.Json / Newtonsoft.Json
AvalonEdit
Microsoft.VisualStudio.SDK 17.8.x
Licencia
Sin especificar todavía.