ConvertFrom-Json max length

У меня проблема с использованием PowerShell v3 при преобразовании строк JSON размером более 2 МБ. Предел по умолчанию в сериализаторе JSON, используемом PowerShell, устанавливается в 2 МБ, что объясняет ошибку.

Однако, когда я десериализую объект с помощью ConvertFrom-Json на меньшем наборе (у меня есть разные объекты данных с меньшими и большими внутренними коллекциями, но это те же объекты), он возвращает очень хороший объект со всеми свойствами, к которым я могу легко получить доступ.

Чтобы преодолеть ограничения сериализатора, я попытался десериализовать данные вручную:

$jsser = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$jsser.MaxJsonLength = $jsser.MaxJsonLength * 10
$jsser.RecursionLimit = 99    

$outObject = $jsser.DeserializeObject($json)

Объект выглядит по-другому, кажется, что внутренние коллекции не были десериализованы, и когда я пытаюсь выполнить свойства, они возвращают пустые результаты.

Мои вопросы:

  1. Успение ConvertFrom-Json делает некоторую дополнительную магию или каким-то образом создает шаблон для объекта перед сериализацией. Любая идея, как его реплицировать?

  2. Объект, который я получаю, всегда является PSCustomObject; если я получаю объект, который я хочу настроить ConvertFrom-Json все равно использовать его как тип объекта в JsonSerializer?

Ответ 1

У меня была та же проблема и я смог решить ее так:

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")        
$jsonserial= New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer 
$jsonserial.MaxJsonLength  = 67108864
$Obj = $jsonserial.DeserializeObject($CourseTypesResponse)

Вы можете использовать $jsonserial.MaxJsonLength для управления свойством MaxJsonLength

source: https://social.technet.microsoft.com/Forums/windowsserver/en-US/833c99c1-d8eb-400d-bf58-38f7265b4b0e/error-when-converting-from-json?forum=winserverpowershell&prof=required

Ответ 2

У меня был тот же самый знак при использовании Invoke-RestMethod и больших коллекций JSON в результате. Я закончил тем, что адаптировал методы из Parsing json с PowerShell и Json.NET для преобразования коллекций JSON в объекты PowerShell.

    # .NET JSON Serializer 
    $global:javaScriptSerializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer
    $global:javaScriptSerializer.MaxJsonLength = [System.Int32]::MaxValue
    $global:javaScriptSerializer.RecursionLimit = 99

    # Functions necessary to parse JSON output from .NET serializer to PowerShell Objects
    function ParseItem($jsonItem) {
            if($jsonItem.PSObject.TypeNames -match "Array") {
                    return ParseJsonArray($jsonItem)
            }
            elseif($jsonItem.PSObject.TypeNames -match "Dictionary") {
                    return ParseJsonObject([HashTable]$jsonItem)
            }
            else {
                    return $jsonItem
            }
    }

    function ParseJsonObject($jsonObj) {
            $result = New-Object -TypeName PSCustomObject
            foreach ($key in $jsonObj.Keys) {
                    $item = $jsonObj[$key]
                    if ($item) {
                            $parsedItem = ParseItem $item
                    } else {
                            $parsedItem = $null
                    }
                    $result | Add-Member -MemberType NoteProperty -Name $key -Value $parsedItem
            }
            return $result
    }

    function ParseJsonArray($jsonArray) {
            $result = @()
            $jsonArray | ForEach-Object {
                    $result += , (ParseItem $_)
            }
            return $result
    }

    function ParseJsonString($json) {
            $config = $javaScriptSerializer.DeserializeObject($json)
            return ParseJsonObject($config)
    }

Ответ 3

Я поместил это в свой код:

     JavaScriptSerializer oSerializer = new JavaScriptSerializer();
     oSerializer.MaxJsonLength *= 2;
     ws_Out = (ClsWsOut)oSerializer.Deserialize(jsonOut, ws_Out.GetType());

Где ws_Out.GetType() - это класс, который я определяю для синтаксического анализа json.

public class ClsLogin_In :ClsWsIn
{
  public string login { get; set; }
  public string passwd { get; set; }
}

public class ClsLogin_Out : ClsWsOut
{
  public int error { get; set; }
  public string error_desc { get; set; }
  public int key { get; set; }
}

отредактированный

в PowerShell V3, когда json, возвращаемый веб-службой, очень большой, PowerShell V3 отправляет исключение. Поэтому я использую сериализацию XML, вот моя функция, она также использует внешние сборки, но они являются базовыми, XML немного подробный, но он работает.

Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization
$utf8 = [System.Text.Encoding]::UTF8    

function Write-String

{
  PARAM([Parameter()]$stream,
        [Parameter(ValueFromPipeline=$true)]$string)

  PROCESS
  {
    $bytes = $utf8.GetBytes($string)
    $stream.Write( $bytes, 0, $bytes.Length )
  }  
}

function Convert-JsonToXml

{
  PARAM([Parameter(ValueFromPipeline=$true)][string[]]$json)

  BEGIN
  { 
    $mStream = New-Object System.IO.MemoryStream 
  }

  PROCESS
  {
    $json | Write-String -stream $mStream
  }

  END
  {
    $mStream.Position = 0
    try
    {
       $jsonReader = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonReader($mStream,[System.Xml.XmlDictionaryReaderQuotas]::Max)
       $xml = New-Object Xml.XmlDocument
       $xml.Load($jsonReader)
       $xml
    }
    finally
    {
       $jsonReader.Close()
       $mStream.Dispose()
    }
  }
}

function Convert-XmlToJson
{
  PARAM([Parameter(ValueFromPipeline=$true)][Xml]$xml)

  PROCESS
  {
    $mStream = New-Object System.IO.MemoryStream
    $jsonWriter = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonWriter($mStream)
    try
    {
      $xml.Save($jsonWriter)
      $bytes = $mStream.ToArray()
      [System.Text.Encoding]::UTF8.GetString($bytes,0,$bytes.Length)
    }
    finally
    {
      $jsonWriter.Close()
      $mStream.Dispose()
    }
  }
}

Вот пример.

$json = @'
{
  "data": {
    "langid": 7, 
    "results": [{
       "first_aired": "2010-11-15", 
        "name": "Accused", 
       "tvdbid": 72663
       }, 
       {
       "first_aired": "2010-01-17", 
       "name": "Enzai: Falsely Accused", 
       "tvdbid": 135881
       }]
  }, 
  "message": "", 
  "result": "success"
}
'@

$xmlOut = Convert-JsonToXml -json $json
($xmlOut.root.data.results).ChildNodes[0].tvdbid.InnerText
($xmlOut.root.data.results).ChildNodes[1].tvdbid.InnerText