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?
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.
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With