0

Please Please Please could somebody help me finish implementing the code below. I followed the example at http://dotnetbyexample.blogspot.com/2012/02/json-deserialization-with-jsonnet-class.html This example is posted all over on lots of blogs.

I'm trying to find a somewhat reusable way to handle abstract parameters in Web API actions. It works perfectly in Fiddler, but the EntityNote returned is null when I try to call Get via HttpClient. I find that the ReadJson method is never called, so Create is also never called. I guess I do not understand the flow of Web API enough to understand where ReadJson is supposed to be called.

Global.asax.cs

config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.LocalOnly;
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new JsonDeviceConverter());

The converter from the link (Nobody shows how to implement WriteJson)

public abstract class JsonCreationConverter<T> : JsonConverter
{
    protected abstract T Create(Type objectType, JObject jsonObject);

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsSubclassOf(typeof(T));
    }

    //This method never gets called
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        var target = Create(objectType, jsonObject);
        serializer.Populate(jsonObject.CreateReader(), target);
        return target;
    }

    //I just kinda guessed at this code
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (this.CanConvert(value.GetType()))
        {
            serializer.Serialize(writer, value);
        }
    }
}

EntityNote is an abstract class with PortalProviderRefundNote as an implementation.

public class JsonDeviceConverter : JsonCreationConverter<EntityNote>
{
    //This method never gets called, because ReadJson is never called
    protected override EntityNote Create(Type objectType, JObject jsonObject)
    {
        var typeName = jsonObject["EntityNote"].ToString();
        switch (typeName)
        {
            case "PortalProviderRefundNote":
                return new PortalProviderRefundNote() { EntityId = 1 };
            default: return null;
        }
    }
}

HttpClient - the tutorial uses the JsonConvert.DeserializeObject, but I can't figure out how that fits in here...ReadAsAsync does this task

//simplified **Suggested Edit**
this.jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
jsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
jsonFormatter.SerializerSettings.Converters.Add(new JsonDeviceConverter());

new HttpClient().GetAsync("http://localhost/api/EntityNotesController/").Result.Content.ReadAsAsync<EntityType>(new List<MediaTypeFormatter>(){ jsonFormatter }).Result;

Service Controller

public EntityNote Get(int id)
{
    return new PortalProviderRefundNote() { EntityId = 1 };
}
2
  • so your converter's ReadJson method never gets called on the client side? Commented Dec 10, 2012 at 21:28
  • I put a breakpoint on it and it never gets called. Like I said, I'm not sure when it's supposed to be called, but it never is. Commented Dec 10, 2012 at 21:38

2 Answers 2

1

You'll need make the same serializer settings changing on the JsonMediaTypeFormatter on the client side as well:

var jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
jsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
jsonFormatter.SerializerSettings.Converters.Add(new JsonDeviceConverter());

response.Content.ReadAsAsync<EntityNote>(new MediaTypeFormatter() { jsonFormatter }).Result;
Sign up to request clarification or add additional context in comments.

1 Comment

That makes perfect sense, but this addition (as shown in the original question) did not resolve the issue
0

I switched to XML and used the KnownType attribute. This works out of the box. I'd be interested to know if there is a solution with JSON, but this works good enough.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.