4

With webapi it is possible to POST dynamic JSON to an action using either JObject or dynamic as your parameter type:

Passing Dynamic JSON Object to Web API - Newtonsoft Example

If I try this on a non-api action in MVC4 this doesn't seem to work. My action signature is:

public async Task<ActionResult> Post(JObject requestObj)

When I use dynamic I just get a seemingly non-dynamic object. If I try JObject I get the following error:

[MissingMethodException]: Cannot create an abstract class.

Is something similar to this possible on a non-api action in MVC4?

Community
  • 1
  • 1
mutex
  • 7,536
  • 8
  • 45
  • 66
  • Care to explain the downvote so I can improve the question?? – mutex Aug 26 '13 at 21:06
  • Check this out, it might help you out. [Deserialize JSON into C# dynamic object?](http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object) – Reza Shirazian Aug 26 '13 at 21:12
  • @RezaShirazian: Thanks, I know how to deserialize to a dynamic object, was just wondering if there is a method to automatically do it. My current approach is implementing a custom model binder to do it, but was looking for other ideas. – mutex Aug 26 '13 at 21:30
  • Have you found a way to achieve this? – Serhiy Aug 20 '15 at 19:25
  • @Serhiy: See my sample code below. When I originally asked this question I think I was looking for alternative approaches to this sample, but in the end I think it was the only way I could get it to work. (this is going back a while and my memory is a little hazy though :) ) – mutex Aug 21 '15 at 02:43

3 Answers3

3

In a previous project we needed to post dynamic JSON to a Web Api controller. What we ended up doing was taking the JSON on the client side and Base64 encode it. We could then simply post the Base64 encoded JSON to our backend. Our backend then decoded the Base64 input and used Newtonsoft JSON to convert it into a dynamic object (actually it was converted to strongly typed classes and the fallback was dynamic). I agree, it's hacky, but it worked.

Martin
  • 1,634
  • 1
  • 11
  • 24
3

I'm not sure if it will be helpful at all, but I mentioned in my comments above that I ended up using a custom model binder to do this. I dug up what I believe was the original code that prompted this question, and this is what I ended up with:

    public async Task<ActionResult> Post(dynamic request)
    {
        return await ExecuteRequest(request, "application/json");
    }

and a custom model binder as follows (it works on actions called "post" or "public" though you could choose your own convention - and falls back to default on all other actions)

public class MyModelBinder : DefaultModelBinder
{        
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var actionName = controllerContext.RouteData.Values["Action"];
        if (controllerContext.Controller.GetType() == typeof(MyController) && actionName != null && 
            (string.Compare(actionName.ToString(), "post", StringComparison.OrdinalIgnoreCase) == 0 ||
            string.Compare(actionName.ToString(), "public", StringComparison.OrdinalIgnoreCase) == 0))
        {
            string contentText;

            using (var stream = controllerContext.HttpContext.Request.InputStream)
            {
                stream.Seek(0, SeekOrigin.Begin);
                using (var reader = new StreamReader(stream))
                    contentText = reader.ReadToEnd();
            }

            if (string.IsNullOrEmpty(contentText)) return (null);

            return JObject.Parse(contentText);
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

Then register the custom model binder in the beginning of Application_Start:

System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new MyModelBinder();
mutex
  • 7,536
  • 8
  • 45
  • 66
0

It seems to be impossible. Read the MSDN docs https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.aspx:

Action methods cannot have unbounded generic type parameters. An unbounded generic type parameter has an empty parameter list. An unbounded generic type is also known as an open generic type. For information about unbounded generic type parameters, see the section "Unbounded Type Parameters" in Constraints on Type Parameters.

You should derive from APIController, or perhaps create a CustomModelBinder (I'm not sure about this one)

Take a look the following links:

posting a JObject to an action

.NET MVC Action parameter of type object

Can abstract class be a parameter in a controller's action?

Hope it helps!

Community
  • 1
  • 1
Fabio
  • 11,892
  • 1
  • 25
  • 41
  • What if I have a strongly typed Model with one property I want to be binded as JObject? – Serhiy Aug 20 '15 at 20:09
  • Wait, the parameter of the action is a custom class or a JObject? – Fabio Aug 20 '15 at 20:13
  • In my situation there is a custom class for model and a JObject property. – Serhiy Aug 20 '15 at 20:17
  • I am getting "Cannot create an abstract class". – Serhiy Aug 20 '15 at 20:20
  • You can use a string property and convert it to a dynamic object. http://stackoverflow.com/questions/4535840/deserialize-json-object-into-dynamic-object-using-json-net – Fabio Aug 20 '15 at 20:21
  • In that case I will have to pass this value as string from client side(serialized with JSON.stringify). This approach works but looks a bit ugly. – Serhiy Aug 20 '15 at 20:23
  • Indeed. You can also use the `FormCollection` and iterate over the items. http://stackoverflow.com/questions/5022958/passing-dynamic-json-object-to-c-sharp-mvc-controller. This one looks better – Fabio Aug 20 '15 at 20:30