Accept a generic JObject as parameter?

Topics: Web Api
Sep 6, 2011 at 3:25 AM

Hi there,

I would like the POST'ed Content to be serialized to some kind of 'dynamic' object, such as JObject or ExpandoObject?

This code should make my intent clear:

        [OperationContract]
        [WebInvoke(UriTemplate = "", Method = "POST", ResponseFormat = WebMessageFormat.Json)]
        public AuthResponse TestPost(JObject jsonObject)
OR
        [OperationContract]
        [WebInvoke(UriTemplate = "", Method = "POST", ResponseFormat = WebMessageFormat.Json)]
        public AuthResponse TestPost(ExpandoObject dynObj)
Is this possible?
Coordinator
Sep 6, 2011 at 3:38 AM

Hi Santiago

1. Don't use ResponseFormat, it is completely ignored in web api. Format is determined based on content negotiation (conneg)

2. We have a custom type called JsonValue which is a dynamic. You can use it for json. You basically put JsonValue on the signature of your methods. If you look in our Preview 4 samples you will see a JsonValue Sample that shows how to use this. JsonValue is not working in our latest code in our repo yet, but we will be updating it to work shortly. You can check out Preview 4 to see play with it now though.

3. You can also author a custom MediaTypeFormatter to handle JObject from JSON.NET or Expando. To do that you will write a custom formatter and register it using the configuration class. The formatter has CanReadAsType and CanWriteAsType methods, you'll want to set those to true if the type is JObject or ExpandoObject. You can see an example of how to do this in the JsonValueMediaTypeFormatter in Preview 4. You will need to insert your formatter at the beginning of the list. In our latest preview you can do this by using the Insert method on the Formatters collection off of the config object.

Thanks
Glenn

Sep 6, 2011 at 5:25 PM

Glenn,

we are now happily and succesfully using JsonValue.

Thanks!

Sep 6, 2011 at 5:49 PM

Just one more thing, I'm using myObject.ToJsonObject()["myKey"].ToString() to extract the values read from the JsonValue parameter and converting them to the appropriate types.

J

Sep 12, 2011 at 3:31 AM

Example usage:

public ApiResponse UnlockAchievement(JsonValue apiRequest)
{  
   dynamic jsonRequest = apiRequest;
   long memberId = jsonRequest.MemberId;

Sep 12, 2011 at 10:09 PM

I've hit a roadblock. Maybe someone can help.

I can receive a JsonValue as an argument. No problems there.
I would like however to use json.net's JValue as an argument.
I have added the custom MediaTypeFormatter.
But the code fails before it even reaches my MediaTypeFormatter:

The service '/api/achievement' cannot be activated due to an exception during compilation.  The exception message is: To be XML serializable, types which inherit from IEnumerable must have an implementation of Add(System.Object) at all levels of their inheritance hierarchy. Newtonsoft.Json.Linq.JValue does not implement Add(System.Object)

If I just replace JValue with JsonValue it all works fine.

Coordinator
Sep 12, 2011 at 11:24 PM

Could you please post the stack trace?

Sep 12, 2011 at 11:32 PM

Have you tried inserting your MediaTypeFormatter into the beginning of the formatter collection so that it gets processed first?

Sep 13, 2011 at 2:30 AM

I was able to easily reproduce the problem with the JsonValue sample from preview 4.

Here is the link to the bug report:

http://wcf.codeplex.com/workitem/73

@Darrel, yes formatter is inserted first. However if you refer to the workitem above you see problem has actually nothing to do with the MediaFormatter.

@danrorth27, I included the stack trace (as much as I could get) in the workitem descr.