-1

Using HttpClient I post a json document to my controller.

   public async Task<string> PostAsync<T>(string url, T doc)
   {
        var json = JsonConvert.SerializeObject(doc);
        var response = await mHttp.PostAsync(url, new StringContent(json));
   }

When I inspect the controller here:

public async Task<ActionResult> Post([FromBody] object doc,string fid)

The object doc has this format:

ValueKind = Object : "{"id": "101zsdfgfgh","fid": "test1",......}

How can Ideserialize this if the type is unknown?

dbc
  • 104,963
  • 20
  • 228
  • 340
Paul Stanley
  • 1,999
  • 1
  • 22
  • 60
  • 1
    Does this answer your question? [Deserialize JSON into C# dynamic object?](https://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object) – Ricardo Pontual Jan 30 '21 at 18:29
  • Was using System.Text.Json – Paul Stanley Jan 30 '21 at 20:44
  • 1
    Then do these answer your question? [C# - Deserializing nested json to nested Dictionary](https://stackoverflow.com/q/65972825/3744182) (the answer shows deserializing to an ExpandoObject) + [System.Text.Json.JsonElement ToObject workaround](https://stackoverflow.com/q/58138793/3744182). – dbc Feb 01 '21 at 01:13

2 Answers2

2

I wanted to convert from JsonDocument like this

dynamic obj=jsonDoc.ToObject();

So I made an extension method. The properties ultimately are JsonElements - that's fine with me, normally I need to do a ToString().

So this is my code (not thoroughly tested, be warned...)

using System.Dynamic;
using System.Text.Json;
using System.Collections.Generic;

namespace MyJsonExtensions
{
    public static class Extensions
    {
        public static object ToObject(this JsonDocument jsonDoc)
        {
            return Convert(jsonDoc.RootElement);
        }

        private static object Convert(JsonElement json)
        {

          if (json.ValueKind!=JsonValueKind.Array && json.ValueKind!=JsonValueKind.Object)
          {
            return json;
          }

          var serialized=JsonSerializer.Deserialize<ExpandoObject>(json.GetRawText());
          var output=new ExpandoObject();
          var outputDict=(IDictionary<string,object>)output;
          
          foreach (var prop in (IDictionary<string,object>)serialized)
          {
            var propValue=(JsonElement)prop.Value;

            switch (propValue.ValueKind)
            {
              case JsonValueKind.Array:
                var list=new List<object>();
                foreach (var item in propValue.EnumerateArray())
                {
                  list.Add(Convert(item));
                }
                outputDict[prop.Key]=list.ToArray();
                break;

              case JsonValueKind.Object:
                ExpandoObject val=new ExpandoObject();
                var node=(IDictionary<string,object>)val;
                foreach (var objElement in propValue.EnumerateObject())
                {
                  var v=Convert(objElement.Value);
                  node.Add(objElement.Name,v);
                }
                outputDict[prop.Key]=val;
                break;

              default:
                outputDict[prop.Key]=prop.Value;
                break;
            }            
          }

          return output;
        }

    }
}
hbjoroy
  • 21
  • 2
0

I might be wrong but if you use a parameter your stuck with

 System.Text.Json 

so I think the answer is not to use a parameter

public async Task<ActionResult> Post([FromBody] object doc,string fid)

change to

public async Task<ActionResult> Post(string fid)

then deserialize the content of the request like this.

   string obj = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
   var doc = JsonConvert.DeserializeObject<dynamic>(obj);

Then you can use JsonConvert to deserialize.Seems to work well.

Paul Stanley
  • 1,999
  • 1
  • 22
  • 60