Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json circular reference in powershell 2.0 with javascriptSerializer

I´m writing a script in powershell 2.0 and an upgrade to 3.0 or higher is not possible right now. In this script I try to serialize some data to JSON with the code from this link (PowerShell 2.0 ConvertFrom-Json and ConvertTo-Json implementation):

function ConvertTo-Json20([object] $item){
    add-type -assembly system.web.extensions
    $ps_js=new-object system.web.script.serialization.javascriptSerializer
    return $ps_js.Serialize($item)
}

My problem is that I somehow get a circular reference and I really don´t know why. I set up a litte piece of test data and the structure looks in powershell like this:

$testRoot = @{
    "id" = "1"
    "children" = @( 
        @{
            "id" = "2"
            "children" = @( 
                @{
                    "id" = "2";
                };
                @{
                    "id" = "3";
                }
            );
        };
        @{
            "id" = "4"
            "children" = @( 
                @{
                    "id" = "5";
                }
            );
        }
    )
}

I know it looks junky, but I just need it in this format.

The structures I need to serialize have a few more layers, so even more "children" and there is the point where it gets strange.

When I try this:

ConvertTo-Json20 $testRoot

everything works fine. The structure gets parsed like this:

{
   "id":"1",
   "children":[
        {
            "id":"2",
            "children":[
               {
                   "id":"2"
               },
               {
                   "id":"3"
               }
            ]
        },
        {
            "id":"4",
            "children":[
               {
                   "id":"5"
               }
            ]
        }
   ]
}

But now comes the problem. As mentioned the structure has more layers, so I try this which just sets the data in an array.

ConvertTo-Json20 @($testRoot)

But it does not work I just get an error message saying:

Exception in method "Serialize" with 1 argument(s):  
"While serializing an object of type "System.Management.Automation.PSParameterizedProperty" a circular reference was discovered."
At C:\Users\a38732\Desktop\Temp.ps1:34 symbol:28
+     return $ps_js.Serialize <<<< ($item)
+ CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

(I translated the error message from german, so there might be some words different in the english version...)

like image 549
Michael Zappe Avatar asked Aug 26 '16 08:08

Michael Zappe


1 Answers

One problem is the use of the JavaScriptSerializer class itself. As of this date the documentation itself concedes it should not be used to serialize nor deserialize JSON. To quote:

Json.NET should be used serialization and deserialization.

If you're able to use third-party libraries like Json.NET, here's a simple function that does what you need given the data structure in the OP:

function ConvertTo-JsonNet {
   [CmdletBinding()]
    param(
        [Parameter(Mandatory)] $object,
        [Parameter(Mandatory)] [string]$jsonNetPath,
        [switch]$indent,
        [switch]$preserveReferencesHandling
    )
    Add-Type -Path $jsonNetPath;

    $formatting = if ($indent.IsPresent) { [Newtonsoft.Json.Formatting]::Indented; }
    else { [Newtonsoft.Json.Formatting]::None; }

    $settings = New-Object Newtonsoft.Json.JsonSerializerSettings;
    if ($preserveReferencesHandling.IsPresent) { 
        $settings.PreserveReferencesHandling = [Newtonsoft.Json.PreserveReferencesHandling]::Objects;
    }

    [Newtonsoft.Json.JsonConvert]::SerializeObject($object, $formatting, $settings);
}

Simple usage, assuming Newtonsoft.Json.dll is in the same directory as your script:

$dllPath = Join-Path $PSScriptRoot 'Newtonsoft.Json.dll';
ConvertTo-JsonNet @($testRoot) $dllPath;

Output:

[{"id":"1","children":[{"id":"2","children":[{"id":"2"},{"id":"3"}]},{"id":"4","children":[{"id":"5"}]}]}]

You can manually download the .dll from the nuget package project site. It has a .nupkg file extension, but it's a zipped archive, so rename the extension to .zip and you're set. In the lib sub-directory there are .dll files for .NET versions from 2.0 through 4.5.

like image 96
kuujinbo Avatar answered Oct 20 '22 19:10

kuujinbo