Use Json.Net as default formatter in MVC, Not API [duplicate] - asp.net-mvc

This question already has answers here:
Setting the default JSON serializer in ASP.NET MVC
(2 answers)
Closed 8 years ago.
I just solved a recent problem where Json.Net allows me to include the 'type' of an object when it serializes it going to the Client. The reason for this is that the class that I'm sending back and forth has a property that is typed as a BaseClass to 4 Subclasses. The great thing now is that my client is showing each one correctly with the type attribute on the Json.
Now I need to send the object back to my Controller, not to an API controller. I've seen a bunch of posts about the api controller using Json.Net as the default JsonFormatter, but this doesn't work for a regular MVC Controller.
So my question is....How can I get my Controller to use the Json.Net Serializer by default? And...will this cause an issue for other items potentially making ajax calls?
I was able to send my json back to my controller as a string and then use JsonConvert to Deserialize my object successfully, so I know it can be done.
Any thoughts are appreciated.
EDIT:
Ok, so I followed the instructions here to change out the JsonValueProviderFactory and that seems to be working, however its not helping the original issue.
The problem is that the JsonFormatter is still the old one and not using Json.Net. So the ProviderFactory is building the dictionary correctly, but when it tries to Deserialize my object, I'm only getting my properties cast as the BaseClass, and not the Derived Class that I'm expecting.
Thoughts on that part?
EDIT:
Simply...how do I create my own JsonNetMediaTypeFormatter in MVC4? I've changed the ProviderFactory, but that only changes how each individual parameter is serialized to its corresponding value. What I need to do is to use Json.Net so that my Parameters that are typed as a Hierarchy is serialized to the correct derived class...not typed as the Baseclass.
Edit - Last:
Ok...so I did verify that if I call an ApiController, it maps the incoming parameter with the correct subclass. So, I can go this route, but I'd really like to find a way to have the same result with my regular Controller.

I had the same issue and resolved it by simply overriding the Json method on my base controller class.
EX:
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
{
var result = new JsonNetResult
{
Data = data,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior
};
return result;
}

Related

How to bind JSON to model within a method?

I understand that MVC4 can automatically bind json to type models.
For example, take an HTMLItem model.
In part of a method I retrieve the HTMLItem model data in json format from an external site using HttpRequest and StreamReader. I grab this as a string and then want to pass it into another method that takes HTMLItem as a parameter.
How do I ensure that the receiving method handles this as the type I require (HTMLItem)? It currently doesn't recognise it as such.
I tried assigning the string to the model in the originating method, but the IDE gives me the red squiggly for assigning a string to another type.
I don't want to have to go through the json string and assign each field manually if possible.
Any help, as always, much appreciated. Thanks.
You could deserialize the JSON to your model like:
using System.Web.Script.Serialization;
...
JavaScriptSerializer serializer = new JavaScriptSerializer();
YourModelType model = serializer.Deserialize<YourModelType>(yourJSON);

Mvc4 default model binder - Dictionary

I have a form which posts these values:
survey[0].Key 75
survey[0].Value 4
survey[1].Key 76
survey[1].Value 4
I'm trying to use a default model binder to map it onto Dictionary type:
[HttpPost]
public ActionResult CompleteSurvey(Dictionary<int, int> answers)
{
...
}
but I get InvalidCastException: Specified cast is not valid.
Why??
Im just guessing here but i think It's because your argument is called 'answers' not 'survey'. You should look at what is being posted to your method by looking in the post headers easy to do in firebug or chrome. It makes more sense when you inspect the stuff being transmitted 'over the wire'
The cast not valid thing is probably because in your scenario answers is null when the model binder wants to do its job. If you used formscollection instead of dictionary you'd find everything you post is there.
For some strange reason when I removed "survey" and left iteration by itself (i.e. [0].Key) binding works fine.
I was basing my knowledge on this article:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
which appears to be wrong then??? or does it refer to the previous versions of MVC???

Best way to add filter to URL in .NET MVC

I'll try to make this as concise as possible.
Webpage contains a table that allows for filtering and sorting
Changes to filtering and sorting should be reflected in the URL so the user can bookmark or share filtered views.
The question is: What is an effective convention of allowing all of the sort and filter syntax to be part of the URL and easily interpret/use it on the server without having to write a bunch of custom code that interprets it?
I've been doing some research and I came across the OData URI conventions and I like the way they do things.
http://www.odata.org/developers/protocols/uri-conventions
More research shows the the MVC 4 Web API allows for use of that convention by returning an IQueryable. This looks fantastic except for one part... I'm not implementing a RESTful API at this point and that's all it seems to work with. So how can I use something like OData and still return a View or PartialView? Is there something that will parse the OData URI convention into a C# object?
If anyone has any insights into this problem or suggestions, I'm all ears.
As for the url convention part of your question, I think you have answered your own question with OData. As for getting this data into a C# object I would use the following approach:
Use an action filter to interperet the url parameters and parse them into a c# object.
In your action filter add the url parameters to the route data and the c# object will be available in your action.
ASP.NET MVC Pass object from Custom Action Filter to Action
Take a look at the Telerik MVC grid, they use a GridAction action filter that does pretty much what you are asking.
I would look at custom model binding. A good overview can be found here: http://weblogs.asp.net/nmarun/archive/2010/02/25/asp-net-mvc-model-binding.aspx
It's typically used for POST requests with forms but there's no reason why you can't use it for GET requests too.
Basically, your approach should be to:
Create a new Model class with your filter/sorting parameters as properties:
public class TableParameters {
public string TableFilter { get; set; }
}
In your Controller's Action, add the model as a parameter
public ActionResult TableAction(TableParameters parameters) { /* Action logic */ }
Set your parameters in the URL by saying:
/Controller/TableAction?TableFilter=[your-filter-string]
The parameters object in your action will have the property populated with the value from the query string.

ModelBinding a single parameter within an Action

Due to some refection-fu I want to use the MVC ModelBinders to bind the request to an object with a name and Type that is only known at runtime.
e.g.
public ActionResult BindSomething()
{
Type type = typeof(Some.Type);
string parameterName = "someParameter"; //this corresponds to a particular form input name
var binder = Binders.GetBinder(desiredType, true);
var x = binder.BindModel(this.ControllerContext, ???) //??? should be a ModelBindingContext. Where can I get this from
return View(x);
}
I think I need to get hold of the ModelBindingContext, or create a new, valid one, but how do I do this?
edit: apologies if I wasn't clear enough - I already know about TryUpdateModel, but, as far as I understand it that binds ALL the posted values to properties of the model object you pass in. I just want to get the corresponding object for a single posted parameter.
You can use TryUpdateModel as rouen suggested, you could also implement a custom model binder that can bind the correct type. This approach has the advantage of letting you deal with Interfaces or Abstract models and keeps your binding code out of your actions. It's a little neater but I would only really recommend it if it's going to be reused in other parts of your code.
Use controller method TryUpdateModel
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.tryupdatemodel.aspx
It will choose appropriate binder according argument type and perform model binding for you.

Silverlight and MVC: post object to controller method

I have an MVC project in which a controller action returns some JSON data (i.e. via /Home/GetData URL). This action also takes a custom object as a param.
This signature for the action is JsonResult GetData (MyCustomObject o)
I also have a client Silverlight project in which I'm constructing MyCustomObject and trying to call this URL (/Home/GetData/) via HttpWebRequest. However, I'm having trouble figuring out how to post in my object in this call. Do I need to serialize it to Json in order to pass it in?
Thanks so much!
MVC can accept and bind the submitted data to your MyCustomObject object, regardless of whether it is submitted as JSON, XML, a query string, a standard form POST, etc.
MVC does not require the object to be submitted in a particular fashion. That is up to you as the designer to determine what works best under the particular circumstances, given all of your requirements.
When submitted, MVC will use the ValueProvider suitable to the form of the data submitted, and the DefaultModelBinder will attempt to use the values in the ValueProvider to bind to your model.
Thanks for your help! Since the web app handles this with a getJSON call, I ended posting the object as a query string param i.e. I'm making a web request to http://../controller/action/view.aspx?custObject.property1=<value>&custObject.property2=<value> etc

Resources