using System; using System.Collections.Generic; using System.Linq; using System.Web; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Globalization; using Microsoft.VisualBasic.CompilerServices; using System.Data; namespace MESws { /// /// 20210513 13871,Json相關擴充方法 /// internal static class JsonSerializationExceptionHelper { public static JsonSerializationException Create(this JsonReader reader, string format, params object[] args) { IJsonLineInfo lineInfo = reader as IJsonLineInfo; string path = reader == null ? null : reader.Path; string message = string.Format(CultureInfo.InvariantCulture, format, args); if (Convert.ToBoolean(!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))) { message = message.Trim(); if (Convert.ToBoolean(!message.EndsWith(".", StringComparison.Ordinal))) message += "."; message += " "; } message += string.Format(CultureInfo.InvariantCulture, "Path '{0}'", path); if (lineInfo != null && lineInfo.HasLineInfo()) message += String.Format(CultureInfo.InvariantCulture, ", line {0}, position {1}", lineInfo.LineNumber, lineInfo.LinePosition); message += "."; return new JsonSerializationException(Convert.ToString(message)); } } internal static class StringUtils { public static string FormatWith(this string format, IFormatProvider provider, object arg0) { return format.FormatWith(provider, new[] { arg0 }); } private static string FormatWith(string format, IFormatProvider provider, params object[] args) { return string.Format(provider, format, args); } } internal static class JsonReaderExtensions { public static void ReadAndAssert(this JsonReader reader) { if (reader == null) throw new ArgumentNullException("reader"); if (!reader.Read()) { throw reader.Create("Unexpected end when reading JSON."); } } } /// /// 20210513 13871,Json DataTableConverter類別,自定義轉型方法,排除浮點數被轉成整數問題 /// internal class TypeInferringDataTableConverter : Newtonsoft.Json.Converters.DataTableConverter { public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { return null; } DataTable dt = existingValue as DataTable; if (dt == null) { dt = objectType == typeof(DataTable) ? new DataTable() : (DataTable)Activator.CreateInstance(objectType); } if (reader.TokenType == JsonToken.PropertyName) { dt.TableName = Convert.ToString(reader.Value); reader.ReadAndAssert(); if (reader.TokenType == JsonToken.Null) { return dt; } } if (reader.TokenType != JsonToken.StartArray) { throw reader.Create("Unexpected JSON token when reading DataTable. Expected StartArray, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } reader.ReadAndAssert(); object ambiguousColumnTypes = new HashSet(); while (reader.TokenType != JsonToken.EndArray) { CreateRow(reader, dt, serializer, (HashSet)ambiguousColumnTypes); reader.ReadAndAssert(); } return dt; } private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer serializer, HashSet ambiguousColumnTypes) { var dr = dt.NewRow(); reader.ReadAndAssert(); while (reader.TokenType == JsonToken.PropertyName) { string columnName = Convert.ToString(reader.Value); reader.ReadAndAssert(); DataColumn column = dt.Columns[columnName]; // 20211203 13871,DataTable內欄位如果是陣列、物件則不處理 if (column == null) { bool isAmbiguousType = false; Type columnType = GetColumnDataType(reader, ref isAmbiguousType); if (columnType == null) //20211203 13871,DataTable內欄位如果是陣列、物件則不處理 { reader.ReadAndAssert(); continue; } column = new DataColumn(columnName, columnType); dt.Columns.Add(column); if (isAmbiguousType) ambiguousColumnTypes.Add(columnName); } else if (ambiguousColumnTypes.Contains(columnName)) { bool isAmbiguousType = false; Type newColumnType = GetColumnDataType(reader, ref isAmbiguousType); if (!isAmbiguousType) ambiguousColumnTypes.Remove(columnName); if (newColumnType != column.DataType) { column = ReplaceColumn(dt, column, newColumnType, serializer); } } if (column.DataType == typeof(DataTable)) { if (reader.TokenType == JsonToken.StartArray) { reader.ReadAndAssert(); } var nestedDt = new DataTable(); object nestedUnknownColumnTypes = new HashSet(); while (reader.TokenType != JsonToken.EndArray) { CreateRow(reader, nestedDt, serializer, (HashSet)nestedUnknownColumnTypes); reader.ReadAndAssert(); } dr[columnName] = nestedDt; } else if (column.DataType.IsArray && column.DataType != typeof(byte[])) { if (reader.TokenType == JsonToken.StartArray) { reader.ReadAndAssert(); } var o = new List(); while (reader.TokenType != JsonToken.EndArray) { o.Add(reader.Value); reader.ReadAndAssert(); } var destinationArray = Array.CreateInstance(column.DataType.GetElementType(), o.Count); Array.Copy(o.ToArray(), destinationArray, o.Count); dr[columnName] = destinationArray; } else { var columnValue = reader.Value != null ? serializer.Deserialize(reader, column.DataType) ?? DBNull.Value : DBNull.Value; dr[columnName] = columnValue; } reader.ReadAndAssert(); } dr.EndEdit(); dt.Rows.Add(dr); } private static object RemapValue(object oldValue, Type newType, JsonSerializer serializer) { if (oldValue == null) return null; if (Convert.ToBoolean(Operators.ConditionalCompareObjectEqual(oldValue, DBNull.Value, false))) return oldValue; return JToken.FromObject(oldValue, serializer).ToObject(newType, serializer); } private static DataColumn ReplaceColumn(DataTable dt, DataColumn column, Type newColumnType, JsonSerializer serializer) { List newValues = Enumerable.Range(0, dt.Rows.Count).Select(i => dt.Rows[i]).Select(r => RemapValue(r[column], newColumnType, serializer)).ToList(); int ordinal = column.Ordinal; string name = column.ColumnName; string @namespace = column.Namespace; DataColumn newColumn = new DataColumn(Convert.ToString(name), newColumnType); newColumn.Namespace = @namespace; dt.Columns.Remove(column); dt.Columns.Add(newColumn); newColumn.SetOrdinal(ordinal); for (int i = 0, loopTo = dt.Rows.Count - 1; i <= loopTo; i++) dt.Rows[i][newColumn] = newValues[i]; return (DataColumn)newColumn; } private static Type GetColumnDataType(JsonReader reader, ref bool isAmbiguous) { var tokenType = reader.TokenType; switch (tokenType) { case JsonToken.Integer: { isAmbiguous = false; return Type.GetType("System.Decimal"); } case JsonToken.Float: { isAmbiguous = false; return Type.GetType("System.Decimal"); } case JsonToken.Null: case JsonToken.Undefined: { isAmbiguous = false; return typeof(string); } case JsonToken.Boolean: { return Type.GetType("System.Boolean"); } // 20211203 13871,DataTable內欄位如果是陣列、物件則不處理 case JsonToken.StartArray: { isAmbiguous = false; int iCount = 1; while (iCount > 0) { reader.ReadAndAssert(); var tokenType2 = reader.TokenType; if (tokenType2 == JsonToken.StartArray) iCount += 1; if (tokenType2 == JsonToken.EndArray) iCount -= 1; } return null; } case JsonToken.StartObject: { isAmbiguous = false; int iCount = 1; while (iCount > 0) { reader.ReadAndAssert(); var tokenType2 = reader.TokenType; if (tokenType2 == JsonToken.StartObject) iCount += 1; if (tokenType2 == JsonToken.EndObject) iCount -= 1; } return null; } default: { isAmbiguous = false; return reader.ValueType; } } } } }