Convertir JSON a tabla de datos
Tengo JSON en el siguiente formato:
[
{"id":"10","name":"User","add":false,"edit":true,"authorize":true,"view":true},
{"id":"11","name":"Group","add":true,"edit":false,"authorize":false,"view":true},
{"id":"12","name":"Permission","add":true,"edit":true,"authorize":true,"view":true}
]
¿ Cómo puedo convertir eso en un DataTable
objeto C# de la siguiente manera?
---------------------------------------------------------------------
ID | Name | Add | Edit | View | Authorize
---------------------------------------------------------------------
10 | User | true | true | true | true
11 | Group | true | true | true | true
12 | Permission| true | true | true | true
Existe un método más sencillo que las otras respuestas aquí, que requieren primero deserializar en la clase ac# y luego convertirla en una tabla de datos.
Es posible ir directamente a una tabla de datos, con JSON.NET y código como este:
DataTable dt = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));
Deserializa tu jsonstring a alguna clase
List<User> UserList = JsonConvert.DeserializeObject<List<User>>(jsonString);
Escriba el siguiente método de extensión para su proyecto
using System.ComponentModel;
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for(int i = 0 ; i < props.Count ; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
Método de extensión de llamada como
UserList.ToDataTable<User>();
No siempre se sabe en qué tipo deserializar. Por lo tanto, sería útil poder tomar cualquier JSON (que contenga alguna matriz) y generar dinámicamente una tabla a partir de él.
Sin embargo, puede surgir un problema en el que el deserializador no sabe dónde buscar la matriz para tabular. Cuando esto sucede, recibimos un mensaje de error similar al siguiente:
Token JSON inesperado al leer DataTable. StartArray esperado, obtuve StartObject. Ruta '', línea 1, posición 1.
Incluso si lo animamos o preparamos nuestro json en consecuencia, los tipos de "objetos" dentro de la matriz aún pueden evitar que se produzca la tabulación, donde el deserializador no sabe cómo representar los objetos en términos de filas, etc. , se producen errores similares a los siguientes:
Token JSON inesperado al leer DataTable: StartObject. Ruta '[0].__metadata', línea 3, posición 19.
El siguiente ejemplo JSON incluye estas dos características problemáticas:
{
"results":
[
{
"Enabled": true,
"Id": 106,
"Name": "item 1",
},
{
"Enabled": false,
"Id": 107,
"Name": "item 2",
"__metadata": { "Id": 4013 }
}
]
}
Entonces, ¿cómo podemos resolver esto y seguir manteniendo la flexibilidad de no saber en qué tipo desrializar?
Bueno, aquí hay un enfoque simple que se me ocurrió (suponiendo que esté dispuesto a ignorar las propiedades del tipo de objeto, como __metadata en el ejemplo anterior):
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Data;
using System.Linq;
...
public static DataTable Tabulate(string json)
{
var jsonLinq = JObject.Parse(json);
// Find the first array using Linq
var srcArray = jsonLinq.Descendants().Where(d => d is JArray).First();
var trgArray = new JArray();
foreach (JObject row in srcArray.Children<JObject>())
{
var cleanRow = new JObject();
foreach (JProperty column in row.Properties())
{
// Only include JValue types
if (column.Value is JValue)
{
cleanRow.Add(column.Name, column.Value);
}
}
trgArray.Add(cleanRow);
}
return JsonConvert.DeserializeObject<DataTable>(trgArray.ToString());
}
Sé que esto podría ser más "LINQy" y no tiene absolutamente ningún manejo de excepciones, pero espero que se transmita el concepto.
Estamos empezando a utilizar cada vez más servicios en mi trabajo que escupen JSON, por lo que liberarnos de escribir todo con fuerza es mi preferencia obvia porque soy vago.