JSON.net сериализуется непосредственно из oledbconnection

В настоящее время у меня есть обработчик, который принимает путь к файлу и имя таблицы для файла excel, обрабатывает файл в datatable и затем сериализует таблицу в возвращаемую строку json. Это работает, пока я не попытаюсь обработать большой файл, а затем получаю исключение из памяти.

Я думал, что это уменьшит использование памяти, если я сначала не загружу все в данные, а вместо этого загружу прямо в строку json. Однако я не смог найти примеров того, как это сделать.

Могу ли я сериализовать непосредственно из OleDbConnection в строку? Как?

public void ProcessRequest(HttpContext context) { string path = context.Request["path"]; string tableNames = context.Request["tableNames"]; string connectionString = string.Empty; if (path.EndsWith(".xls")) { connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0; Data Source={0}; Extended Properties=""Excel 8.0;HDR=YES;IMEX=1""", path); } else if (path.EndsWith(".xlsx")) { connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0; Data Source={0}; Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1""", path); } DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb"); DbDataAdapter adapter = factory.CreateDataAdapter(); OleDbConnection conn = new OleDbConnection(connectionString); conn.Open(); DataTable tmp = new DataTable(); DbCommand selectCommand = factory.CreateCommand(); selectCommand.CommandText = String.Format("SELECT * FROM [{0}]", tableNames); selectCommand.Connection = conn; adapter.SelectCommand = selectCommand; adapter.Fill(tmp); string tabdata = JsonConvert.SerializeObject(tmp); context.Response.Write(tabdata); } 

    Во-первых, вы должны прекратить сериализацию в промежуточную string и вместо этого сериализовать непосредственно в HttpResponse.OutputStream , используя следующие простые методы:

     public static class JsonExtensions { public static void SerializeToStream(object value, System.Web.HttpResponse response, JsonSerializerSettings settings = null) { if (response == null) throw new ArgumentNullException("response"); SerializeToStream(value, response.OutputStream, settings); } public static void SerializeToStream(object value, TextWriter writer, JsonSerializerSettings settings = null) { if (writer == null) throw new ArgumentNullException("writer"); var serializer = JsonSerializer.CreateDefault(settings); serializer.Serialize(writer, value); } public static void SerializeToStream(object value, Stream stream, JsonSerializerSettings settings = null) { if (stream == null) throw new ArgumentNullException("stream"); using (var writer = new StreamWriter(stream)) { SerializeToStream(value, writer, settings); } } } 

    Так как для большой строки требуется большой непрерывный блок памяти для базового массива char , вы сначала должны выходить из памяти. См. Также Советы по производительности Json.NET

    Чтобы минимизировать использование памяти и количество выделенных объектов, Json.NET поддерживает сериализацию и десериализацию непосредственно в streamе. Чтение или запись JSON fragmentа за раз, а не полная строка JSON, загружаемая в память, особенно важна при работе с документами JSON размером более 85 КБ, чтобы избежать того, что строка JSON заканчивается в кучке большого объекта.

    Затем не забудьте обернуть все свои расходные материалы в оператор using , как показано ниже.

    Это может решить вашу проблему, но если это не так, вы можете сериализовать IDataReader в JSON, используя следующий JsonConverter :

     public class DataReaderConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(IDataReader).IsAssignableFrom(objectType); } public override bool CanRead { get { return false; } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var reader = (IDataReader)value; writer.WriteStartArray(); while (reader.Read()) { writer.WriteStartObject(); for (int i = 0; i < reader.FieldCount; i++) { writer.WritePropertyName(reader.GetName(i)); if (reader.IsDBNull(i)) writer.WriteNull(); else serializer.Serialize(writer, reader[i]); } writer.WriteEndObject(); } writer.WriteEndArray(); } } 

    А затем сериализуйте в stream следующим образом:

     public static class ExcelExtensions { private static string GetExcelConnectionString(string path) { string connectionString = string.Empty; if (path.EndsWith(".xls")) { connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0; Data Source={0}; Extended Properties=""Excel 8.0;HDR=YES;IMEX=1""", path); } else if (path.EndsWith(".xlsx")) { connectionString = String.Format(@"Provider=Microsoft.ACE.OLEDB.12.0; Data Source={0}; Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1""", path); } return connectionString; } public static string SerializeJsonToString(string path, string workSheetName, JsonSerializerSettings settings = null) { using (var writer = new StringWriter()) { SerializeJsonToStream(path, workSheetName, writer, settings); return writer.ToString(); } } public static void SerializeJsonToStream(string path, string workSheetName, Stream stream, JsonSerializerSettings settings = null) { using (var writer = new StreamWriter(stream)) SerializeJsonToStream(path, workSheetName, writer, settings); } public static void SerializeJsonToStream(string path, string workSheetName, TextWriter writer, JsonSerializerSettings settings = null) { settings = settings ?? new JsonSerializerSettings(); var converter = new DataReaderConverter(); settings.Converters.Add(converter); try { string connectionString = GetExcelConnectionString(path); DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb"); using (OleDbConnection conn = new OleDbConnection(connectionString)) { conn.Open(); using (DbCommand selectCommand = factory.CreateCommand()) { selectCommand.CommandText = String.Format("SELECT * FROM [{0}]", workSheetName); selectCommand.Connection = conn; using (var reader = selectCommand.ExecuteReader()) { JsonExtensions.SerializeToStream(reader, writer, settings); } } } } finally { settings.Converters.Remove(converter); } } } 

    Примечание - слегка протестировано. Обязательно выполните тестирование с использованием существующего метода перед его внедрением! Для кода конвертера я использовал JSON Serialization DataReader в качестве вдохновения.

    Обновить

    Мой конвертер выдает JSON в той же структуре, что и DataTableConverter Json.NET. Таким образом, вы сможете автоматически десериализовать DataTable с помощью Json.NET. Если вы предпочитаете более компактный формат, вы можете определить свои собственные, например:

     { "columns": [ "Name 1", "Name 2" ], "rows": [ [ "value 11", "value 12" ], [ "value 21", "value 22" ] ] } 

    И они создают следующий конвертер:

     public class DataReaderArrayConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(IDataReader).IsAssignableFrom(objectType); } public override bool CanRead { get { return false; } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } static string[] GetFieldNames(IDataReader reader) { var fieldNames = new string[reader.FieldCount]; for (int i = 0; i < reader.FieldCount; i++) fieldNames[i] = reader.GetName(i); return fieldNames; } static void ValidateFieldNames(IDataReader reader, string[] fieldNames) { if (reader.FieldCount != fieldNames.Length) throw new InvalidOperationException("Unequal record lengths"); for (int i = 0; i < reader.FieldCount; i++) if (fieldNames[i] != reader.GetName(i)) throw new InvalidOperationException(string.Format("Field names at index {0} differ: \"{1}\" vs \"{2}\"", i, fieldNames[i], reader.GetName(i))); } const string columnsName = "columns"; const string rowsName = "rows"; public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var reader = (IDataReader)value; writer.WriteStartObject(); string[] fieldNames = null; while (reader.Read()) { if (fieldNames == null) { writer.WritePropertyName(columnsName); fieldNames = GetFieldNames(reader); serializer.Serialize(writer, fieldNames); writer.WritePropertyName(rowsName); writer.WriteStartArray(); } else { ValidateFieldNames(reader, fieldNames); } writer.WriteStartArray(); for (int i = 0; i < reader.FieldCount; i++) { if (reader.IsDBNull(i)) writer.WriteNull(); else serializer.Serialize(writer, reader[i]); } writer.WriteEndArray(); } if (fieldNames != null) { writer.WriteEndArray(); } writer.WriteEndObject(); } } 

    Конечно, вам нужно будет создать собственный конвертер десериализации на стороне клиента.

    В качестве альтернативы вы можете рассмотреть возможность сжатия вашего ответа. Я никогда не пробовал, но вижу HttpWebRequest и GZip Http-ответы и ASP.NET-кодировки GZip .

    Interesting Posts

    Не удалось решить: com.android.support:cardview-v7:26.0.0 android

    Spark Error: ожидаемые нулевые аргументы для построения ClassDict (для numpy.core.multiarray._reconstruct)

    Положение камеры в мировой координате из cv :: solvePnP

    Как использовать метод расширения LINQPad Dump () в Visual Studio?

    Фоновый оттенок Lollipop не влияет на кнопку

    Как я могу вызвать метод в Objective-C?

    Обработка нескольких параметров запроса в Джерси

    Функция IF в значениях времени

    В Java, как мне получить доступ к внешнему classу, когда я не во внутреннем classе?

    Могу ли я использовать 27-дюймовый iMac в качестве дополнительного монитора для другого 27-дюймового iMac?

    Как я могу переименовать столбец базы данных в миграции Ruby on Rails?

    Когда частный конструктор не является частным конструктором?

    В каратэ, как мы можем совместно работать с BA для автоматизации бизнес-сценариев

    Выбирать учетную запись google google

    Почему в некоторых телефонах ошибка «Это приложение было построено с неправильной конфигурацией»?

    Давайте будем гением компьютера.