2

I have an API request that goes off and the response structure back looks like this:

{
    "MessageBody": {
        "foo" : ""
    }
}

The properties under MessageBody can be anything, not only foo, but its value is always a string.

eg. {"MessageBody": { "Token": "abc" }} or {"MessageBody": { "Name": "abc" }}

How can I capture this response from the API as a generic object for the property under MessageBody?

I can represent the first example above as:

public class MessageBody
{
    public string Token { get; set; }
}

How would I represent both Token or Name properties under the same MessageBody object? There's a bunch of different values that MessageBody can have, but again they would all be of type string.

Jimenemex
  • 3,104
  • 3
  • 24
  • 56
  • 6
    Maybe use a `Dictionary` where you can query the keys and support whatever key you need? `public class MyObj { public Dictionary MessageBody {get;set;} }` – Amir Popovich Jul 20 '20 at 18:14
  • 2
    or use `JObject` and json linq – Pavel Anikhouski Jul 20 '20 at 18:18
  • 1
    Declare `Token` as a `JToken`. See: [JSON.NET: Why Use JToken--ever?](https://stackoverflow.com/q/38211719/3744182) and [Deserializing JSON to .NET object using Newtonsoft (or LINQ to JSON maybe?)](https://stackoverflow.com/q/4749639/3744182). – dbc Jul 20 '20 at 19:04
  • 1
    Alternatively, if you really need `Token` to be a string, apply `[JsonConverter(typeof(RawConverter))]` to the property, where `RawConverter` comes from [this answer](https://stackoverflow.com/a/40539360/3744182) to [How can I serialize and deserialize a type with a string member that contains “raw” JSON, without escaping the JSON in the process](https://stackoverflow.com/q/40529125/3744182). – dbc Jul 20 '20 at 19:04
  • 1
    What you have shown is not a valid json. Without the brackets, it's just a piece of text. – Alexander Petrov Jul 20 '20 at 19:09

1 Answers1

2

I have acheived something similar using Newtonsoft

Your route should take the body in as a generic object and it can then be deserialized into any object you'd like:

/*Using this method, the controller will automatically handle
validating proper Json format*/
[HttpPost]
public async Task<IActionResult> Post([FromBody] object Body)
{
     
    /*here you will send the generic object to a service which will deserialize.
    the object into an expected model.*/
       
    customService.HandlePost(Body);
}

Now create an object with any expected fields you would get from the body. (Json2csharp.com is extremely useful!)

public class MessageBody    
{
    public string Token { get; set; } 
    public string Name { get; set; } 

}

Inside your service you can handle the object like this:

using Newtonsoft.Json
using Models.MessageBody

public class customService()
{
    
   public void HandlePost(object body)
   {
      
       var DeserializedBody = JsonConvert.DeserializeObject<MessageBody>(body);

       //Any Values that were not assigned will be null in the deserialized object
       if(DeserializedBody.Name !== null)
       {
          //do something
       }
    
   }

}

This is obviously a very bare bones implementation, error handling will be important to catch any invalid data. Instead of using one object and null fields to get the data you need, I would recommend adding a "subject" route variable (string) that you can use to determine which object to deserialize the body into.

post *api/MessageBody/{Subject}

Alex
  • 375
  • 3
  • 13