Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast object of (string, multidimensional-array) as JSON result in C# Dotnet 5.0

I have a controller that has the following structure/classes:

// model
public class Result
{
    public string Document { get; set; } = "";

    public int[,] Segments { get; set; } = new int[,] { };
}

// controller
public class SearchController : ControllerBase {
    [HttpGet]
    [Route("/api/v1/[controller]")]
    [Produces("application/json")]
    public IActionResult Search(//metadata list)
    {
      try {
            Result result = <service-call-returning Result object>;
            return Ok(result);
      } catch (Exception e) {
            return BadRequest("bad");
      }
    }
}

It seems that it's not able to serialize the Result object, I am getting the following exception:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]

An unhandled exception has occurred while executing the request.

System.NotSupportedException: The type 'System.Int32[,]' is not supported.

at System.Text.Json.ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(Type propertyType)
at System.Text.Json.Serialization.Converters.IEnumerableConverterFactory.CreateConverter(Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.Serialization.JsonConverterFactory.GetConverterInternal(Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonSerializerOptions.GetConverter(Type typeToConvert)

How do I go about serializing an object with (string, multidimensional array)? Also I have a react app that expects a result, the string is going to be serialized as well (has \n\n \r ....), is it the job for the client app to deserialize it or I need to find a way to return the JSON object as it is non-serialized?

like image 380
islamhamdi Avatar asked Mar 01 '23 19:03

islamhamdi


2 Answers

The problem is in fact your int[,] type. You could replace your multidimensional array by int[][], for example.

In fact, the snippet below throws an exception similar to yours.

using System;
using System.Text.Json;
                    
public class Program
{
    public static void Main()
    {
        var example = new int[,]  { { 99, 98, 92 }, { 97, 95, 45 } };
        Console.WriteLine(JsonSerializer.Serialize(example));
    }
}

The exception:

Unhandled exception. System.NotSupportedException: The type 'System.Int32[,]' is not supported.
   at System.Text.Json.ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(Type propertyType)
   ...

However, if you replace the example declaration by an int[][], then we can have:

var example = new int[][]  { new int[] { 99, 98, 92 },  new int[] { 97, 95, 45 }, };

This is serializable to:

[[99,98,92],[97,95,45]]
like image 156
nunohpinheiro Avatar answered Mar 04 '23 09:03

nunohpinheiro


According to How to serialize and deserialize (marshal and unmarshal) JSON in .NET, multi-dimensional arrays are not supported by System.Text.Json:

Supported types include:

  • .NET primitives that map to JavaScript primitives, such as numeric types, strings, and Boolean.
  • User-defined plain old CLR objects (POCOs).
  • One-dimensional and jagged arrays (T[][]).
  • Collections and dictionaries from the following namespaces.
    • System.Collections
    • System.Collections.Generic
    • System.Collections.Immutable
    • System.Collections.Concurrent
    • System.Collections.Specialized
    • System.Collections.ObjectModel

So one option I could see you can do is convert your multi-dimensional array to a list:

public class Result
{
    public string Document { get; set; } = "";

    public IList<IList<int>> Segments { get; set; } = new List<IList<int>>();
}

Or use a jagged array:

public class Result
{
    public string Document { get; set; } = "";

    public int[][] Segments { get; set; } = new int[][] { };
}

UPDATE

Another alternative, if you know the dimensions of the array, is to write a custom getter/setter only for your JSON property. This example assumes the multi-dimension array has 2 as second dimension.

public class Result
{
    public string Document { get; set; } = "";

    [JsonIgnore]
    public int[,] Segments { get; set; } = new int[,] { };

    [JsonPropertyName("segments")]
    public IList<IList<int>> JsonSegments
    {
        get
        {
            var value = new List<IList<int>>();
            for (int i = 0; i < Segments.Length / 2; i++)
            {
                value.Add(new List<int> { Segments[i, 0], Segments[i, 1] });
            }
            return value;
        }
        set
        {
            var dimension = value.Count;
            Segments = new int[dimension,2];
            var index = 0;
            foreach (var item in value)
            {
                if (item.Count == 2)
                {
                    Segments[index, 0] = item[0];
                    Segments[index, 1] = item[1];
                    index += 1;
                }
            }
        }
    }
}
like image 27
Frank Fajardo Avatar answered Mar 04 '23 10:03

Frank Fajardo