1

I'm experimenting with the MVC4 WebApi for building rest/json services.

In my controller I have the method:

    public HttpResponseMessage Post(dynamic message)

This contains a single object which always has two fields, type and action.

Action is either Create or Cancel.

I wrote three classes, Message, CreateMessage and CancelMessage, Message is the base class the other two inherit.

After reading the blurb on dynamic I thought I'd be able to do this:

    public void ProcessMessage(dynamic message)
    {
        switch ((string)message.action)
        {
            case "CREATE":
                ProcessCreateMessage(message);
                break;
            case "CANCEL":
                ProcessCancelMessage(message);
                break;
        }
    }

    private void ProcessCancelMessage(CancelMessage message)
    {
          //Cancell
    }

    private void ProcessCreateMessage(CreateMessage message)
    {
        //Create
    }

But I just get either a message about there not being an overload (implicit cast) or "Cannot convert type 'Newtonsoft.Json.Linq.JObject' to 'CancelMessage'"

The classes

public class Message
{
    public string type { get; set; }
    public string action { get; set; }
}

public class CancelMessage : Message
{
    public string ref { get; set; }
    public string message { get; set; }
}

The Json:

{
    "type" : "type",
    "action" : "cancel",
    "ref" : "RefNo",
    "message" : "a message"
}

What am I not getting here?

RoboJ1M
  • 1,590
  • 2
  • 27
  • 34

3 Answers3

2

You can deserialize JSON to c# object like

var cancelMessage = new JavaScriptSerializer().Deserialize<CancelMessage>(message);

I think that you can't cast string(JSON) to object by default.

sglogowski
  • 321
  • 3
  • 12
1

Please go through Arcrain's answer.

Deserializing JSON to .NET object using Newtonsoft (or LINQ to JSON maybe?)

I think in your case It will help you from the same url link.

You can use the C# dynamic type to make things easier. This technique also makes re-factoring simpler as it does not rely on magic-strings.

Json

The json string below is a simple response from an http api call and it defines two properties: Id and Name.

{"Id": 1, "Name": "biofractal"}

C#

Use JsonConvert.DeserializeObject<dynamic>() to deserialize this string into a dynamic type then simply access its properties in the usual way.

var results = JsonConvert.DeserializeObject<dynamic>(json);
var id = results.Id;
var name= results.Name;

Note: The NuGet link for the NewtonSoft assembly is http://nuget.org/packages/newtonsoft.json

Hope it will resolve your problem.

Community
  • 1
  • 1
Janty
  • 1,708
  • 2
  • 15
  • 29
  • I don't have the Json though, I already have a dynamic object. I tried `var cancelMessage = JsonConvert.DeserializeObject(message);` and I just get a runtime error saying Deserialize expects a string. – RoboJ1M Jul 30 '14 at 08:12
  • @RoboJ1M try JsonConvert.DeserializeObject(message); – Janty Jul 30 '14 at 08:21
  • I've got it, `var createMessage = JsonConvert.DeserializeObject(message.ToString());` where message is a JObject. JObject's ToString() overload returns the underlying Json string – RoboJ1M Jul 30 '14 at 08:55
  • Ok Good try..well done...thanks i will also care about it in future. – Janty Jul 30 '14 at 09:09
0

Here's another solution, using information posted by Janty and Babinicz

Using the ApiController in MVC 4 as I am, if you state dynamic as your single incoming parameter.

(I'm following Microsoft's beginner's guides to Web Api in MVC4)

When you try to cast dynamic to something, it's supposed to magically work, but I was getting an error.

Tried writing a custom cast operator, but you can't do that to or from dynamic

But it appears that dynamic is a lot like object in that it knows what it's underlying type is, and that type is Newtonsoft's JObject

And that casting to and from dynamic just does normal casting, compiled at runtime instead of design time.

So by adding implicit cast operators to the model classes:

public class Message
{
    public string type { get; set; }
    public string action { get; set; }
}

public class CancelMessage : Message
{
    public string ref { get; set; }
    public string message { get; set; }

    public static implicit operator CancelMessage(JObject message)
    {
        var output = JsonConvert.DeserializeObject<CancelMessage>(message.ToString());            
        return output;
    }
}

public void ProcessMessage(dynamic message)
{
    switch ((string)message.action)
    {
        case "CANCEL":
            ProcessCancelMessage(message);
            break;
    }
}

private void ProcessCancelMessage(CancelMessage message)
{
      //Cancel
}

That just works.

Of course, it's also arguable that if I just pass this dynamic thing around, my code will just work as long as the field names in the json match what's expected.

RoboJ1M
  • 1,590
  • 2
  • 27
  • 34