6

I can't serialize tuples. I create a template VS2019 .Net Core API project and replace the controller with:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public List<(int number, string text)> Get()
    {
        var x = new List<(int number, string text)>
        {
            (1, "one"),
            (2, "two"),
            (3, "three")
        };
        return x;
    }

    /*[HttpGet]
    public List<string> Get()
    {
        var x = new List<string>
        {
            "one",
            "two",
            "three"
        };
        return x;
    }*/
}

When called, the first method will return: [{},{},{}] and the second (when uncommented): ["one","two","three"]

Why aren't the tuples serialized? The example is easy to replroduce.

Yehor Androsov
  • 4,885
  • 2
  • 23
  • 40
Marko
  • 1,502
  • 5
  • 21
  • 40

4 Answers4

1

Anonymous objects serialize better than value tuples, but declaring them is more verbose:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IList<object> Get()
    {
        var x = new List<object>
        {
            new {number = 1, text = "one"},
            new {number = 2, text = "two"},
            new {number = 3, text = "three"}
        };
        return x;
    }
}

I think this makes them clearer and more importantly it returns the expected: [{"number":1,"text":"one"},{"number":2,"text":"two"},{"number":3,"text":"three"}]

If you want to be really clear what your API methods are returning then I would declare DTO/model ojects to return.

Richard Garside
  • 87,839
  • 11
  • 80
  • 93
0

I think most serialization libraries use public properties for output generation, and C# 7 tuples are using public fields instead. We can check this by doing some reflection. You can see that if you return object of your own class with public fields only, json response will have the same output. If it does not match your expectations, you could use different serialization strategy. Some handy answers are here

using Microsoft.AspNetCore.Mvc;

namespace WebApplication1.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet]
        public object Get()
        {
            var x = (1, 1);

            var properties = x.GetType().GetProperties(); // count == 0
            var fields = x.GetType().GetFields(); // count == 2

            return x;
        }

        [HttpGet("obj")]
        public object GetMyObj()
        {
            return new MyObj();
        }

        public class MyObj
        {
            public int i = 1;
        }
    }
}
Yehor Androsov
  • 4,885
  • 2
  • 23
  • 40
-1

You need use Newtonsoft.Json to serialize. Install the package from Nuget:

Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.9

And use the below code to serilize it:

var y = JsonConvert.SerializeObject(x);
mj1313
  • 7,930
  • 2
  • 12
  • 32
  • you don't need library to serialize objects, they will be serialized automatically if returned from API controller. this is a workaround, not a direct answer – Yehor Androsov Nov 06 '20 at 08:53
  • Newtonsoft.Json does a slightly better job of serializing value tuples, but it does not get the property names you declare. – Richard Garside Dec 02 '20 at 13:40
-1

You can return an OK response:

[HttpGet]
public IHttpActionResult Get()
{
    var x = new List<(int number, string text)>
    {
        (1, "one"),
        (2, "two"),
        (3, "three")
    };
    return Ok(x);
}
Mike Bovenlander
  • 5,236
  • 5
  • 28
  • 47