MESSeries_Bate/MESws_STD/JsonConevertExtensions.cs
2025-05-20 17:00:22 +08:00

299 lines
11 KiB
C#

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
{
/// <summary>
/// 20210513 13871,Json相關擴充方法
/// </summary>
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.");
}
}
}
/// <summary>
/// 20210513 13871,Json DataTableConverter類別,自定義轉型方法,排除浮點數被轉成整數問題
/// </summary>
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<string>();
while (reader.TokenType != JsonToken.EndArray)
{
CreateRow(reader, dt, serializer, (HashSet<string>)ambiguousColumnTypes);
reader.ReadAndAssert();
}
return dt;
}
private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer serializer, HashSet<string> 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<string>();
while (reader.TokenType != JsonToken.EndArray)
{
CreateRow(reader, nestedDt, serializer, (HashSet<string>)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<object>();
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<object> 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;
}
}
}
}
}